【问题标题】:Select or drop rows by group threshold按组阈值选择或删除行
【发布时间】:2019-04-05 16:51:10
【问题描述】:

拥有如下所示的数据框:

import pandas as pd
import numpy as np

df = pd.DataFrame(
            {'Beverage': ['Beer', 'Wine', 'Whisky'],
            'G1_1': [11, 5.1, 2.8],
            'G1_2': [6, 4, 0],
            'G1_3': [0, 2, 0],
            'G2_1': [0, 4.1, 0.8],
            'G2_2': [0, 6, 0.1],
            'G2_3': [0, 9.4, 0],
            }
                )

group1 = ['G1_1', 'G1_2', 'G1_3']

df

  Beverage  G1_1    G1_2    G1_3    G2_1    G2_2    G2_3
0   Beer    11.0    6       0       0       0       0
1   Wine    5.1     4       2       4.1     6.0     9.4
2   Whisky  2.8     0       0       0.8     0.1     0.0

如果我们要选择group1 样本至少有2 个非零值的所有行,一种可能的解决方案是将零值转换为NaN,然后使用pandas DF.dropna 进行过滤。例如:

df.replace({0: np.nan}).dropna(axis=0, thresh=2, subset=group1)
df

  Beverage  G1_1    G1_2    G1_3    G2_1    G2_2    G2_3
0   Beer    11.0    6       NaN     NaN     NaN     NaN
1   Wine    5.1     4       2       4.1     6.0     9.4

上面删除了Whisky 行,因为group1 中具有非零值的样本少于两个。

如何应用类似的过滤器,但不是过滤零,而是应用一些特定条件,例如,group1 中的至少 2 个样本具有值 >5? (在这种情况下,应该只打印Beer 行)

编辑:

另外,有没有更有效的方法来完成同样的事情?我问这个是因为我必须将过滤器应用于一个非常大的数据框。

【问题讨论】:

    标签: python pandas


    【解决方案1】:

    使用DataFrame 比较运算符(eq、ne、le、lt、ge、gt),然后使用sum 沿行的布尔值形成掩码。

    # At least 2 non-zero values
    thresh = 2
    m = df[group1].ne(0).sum(1).ge(thresh)
    df.loc[m]
    #  Beverage  G1_1  G1_2  G1_3  G2_1  G2_2  G2_3
    #0     Beer  11.0     6     0   0.0   0.0   0.0
    #1     Wine   5.1     4     2   4.1   6.0   9.4
    
    # At least 2 values greater than 5
    thresh = 2
    m = df[group1].gt(5).sum(1).ge(thresh)
    df.loc[m]
    #  Beverage  G1_1  G1_2  G1_3  G2_1  G2_2  G2_3
    #0     Beer  11.0     6     0   0.0   0.0   0.0
    

    可以通过将这些与&| 组合来创建更复杂的选择。例如,区间 (2, 4] 内的值:

    df[group1].gt(2) & df[group1].le(4) 
    

    【讨论】:

    • 在我的粗略测试中,这种方法比其他方法稍快。
    【解决方案2】:

    您还可以使用以下逻辑:

     inds = (df[group_1] > 5).sum(axis=1) >= 2
     df.loc[inds, :]
    

    换句话说,这翻译为:

    1. 检查所有值的条件(例如> 5),然后
    2. 检查每行满足此条件的频率 (.sum(axis=1)),然后
    3. 指定必须满足此条件的次数才能保留该行 (>= 2)

    我喜欢这种方法,因为它用途广泛,可以很容易地转化为不同的问题

    【讨论】:

      【解决方案3】:

      认为一种可能的解决方案是为df.replace 生成一个合适的映射字典。例如:

      rep_d = {k: np.nan for k in range(0, 5)}
      df.replace(rep_d).dropna(axis=0, thresh=2, subset=group1)
      df
      
        Beverage  G1_1    G1_2    G1_3    G2_1    G2_2    G2_3
      0   Beer    11.0    6       NaN     NaN     NaN     NaN
      

      但不确定此解决方案对于非常大的数据帧的效率如何。

      【讨论】:

        猜你喜欢
        • 2017-09-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-11-29
        • 1970-01-01
        相关资源
        最近更新 更多