Python 提高应用方法的性能
我想通过df“cod_id”的变量进行分组,然后应用此函数:Python 提高应用方法的性能,python,pandas,performance,apply,pandas-groupby,Python,Pandas,Performance,Apply,Pandas Groupby,我想通过df“cod_id”的变量进行分组,然后应用此函数: [df.loc[df['dt_op'].between(d, d + pd.Timedelta(days = 7)), 'quantity'].sum() \ for d in df['dt_op']] 从该df开始: print(df) dt_op quantity cod_id 20/01/18 1 613 21/01/18
[df.loc[df['dt_op'].between(d, d + pd.Timedelta(days = 7)), 'quantity'].sum() \
for d in df['dt_op']]
从该df开始:
print(df)
dt_op quantity cod_id
20/01/18 1 613
21/01/18 8 611
21/01/18 1 613
...
对于这一点:
print(final_df)
n = 7
dt_op quantity product_code Final_Quantity
20/01/18 1 613 2
21/01/18 8 611 8
25/01/18 1 613 1
...
我试过:
def lookforward(x):
L = [x.loc[x['dt_op'].between(row.dt_op, row.dt_op + pd.Timedelta(days=7)), \
'quantity'].sum() for row in x.itertuples(index=False)]
return pd.Series(L, index=x.index)
s = df.groupby('cod_id').apply(lookforward)
s.index = s.index.droplevel(0)
df['Final_Quantity'] = s
print(df)
dt_op quantity cod_id Final_Quantity
0 2018-01-20 1 613 2
1 2018-01-21 8 611 8
2 2018-01-21 1 613 1
但这不是一个有效的解决方案,因为它在计算上很慢
我如何改进它的性能?
即使使用新代码/新函数也能达到同样的效果。
编辑:
原始数据集的子集,只有一个产品(cod_id==2),我试图运行“w-m”提供的代码:
编辑181017:由于pandas在稀疏时间序列上具有前向滚动功能,此方法不起作用,请参见注释。 在执行操作时,使用for循环可能是性能杀手 行周围的for循环加上7天的时间增量可以替换为
.rolling(“7D”)
。为了获得向前滚动的时间增量(当前日期+7天),我们按日期反转df
,如图所示
这样就不再需要自定义函数,您可以从groupby获取.quantity.sum()
quant_sum = df.sort_values("dt_op", ascending=False).groupby("cod_id") \
.rolling("7D", on="dt_op").quantity.sum()
cod_id dt_op
611 2018-01-21 8.0
613 2018-01-21 1.0
2018-01-20 2.0
Name: quantity, dtype: float64
result = df.set_index(["cod_id", "dt_op"])
result["final_sum"] = quant_sum
result.reset_index()
cod_id dt_op quantity final_sum
0 613 2018-01-20 1 2.0
1 611 2018-01-21 8 8.0
2 613 2018-01-21 1 1.0
由于pandas中存在两个缺点,很难实现问题中的精确行为:既没有实现groupby/rolling/transform,也没有实现前瞻性滚动稀疏日期(有关更多详细信息,请参见其他答案) 这个答案试图通过重新采样数据、填写所有天数,然后将定量和与原始数据合并,来解决这两个问题
# Create a temporary df with all in between days filled in with zeros
filled = df.set_index("dt_op").groupby("cod_id") \
.resample("D").asfreq().fillna(0) \
.quantity.to_frame()
# Reverse and sum
filled["quant_sum"] = filled.reset_index().set_index("dt_op") \
.iloc[::-1] \
.groupby("cod_id") \
.rolling(7, min_periods=1) \
.quantity.sum().astype(int)
# Join with original `df`, dropping the filled days
result = df.set_index(["cod_id", "dt_op"]).join(filled.quant_sum).reset_index()
@jpp我添加了一个解决方案,它要求索引设置为
“RollingGroupby”对象没有属性“transform”
。你能想出一个更好的方法来做这件事吗?不,我试图使用GroupBy
+transform
和滚动
,但失败了。仅供参考,由于某种原因,我认为您的结果与OP不匹配。@w-m它似乎不起作用;看一看“最终df”:它应该提前计算未来7天的总和。因此,对于cod_id 613,总和应该是20日的2和21日的121th@w-m、 这似乎奏效了。这种情况经常发生,我希望熊猫只允许负面窗口!经过调查,这实际上是行不通的<代码>在反转序列(向后日期)上滚动(“7D”)不受pandas-支持。如果不使用groupby
,pandas会抛出一个ValueError:dt_op必须是单调的
。groupby
似乎隐藏了这个错误,熊猫计算出了一些错误(我认为这是一个bug)。cc@jpp非常感谢你;爱丽丝
# Create a temporary df with all in between days filled in with zeros
filled = df.set_index("dt_op").groupby("cod_id") \
.resample("D").asfreq().fillna(0) \
.quantity.to_frame()
# Reverse and sum
filled["quant_sum"] = filled.reset_index().set_index("dt_op") \
.iloc[::-1] \
.groupby("cod_id") \
.rolling(7, min_periods=1) \
.quantity.sum().astype(int)
# Join with original `df`, dropping the filled days
result = df.set_index(["cod_id", "dt_op"]).join(filled.quant_sum).reset_index()