Лаб. работа "Предобработка данных"

Лабораторная работа: Методы предобработки данных в интеллектуальных системах

Цель работы

Изучение и практическое применение основных методов предобработки данных: обработка пропусков, кодирование категориальных признаков, масштабирование числовых признаков и работа с выбросами. Формирование навыков подготовки наборов данных для их использования в моделях машинного обучения.

Краткие теоретические сведения

Предобработка данных (Data Preprocessing) — это этап подготовки “сырых” данных к анализу и построению моделей. Качество данных напрямую влияет на производительность и точность интеллектуальных систем. Основные задачи предобработки включают:

  1. Обработка пропущенных значений: Данные могут отсутствовать по разным причинам. Основные стратегии:

    • Удаление: Удаление строк или столбцов с пропусками. Целесообразно, если пропусков мало или столбец неинформативен.
    • Заполнение (Imputation): Замена пропусков некоторым значением:
      • Среднее (mean): Для числовых признаков без сильных выбросов.
      • Медиана (median): Для числовых признаков с выбросами, так как медиана более устойчива к ним.
      • Мода (mode): Для категориальных признаков (заполнение наиболее часто встречающимся значением).
      • Константа: Заполнение нулем, строкой “unknown” и т.д.
  2. Кодирование категориальных признаков: Большинство моделей машинного обучения работают с числами, поэтому текстовые категории нужно преобразовать.

    • Label Encoding (Порядковое кодирование): Каждой уникальной категории присваивается целое число (0, 1, 2…). Подходит для порядковых признаков, где есть естественная иерархия (например, “плохо”, “хорошо”, “отлично”).
    • One-Hot Encoding (Прямое кодирование): Для каждой категории создается новый бинарный столбец (0 или 1). Подходит для номинальных признаков, где нет порядка (например, “красный”, “зеленый”, “синий”).
    Исходный признакLabel EncodingOne-Hot Encoding (color_red, color_green)
    red01, 0
    green10, 1
    red01, 0
  3. Масштабирование числовых признаков: Признаки с разными диапазонами значений (например, возраст от 0 до 100 и доход от 20 000 до 200 000) могут некорректно влиять на модели, основанные на расстоянии (kNN, SVM) или градиентном спуске.

    • Стандартизация (Standardization): Приводит данные к распределению со средним $0$ и стандартным отклонением $1$. $$ Z = \frac{x - \mu}{\sigma} $$ где $\mu$ — среднее значение, $\sigma$ — стандартное отклонение.
    • Нормализация (Normalization): Масштабирует данные в заданный диапазон, обычно $[0, 1]$. $$ X_{norm} = \frac{x - x_{min}}{x_{max} - x_{min}} $$ где $x_{min}$ и $x_{max}$ — минимальное и максимальное значения признака.
  4. Обработка выбросов (Outliers): Выбросы — это значения, которые сильно отличаются от основной массы данных. Они могут искажать результаты обучения. Один из популярных методов их обнаружения — метод межквартильного размаха (IQR). Выбросами считаются значения, выходящие за пределы:

    • Нижняя граница: $Q_1 - 1.5 \times IQR$
    • Верхняя граница: $Q_3 + 1.5 \times IQR$ где $Q_1$ — первый квартиль (25-й перцентиль), $Q_3$ — третий квартиль (75-й перцентиль), $IQR = Q_3 - Q_1$.

Порядок выполнения работы

