如果您确切知道如何过滤数据框,那么解决方案很简单:
df[(df.A == 1) & (df.B == 1)]
但是,如果您接受用户输入并且事先不知道用户想要使用多少条件,该怎么办?例如,用户想要一个过滤的数据框,其中列[A,B,C] == 1.是否可以执行以下操作:
def filterIt(*args, value):
return df[(df.*args == value)]
因此,如果用户调用filterIt(A, B, C, value=1)
,则会返回:
df[(df.A == 1) & (df.B == 1) & (df.C == 1)]
答案 0 :(得分:5)
我认为最优雅的方法是使用df.query()
,您可以使用所有条件构建字符串,例如:
import pandas as pd
import numpy as np
cols = {}
for col in ('A', 'B', 'C', 'D', 'E'):
cols[col] = np.random.randint(1, 5, 20)
df = pd.DataFrame(cols)
def filter_df(df, filter_cols, value):
conditions = []
for col in filter_cols:
conditions.append('{c} == {v}'.format(c=col, v=value))
query_expr = ' and '.join(conditions)
print('querying with: {q}'.format(q=query_expr))
return df.query(query_expr)
示例输出(由于随机生成的数据,您的结果可能会有所不同):
filter_df(df, ['A', 'B'], 1)
querying with: A == 1 and B == 1
A B C D E
6 1 1 1 2 1
11 1 1 2 3 4
答案 1 :(得分:5)
这是另一种方法。它更干净,性能更高,并且具有columns
可以为空的优点(在这种情况下,返回整个数据框)。
def filter(df, value, *columns):
return df.loc[df.loc[:, columns].eq(value).all(axis=1)]
<强>解释强>
values = df.loc[:, columns]
仅选择我们感兴趣的列。masks = values.eq(value)
给出一个布尔数据框,表示与目标值相等。mask = masks.all(axis=1)
跨列应用AND(返回索引掩码)。请注意,您可以使用masks.any(axis=1)
进行OR。return df.loc[mask]
将索引掩码应用于数据框。<强>演示强>
import numpy as np
import pandas as pd
df = pd.DataFrame(np.random.randint(0, 2, (100, 3)), columns=list('ABC'))
# both columns
assert np.all(filter(df, 1, 'A', 'B') == df[(df.A == 1) & (df.B == 1)])
# no columns
assert np.all(filter(df, 1) == df)
# different values per column
assert np.all(filter(df, [1, 0], 'A', 'B') == df[(df.A == 1) & (df.B == 0)])
<强>替代强>
对于少量列(&lt; 5),基于steven's answer的以下解决方案比上述解决方案更具性能,但灵活性较差。原样,它不适用于空columns
集,并且不会使用每列不同的值。
from operator import and_
def filter(df, value, *columns):
return df.loc[reduce(and_, (df[column] == value for column in columns))]
按键(Series
)检索df[column]
对象要比围绕列子集DataFrame
)构建df.loc[:, columns]
对象快得多。
In [4]: %timeit df['A'] == 1
100 loops, best of 3: 17.3 ms per loop
In [5]: %timeit df.loc[:, ['A']] == 1
10 loops, best of 3: 48.6 ms per loop
然而,当处理大量列时,这种加速变得可以忽略不计。瓶颈变为将掩模与AND编号在一起,reduce(and_, ...)
远比Pandas内置all(axis=1)
慢。
答案 2 :(得分:1)
这很乱,但似乎有效。
import operator
def filterIt(value,args):
stuff = [getattr(b,thing) == value for thing in args]
return reduce(operator.and_, stuff)
a = {'A':[1,2,3],'B':[2,2,2],'C':[3,2,1]}
b = pd.DataFrame(a)
filterIt(2,['A','B','C'])
0 False
1 True
2 False
dtype: bool
(b.A == 2) & (b.B == 2) & (b.C ==2)
0 False
1 True
2 False
dtype: bool
答案 3 :(得分:1)
感谢帮助人员。在找到df.query()后,我想出了类似于Marius的东西:
def makeQuery(cols, equivalence=True, *args):
operator = ' == ' if equivalence else ' != '
query = ''
for arg in args:
for col in cols:
query = query + "({}{}{})".format(col, operator, arg) + ' & '
return query[:-3]
query = makeQuery([A, B, C], False, 1, 2)
查询内容是一个字符串:
(A != 1) & (B != 1) & (C != 1) & (A != 2) & (B != 2) & (C != 2)
可以传递给df.query(查询)