【问题标题】:generic function for conditional filtering in pandas dataframe熊猫数据框中条件过滤的通用函数
【发布时间】:2018-10-03 17:37:25
【问题描述】:

样本过滤条件:-

数据

x  y  z 
1  2  1
1  3  2
1  2  5
1  3  1

现在我想从给定的数据中过滤上述指定的条件。 为此我需要一个通用函数,即该函数应该适用于任何过滤器,而不仅仅是上述指定的过滤器。

我知道如何在 python 中针对多个条件手动过滤数据。

我认为泛型函数可能需要两个参数,一个是数据,另一个是过滤条件。

但是我找不到编写通用函数来过滤数据的逻辑。

任何人都可以帮助我解决问题。

提前致谢。

【问题讨论】:

    标签: python pandas filter


    【解决方案1】:

    您可以创建conditions 的列表,然后创建np.logical_and.reduce

    x1 = df.x==1
    y2 = df.y==2 
    z1 = df.z==1
    y3 = df.y==3
    
    m1 = np.logical_and.reduce([x1, y2, z1])
    m2 = np.logical_and.reduce([x1, y3, z1])
    

    concat all mask tohether 并检查DataFrame.all 每行的所有Trues:

    m1 = pd.concat([x1, y2, z1], axis=1).all(axis=1)
    m2 = pd.concat([x1, y3, z1], axis=1).all(axis=1)
    

    编辑:

    如果可能的话,用字典中的过滤值定义列名:

    d1 = {'x':1, 'y':2, 'z':1}
    d2 = {'x':1, 'y':3, 'z':1}
    
    m1 = np.logical_and.reduce([df[k] == v for k, v in d1.items()])
    m2 = np.logical_and.reduce([df[k] == v for k, v in d2.items()])
    

    merge 的另一种方法是通过从字典创建的一行 DataFrame:

    df1 = pd.DataFrame([d1]).merge(df)
    

    编辑:

    对于一般解决方案,可以将文件的每个值解析为元组并使用operators

    df1 = pd.DataFrame({0: ['x==1', 'x==1'], 1: ['y==2', 'y<=3'], 2: ['z!=1', 'z>1']})
    print (df1)
          0     1     2
    0  x==1  y==2  z!=1
    1  x==1  y<=3   z>1
    
    
    import operator, re
    
    ops = {'>': operator.gt,
            '<': operator.lt,
           '>=': operator.ge,
           '<=': operator.le,
           '==': operator.eq,
            '!=': operator.ne}
    
    #if numeric, parse to float, else not touch ()e.g. if string
    def try_num(x):
        try:
            return float(x)
        except ValueError:
            return x
    
    L = df1.to_dict('r')
    #https://stackoverflow.com/q/52620865/2901002
    rgx = re.compile(r'([<>=!]+)')
    parsed = [[rgx.split(v) for v in d.values()] for d in L]
    L = [[(x, op, try_num(y)) for x,op,y in ps] for ps in parsed]
    print (L)
    [[('x', '==', 1.0), ('y', '==', 2.0), ('z', '!=', 1.0)], 
     [('x', '==', 1.0), ('y', '<=', 3.0), ('z', '>', 1.0)]]
    

    现在按列表的第一个值过滤 - 文件的第一行:

    m = np.logical_and.reduce([ops[j](df[i], k) for i, j, k in L[0]])
    print (m)
    [False False  True False]
    

    【讨论】:

    • 感谢您的回复,如果可能的话,您可以添加如何将一个条件拆分为多个条件,在这里您可以手动完成,但我需要通用功能。还有一件事是过滤条件也是 pandas 数据帧格式。
    • 上述答案仅在我的输入为字典格式时才有效。但这对我来说还不够,我必须根据问题中提到的条件过滤数据。有没有办法像那样过滤数据?
    • @neeraja - 抱歉,不明白。你的泛型函数到底输入了什么?
    • @neeraja - 总是有== ?
    • @jezrael,我喜欢你的专业知识和将东西放在这里作为像我们这样的许多学习者的解决方案的方式,你的熊猫技巧真的很棒,我的一分钱和 +1。
    【解决方案2】:

    由于您只有一个数字 dtype,因此您可以使用底层 NumPy 数组:

    res = df[(df.values == [1, 2, 1]).all(1)]
    
    print(res)
    
       x  y  z
    0  1  2  1
    

    对于带有list 输入的通用函数:

    def filter_df(df, L):
        return df[(df.values == L).all(1)]
    
    res = filter_df(df, [1, 2, 1])
    

    如果您需要字典输入:

    def filter_df(df, d):
        L = list(map(d.get, df))
        return df[(df.values == L).all(1)]
    
    res = filter_df(df, {'x': 1, 'y': 2, 'z': 1})
    

    【讨论】:

      【解决方案3】:
      def filter_function(df,filter_df):
        lvl_=list()
        lvl=list()
        vlv=list()
        df1=pd.DataFrame()
        n=filter_df.apply(lambda x: x.tolist(), axis=1)
        for i in range(0,len(n)):
            for j in range(0,len(n[i])):
                if i==0:
                   lvl_.append(n[i][j].split('==')[0])
                lvl.append(n[i][j].split('==')[1])
                if len(lvl)==len(n[i]):
                   vlv.append(lvl)
                   lvl=list()
        final_df=df[lvl_]
        for k in range(0,len(vlv)):
            df1=df1.append(final_df[final_df.isin(vlv[k])].dropna())
        return(df1)
      
      filter_function(df,filter_df)
      

      【讨论】:

        猜你喜欢
        • 2017-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-02-25
        相关资源
        最近更新 更多