Какие методы обработки пропущенных значений (missing values) вы используете?

Ответ

Стратегия обработки пропусков зависит от природы данных, доли пропусков и типа признака. Я выбираю метод исходя из этого анализа.

1. Удаление (Deletion):

  • Удаление строк: Применимо, если пропусков мало (<5%) и они случайны (MCAR). Риск — потеря данных.
    df_dropped_rows = df.dropna(axis=0)
  • Удаление столбцов: Если признак имеет очень высокий процент пропусков (>40-50%) и не является критически важным.
    df_dropped_cols = df.dropna(axis=1, thresh=len(df)*0.5) # Удаляем колонки, где >50% NaN

2. Замена константами (Imputation with Constants):

  • Для числовых признаков: 0, -1, или крайнее значение (например, 999).
  • Для категориальных признаков: отдельная категория 'Missing' или 'Unknown'.
    df_filled = df.copy()
    df_filled['age'].fillna(-1, inplace=True)
    df_filled['education'].fillna('Unknown', inplace=True)

3. Замена статистическими метриками (Statistical Imputation):

  • Среднее (Mean) или Медиана (Median): Для числовых признаков. Медиана более устойчива к выбросам.
    median_age = df['age'].median()
    df['age'].fillna(median_age, inplace=True)
  • Мода (Mode): Для категориальных признаков.
    most_frequent_city = df['city'].mode()[0]
    df['city'].fillna(most_frequent_city, inplace=True)

4. Импутация с использованием моделей (Model-Based Imputation): Более продвинутый подход, где пропуски предсказываются на основе других признаков.

  • K-Nearest Neighbors (KNNImputer): Заменяет пропуск средним значением от k наиболее похожих наблюдений.
    from sklearn.impute import KNNImputer
    imputer = KNNImputer(n_neighbors=5, weights='uniform')
    df_imputed = pd.DataFrame(imputer.fit_transform(df_numeric), columns=df_numeric.columns)
  • Итеративная импутация (IterativeImputer): Моделирует каждый признак с пропусками как функцию других признаков (часто на основе регрессии).
    from sklearn.experimental import enable_iterative_imputer
    from sklearn.impute import IterativeImputer
    from sklearn.ensemble import RandomForestRegressor
    imputer = IterativeImputer(estimator=RandomForestRegressor(), random_state=42)
    df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)

5. Интерполяция (Interpolation): В основном для временных рядов, где есть естественный порядок.

df['temperature'] = df['temperature'].interpolate(method='time') # Учитывает временные интервалы
# или линейная интерполяция
df['value'] = df['value'].interpolate(method='linear')

Важное правило: Метод импутации, рассчитанный на трейновой выборке (например, медиана), должен быть сохранен и применен к валидационной и тестовой выборкам для корректной оценки модели. Я всегда создаю флаги is_missing для важных признаков, чтобы модель знала, что значение было пропущено.

Ответ 18+ 🔞

А, ну вот, опять эти пропуски в данных, ебать мои старые костыли. Слушай, тут главное — не тупить и не лепить везде одно и то же. Сначала смотришь, что за признак и сколько там дыр, а потом уже решаешь, какую дичь применить.

1. Просто выкинуть нахуй (Deletion):

  • Строки выкинуть: Если пропусков кот наплакал, ну там меньше 5%, и они как попало разбросаны. Риск — данных станет меньше, но иногда это лучше, чем говно в данные пихать.
    df_dropped_rows = df.dropna(axis=0)
  • Столбцы выкинуть: А вот если в какой-то колонке овердохуища пропусков, больше половины, и она не особо важная — нахуй её, не жалко.
    df_dropped_cols = df.dropna(axis=1, thresh=len(df)*0.5) # Выкидываем колонки, где >50% NaN

2. Забить чем попало (Imputation with Constants):

  • Для циферок: Можно нулём, минус единицей, или вообще какой-нибудь дичью вроде 999, чтобы потом модель поняла, что это левый артефакт.
  • Для категорий: Просто создаёшь новую категорию 'Missing' или 'Unknown'. Пусть модель сама разбирается, что это за зверь.
    df_filled = df.copy()
    df_filled['age'].fillna(-1, inplace=True)
    df_filled['education'].fillna('Unknown', inplace=True)

3. Забить средним по больнице (Statistical Imputation):

  • Среднее (Mean) или Медиана (Median): Для чисел. Медиана обычно круче, потому что если в данных есть уроды-выбросы, она их не так сильно боится.
    median_age = df['age'].median()
    df['age'].fillna(median_age, inplace=True)
  • Мода (Mode): Для категориальных. Берёшь самое частое значение и лепишь его везде, где дыра. Просто, как три копейки.
    most_frequent_city = df['city'].mode()[0]
    df['city'].fillna(most_frequent_city, inplace=True)

4. Умная замена через модели (Model-Based Imputation): Вот это уже поинтереснее, тут нужно думать. Пропуски предсказываются на основе других колонок.

  • K-Nearest Neighbors (KNNImputer): Ищешь пять (или сколько задашь) самых похожих строк и берёшь у них среднюю температуру по больнице.
    from sklearn.impute import KNNImputer
    imputer = KNNImputer(n_neighbors=5, weights='uniform')
    df_imputed = pd.DataFrame(imputer.fit_transform(df_numeric), columns=df_numeric.columns)
  • Итеративная импутация (IterativeImputer): Вообще хитрая жопа. Каждый признак с дырой моделируется как функция от других признаков, обычно через регрессию. Круто, но и считать будет дольше.
    from sklearn.experimental import enable_iterative_imputer
    from sklearn.impute import IterativeImputer
    from sklearn.ensemble import RandomForestRegressor
    imputer = IterativeImputer(estimator=RandomForestRegressor(), random_state=42)
    df_imputed = pd.DataFrame(imputer.fit_transform(df), columns=df.columns)

5. Интерполяция (Interpolation): Это чисто для временных рядов, где есть порядок во времени. Между двумя известными точками проводишь линию и берёшь значение.

df['temperature'] = df['temperature'].interpolate(method='time') # Учитывает время между замерами
# или просто линейно
df['value'] = df['value'].interpolate(method='linear')

И главное правило, ёпта: Если ты на тренировочных данных посчитал медиану, чтобы дыры затыкать, то эту же, блядь, медиану ты должен использовать и на валидации, и на тесте. Нельзя пересчитывать заново, иначе всё, доверия ебать ноль. И ещё лайфхак: создавай флаги is_missing для важных признаков. Пусть модель знает, что вот тут значение было пропущено, а не просто -1 стояло.