Pandas 滚动总和,可变长度
Pandas rolling sum, variating length
我将尝试解释我目前遇到的关于 Python 中 DataFrames 的累积和的问题,希望你能理解它!
给定一个 pandas DataFrame df
和一个 returns
列:
returns
Date
2014-12-10 0.0000
2014-12-11 0.0200
2014-12-12 0.0500
2014-12-15 -0.0200
2014-12-16 0.0000
在此 DataFrame 上应用累加和很容易,只需使用例如df.cumsum()
。但是是否有可能每隔 X
天(或数据点)应用一个累积总和,只产生最后 Y
天(数据点)的累积总和。
澄清:给定上述每日数据,我如何获得最近 Y
天的累计总和,每 X
天重新评估(从零开始)?
希望它够清楚,
谢谢,
N
我不确定是否有内置方法,但编写一个似乎并不难。
例如,这是 pandas 系列的一个。
def cum(df, interval):
all = []
quotient = len(df)//interval
intervals = range(quotient)
for i in intervals:
all.append(df[0:(i+1)*interval].sum())
return pd.Series(all)
>>>s1 = pd.Series(range(20))
>>>print(cum(s1, 4))
0 6
1 28
2 66
3 120
4 190
dtype: int64
我的方法是使用辅助列。有点笨拙,但应该可以用:
numgroups = int(len(df)/(x-1))
df['groupby'] = sorted(list(range(numgroups))*x)[:len(df)]
df['mask'] = (([0]*(x-y)+[1]*(y))*numgroups)[:len(df)]
df['masked'] = df.returns*df['mask']
df.groupby('groupby').masked.cumsum()
"Every X days"和"every X data points"是非常不同的;以下假设您真正指的是第一个,因为您提到它的频率更高。
如果索引是DatetimeIndex
,你可以resample
to a daily frequency, take a rolling_sum
,然后select只有原始日期:
>>> pd.rolling_sum(df.resample("1d"), 2, min_periods=1).loc[df.index]
returns
Date
2014-12-10 0.00
2014-12-11 0.02
2014-12-12 0.07
2014-12-15 -0.02
2014-12-16 -0.02
或者,一步一步:
>>> df.resample("1d")
returns
Date
2014-12-10 0.00
2014-12-11 0.02
2014-12-12 0.05
2014-12-13 NaN
2014-12-14 NaN
2014-12-15 -0.02
2014-12-16 0.00
>>> pd.rolling_sum(df.resample("1d"), 2, min_periods=1)
returns
Date
2014-12-10 0.00
2014-12-11 0.02
2014-12-12 0.07
2014-12-13 0.05
2014-12-14 NaN
2014-12-15 -0.02
2014-12-16 -0.02
感谢@DSM,我设法想出了他的解决方案的一个变体,实际上它几乎可以满足我的需求:
import numpy as np
import pandas as pd
df.resample("1w"), how={'A': np.sum})
为下面的示例生成我想要的结果:
rng = range(1,29)
dates = pd.date_range('1/1/2000', periods=len(rng))
r = pd.DataFrame(rng, index=dates, columns=['A'])
r2 = r.resample("1w", how={'A': np.sum})
输出:
>> print r
A
2000-01-01 1
2000-01-02 2
2000-01-03 3
2000-01-04 4
2000-01-05 5
2000-01-06 6
2000-01-07 7
2000-01-08 8
2000-01-09 9
2000-01-10 10
2000-01-11 11
...
2000-01-25 25
2000-01-26 26
2000-01-27 27
2000-01-28 28
>> print r2
A
2000-01-02 3
2000-01-09 42
2000-01-16 91
2000-01-23 140
2000-01-30 130
即使在这种情况下它没有开始 "one week in"(在第一种情况下总和为 3),它总是会得到正确的滚动总和,从前一个日期开始并具有初始值为零。
我将尝试解释我目前遇到的关于 Python 中 DataFrames 的累积和的问题,希望你能理解它!
给定一个 pandas DataFrame df
和一个 returns
列:
returns
Date
2014-12-10 0.0000
2014-12-11 0.0200
2014-12-12 0.0500
2014-12-15 -0.0200
2014-12-16 0.0000
在此 DataFrame 上应用累加和很容易,只需使用例如df.cumsum()
。但是是否有可能每隔 X
天(或数据点)应用一个累积总和,只产生最后 Y
天(数据点)的累积总和。
澄清:给定上述每日数据,我如何获得最近 Y
天的累计总和,每 X
天重新评估(从零开始)?
希望它够清楚,
谢谢, N
我不确定是否有内置方法,但编写一个似乎并不难。 例如,这是 pandas 系列的一个。
def cum(df, interval):
all = []
quotient = len(df)//interval
intervals = range(quotient)
for i in intervals:
all.append(df[0:(i+1)*interval].sum())
return pd.Series(all)
>>>s1 = pd.Series(range(20))
>>>print(cum(s1, 4))
0 6
1 28
2 66
3 120
4 190
dtype: int64
我的方法是使用辅助列。有点笨拙,但应该可以用:
numgroups = int(len(df)/(x-1))
df['groupby'] = sorted(list(range(numgroups))*x)[:len(df)]
df['mask'] = (([0]*(x-y)+[1]*(y))*numgroups)[:len(df)]
df['masked'] = df.returns*df['mask']
df.groupby('groupby').masked.cumsum()
"Every X days"和"every X data points"是非常不同的;以下假设您真正指的是第一个,因为您提到它的频率更高。
如果索引是DatetimeIndex
,你可以resample
to a daily frequency, take a rolling_sum
,然后select只有原始日期:
>>> pd.rolling_sum(df.resample("1d"), 2, min_periods=1).loc[df.index]
returns
Date
2014-12-10 0.00
2014-12-11 0.02
2014-12-12 0.07
2014-12-15 -0.02
2014-12-16 -0.02
或者,一步一步:
>>> df.resample("1d")
returns
Date
2014-12-10 0.00
2014-12-11 0.02
2014-12-12 0.05
2014-12-13 NaN
2014-12-14 NaN
2014-12-15 -0.02
2014-12-16 0.00
>>> pd.rolling_sum(df.resample("1d"), 2, min_periods=1)
returns
Date
2014-12-10 0.00
2014-12-11 0.02
2014-12-12 0.07
2014-12-13 0.05
2014-12-14 NaN
2014-12-15 -0.02
2014-12-16 -0.02
感谢@DSM,我设法想出了他的解决方案的一个变体,实际上它几乎可以满足我的需求:
import numpy as np
import pandas as pd
df.resample("1w"), how={'A': np.sum})
为下面的示例生成我想要的结果:
rng = range(1,29)
dates = pd.date_range('1/1/2000', periods=len(rng))
r = pd.DataFrame(rng, index=dates, columns=['A'])
r2 = r.resample("1w", how={'A': np.sum})
输出:
>> print r
A
2000-01-01 1
2000-01-02 2
2000-01-03 3
2000-01-04 4
2000-01-05 5
2000-01-06 6
2000-01-07 7
2000-01-08 8
2000-01-09 9
2000-01-10 10
2000-01-11 11
...
2000-01-25 25
2000-01-26 26
2000-01-27 27
2000-01-28 28
>> print r2
A
2000-01-02 3
2000-01-09 42
2000-01-16 91
2000-01-23 140
2000-01-30 130
即使在这种情况下它没有开始 "one week in"(在第一种情况下总和为 3),它总是会得到正确的滚动总和,从前一个日期开始并具有初始值为零。