groupby mean и median
Имеется датафрейм:
df.head()
title birthday today age
0 Group 1 1997-07-24 2020-05-04 8320 days
1 Group 1 1997-07-24 2020-05-04 8320 days
2 Group 1 1997-07-24 2020-05-04 8320 days
3 Group 1 1997-07-24 2020-05-04 8320 days
4 Group 1 1997-07-24 2020-05-04 8320 days
<class 'pandas.core.frame.DataFrame'>
Int64Index: 329739 entries, 0 to 350675
Data columns (total 4 columns):
title 329739 non-null object
birthday 329739 non-null datetime64[ns]
today 329739 non-null datetime64[ns]
age 329739 non-null timedelta64[ns]
dtypes: datetime64[ns](2), object(1), timedelta64[ns](1)
memory usage: 22.6+ MB
Мне необходимо узнать максимальный, минимальный, средний и медианный возраст на каждом курсе. Но применение
df[['age', 'title']].groupby('title').agg(['max', 'min', 'mean', 'median'])
Выдает ошибку
ValueError: no results
Однако считаются максимальные и минимальные значения, а также mean и median без группировки:
df['age'].median()
Timedelta('10684 days 00:00:00')
Заранее благодарю!
Ответы (2 шт):
Проблема в том, что тип данных timedelta64[ns] - нечисловой и поэтому Pandas не позволяет делать агрегирование. Поэтому можно сначала создать виртуальный числовой столбец (например вычленить число дней из timedelta64[ns]) и тогда уже делать арифметику с ним:
In [51]: (df
.assign(days=df["age"].dt.days)
.groupby('title')
["days"]
.agg(['max', 'min', 'mean', 'median']))
Out[51]:
max min mean median
title
Group 1 8320 8320 8320 8320
Короткое решение (одно из возможных) - примените методы серии:
df[['age', 'title']].groupby('title').agg(['max', 'min', pd.Series.mean, pd.Series.median])
Результат:
age max min mean median title Group 1 8320 days 8320 days 8320 days 8320 days
Анализ проблемы и объяснение:
Многие методы класса DataFrame имеют ключевой параметр numeric_only; у метод класса Series такого параметра нет.
Примеры таких методов: Все, которые вы применили: .max(), .min(), .mean(), .median().
Параметр numeric_only определяет столбцы, ко которым метод будет приниматься. У него 3 возможные значения:
None(стандартное значение) - то же самое, какFalse,True- только столбцы типаint,floatиbool,False- все столбцы, для которых метод умеет работать.
При применении методов класса DataFrame к объектам типа DataFrameGroupBy (ваш случай) используется индивидуальное значение параметра numeric_only в зависимости от конкретного метода, например в вашем случае:
- для метода
.max(): стандартное значение (None), - для метода
.min(): стандартное значение (None), - для метода
.mean():.mean(numeric_only=True) - для метода
.median():.median(numeric_only=True)
Вы применяете эти 4 методы для вашего столбца 'age', который типа ни int, ни float, ни bool. Значит, он будет исключен из применения методов .mean() и .median(), что мешает сделать комплектный результат в виде таблицы со всеми 4 вами требуемыми столбцами и выдает ошибку
ValueError: no results
Как это обойти — несколько примеров:
Применить методы класса
Series, которые работают всегда, когда возможнопрямо (как я это сделал в начале ответа):
df[['age', 'title']].groupby('title').agg(['max', 'min', pd.Series.mean, pd.Series.median])использованием этой идеи для вами созданной или ламбда функции, например
def my_mean(series): return series.mean() df[['age', 'title']].groupby('title').agg(['max', 'min', my_mean, lambda s: s.median()])
Использованием методов класса
DataFrameс параметромnumeric_only=Falseдля создания (и в последствии применения) собственной функций, например так:from functools import partial my_mean = partial(pd.DataFrame.mean, numeric_only=False) my_median = partial(pd.DataFrame.median, numeric_only=False) df[['age', 'title']].groupby('title').agg(['max', 'min', my_mean, my_median])Использовать функции NumPy (ведь это в заднем плане делает сам pandas - всегда, и в предыдущих двух пунктах), но косвенно, чтобы pandas это «не заметил», например:
def my_mean(x): return np.mean(x) my_median = lambda x: np.median(x) df[['age', 'title']].groupby('title').agg(['max', 'min', my_mean, my_median])