resampling
похож на группировку с TimeGrouper
. В то время как how
параметр resampling
«s только позволяет указать один агрегатор для каждого столбца, GroupBy
объект, возвращаемый df.groupby(...)
имеет agg
метод, который может быть передан различные функции (например, mean
, sum
или count
) агрегировать группы различными способами , Вы можете использовать эти результаты для создания желаемого DataFrame:
import datetime as DT
import numpy as np
import pandas as pd
np.random.seed(2016)
date_times = pd.date_range(DT.datetime(2012, 4, 5, 8, 0),
DT.datetime(2012, 4, 5, 12, 0),
freq='1min')
tamb = np.random.sample(date_times.size) * 10.0
radiation = np.random.sample(date_times.size) * 10.0
df = pd.DataFrame(data={'tamb': tamb, 'radiation': radiation},
index=date_times)
resampled = df.resample('1H', how={'radiation': np.sum, 'tamb': np.mean})
print(resampled[['radiation', 'tamb']])
# radiation tamb
# 2012-04-05 08:00:00 279.432788 4.549235
# 2012-04-05 09:00:00 310.032188 4.414302
# 2012-04-05 10:00:00 257.504226 5.056613
# 2012-04-05 11:00:00 299.594032 4.652067
# 2012-04-05 12:00:00 8.109946 7.795668
def using_agg(df):
grouped = df.groupby(pd.TimeGrouper('1H'))
return pd.DataFrame(
{'radiation': grouped['radiation'].agg('sum'),
'tamb': grouped['tamb'].agg('mean'),
'new_column': grouped['tamb'].agg('count')})
print(using_agg(df))
дающего
new_column radiation tamb
2012-04-05 08:00:00 60 279.432788 4.549235
2012-04-05 09:00:00 60 310.032188 4.414302
2012-04-05 10:00:00 60 257.504226 5.056613
2012-04-05 11:00:00 60 299.594032 4.652067
2012-04-05 12:00:00 1 8.109946 7.795668
Примечания моего первого ответа предложили использовать groupby/apply
:
def using_apply(df):
grouped = df.groupby(pd.TimeGrouper('1H'))
result = grouped.apply(foo).unstack(-1)
result = result.sortlevel(axis=1)
return result[['radiation', 'tamb', 'new_column']]
def foo(grp):
radiation = grp['radiation'].sum()
tamb = grp['tamb'].mean()
cnt = grp['tamb'].count()
return pd.Series([radiation, tamb, cnt], index=['radiation', 'tamb', 'new_column'])
Оказывается, что с помощью apply
здесь гораздо медленнее, чем при использовании agg
.Если мы ориентируемся using_agg
против using_apply
на 1681-рядный DataFrame:
np.random.seed(2016)
date_times = pd.date_range(DT.datetime(2012, 4, 5, 8, 0),
DT.datetime(2012, 4, 6, 12, 0),
freq='1min')
tamb = np.random.sample(date_times.size) * 10.0
radiation = np.random.sample(date_times.size) * 10.0
df = pd.DataFrame(data={'tamb': tamb, 'radiation': radiation},
index=date_times)
Я считаю, используя %timeit
функции IPython в
In [83]: %timeit using_apply(df)
100 loops, best of 3: 16.9 ms per loop
In [84]: %timeit using_agg(df)
1000 loops, best of 3: 1.62 ms per loop
using_agg
значительно быстрее, чем using_apply
и (на основе дополнительных %timeit
тестов) скорость преимущество в пользу using_agg
растет как len(df)
растет.
Кстати, о
frame.resample('1H', how={'radiation': np.sum, 'tamb': np.mean,\
'new_column': count()})
помимо проблемы, что how
ДИКТ не принимает несуществующие имена столбцов, скобки в count
проблематичны. Значения в файле how
dict должны быть объектами функции. count
- объект функции, но count()
- это значение, возвращаемое вызовом count
.
Поскольку Python оценивает аргументы перед вызовом функций, count()
становится вызывается перед frame.resample(...)
, а возвращаемое значение count()
затем связывается с ключом 'new_column'
в Словаре, связанного с параметром how
. Это не то, что вы хотите.
Что касается обновленного вопроса: предвычисления значения, которые будут нуждаться в перед вызова groupby/agg
:
Вместо
grouped = df.groupby(['name1',pd.TimeGrouper('M')])
return pd.DataFrame(
{'new_col1': grouped['col1'][grouped['col1'] > 0].agg('sum')
...
# ImplementationError since `grouped['col1']` does not implement __getitem__
использование
df['col1_pos'] = df['col1'].clip(lower=0)
grouped = df.groupby(['name1',pd.TimeGrouper('M')])
return pd.DataFrame(
{'new_col1': grouped['col1_pos'].agg('sum')
...
Смотрите bottom of this post для больше o n почему предварительные вычисления помогают производительности.
Благодарим за подробное и вдумчивое объяснение. Я действительно ценю это. Ответ меня многому научил. Спасибо. – codingknob
Вопрос: существует ли разница в том, как выполняется каждый из агрегаторов для операций с столбцами в сравнении с последовательным вычислением агрегаторов в foo (grp). В моем случае у меня есть 30 агрегаторов в foo (grp), которые занимают много времени, потому что они должны проходить через каждый агрегатор за один раз над одним и тем же набором групп. Не уверен, работает ли так =. Мне интересно, есть ли способ векторизации вычислений для скорости? – codingknob
Действительно, я думаю, что мое первое предложение использовать 'apply' было не очень хорошим. Существует гораздо более быстрый способ: используйте 'groupby/agg' вместо' groupby/apply'. Я редактировал свой пост, чтобы показать, что я имею в виду. – unutbu