如何按多列过滤熊猫数据框


99

要按单列过滤数据帧(df),如果我们考虑男性和女性的数据,则可以:

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

问题1-但是,如果数据跨越多年并且我只想看2014年的男性,该怎么办?

在其他语言中,我可能会做类似的事情:

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

(除了我要执行此操作,并在新的数据框对象中获取原始数据框的子集)

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

for y in year:

for g in gender:

df = .....

您要过滤还是将其分组?如果要为每个唯一的年份和性别集创建一个单独的DataFrame,请参阅groupby
BrenBarn 2014年

1
该答案全面概述了熊猫中的布尔索引和逻辑运算符。
cs95

Answers:


169

使用&运算符时,不要忘了用():包裹子语句:

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

要将数据帧存储在dictfor循环中:

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 2014年

@yoshiserry你的key情况如何getDF?一个参数还是键元组?请具体说明;)
zhangxaochen 2014年

嗨,这是一个按键,只是一个单词,对应于性别(男或女)或年份(13、14)。不知道您可以拥有一个键元组。您能否举例说明何时以及如何进行此操作?
yoshiserry 2014年

你也可以看看这个问题吗?我觉得你可以回答。再次与pandas数据框相关。 stackoverflow.com/questions/22086619/...
yoshiserry

1
注意,GenderYear都应该是字符串,即'Gender''Year'
史蒂文·豪威尔

22

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

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。



6

如果有人想知道什么是更快的过滤方法(可接受的答案或来自@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()经过50万行之后速度会更快。此外,字符串搜索Year=="2014"有不必要的开销(Year==2014更快)。


1

您可以使用query中创建自己的过滤器功能pandas。在这里,您可以df按所有kwargs参数过滤结果。不要忘记添加一些验证器(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)

感谢您的优雅解决方案!我认为这是所有其他方法中最好的。它结合了使用查询的效率和将其作为功能的多功能性。
Merii

0

您可以使用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]
})
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.