Ответ
Стратегия обработки пропусков зависит от природы данных, доли пропусков и типа признака. Я выбираю метод исходя из этого анализа.
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 стояло.