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_series 在 df 中设置另一列:
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
我有以下数据框:
>>> 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_series 在 df 中设置另一列:
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