Python 使用dict中的值筛选数据帧

Python 使用dict中的值筛选数据帧,python,pandas,Python,Pandas,我需要使用dict过滤数据帧,该dict构造为键为列名,值为我要过滤的值: filter_v = {'A':1, 'B':0, 'C':'This is right'} # this would be the normal approach df[(df['A'] == 1) & (df['B'] ==0)& (df['C'] == 'This is right')] 但我想在网上做点什么 for column, value in filter_v.items(): d

我需要使用dict过滤数据帧,该dict构造为键为列名,值为我要过滤的值:

filter_v = {'A':1, 'B':0, 'C':'This is right'}
# this would be the normal approach
df[(df['A'] == 1) & (df['B'] ==0)& (df['C'] == 'This is right')]
但我想在网上做点什么

for column, value in filter_v.items():
    df[df[column] == value]
但这将对数据帧进行多次过滤,每次过滤一个值,并且不会同时应用所有过滤器。有没有一种方法可以通过编程实现

编辑:例如:

df1 = pd.DataFrame({'A':[1,0,1,1, np.nan], 'B':[1,1,1,0,1], 'C':['right','right','wrong','right', 'right'],'D':[1,2,2,3,4]})
filter_v = {'A':1, 'B':0, 'C':'right'}
df1.loc[df1[filter_v.keys()].isin(filter_v.values()).all(axis=1), :]
给予

但预期的结果是

    A   B   C   D
3   1   0   right   3

只能选择最后一个。

以下是一种方法:

df.loc[df[filter_v.keys()].isin(filter_v.values()).all(axis=1), :]
更新:

如果各列的值相同,则可以执行以下操作:

# Create your filtering function:

def filter_dict(df, dic):
    return df[df[dic.keys()].apply(
            lambda x: x.equals(pd.Series(dic.values(), index=x.index, name=x.name)), asix=1)]

# Use it on your DataFrame:

filter_dict(df1, filter_v)
df1.filter_dict_(filter_v)
>>> df1.loc[(df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1)]
   A  B      C  D
3  1  0  right  3
这将产生:

   A  B      C  D
3  1  0  right  3            
如果它是您经常做的事情,您可以尽量修补DataFrame,以便轻松访问此筛选器:

pd.DataFrame.filter_dict_ = filter_dict
然后像这样使用此过滤器:

# Create your filtering function:

def filter_dict(df, dic):
    return df[df[dic.keys()].apply(
            lambda x: x.equals(pd.Series(dic.values(), index=x.index, name=x.name)), asix=1)]

# Use it on your DataFrame:

filter_dict(df1, filter_v)
df1.filter_dict_(filter_v)
>>> df1.loc[(df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1)]
   A  B      C  D
3  1  0  right  3
这将产生相同的结果

但显然,这不是正确的方法。 我会使用DSM的方法。

还有另一种方法:

filterSeries = pd.Series(np.ones(df.shape[0],dtype=bool))
for column, value in filter_v.items():
    filterSeries = ((df[column] == value) & filterSeries)
这使得:

>>> df[filterSeries]
   A  B      C  D
3  1  0  right  3 

IIUC,你应该能做这样的事情:

# Create your filtering function:

def filter_dict(df, dic):
    return df[df[dic.keys()].apply(
            lambda x: x.equals(pd.Series(dic.values(), index=x.index, name=x.name)), asix=1)]

# Use it on your DataFrame:

filter_dict(df1, filter_v)
df1.filter_dict_(filter_v)
>>> df1.loc[(df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1)]
   A  B      C  D
3  1  0  right  3

这项工作通过制作一个系列来比较:

>>> pd.Series(filter_v)
A        1
B        0
C    right
dtype: object
选择df1的相应部分:

>>> df1[list(filter_v)]
    A      C  B
0   1  right  1
1   0  right  1
2   1  wrong  1
3   1  right  0
4 NaN  right  1
查找它们的匹配位置:

>>> df1[list(filter_v)] == pd.Series(filter_v)
       A      B      C
0   True  False   True
1  False  False   True
2   True  False  False
3   True   True   True
4  False  False   True
查找它们的匹配位置:

最后,使用此索引到df1:

>>> df1.loc[(df1[list(filter_v)] == pd.Series(filter_v)).all(axis=1)]
   A  B      C  D
3  1  0  right  3

对于python2,在@primer的回答中这是可以的。但是,在Python3中应该小心,因为dict\u键是的。比如说,

>> df.loc[df[filter_v.keys()].isin(filter_v.values()).all(axis=1), :]
>> TypeError: unhashable type: 'dict_keys'
通往Python3的正确方法:

df.loc[df[list(filter_v.keys())].isin(list(filter_v.values())).all(axis=1), :]

要跟进DSM的答案,您还可以使用
any()
将查询转换为OR操作(而不是AND):


df1.loc[(df1[list(filter_v)]==pd.Series(filter_v)).any(axis=1)]

在传递过滤器值数组而非单个值的情况下,对上述内容进行抽象(类似于pandas.core.Series.Series.isin()。使用相同的示例:

df1 = pd.DataFrame({'A':[1,0,1,1, np.nan], 'B':[1,1,1,0,1], 'C':['right','right','wrong','right', 'right'],'D':[1,2,2,3,4]})
filter_v = {'A':[1], 'B':[1,0], 'C':['right']}
##Start with array of all True
ind = [True] * len(df1)

##Loop through filters, updating index
for col, vals in filter_v.items():
    ind = ind & (df1[col].isin(vals))

##Return filtered dataframe
df1[ind]

##Returns

    A   B    C      D
0   1.0 1   right   1
3   1.0 0   right   3

我遇到了一个问题,因为我的字典对同一个键有多个值

我能够将DSM的查询更改为:

df1.loc[df1[list(filter_v)].isin(filter_v).all(axis=1), :]

所需的输出是什么?一个数据帧,其中只有同时对应于所有条件的值。谢谢,但这似乎也只应用了dict上的最后一个密钥对。我不确定我是否理解您所说的。。。这种方法是对
filter
字典中编码为键的所有列进行简单筛选,然后筛选行中的所有值以匹配字典中的值。也许你可以用可重复的例子来说明这个问题?很好的解决方案和令人敬畏的解释。@DSM你如何检查
dict.keys
中的
df
列是否包含
str
from
dict.values
?使用list(filter_v)和Series(filter_v)使这个解决方案变得神秘。为什么不直接使用
df1[filter\u v.keys()]==filter\u v.values()
作为内部条件呢?我从来没有听说过你可以用这样的系列来掩盖它!这真是一个很棒的食谱。“我认为应该在食谱中。”普拉萨达查拉萨尼-我认为这不管用。您需要创建一个系列,以使
==
运算符在右列上生成一个掩码。@Muhammad感谢您的编辑。我还不熟悉格式,因为这是我的第一篇文章。