【问题标题】:Pandas DataFrame : How to select rows on multiple conditions?Pandas DataFrame:如何在多个条件下选择行?
【发布时间】:2018-01-17 08:22:10
【问题描述】:

我正在尝试根据需要全部满足的条件列表来选择 DataFrame 的行。 这些条件存储在字典中,格式为 {column: max-value}。

这是一个例子:dict = {'name': 4.0, 'sex': 0.0, 'city': 2, 'age': 3.0}

我需要选择对应属性小于等于字典中对应值的所有DataFrame行。

我知道根据两个或多个条件选择行我可以写:

rows = df[(df[column1] <= dict[column1]) & (df[column2] <= dict[column2])]

我的问题是,如何以 Pythonic 方式选择与字典中存在的条件匹配的行? 我试过这样,

keys = dict.keys() 
rows = df[(df[kk] <= dict[kk]) for kk in keys]

但它给了我一个错误 = "[ expected",即使放置 [ 符号也不会消失。

【问题讨论】:

  • 不要将变量命名为dict,因为dict 是一个内置的python 字典构造函数。

标签: python pandas dictionary


【解决方案1】:

我们可以像这样使用DataFrame.query() 方法:

In [109]: dct = {'name': 4.0, 'sex': 0.0, 'city': 2, 'age': 3.0}

In [110]: qry = ' and '.join(['{} <= {}'.format(k,v) for k,v in dct.items()])

In [111]: qry
Out[111]: 'name <= 4.0 and sex <= 0.0 and city <= 2 and age <= 3.0'

In [112]: df.query(qry)
...

【讨论】:

    【解决方案2】:

    您可以利用 Pandas 的自动轴对齐功能。给定一个包含 ['age', 'city', 'name', 'sex'] 列的 DataFrame 和一个具有相同索引的 Series,您可以使用

    将 DataFrame 中的每个条目与 Series 中的相应值进行比较
    In [29]: df < pd.Series(dct)
    Out[29]: 
          age   city   name    sex
    0   False  False  False  False
    1   False  False  False  False
    2    True  False  False  False
    3   False   True  False  False
    4    True   True   True  False
    ...
    

    然后你可以找到所有True使用的行

    mask = (df <= pd.Series(dct)).all(axis=1)
    

    并选择带有df.loc[mask, :] 的行。例如,

    import numpy as np
    import pandas as pd
    np.random.seed(2017)
    N = 300
    df = pd.DataFrame({'name':np.random.randint(10, size=N),
                       'sex':np.random.randint(2, size=N),
                       'city':np.random.randint(10, size=N),
                       'age':np.random.randint(10, size=N)})
    dct = {'name': 4.0, 'sex': 0.0, 'city': 2, 'age': 3.0}
    
    mask = (df <= pd.Series(dct)).all(axis=1)
    print(df.loc[mask, :])
    

    产量

         age  city  name  sex
    7      3     2     0    0
    10     1     2     4    0
    150    1     2     4    0
    188    2     2     2    0
    198    3     2     3    0
    229    1     2     0    0
    254    1     2     2    0
    275    3     2     1    0
    276    0     1     4    0
    299    3     1     2    0
    

    【讨论】:

    • 有谁知道@MaxU 和@unutbu 的答案比较起来如何?
    • @srcerer:在我的机器上,尤其是对于较大的 DataFrame,MaxU's answer(使用query)更快。既然知道如何自己测试它,你可能想看看the timeit module,或者为了更方便,IPython's %timeit magic function。
    • 谢谢,我只是懒得自己测试。我喜欢你的方法不需要生成字符串。
    【解决方案3】:

    你也可以试试:

    import pandas as pd
    import numpy as np
    
    
    N = 300
    
    df = pd.DataFrame({'name':np.random.randint(10, size=N),
                       'sex':np.random.randint(2, size=N),
                       'city':np.random.randint(10, size=N),
                       'age':np.random.randint(10, size=N)})
    
    dct = {'name': 4.0, 'sex': 0.0, 'city': 2, 'age': 3.0}
    
    df.loc[np.prod([df[k] <= v for k,v in dct.items()],axis=0).astype(bool),:]
    
    #      age  city  name  sex
    # 7      3     2     0    0
    # 10     1     2     4    0
    # 150    1     2     4    0
    # 188    2     2     2    0
    # 198    3     2     3    0
    # 229    1     2     0    0
    # 254    1     2     2    0
    # 275    3     2     1    0
    # 276    0     1     4    0
    # 299    3     1     2    0
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-09-23
      • 1970-01-01
      • 2017-07-25
      • 2019-05-25
      • 1970-01-01
      • 2023-03-21
      相关资源
      最近更新 更多