🐼 Pandas-задача с подвохом: “Почему ничего не работает?”
📘 Условие
Дано: DataFrame
df
:
import pandas as pd
import numpy as np
df = pd.DataFrame({
'user_id': [1, 1, 2, 2, 3, 3],
'score': [100, 90, np.nan, 85, 75, 95]})
Ты хочешь:
1) Для каждого пользователя найти средний score
,
2) Заполнить пропущенные значения score
средним по этому пользователю.
Ты пишешь код:
df['score_filled'] = df.groupby('user_id')['score'].apply(lambda x: x.fillna(x.mean()))
Ожидаешь, что пропущенное значение будет заменено на `85.0`.
Но вместо этого… возникает ошибка или неверный результат.
❓ Вопрос:
1) Почему этот код не работает как ты ожидаешь?
2) Какое поведение apply()
вызывает подвох?
3) Как правильно решить задачу?
—
✅ Разбор:
💥 Проблема в `.apply()` + присваивание по индексу
Функция `groupby().apply()` возвращает **объединённый результат с вложенным индексом**, который **не совпадает с индексом исходного DataFrame**.
Пример:
“`python
df.groupby(‘user_id’)[‘score’].apply(lambda x: x.fillna(x.mean()))
“`
→ возвращает Series с уровнем индекса: `(user_id, original_index)`,
а `df[‘score_filled’] = …` ожидает индекс, совпадающий с `df.index`.
📌 Результат: pandas либо выбрасывает `ValueError`, либо вставляет неправильные значения.
✅ Правильные способы
Способ 1: использовать `transform` (индекс сохраняется!):
“`python
df[‘score_filled’] = df[‘score’].fillna(
df.groupby(‘user_id’)[‘score’].transform(‘mean’)
)
“`
Способ 2: в два шага:
“`python
user_means = df.groupby(‘user_id’)[‘score’].transform(‘mean’)
df[‘score_filled’] = df[‘score’]df.loc[df[‘score’].isna(), ‘score_filled’] = user_means
“`
🎯 Так `NaN` будет корректно заполнен значением `85.0`.
⚠️ Подвох
• `groupby().apply()` не гарантирует совпадение индексов
• `transform()` — безопаснее, если хочешь сохранить структуру
• Даже опытные часто используют `apply` “по привычке” и попадают в ловушку
• Такие ошибки не всегда приводят к crash — они хуже: создают **тихие баги**
Хочешь сделать вторую часть , ставь 👍