如何按多列过滤pandas数据帧

yos*_*rry 80 python filter pandas

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

males = df[df[Gender]=='Male']
Run Code Online (Sandbox Code Playgroud)

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

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

if A = "Male" and if B = "2014" then 
Run Code Online (Sandbox Code Playgroud)

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

问题2.如何在循环中执行此操作,并为每个独特的年份和性别集创建数据框对象(即:2013年男性,2013年女性,2014年男性和2014年女性的df

for y in year:

for g in gender:

df = .....
Run Code Online (Sandbox Code Playgroud)

zha*_*hen 134

使用&运算符,不要忘记用以下内容包装子语句():

males = df[(df[Gender]=='Male') & (df[Year]==2014)]
Run Code Online (Sandbox Code Playgroud)

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

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
Run Code Online (Sandbox Code Playgroud)

编辑:

您的演示getDF:

def getDF(dic, gender, year):
  return dic[gender][year]

print genDF(dic, 'male', 2014)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,`Gender` 和`Year` 都应该是字符串,即`'Gender'` 和`'Year'`。 (3认同)

小智 20

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

df = df[df[['col_1','col_2']].apply(lambda x: f(*x), axis=1)]
Run Code Online (Sandbox Code Playgroud)

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

  • 一个充实的例子,其中你还定义了 f 会改善这个答案。 (2认同)

Bou*_*ner 20

如果有人想知道什么是更快的过滤方式(接受的答案或来自@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)]
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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)
Run Code Online (Sandbox Code Playgroud)

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

  • 然而,我认为“查询”语法更简洁并且更接近 SQL,这使得它对于数据来说非常好。蛋糕上的好处是,行数多时速度更快:) (3认同)

小智 19

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

df.query('Gender=="Male" & Year=="2014" ')
Run Code Online (Sandbox Code Playgroud)

  • 这个答案可以通过显示基准来改进 (15认同)
  • 为什么这比公认的答案更有效? (2认同)
  • 这效率不高。使用 %timeit,“df.query(blah)”每个循环得分为 1.81 ms ± 99.7 µs(7 次运行,每个循环 1000 个),而“df[(blah) & (blah)]”得分更快,为 501 µs ± 15.3 µs每个循环(7 次运行,每次 1000 次循环) (2认同)

小智 8

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

你可以使用loc

df = df.loc[df['Column_A'].eq('Value_A') & df['Column_B'].eq('Value_B')]
Run Code Online (Sandbox Code Playgroud)

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


Ale*_*lex 5

您可以使用queryin创建自己的过滤器函数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)
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这假设值“kwargs[key]”是一个字符串;它可以通过像 `val = kwargs[key]` 和 `val_str = f'"{val}"' if isinstance(val, str) else f'{str 这样的东西变得更通用(至少是整数和字符串) (val)}` 和 `query_list.append(f'{key}=={val_str}')` (2认同)