pandas: select 符合多个条件的所有行

pandas: select all rows matching multiple conditions

我有以下数据框:

 >>> df = pd.DataFrame({'col1': [1, 2, 1], 'col2': [6, 3, 6]})
 >>> df
    col1  col2
  0     1     6
  1     2     3
  2     1     6

和以下词典:

 >>> di = {'col1': 1, 'col2': 6}
 >>> di
 {'col2': 6, 'col1': 1}

我正在寻找一种解决方案,它将遍历 di 并在 df 中找到匹配的行。我不想写一行专门使用列名和值。我在论坛上看到过这些解决方案,但这不是我在这里要做的。我采用的(糟糕的非)解决方案是:

 is_not_first = True
 tf_series = None
 for key, val in di.iteritems():
      if is_not_first:
           tf_series = (tf_series & (df[key] == val))
      else:
           tf_series = (df[key] == val)
           is_not_first = False

我计划稍后使用 tf_seriesdf 中设置另一列:

 df.loc[tf_series, 'col3'] = True

从我看到的许多优秀的 pandas 帖子来看,我确信有一些更简洁的东西,更不用说,一些实际有效的东西。谢谢!

您可以将所有逻辑合并到一行中,而不是构建一个冗余系列,您可以构建另一个具有与您的 df 相同 Index/Column 的 DataFrame并直接分配给 df['col3'],这是实现此目的的一种方法:

In [1]: import pandas as pd

In [2]: df = pd.DataFrame({'col1': [1, 2, 1], 'col2': [6, 3, 6]})

In [3]: di = {'col1': 1, 'col2': 6}

In [4]: df['col3'] = pd.DataFrame([df[k]==v for k,v in di.iteritems()]).all()

In [5]: df
Out[5]: 
   col1  col2   col3
0     1     6   True
1     2     3  False
2     1     6   True

或者使用 map 的更快更简略的版本:

In [6]: df['col3'] = pd.DataFrame(map(lambda k: df[k]==di[k], di)).all()

明细说明

如果你查看 list,当你迭代字典 di 时,它会给你 key/value 对,实际上是你原来的 df 的 columns/values。 所以 df[column] 会给你它的值,你将它与字典的 v 进行比较,它会产生 True/False.

In [8]: [df[k]==v for k,v in di.iteritems()]
Out[8]: 
[0     True
 1    False
 2     True
 Name: col2, dtype: bool, 0     True
 1    False
 2     True
 Name: col1, dtype: bool]

然后你从那个结果构建一个影子数据帧,会给你这个:

pd.DataFrame([df[k]==v for k,v in di.iteritems()])
Out[9]: 
         0      1     2
col2  True  False  True
col1  True  False  True

编辑

正如@ant 指出的那样,我错误地使用了 any() 而它应该是 all() 来满足所有 True 值:

最后,all() 其中 return index/result 上面的列满足所有 条件:

In [10]: pd.DataFrame([df[k]==v for k,v in di.iteritems()]).all()
Out[10]: 
0     True
1    False
2     True
dtype: bool 

您只需将此结果列分配给 df['col3'],就大功告成了。

为了避免SettingWithCopy警告,你只需要将一个衬里分成2个:

new_col = pd.DataFrame(df[k]==v for k,v in di.iteritems()).all()
df['col3'] = new_col