数据帧序列检测:查找连续三行具有负值的组
Dataframe sequence detection: Find groups where three rows in a row have negative values
假设我有一列 df['test']
:
-1, -2, -3, 2, -4, 3, -5, -4, -3, -7
所以我想过滤掉至少连续三个负值的组。所以
groups = my_grouping_function_by_sequence()
groups[0] = [-1,-2-3]
groups[1] = [-5,-4,-3,-7]
对于 pandas 的数值数据序列测试是否有一些预定义的检查?它不需要是 pandas,但我正在寻找一种快速且适应性强的解决方案。任何意见将是有益的。谢谢!
使用 GroupBy
和 cumsum
创建连续负数组。
grps = df['test'].gt(0).cumsum()
dfs = [d.dropna() for _, d in df.mask(df['test'].gt(0)).groupby(grps) if d.shape[0] >= 3]
输出
for df in dfs:
print(df)
test
0 -1.0
1 -2.0
2 -3.0
test
6 -5.0
7 -4.0
8 -3.0
9 -7.0
说明
让我们一步一步来:
第一行,为连续的负数创建组
print(grps)
0 0
1 0
2 0
3 1
4 1
5 2
6 2
7 2
8 2
9 2
Name: test, dtype: int32
但正如我们所见,它还包括我们不想在输出中考虑的正数。所以我们使用 DataFrame.mask
将这些值转换为 NaN
:
df.mask(df['test'].gt(0))
# same as df.mask(df['test'] > 0)
test
0 -1.0
1 -2.0
2 -3.0
3 NaN
4 -4.0
5 NaN
6 -5.0
7 -4.0
8 -3.0
9 -7.0
然后我们在这个数据框上分组,只保留 >=
3 行的组:
for _, d in df.mask(df['test'].gt(0)).groupby(grps):
if d.shape[0] >= 3:
print(d.dropna())
test
0 -1.0
1 -2.0
2 -3.0
test
6 -5.0
7 -4.0
8 -3.0
9 -7.0
@Erfan 你的回答很精彩,我还在努力理解第二行。你的第一行让我开始尝试以我自己的方式编写它,但效率较低。
import pandas as pd
df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})
df['+ or -'] = df['test'].gt(0)
df['group'] = df['+ or -'].cumsum()
df_gb = df.groupby('group').count().reset_index().drop('+ or -', axis=1)
df_new = pd.merge(df, df_gb, how='left', on='group').drop('+ or -', axis=1)
df_new = df_new[(df_new['test_x'] < 0) & (df_new['test_y'] >=3)].drop('test_y',
axis=1)
for i in df_new['group'].unique():
j = pd.DataFrame(df_new.loc[df_new['group'] == i, 'test_x'])
print(j)
太感谢@erfan 回答优雅但不容易理解。下面是我的尝试。
df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})
有条件地 select 带负数的行
df['j'] = np.where(df['test']<0,1,-1)
df['k']=df['j'].rolling(3, min_periods=1).sum()
df2=df[df['k']==3]
slice 迭代数据框获取上面的第 3 行和连续 2 行
for index, row in df2.iterrows():
print(df.loc[index - 2 : index + 0, 'test'])
假设我有一列 df['test']
:
-1, -2, -3, 2, -4, 3, -5, -4, -3, -7
所以我想过滤掉至少连续三个负值的组。所以
groups = my_grouping_function_by_sequence()
groups[0] = [-1,-2-3]
groups[1] = [-5,-4,-3,-7]
对于 pandas 的数值数据序列测试是否有一些预定义的检查?它不需要是 pandas,但我正在寻找一种快速且适应性强的解决方案。任何意见将是有益的。谢谢!
使用 GroupBy
和 cumsum
创建连续负数组。
grps = df['test'].gt(0).cumsum()
dfs = [d.dropna() for _, d in df.mask(df['test'].gt(0)).groupby(grps) if d.shape[0] >= 3]
输出
for df in dfs:
print(df)
test
0 -1.0
1 -2.0
2 -3.0
test
6 -5.0
7 -4.0
8 -3.0
9 -7.0
说明
让我们一步一步来: 第一行,为连续的负数创建组
print(grps)
0 0
1 0
2 0
3 1
4 1
5 2
6 2
7 2
8 2
9 2
Name: test, dtype: int32
但正如我们所见,它还包括我们不想在输出中考虑的正数。所以我们使用 DataFrame.mask
将这些值转换为 NaN
:
df.mask(df['test'].gt(0))
# same as df.mask(df['test'] > 0)
test
0 -1.0
1 -2.0
2 -3.0
3 NaN
4 -4.0
5 NaN
6 -5.0
7 -4.0
8 -3.0
9 -7.0
然后我们在这个数据框上分组,只保留 >=
3 行的组:
for _, d in df.mask(df['test'].gt(0)).groupby(grps):
if d.shape[0] >= 3:
print(d.dropna())
test
0 -1.0
1 -2.0
2 -3.0
test
6 -5.0
7 -4.0
8 -3.0
9 -7.0
@Erfan 你的回答很精彩,我还在努力理解第二行。你的第一行让我开始尝试以我自己的方式编写它,但效率较低。
import pandas as pd
df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})
df['+ or -'] = df['test'].gt(0)
df['group'] = df['+ or -'].cumsum()
df_gb = df.groupby('group').count().reset_index().drop('+ or -', axis=1)
df_new = pd.merge(df, df_gb, how='left', on='group').drop('+ or -', axis=1)
df_new = df_new[(df_new['test_x'] < 0) & (df_new['test_y'] >=3)].drop('test_y',
axis=1)
for i in df_new['group'].unique():
j = pd.DataFrame(df_new.loc[df_new['group'] == i, 'test_x'])
print(j)
太感谢@erfan 回答优雅但不容易理解。下面是我的尝试。
df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})
有条件地 select 带负数的行
df['j'] = np.where(df['test']<0,1,-1)
df['k']=df['j'].rolling(3, min_periods=1).sum()
df2=df[df['k']==3]
slice 迭代数据框获取上面的第 3 行和连续 2 行
for index, row in df2.iterrows():
print(df.loc[index - 2 : index + 0, 'test'])