pandas DataFrame 中每个元素在 x 天内的累积乘积
Cumulative product for each element over x days in pandas DataFrame
我尝试为 Dataframe
df1
中的每个元素计算 x
天(例如 3)的累积乘积。有没有一种有效的方法来做到这一点?到目前为止,我只知道在行上生成一个正常的累积乘积,而没有将回顾期固定为 x
天 (=df2
)。例如:
- 2022-01-02 ID1:1.0528 =(忽略 NaN)0.94 * 1.12
- 2022-01-05 ID1: 1.2002 = 0.94 * 1.12 * 1.14
- 2022-01-09 ID1: 1.4045 = 1.12 * 1.14 * 1.10
最佳情况下,它还会忽略 NaN 值并计算剩余数字的累积值 return。到目前为止,我只知道如何通过创建副本并移动它来计算它,但我想计算超过 50 行的许多列的累积乘积,这效率不高。
df1:
ID1 ID2
Date
2022-01-02 NaN 0.95
2022-01-05 0.94 0.98
2022-01-09 1.12 NaN
2022-01-10 1.14 1.02
2022-01-11 1.10 1.00
2022-01-12 0.92 0.82
df2:
ID1 ID2
Date
2022-01-02 1.0528 0.9309
2022-01-05 1.2002 0.9996
2022-01-09 1.4045 1.0200
2022-01-10 1.1537 0.8364
2022-01-11 1.0120 0.8200
2022-01-12 0.9200 0.8200
重现性:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({
'Date':['2022-01-02', '2022-01-05', '2022-01-09', '2022-01-10', '2022-01-11', '2022-01-12'],
'ID1':[np.nan, 0.94, 1.12, 1.14, 1.1, 0.92],
'ID2':[0.95, 0.98, np.nan, 1.02, 1, 0.82]})
df1 = df1.set_index('Date')
非常感谢您的建议!
您可以使用 custom rolling indexer for forward-looking windows and np.nanprod
:
import numpy as np
# Window of index i includes rows [i:i+3).
indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=3)
print(df.rolling(indexer, min_periods=1).apply(np.nanprod))
ID1 ID2
Date
2022-01-02 1.052800 0.9310
2022-01-05 1.200192 0.9996
2022-01-09 1.404480 1.0200
2022-01-10 1.153680 0.8364
2022-01-11 1.012000 0.8200
2022-01-12 0.920000 0.8200
您可以使用:
df1.fillna(1)[::-1].rolling(window=3, min_periods=1).agg(lambda x: x.prod())[::-1]
输出:
ID1 ID2
Date
2022-01-02 1.052800 0.9310
2022-01-05 1.200192 0.9996
2022-01-09 1.404480 1.0200
2022-01-10 1.153680 0.8364
2022-01-11 1.012000 0.8200
2022-01-12 0.920000 0.8200
它是如何工作的?
- 滚动使用前面的行(或居中),这里我们反转数组来计算反向滚动
- 我们用 1 填充 NaN(我们也可以使用 np.nanprod)
- 我们使用 min_periods=1 来启用少于 3 个元素的计算
我尝试为 Dataframe
df1
中的每个元素计算 x
天(例如 3)的累积乘积。有没有一种有效的方法来做到这一点?到目前为止,我只知道在行上生成一个正常的累积乘积,而没有将回顾期固定为 x
天 (=df2
)。例如:
- 2022-01-02 ID1:1.0528 =(忽略 NaN)0.94 * 1.12
- 2022-01-05 ID1: 1.2002 = 0.94 * 1.12 * 1.14
- 2022-01-09 ID1: 1.4045 = 1.12 * 1.14 * 1.10
最佳情况下,它还会忽略 NaN 值并计算剩余数字的累积值 return。到目前为止,我只知道如何通过创建副本并移动它来计算它,但我想计算超过 50 行的许多列的累积乘积,这效率不高。
df1:
ID1 ID2
Date
2022-01-02 NaN 0.95
2022-01-05 0.94 0.98
2022-01-09 1.12 NaN
2022-01-10 1.14 1.02
2022-01-11 1.10 1.00
2022-01-12 0.92 0.82
df2:
ID1 ID2
Date
2022-01-02 1.0528 0.9309
2022-01-05 1.2002 0.9996
2022-01-09 1.4045 1.0200
2022-01-10 1.1537 0.8364
2022-01-11 1.0120 0.8200
2022-01-12 0.9200 0.8200
重现性:
import pandas as pd
import numpy as np
df1 = pd.DataFrame({
'Date':['2022-01-02', '2022-01-05', '2022-01-09', '2022-01-10', '2022-01-11', '2022-01-12'],
'ID1':[np.nan, 0.94, 1.12, 1.14, 1.1, 0.92],
'ID2':[0.95, 0.98, np.nan, 1.02, 1, 0.82]})
df1 = df1.set_index('Date')
非常感谢您的建议!
您可以使用 custom rolling indexer for forward-looking windows and np.nanprod
:
import numpy as np
# Window of index i includes rows [i:i+3).
indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=3)
print(df.rolling(indexer, min_periods=1).apply(np.nanprod))
ID1 ID2
Date
2022-01-02 1.052800 0.9310
2022-01-05 1.200192 0.9996
2022-01-09 1.404480 1.0200
2022-01-10 1.153680 0.8364
2022-01-11 1.012000 0.8200
2022-01-12 0.920000 0.8200
您可以使用:
df1.fillna(1)[::-1].rolling(window=3, min_periods=1).agg(lambda x: x.prod())[::-1]
输出:
ID1 ID2
Date
2022-01-02 1.052800 0.9310
2022-01-05 1.200192 0.9996
2022-01-09 1.404480 1.0200
2022-01-10 1.153680 0.8364
2022-01-11 1.012000 0.8200
2022-01-12 0.920000 0.8200
它是如何工作的?
- 滚动使用前面的行(或居中),这里我们反转数组来计算反向滚动
- 我们用 1 填充 NaN(我们也可以使用 np.nanprod)
- 我们使用 min_periods=1 来启用少于 3 个元素的计算