【问题标题】:Dataframe sequence detection: Find groups where three rows in a row have negative values数据帧序列检测:查找连续三行具有负值的组
【发布时间】:2020-06-25 23:03:52
【问题描述】:

假设我有一个专栏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] 

对于熊猫的数字数据中的序列测试是否有一些预定义的检查?它不需要是熊猫,但我正在寻找一种快速且适应性强的解决方案。任何意见将是有益的。谢谢!

【问题讨论】:

    标签: python-3.x database pandas sequence series


    【解决方案1】:

    使用GroupBycumsum 创建连续负数组。

    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
    

    【讨论】:

    • 一如既往——完美回答二凡。
    【解决方案2】:

    @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)
    

    【讨论】:

      【解决方案3】:

      太承认@erfan 回答优雅但不容易理解。我在下面的尝试。

      df = pd.DataFrame({'test': [-1, -2, -3, 2, -4, 3, -5, -4, -3, -7]})
      

      有条件地选择带负数的行

      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'])
      

      【讨论】:

      • 我个人也很喜欢这种方法,最后在我的代码中使用了这种方法,因为它易于阅读。谢谢!
      猜你喜欢
      • 2021-09-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多