Dataframe:比较列值和下面的一行
Dataframe: compare column value and one row below
我有一个带方向的数据框:
Direction:
2/01/19 None
1/31/19 Upward
1/30/19 None
1/29/19 None
1/28/19 Downward
1/27/19 None
1/26/19 None
1/25/19 Upward
我想根据以下条件(从 1/25/19 开始)创建一个 "Momentum" 列:
1. 如果相应日期的方向是 'Upward',然后将值设置为 'Upward'
2. 如果 Momentum 下面的第一行是 "Upward" 将其设置为 'Upward'
3.如果对应日期的Direction为'Downward',则设置为'None'
4.否则,设置为'None'
换句话说,一旦你达到 'Upward' 状态,它应该保持这种状态直到你达到 'Downward'
结果应如下所示:
Direction: Momentum:
2/01/19 None Upward
1/31/19 Upward Upward
1/30/19 None None
1/29/19 None None
1/28/19 Downward None
1/27/19 None Upward
1/26/19 None Upward
1/25/19 Upward Upward
有没有不用循环的方法?
这是一种方法。喝杯咖啡后我会尝试改进它...
df['Momentum:'] = None # Base case.
df.loc[df['Direction:'].eq('Upward'), 'Momentum:'] = 'Upward'
df.loc[df['Direction:'].eq('Downward'), 'Momentum:'] = 1 # Temporary value.
df.loc[:, 'Momentum:'] = df['Momentum:'].bfill()
df.loc[df['Momentum:'].eq(1), 'Momentum:'] = None # Set temporary value back to None.
>>> df
Direction: Momentum:
2/01/19 None Upward
1/31/19 Upward Upward
1/30/19 None None
1/29/19 None None
1/28/19 Downward None
1/27/19 None Upward
1/26/19 None Upward
1/25/19 Upward Upward
通过新数据编辑的答案首先回填 None
值,然后将 Downward
替换为 None
s:
#first replace strings Nones to None type
df['Direction:'] = df['Direction:'].mask(df['Direction:'] == 'None', None)
df['Momentum:'] = df['Direction:'].bfill().mask(lambda x: x == 'Downward', None)
或:
s = df['Direction:'].bfill()
df['Momentum:'] = s.mask(s == 'Downward', None)
print (df)
Direction: Momentum:
2/01/19 None Upward
1/31/19 Upward Upward
1/30/19 None None
1/29/19 None None
1/28/19 Downward None
1/27/19 None Upward
1/26/19 None Upward
1/25/19 Upward Upward
旧答案:
使用 numpy.where
和链式布尔掩码比较移位值和 |
的原始值进行按位或:
mask = df['Direction:'].eq('Upward') | df['Direction:'].shift(-1).eq('Upward')
df['Momentum:'] = np.where(mask, 'Upward', None)
print (df)
Direction: Momentum:
1/31/19 None Upward
1/30/19 Upward Upward
1/29/19 None None
1/28/19 None None
1/27/19 Downward None
1/26/19 None Upward
1/25/19 Upward Upward
我有一个带方向的数据框:
Direction:
2/01/19 None
1/31/19 Upward
1/30/19 None
1/29/19 None
1/28/19 Downward
1/27/19 None
1/26/19 None
1/25/19 Upward
我想根据以下条件(从 1/25/19 开始)创建一个 "Momentum" 列:
1. 如果相应日期的方向是 'Upward',然后将值设置为 'Upward'
2. 如果 Momentum 下面的第一行是 "Upward" 将其设置为 'Upward'
3.如果对应日期的Direction为'Downward',则设置为'None'
4.否则,设置为'None'
换句话说,一旦你达到 'Upward' 状态,它应该保持这种状态直到你达到 'Downward'
结果应如下所示:
Direction: Momentum:
2/01/19 None Upward
1/31/19 Upward Upward
1/30/19 None None
1/29/19 None None
1/28/19 Downward None
1/27/19 None Upward
1/26/19 None Upward
1/25/19 Upward Upward
有没有不用循环的方法?
这是一种方法。喝杯咖啡后我会尝试改进它...
df['Momentum:'] = None # Base case.
df.loc[df['Direction:'].eq('Upward'), 'Momentum:'] = 'Upward'
df.loc[df['Direction:'].eq('Downward'), 'Momentum:'] = 1 # Temporary value.
df.loc[:, 'Momentum:'] = df['Momentum:'].bfill()
df.loc[df['Momentum:'].eq(1), 'Momentum:'] = None # Set temporary value back to None.
>>> df
Direction: Momentum:
2/01/19 None Upward
1/31/19 Upward Upward
1/30/19 None None
1/29/19 None None
1/28/19 Downward None
1/27/19 None Upward
1/26/19 None Upward
1/25/19 Upward Upward
通过新数据编辑的答案首先回填 None
值,然后将 Downward
替换为 None
s:
#first replace strings Nones to None type
df['Direction:'] = df['Direction:'].mask(df['Direction:'] == 'None', None)
df['Momentum:'] = df['Direction:'].bfill().mask(lambda x: x == 'Downward', None)
或:
s = df['Direction:'].bfill()
df['Momentum:'] = s.mask(s == 'Downward', None)
print (df)
Direction: Momentum:
2/01/19 None Upward
1/31/19 Upward Upward
1/30/19 None None
1/29/19 None None
1/28/19 Downward None
1/27/19 None Upward
1/26/19 None Upward
1/25/19 Upward Upward
旧答案:
使用 numpy.where
和链式布尔掩码比较移位值和 |
的原始值进行按位或:
mask = df['Direction:'].eq('Upward') | df['Direction:'].shift(-1).eq('Upward')
df['Momentum:'] = np.where(mask, 'Upward', None)
print (df)
Direction: Momentum:
1/31/19 None Upward
1/30/19 Upward Upward
1/29/19 None None
1/28/19 None None
1/27/19 Downward None
1/26/19 None Upward
1/25/19 Upward Upward