我对使用Pandas进行基本过滤和查询感到满意。例如,如果我有一个名为df
的数据框,我可以df[df['field1'] < 2]
或df[df['field2'] < 3]
。我还可以将多个标准链接在一起,例如:
df[(df['field1'] < 3) & (df['field2'] < 2)]
。
如果我事先不知道需要使用多少条件,该怎么办?有没有办法去&#34;链&#34;任意数量的这些操作在一起?我想传递一个过滤器列表,例如[('field1', 3), ('field2', 2), ('field3', 4)]
,这会导致将这三个条件链接在一起。
谢谢!
答案 0 :(得分:3)
pandas Series对象具有少于,大于等操作作为可以调用的方法。因此df['field1'] < 3
变为df['field1'].lt(3)
。这不是非常重要,但它使代码更具可读性。
要实现您的要求,您可以使用functools中的reduce
函数和运算符包中的and_
(相当于&
)。
from functools import reduce
from operator import and_
reduce(and_, (df.field1.lt(3), df.field2.lt(2), df.field3.lt(4)))
答案 1 :(得分:3)
方法1
使用pd.DataFrame.query
c = [('field1', 3), ('field2', 2), ('field3', 4)]
f = '{0[0]} < {0[1]}'.format
df.query(' & '.join(f(t) for t in c))
方法2
c = [('field1', 3), ('field2', 2), ('field3', 4)]
df[df[[t[0] for t in c]].lt([t[1] for t in c]).all(1)]
方法3
从pd.Series
中创建c
,然后进行比较
c = [('field1', 3), ('field2', 2), ('field3', 4)]
s = pd.Series(dict(c))
df[df[s.index].lt(s).all(1)]
答案 2 :(得分:1)
像add
之类的东西,然后使用all
,你得到布尔值你需要
df1[['f1','f2','f3']].add([-2,-3,-4]).lt(0).all(1)
答案 3 :(得分:0)
我相信reduce( (lambda x, y: x & (df[y[0]]<y[1])), list_of_filters )
会这样做。
答案 4 :(得分:0)
你可以遍历条件并通过&
(逻辑和)布尔掩码一起迭代地构建掩码
def chain_lt(df, conditions):
for i, (field, val) in enumerate(conditions):
res = df[field] < val
if i == 0:
msk = res
else:
msk &= res
return df[msk]
答案 5 :(得分:0)
这是另一种方式:
import pandas as pd
import numpy as np
df = pd.DataFrame([np.arange(4),np.arange(3,7),np.arange(5,9)],
columns = ["field1","field2","field3","field4"])
f = [('field1', 3), ('field2', 4), ('field3', 5)]
mask = np.array([(df[i[0]] == i[1]) for i in f])
# 1 True is enough:
df[mask.any(axis=0)] # [False True False] in this sample
# All must be true
df[mask.all(axis=0)] # [False True False] in this sample
Df看起来像这样:
field1 field2 field3 field4
0 0 1 2 3
1 3 4 5 6
2 5 6 7 8