Работа выполняется в среде Python с использованием библиотек pandas, numpy, scikit-learn и matplotlib/seaborn.

  1. Подготовка окружения. Установите необходимые библиотеки, если они отсутствуют:

    1pip install pandas numpy scikit-learn matplotlib seaborn
    
  2. Загрузка и первичное исследование данных. Мы будем использовать классический набор данных “Титаник”, который содержит пропуски, категориальные и числовые признаки.

     1import pandas as pd
     2import numpy as np
     3import seaborn as sns
     4import matplotlib.pyplot as plt
     5
     6# Загружаем датасет из библиотеки seaborn
     7df = sns.load_dataset('titanic')
     8
     9# Выводим общую информацию о датасете
    10print("Информация о датасете:")
    11df.info()
    12
    13# Выводим первые 5 строк
    14print("\nПервые 5 строк датасета:")
    15print(df.head())
    16
    17# Статистика по числовым признакам
    18print("\nСтатистика по числовым признакам:")
    19print(df.describe())
    
  3. Обработка пропущенных значений. Найдем столбцы с пропущенными значениями.

    1print("\nКоличество пропусков в каждом столбце:")
    2print(df.isnull().sum())
    
    • age (возраст): Заполним пропуски медианным значением, так как распределение возраста может быть скошенным.
    • embarked (порт посадки): Это категориальный признак. Заполним пропуски модой.
    • deck (палуба): Слишком много пропусков. Этот столбец проще удалить.
    • embark_town: Дублирует информацию embarked, его тоже можно удалить.
     1# Заполнение 'age' медианой
     2median_age = df['age'].median()
     3df['age'].fillna(median_age, inplace=True)
     4
     5# Заполнение 'embarked' модой
     6mode_embarked = df['embarked'].mode()[0]
     7df['embarked'].fillna(mode_embarked, inplace=True)
     8
     9# Удаление столбцов
    10df.drop(['deck', 'embark_town'], axis=1, inplace=True)
    11
    12# Проверяем, что пропусков не осталось (кроме 'age' и 'embarked')
    13print("\nКоличество пропусков после обработки:")
    14print(df.isnull().sum())
    
  4. Кодирование категориальных признаков. Преобразуем столбцы sex, embarked, class, who, adult_male, alive, alone. Для примера используем One-Hot Encoding для sex и embarked.

     1# Применение One-Hot Encoding к 'sex' и 'embarked'
     2df_processed = pd.get_dummies(df, columns=['sex', 'embarked'], drop_first=True)
     3
     4# Удалим и другие некатегориальные, но не числовые столбцы для упрощения
     5# Или те, что не несут пользы для гипотетической модели
     6df_processed.drop(['pclass', 'who', 'adult_male', 'class', 'alive', 'alone'], axis=1, inplace=True)
     7
     8
     9print("\nДатасет после One-Hot Encoding:")
    10print(df_processed.head())
    

    drop_first=True используется для удаления одного из новых столбцов, чтобы избежать мультиколлинеарности (избыточности).

  5. Масштабирование числовых признаков. Применим стандартизацию к признакам age и fare.

    1from sklearn.preprocessing import StandardScaler
    2
    3scaler = StandardScaler()
    4# Выбираем столбцы для масштабирования
    5cols_to_scale = ['age', 'fare']
    6df_processed[cols_to_scale] = scaler.fit_transform(df_processed[cols_to_scale])
    7
    8print("\nДатасет после масштабирования 'age' и 'fare':")
    9print(df_processed.head())
    
  6. Работа с выбросами (на примере fare). Визуализируем признак fare до и после обработки выбросов.

     1plt.figure(figsize=(10, 4))
     2plt.subplot(1, 2, 1)
     3sns.boxplot(y=df_processed['fare'])
     4plt.title('Boxplot для Fare (до обработки выбросов)')
     5
     6# Расчет IQR для 'fare'
     7Q1 = df_processed['fare'].quantile(0.25)
     8Q3 = df_processed['fare'].quantile(0.75)
     9IQR = Q3 - Q1
    10lower_bound = Q1 - 1.5 * IQR
    11upper_bound = Q3 + 1.5 * IQR
    12
    13# Ограничение выбросов (Capping)
    14df_processed['fare'] = np.where(df_processed['fare'] > upper_bound, upper_bound, df_processed['fare'])
    15df_processed['fare'] = np.where(df_processed['fare'] < lower_bound, lower_bound, df_processed['fare'])
    16
    17plt.subplot(1, 2, 2)
    18sns.boxplot(y=df_processed['fare'])
    19plt.title('Boxplot для Fare (после обработки выбросов)')
    20plt.tight_layout()
    21plt.show()
    22
    23print("\nФинальный вид обработанного датасета:")
    24print(df_processed.head())
    

Задания для самостоятельной работы

Задание 1

  1. Повторить все шаги, описанные в разделе “Порядок выполнения работы”.
  2. В отчете подробно описать каждый шаг, приложить фрагменты кода и результаты его выполнения (вывод info, head, describe, графики).
  3. В заключении ответить на вопрос: почему для заполнения age была выбрана медиана, а не среднее?

Задание 2

  1. Загрузить датасет “Титаник”.
  2. Для обработки пропусков в столбце age использовать среднее значение.
  3. Для кодирования признака sex применить Label Encoding вместо One-Hot Encoding.
  4. Масштабировать признаки age и fare с помощью нормализации (MinMaxScaler).
  5. Сравнить статистические показатели (describe()) датасета до и после масштабирования.
  6. В заключении проанализировать, в каких случаях применение Label Encoding для признака sex может быть некорректным.

Задание 3

  1. Загрузить датасет “Титаник”.
  2. Столбец age с пропусками не заполнять, а удалить все строки, где возраст не указан. Сравнить размер датасета до и после удаления.
  3. Категориальные признаки sex и embarked закодировать с помощью One-Hot Encoding.
  4. Выполнить стандартизацию для признака fare.
  5. Найти и удалить выбросы в признаке fare по методу IQR (удалить строки, а не ограничить значения).
  6. В заключении оценить, какой подход к обработке пропусков в age (удаление строк или заполнение медианой) привел к большей потере данных.

Требования к отчету

Отчет по лабораторной работе должен содержать:

  1. Цель работы.

  2. Постановка задачи в соответствии с вариантом.

  3. Ход работы: последовательное описание выполненных шагов с приведением ключевых фрагментов кода, скриншотов и/или таблиц с результатами (например, вывод .info(), .describe(), .head()).

  4. Графики и их анализ (например, boxplot для выбросов).

  5. Выводы по работе, включающие ответы на вопросы из задания по варианту и общую оценку проделанной работы.

Контрольные вопросы

  1. Зачем нужна предобработка данных? Какие проблемы она решает?
  2. В чем разница между заполнением пропусков средним, медианой и модой? Когда какой метод предпочтительнее?
  3. Объясните разницу между стандартизацией и нормализацией. Для каких алгоритмов масштабирование признаков критически важно?
  4. В чем принципиальное отличие One-Hot Encoding от Label Encoding? Приведите примеры признаков, для которых подходит каждый из этих методов.
  5. Что такое выбросы и какими методами их можно обнаружить и обработать?
← Лаб. работа "Сбор данных с помощью … Лаб. работа "Машинное обучение: … →