Python 熊猫:根据条件计算从特定日期开始的时间序列的百分比变化
我正在努力用高效后处理的方法来完成以下任务。我有一个时间框架。 基于某种条件,我设置了一个布尔列。之后,我想生成另一列,它是该条件最后一次出现的百分比。例如,在下表中, 行的2、4和5是行1中值的百分比。第6、7和7行是第5行的百分比变化Python 熊猫:根据条件计算从特定日期开始的时间序列的百分比变化,python,pandas,numpy,Python,Pandas,Numpy,我正在努力用高效后处理的方法来完成以下任务。我有一个时间框架。 基于某种条件,我设置了一个布尔列。之后,我想生成另一列,它是该条件最后一次出现的百分比。例如,在下表中, 行的2、4和5是行1中值的百分比。第6、7和7行是第5行的百分比变化 row date value condition pct_change_from_condition 1 04-27-2010 100 TRUE 2 04-28-2010 200
row date value condition pct_change_from_condition
1 04-27-2010 100 TRUE
2 04-28-2010 200 1.0
4 04-29-2010 300 2.0
5 04-30-2010 400 TRUE 3.0
6 05-01-2010 500 0.25
7 05-02-2010 600 0.5
8 05-03-2010 700 0.75
我知道我可以重复这些行,然后这样做……但由于这是熊猫,我希望有一种更“流行”和更有效的方式来做……我只是不确定在这里如何做。
感觉上我需要一些条件转换:
df['pct_change_from_condition'] = (df.value - df.shift(df.condition).value)/df.value
或者使用loc:
df['pct_change_from_condition'] = df.value - df.loc[df.condition].value
当然这些都不起作用,所以我在这里问。。。
感谢您的帮助一种方法是使用
.groupby()
将运行总和保持为condition==True
(移位1),并使用该运行总和计算每组的百分比w.r.t相应的参考值。您可以尝试以下方法:
import numpy as np
import pandas as pd
mask = (df['condition'] == True)
df['group'] = mask.cumsum()
df['first'] = df.groupby(['group'])['value'].transform('first')
df['first'] = np.where(mask, df['first'].shift(), df['first'])
df['pct_change'] = (df['value']-df['first'])/df['first']
# Out[52]:
# 0 NaN
# 1 1.00
# 2 2.00
# 3 3.00
# 4 0.25
# 5 0.50
# 6 0.75
# Name: pct_change, dtype: float64
我们可以将
条件
列与真
进行比较,以创建一个布尔掩码,然后掩码
列中与该布尔掩码对应的值
中的值,然后是移位
和ffill
,以创建一个系列s
,现在用s
减去并除以value
,以计算百分比变化
m = df['condition'].eq('TRUE')
s = df['value'].mask(~m).shift().ffill()
df['% change'] = df['value'].sub(s).div(s)
优雅的解决方案+1,如果您使用:
df['condition'].isna()
并将其插入.mask
您只有两行,可读性类似。感谢@Andreas的好建议,但我认为只有在TRUE
之外的列中没有其他值时,这才有效。例如,如果存在FALSE
值,则我们必须显式检查TRUE
值以创建mask@Andreas您的解决方案也很好(+1;)非常简洁!谢谢你跟进这件事,因为我知道:1。面具的用途是什么?在此之前,我不熟悉该功能。它读起来像是我的要求——基于条件的“转移”。2.如果条件列是布尔型的,我假设它也可以工作:df['value'].mask(df.condition).shift().ffill()
date value condition % change
1 04-27-2010 100 TRUE NaN
2 04-28-2010 200 NaN 1.00
4 04-29-2010 300 NaN 2.00
5 04-30-2010 400 TRUE 3.00
6 05-01-2010 500 NaN 0.25
7 05-02-2010 600 NaN 0.50
8 05-03-2010 700 NaN 0.75