Python 条件扩展群聚合

Python 条件扩展群聚合,python,pandas,Python,Pandas,对于一些数据预处理,我有一个巨大的数据帧,需要在组内获得历史性能。然而,因为它是针对在目标前一周运行的预测模型,所以我不能使用在这两周之间发生的任何数据。每个组每天的行数是可变的,这意味着我不能总是通过在扩展函数上使用shift来丢弃最后7个值,我必须以某种方式对之前的行的datetime进行调整。我可以编写自己的函数来应用于组,但根据我的经验,这通常非常缓慢(尽管很灵活)。我就是这样做的,没有日期限制,只看以前的记录: df.loc[:, 'new_col'] = df_gr['old_col

对于一些数据预处理,我有一个巨大的数据帧,需要在组内获得历史性能。然而,因为它是针对在目标前一周运行的预测模型,所以我不能使用在这两周之间发生的任何数据。每个组每天的行数是可变的,这意味着我不能总是通过在扩展函数上使用shift来丢弃最后7个值,我必须以某种方式对之前的行的datetime进行调整。我可以编写自己的函数来应用于组,但根据我的经验,这通常非常缓慢(尽管很灵活)。我就是这样做的,没有日期限制,只看以前的记录:

df.loc[:, 'new_col'] = df_gr['old_col'].apply(lambda x: x.expanding(5).mean().shift(1))
5表示我希望至少有一个5的样本量,或者把它放到NaN

至少提前一周查看A组内所有样本的平均值的aggr_mean小示例:

group | dt       | value  | aggr_mean
A     | 01-01-16 | 5      | NaN
A     | 03-01-16 | 4      | NaN
A     | 08-01-16 | 12     | 5 (only looks at first row)
A     | 17-01-16 | 11     | 7 (looks at first three rows since all are 
                               at least a week earlier)
新答案
使用@JulienMarrec的更好例子

dt           group  value   
2016-01-01     A      5
2016-01-03     A      4
2016-01-08     A     12
2016-01-17     A     11
2016-01-04     B     10
2016-01-05     B      5
2016-01-08     B     12
2016-01-17     B     11
条件
df
更有用

d1 = df.drop('group', 1)
d1.index = [df.group, df.groupby('group').cumcount().rename('gidx')]
d1

创建一个自定义函数,该函数执行旧的answer所做的操作。然后在
groupby

def lag_merge_asof(df, lag):
    d = df.set_index('dt').value.expanding().mean()
    d.index = d.index + pd.offsets.Day(lag)
    d = d.reset_index(name='aggr_mean')
    return pd.merge_asof(df, d)

d1.groupby(level='group').apply(lag_merge_asof, lag=7)

我们可以用这个设置一些格式

d1.groupby(level='group').apply(lag_merge_asof, lag=7) \
    .reset_index('group').reset_index(drop=True)


旧答案

通过将日期偏移7天来创建一个
回溯
数据框,然后使用它来


在这个数据框中,我添加了另一个组,以便更清楚地看到发生了什么:

dt           group  value                               
2016-01-01     A      5
2016-01-03     A      4
2016-01-08     A     12
2016-01-17     A     11
2016-01-04     B     10
2016-01-05     B      5
2016-01-08     B     12
2016-01-17     B     11
让我们加载它:

df = pd.read_clipboard(index_col=0, sep='\s+', parse_dates=True)
现在我们可以使用groupby,每天重新采样,并进行7天的轮班,然后取平均值:

x = df.groupby('group')['value'].apply(lambda gp: gp.resample('1D').mean().shift(7).expanding().mean())
现在您可以将
left
合并回df:

merged = df.reset_index().set_index(['group','dt']).join(x, rsuffix='_aggr_mean', how='left')
merged

您可以发布您的数据样本吗?是的,忘记做了,只是添加了:)这看起来是个不错的方法,但是如果有几行具有相同的dt,这种重采样方法仍然有效吗?我不知道这是一个要求。。。不,它会弄乱重量。你必须在我的答案(groupby,因为你想按组进行,但不需要重采样,而是移位(freq='7D'))和@piRSquared的merge_asofThanks之间进行混合,抱歉,我不够清楚,应该在示例中添加它。你能在
['group','dt']
两个
上都做
merge_asof
吗?因为OP的要求是在组内完成的(不太清楚,因为样本数据只有一个组,但它写在简介中),所以我现在正在进行这方面的工作。。。尽量不要睡着;-)不幸的是,我没有说清楚,重采样方法可能不允许有几天有多行,我可以用类似的方式使用你的旧方法,对吗?啊,有一个答案。我现在太累了,不能做这件事。它可以留作你的练习。我不必设置索引。我可以将
dt
留在数据帧的数据部分,并跟踪我的索引。这应该是足够的线索了。+1作为记录,我检查了一下,你的“新答案”似乎有效,即使同一日期有多行。一个平均值被合并到多个行中,用于同一个以后的日期,如果每个日期都有多个行需要包含在平均值函数中,也就完成了。
x = df.groupby('group')['value'].apply(lambda gp: gp.resample('1D').mean().shift(7).expanding().mean())
merged = df.reset_index().set_index(['group','dt']).join(x, rsuffix='_aggr_mean', how='left')
merged