如何使用滚动总计构建Python函数?
我希望构建一个函数,为下面的数据帧按代码逐日创建滚动总计,其中日期上每个代码的输入从日期上每个代码的输出中减去,此小计是从前几天的总计中减去的,但总计必须大于等于0(我在下面的所需输出中包含了一个示例) 下面是我的输入和使用的函数的示例,以及我所需输出的示例 df1-In如何使用滚动总计构建Python函数?,python,pandas,function,lambda,Python,Pandas,Function,Lambda,我希望构建一个函数,为下面的数据帧按代码逐日创建滚动总计,其中日期上每个代码的输入从日期上每个代码的输出中减去,此小计是从前几天的总计中减去的,但总计必须大于等于0(我在下面的所需输出中包含了一个示例) 下面是我的输入和使用的函数的示例,以及我所需输出的示例 df1-In s = """ Date Code Quantity 0 10/01/2019 A 20 3 11/01/2019 A 2 7 12/01/201
s = """ Date Code Quantity
0 10/01/2019 A 20
3 11/01/2019 A 2
7 12/01/2019 A 4
11 13/01/2019 A 10
"""
df2-输出
s =''' Date Code Quantity
0 11/01/2019 A 5
3 12/01/2019 A 100
4 15/01/2019 A 1
6 16/01/2019 A 2
'''
s = """ Date Code Quantity
0 10/01/2019 A 20
3 11/01/2019 A 17
7 12/01/2019 A 0
11 13/01/2019 A 10
12 14/01/2019 A 10
15 15/01/2019 A 9
16 16/01/2019 A 7
"""
代码
df3 = df1.merge(df2, how='outer', left_on=['date', 'code'], right_on=['date', 'code']).fillna(0)
df3['qty1'] = df3['qty_x'] - df3['qty_y']
df3['qty'] = 0
def final_adder(x):
x.qty_x = x.qty_x
print(x)
return x
df_final = df3.groupby(['code']).apply(final_adder)
df_final['qty'] = df_final['qty'].clip(lower=0)
df_final.drop(['qty_x', 'qty_y','qty1'], inplace=True, axis=1)
date code qty_x qty_y qty1 qty
0 10/01/2019 A 20.0 0.0 20.0 0
3 11/01/2019 A 2.0 5.0 -3.0 0
7 12/01/2019 A 4.0 100.0 -96.0 0
11 13/01/2019 A 10.0 0.0 10.0 0
所需输出
s =''' Date Code Quantity
0 11/01/2019 A 5
3 12/01/2019 A 100
4 15/01/2019 A 1
6 16/01/2019 A 2
'''
s = """ Date Code Quantity
0 10/01/2019 A 20
3 11/01/2019 A 17
7 12/01/2019 A 0
11 13/01/2019 A 10
12 14/01/2019 A 10
15 15/01/2019 A 9
16 16/01/2019 A 7
"""
关于SO,有一整套问题涉及具有限制的累积运算(例如:“当累积和变为负值时重置为零”)。这与具有已知重置点的累积运算不同(例如,来自另一列,或存在NaN等),因为条件涉及累积值本身 在当前的熊猫或numpy中,没有干净的方法以矢量化的方式实现这一点 我所知道的最好(最快)的方法是使用
numba
。根据您的问题稍加修改和调整:
来自numba import njit
@njit
def poscumsum(x):
总数=0
结果=np.空(x.形)
对于枚举(x)中的i,y:
总计+=y
如果总数<0:
总数=0
结果[i]=总数
返回结果
使用此功能,您可以执行以下操作:
a=df1.设置索引(['code','Date'])
b=df2.set_索引(['Code','Date'])
idx=a.index.union(b.index.sort_值()
df3=(a.reindex(idx,fill_值=0)-b.reindex(idx,fill_值=0))
#可选:在每个组内将日期重采样为每日:
df3=df3.groupby('Code')。重采样('D',level='Date')。sum()
df3['Quantity']=df3.groupby('Code')['Quantity'].transform(
lambda g:poscumsum(g.values))
关于问题中提供的数据:
>>df3
量
代码日期
A 2019-01-10 20
2019-01-11 17
2019-01-12 0
2019-01-13 10
2019-01-14 10
2019-01-15 9
2019-01-16 7
如果愿意,也可以使用“合并”。下面是一个示例,其中保存了所有中间结果(用于法医分析):
df3=df1.merge(df2,on=['code','Date'],how='outer',sort=True)。fillna(0)
#可选:在每个组内将日期重采样为每日:
df3=df3.set_index(['Code','Date']).groupby('Code').resample('D',level='Date').sum()
df3['diff']=df3['Quantity\u x']-df3['Quantity\u y']
df3['cumdiff']=df3.groupby('Code')['diff'].transform(
lambda g:poscumsum(g.values))
df3
#输出:
数量×数量×差异
代码日期
A 2019-01-10 20.0 0.0 20.0 20.0
2019-01-11 2.0 5.0 -3.0 17.0
2019-01-12 4.0 100.0 -96.0 0.0
2019-01-13 10.0 0.0 10.0 10.0
2019-01-14 0.0 0.0 0.0 10.0
2019-01-15 0.0 1.0 -1.0 9.0
2019-01-16 0.0 2.0 -2.0 7.0
最简单的是合并后的for循环。感谢您的帮助,当我有一个“代码”时,它可以完美地工作。但是,如果我引入第二个“代码”,“B”,我会遇到以下错误:ValueError:无法处理非唯一的多索引!不确定“如果我引入第二个代码”是什么意思.我测试了多个代码混合在一起,效果很好(不包括code,date
但不在df1
中)。您可能希望用额外的示例更新您的问题(当前建议的答案不适合您的需要的示例)。我现在已经修复了错误,我刚刚编辑了df2的输入数据和所需的输出。如果代码有“数量”,我希望它在未来的每一天出现,即使它没有出现在每天的输入或输出数据帧中。我想更新的问题现在显示了这一点。我希望这是有意义的。我明白了:您想要整个外部连接。没问题。更新的答案。当然,请参阅更新答案中的“可选重采样”:只需在进行累积和之前,为每个代码组插入日期的每日重采样:df3=df3.groupby('Code')。重采样('D',level='Date')。sum()
。