2016-03-29 3 views
3

Я читал, resample a dataframe with different functions applied to each column?вставка новый несуществующий столбец как = из RESAMPLE

Решение было:

frame.resample('1H', how={'radiation': np.sum, 'tamb': np.mean}) 

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

Можно ли сделать:

frame.resample('1H', how={'radiation': np.sum, 'tamb': np.mean,\ 
       'new_column': count()}) 

Примечание, new_column НЕ существующий столбец исходного кадра данных.

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

Я пытаюсь сделать это прямо сейчас, и, похоже, он занимает очень много времени (без синтаксических ошибок). Не уверен, что python попадает в какой-то цикл forever.

Update:

Я реализовал предложение использовать AGG (спасибо любезно для этого).

Однако, я получил следующее сообщение об ошибке при вычислении первого агрегатор:

grouped = df.groupby(['name1',pd.TimeGrouper('M')]) 
    return pd.DataFrame(
    {'new_col1': grouped['col1'][grouped['col1'] > 0].agg('sum') 
    ... 


/Users/blahblah/anaconda/lib/python2.7/site-packages/pandas/core/groupby.pyc in __getitem__(self, key) 
    521 
    522  def __getitem__(self, key): 
--> 523   raise NotImplementedError('Not implemented: %s' % key) 
    524 
    525  def _make_wrapper(self, name): 

NotImplementedError: Not implemented: True 

следующие работы, когда я использую grouped.apply(foo).

new_col1 = grp['col1'][grp['col1'] > 0].sum() 

ответ

3

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 почему предварительные вычисления помогают производительности.

+0

Благодарим за подробное и вдумчивое объяснение. Я действительно ценю это. Ответ меня многому научил. Спасибо. – codingknob

+0

Вопрос: существует ли разница в том, как выполняется каждый из агрегаторов для операций с столбцами в сравнении с последовательным вычислением агрегаторов в foo (grp). В моем случае у меня есть 30 агрегаторов в foo (grp), которые занимают много времени, потому что они должны проходить через каждый агрегатор за один раз над одним и тем же набором групп. Не уверен, работает ли так =. Мне интересно, есть ли способ векторизации вычислений для скорости? – codingknob

+0

Действительно, я думаю, что мое первое предложение использовать 'apply' было не очень хорошим. Существует гораздо более быстрый способ: используйте 'groupby/agg' вместо' groupby/apply'. Я редактировал свой пост, чтобы показать, что я имею в виду. – unutbu

Смежные вопросы