以下是我的数据框的外观, Group Signal Value1 Value2 Expected_Output
0 1 0 3 1 NaN
1 1 1 4 2 NaN
2 1 0 7 4 NaN
3 1 0 8 9 1.0
4 1 0 5 3 NaN
5 2 1 3 6 NaN
6 2 1 1 2 1.0
7 2 0 3 4 1.0
是我想要的列。
Group
对于给定的Signal == 1
,如果为Value1 < Value2
,那么我尝试查看接下来的三行(而不是当前行),并检查是否为Expected_Output
。如果该条件成立,那么我在Value < Value2
列中返回1。例如,如果出于多种原因满足了Signal == 1
条件,因为它位于第5和6行中Group 2
的下3行中(Expected_Output
),那么我还要返回1 in group by object
。
我假设np.where
,any
,shift
,{{1}}的正确组合可能是解决方案,但不能完全解决。
NB:-亚历山大指出评论中有冲突。理想情况下,由于前一行中的信号而设置的值将取代给定行中的当前行规则冲突。
答案 0 :(得分:2)
如果您要检查很多先前的行,则多次移位很快就会变得混乱,但是在这里还算不错:
s = df.groupby('Group').Signal
condition = ((s.shift(1).eq(1) | s.shift(2).eq(1) | s.shift(3).eq(1))
& df.Value1.lt(df.Value2))
df.assign(out=np.where(condition, 1, np.nan))
Group Signal Value1 Value2 out
0 1 0 3 1 NaN
1 1 1 4 2 NaN
2 1 0 7 4 NaN
3 1 0 8 9 1.0
4 1 0 5 3 NaN
5 2 1 3 6 NaN
6 2 1 1 2 1.0
7 2 0 3 4 1.0
如果您担心使用这么多班次的表现,我不会太担心,这里是一百万行的示例:
In [401]: len(df)
Out[401]: 960000
In [402]: %%timeit
...: s = df.groupby('Group').Signal
...:
...: condition = ((s.shift(1).eq(1) | s.shift(2).eq(1) | s.shift(3).eq(1))
...: & df.Value1.lt(df.Value2))
...:
...: np.where(condition, 1, np.nan)
...:
...:
94.5 ms ± 524 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
@Alexander确定了规则中的冲突,以下是使用符合要求的掩码的版本:
s = (df.Signal.mask(df.Signal.eq(0)).groupby(df.Group)
.ffill(limit=3).mask(df.Signal.eq(1)).fillna(0))
现在,您可以简单地将此列与其他条件一起使用:
np.where((s.eq(1) & df.Value1.lt(df.Value2)).astype(int), 1, np.nan)
array([nan, nan, nan, 1., nan, nan, nan, 1.])
答案 1 :(得分:1)
您可以创建一个与您的条件匹配的索引,然后使用它将预期的输出设置为1。
当规则冲突时,如何处理预期的输出尚不清楚。例如,在第6行上,预期输出将为1,因为它满足了来自第5行的信号标准并适合“随后的三行,其中值1 <值2”。但是,这可能与忽略第一个信号行的规则相冲突。
idx = (df
.assign(
grp=df['Signal'].eq(1).cumsum(),
cond=df.eval('Value1 < Value2'))
.pipe(lambda df: df[df['grp'] > 0]) # Ignore data preceding first signal.
.groupby(['Group', 'grp'], as_index=False)
.apply(lambda df: df.iloc[1:4, :]) # Ignore current row, get rows 1-3.
.pipe(lambda df: df[df['cond']]) # Find rows where condition is met.
.index.get_level_values(1)
)
df['Expected_Output'] = np.nan
df.loc[idx, 'Expected_Output'] = 1
>>> df
Group Signal Value1 Value2 Expected_Output
0 1 0 3 1 NaN
1 1 1 4 2 NaN
2 1 0 7 4 NaN
3 1 0 8 9 1.0
4 1 0 5 3 NaN
5 2 1 3 6 NaN
6 2 1 1 2 NaN # <<< Intended difference vs. "expected"
7 2 0 3 4 1.0