【问题标题】:how do you filter pandas dataframes by multiple columns你如何按多列过滤熊猫数据框
【发布时间】:2014-03-31 22:06:39
【问题描述】:

要按单列过滤数据框 (df),如果我们考虑包含男性和女性的数据,我们可能会:

males = df[df[Gender]=='Male']

问题 1 - 但是如果数据跨越多年,而我只想查看 2014 年的男性呢?

在其他语言中,我可能会这样做:

if A = "Male" and if B = "2014" then 

(除非我想这样做并在新数据框对象中获取原始数据框的子集)

问题 2。如何循环执行此操作,并为每个唯一的年份和性别集创建一个数据框对象(即 df 为:2013-Male、2013-Female、2014-Male 和 2014-Female

for y in year:

for g in gender:

df = .....

【问题讨论】:

  • 您要过滤还是分组?如果您想为每组独特的年份和性别创建一个单独的 DataFrame,请查看groupby
  • This answer 全面概述了 pandas 中的布尔索引和逻辑运算符。

标签: python filter pandas


【解决方案1】:

由于您要查找的行基本上满足 Column_A='Value_A' 和 Column_B='Value_B' 的条件

你可以使用loc

df = df.loc[df['Column_A'].eq('Value_A') & df['Column_B'].eq('Value_B')]

你可以在这里找到完整的文档panda loc

【讨论】:

    【解决方案2】:

    您可以在pandas 中使用query 创建自己的过滤器函数。在这里,您可以通过所有 kwargs 参数过滤 df 结果。不要忘记添加一些验证器(kwargs 过滤)来为您自己的df 获取过滤功能。

    def filter(df, **kwargs):
        query_list = []
        for key in kwargs.keys():
            query_list.append(f'{key}=="{kwargs[key]}"')
        query = ' & '.join(query_list)
        return df.query(query)
    

    【讨论】:

    • 感谢优雅的解决方案!我认为这是所有其他人中最好的。它结合了使用查询的效率和将其作为函数的多功能性。
    • 请注意,这里假定值kwargs[key] 是一个字符串;可以通过 val = kwargs[key]val_str = f'"{val}"' if isinstance(val, str) else f'{str(val)}query_list.append(f'{key}=={val_str}') 之类的东西使其更通用(至少是整数和字符串)
    【解决方案3】:

    如果有人想知道什么是更快的过滤方式(接受的答案或来自@redreamality 的答案):

    import pandas as pd
    import numpy as np
    
    length = 100_000
    df = pd.DataFrame()
    df['Year'] = np.random.randint(1950, 2019, size=length)
    df['Gender'] = np.random.choice(['Male', 'Female'], length)
    
    %timeit df.query('Gender=="Male" & Year=="2014" ')
    %timeit df[(df['Gender']=='Male') & (df['Year']==2014)]
    

    100,000 行的结果:

    6.67 ms ± 557 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    5.54 ms ± 536 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
    

    10,000,000 行的结果:

    326 ms ± 6.52 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    472 ms ± 25.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
    

    因此结果取决于大小和数据。在我的笔记本电脑上,query() 在 500k 行后变得更快。此外,Year=="2014" 中的字符串搜索有不必要的开销(Year==2014 更快)。

    【讨论】:

    • 然而,我认为query 语法更简洁,更接近于 SQL,这使得它很适合用于数据。蛋糕上的奇瑞在于它有很多行更快:)
    【解决方案4】:

    您可以通过使用np.logical_and 运算符替换&(或np.logical_or 替换|)按多列(多于两列)进行过滤

    如果您为多个字段提供目标值,下面是一个可以完成这项工作的示例函数。您可以调整它以适应不同类型的过滤等等:

    def filter_df(df, filter_values):
        """Filter df by matching targets for multiple columns.
    
        Args:
            df (pd.DataFrame): dataframe
            filter_values (None or dict): Dictionary of the form:
                    `{<field>: <target_values_list>}`
                used to filter columns data.
        """
        import numpy as np
        if filter_values is None or not filter_values:
            return df
        return df[
            np.logical_and.reduce([
                df[column].isin(target_values) 
                for column, target_values in filter_values.items()
            ])
        ]
    

    用法:

    df = pd.DataFrame({'a': [1, 2, 3, 4], 'b': [1, 2, 3, 4]})
    
    filter_df(df, {
        'a': [1, 2, 3],
        'b': [1, 2, 4]
    })
    

    【讨论】:

      【解决方案5】:

      pandas 0.13开始,这是最有效的方式。

      df.query('Gender=="Male" & Year=="2014" ')
      

      【讨论】:

      • 为什么这应该比公认的答案更有效?
      • @Bouncner 只需根据高票数的答案验证它。
      • 这个答案可以通过显示基准来改进
      【解决方案6】:

      对于您希望用作过滤器并且依赖于多个列的更通用的布尔函数,您可以使用:

      df = df[df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)]
      

      其中 f 是一个函数,它应用于 col_1 和 col_2 中的每对元素 (x1, x2),并根据您想要的 (x1, x2) 上的任何条件返回 True 或 False。

      【讨论】:

      • 一个充实的例子,你也定义了 f 会改进这个答案。
      【解决方案7】:

      使用&amp; 运算符,不要忘记用() 包装子语句:

      males = df[(df[Gender]=='Male') & (df[Year]==2014)]
      

      使用 for 循环将数据帧存储在 dict 中:

      from collections import defaultdict
      dic={}
      for g in ['male', 'female']:
        dic[g]=defaultdict(dict)
        for y in [2013, 2014]:
          dic[g][y]=df[(df[Gender]==g) & (df[Year]==y)] #store the DataFrames to a dict of dict
      

      编辑:

      getDF 的演示:

      def getDF(dic, gender, year):
        return dic[gender][year]
      
      print genDF(dic, 'male', 2014)
      

      【讨论】:

      • 很好的答案 zhangxaochen - 您能否编辑您的答案以在底部显示您如何执行 for 循环,该循环创建数据框(包含年份和性别数据),但将它们添加到字典中以便他们可以稍后通过我的 getDF 方法访问? def GetDF(dict,key): 返回 dict[key]
      • @yoshiserry 你的getDF 中的key 是什么?单个参数还是键元组?请具体说明;)
      • 嗨,这是一个键,只是一个词,对应于性别(男性或女性)或年份(13、14) 不知道你可以有一个键元组。您能否分享一个何时以及如何执行此操作的示例?
      • 你也可以看看这个问题。我感觉你可以回答。再次与熊猫数据框相关。 stackoverflow.com/questions/22086619/…
      • 注意GenderYear都应该是字符串,即'Gender''Year'
      猜你喜欢
      • 2018-07-13
      • 1970-01-01
      • 2017-12-15
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2015-09-24
      相关资源
      最近更新 更多