动态比较 n 多个 Pandas 列的值
Posted
技术标签:
【中文标题】动态比较 n 多个 Pandas 列的值【英文标题】:Dynamic comparison of values of n multiple Pandas columns 【发布时间】:2021-11-16 14:31:09 【问题描述】:假设用户可以输入列和值来比较 DF,所以我们可以:
column_list = ['col1', 'col2', 'col3']
value_list = [val1, val2, val3]
所以要选择满足 where col1 >= val1 AND col2 >= val2 AND col3 >= val3 的行,我们会这样写:
selection = (df['col1'] >= val1) & (df['col2'] >= val2) & (df['col3'] >= val3))
也可以是以下形式:
selection = df.loc[(df['col1'] >= val1) & (df['col2'] >= val2) & (df['col3'] >= val3)]
列数是事先不知道的,所以我们可以有n列。我们可以试试这个方法:
if n=1:
selection = (df['col1'] >= val1))
elif n=2:
selection = (df['col1'] >= val1) & (df['col2'] >= val2))
elif n=3:
selection = (df['col1'] >= val1) & (df['col2'] >= val2) & (df['col3'] >= val3))
但这既不可扩展也不高效。我尝试通过在给定输入列表的情况下使用 foror 循环生成字符串“df['col'] >= val)”,但由于 str 格式,它不适用于 Pandas。
对此最好的pythonic方法是什么?避免使用 if 和 else 语句的所有选项。
提前谢谢你!
【问题讨论】:
有不同的>,<, =>, <=
?
OP,你能确认一下你的意思是混合不同的比较运算符吗?
我会更新它,对于所有这些都应该是 ">="
【参考方案1】:
要对所有列使用相同的运算符进行比较,请使用值和列 ID 创建一个系列,并使用它与数据框执行对齐比较:
df[df.gt(pd.Series(value_list, index=column_list)).all(1)]
示例输入:
>>> value_list
[3, 7, 11]
>>> df
col1 col2 col3
0 0 1 2
1 3 4 5
2 6 7 8
3 9 10 11
4 12 13 14
输出:
col1 col2 col3
4 12 13 14
中间体:
>>> pd.Series(value_list, index=column_list)
col1 3
col2 7
col3 11
>>> df.gt(pd.Series(value_list, index=column_list))
col1 col2 col3
0 False False False
1 False False False
2 True False False
3 True True False
4 True True True
>>> df.gt(pd.Series(value_list, index=column_list)).all(1)
0 False
1 False
2 False
3 False
4 True
【讨论】:
特别强调同一个操作符。如果这是 OP 最终需要的很好的解决方案。 这很简单,它解决了所有操作员相同的问题,谢谢! mozway @juanman 请注意,既然你想要>=
,你应该使用ge
而不是gt
。【参考方案2】:
有了这样的df
,
In [1]: df
Out[1]:
a b c
0 1 7 7
1 2 1 1
2 6 2 6
3 2 6 3
4 3 3 8
5 5 9 0
和值、列和任意运算符,
In [2]: import operator
In [3]: values = [1, 2, 7]
In [4]: columns = ['a', 'b', 'c']
In [5]: operators = [operator.gt, operator.ge, operator.le] # >, >=, <=
复制df
并遍历压缩的项目:
In [6]: selection = df.copy()
In [7]: for col, op, val in zip(columns, operators, values):
...: selection = selection[op(selection[col], val)]
...:
In [8]: selection
Out[8]:
a b c
2 6 2 6
3 2 6 3
5 5 9 0
当然,如果您不提前知道有多少列,那么您似乎也可能不提前知道 operators,哪种达不到目的。如果您只需要使用单个运算符,这将变得更加容易,但从您的示例来看,情况似乎并非如此。
如果您的原始帖子确实有拼写错误(所有比较应该是>
,还是都应该是>=
?)并且您确实打算执行单个比较操作,请参阅@987654321 @来自@mozway。
【讨论】:
感谢ddejohn的输入,它允许有其他运算符组合【参考方案3】:这是处理任意长比较列表的另一种可能性(我单独发布,因为方法完全不同):
column_list = ['col1', 'col2', 'col3']
value_list = [3, 7, 11]
operator_list = [pd.Series.gt, pd.Series.ge, pd.Series.gt]
op_dic = dict(zip(column_list, operator_list))
val_dic = dict(zip(column_list, value_list))
df[df.apply(lambda c: op_dic[c.name](c, val_dic[c.name])).all(1)]
工作原理:
使用apply
,我们对所有列执行自定义操作,每行返回一个布尔值,然后取所有为真的行。
输入:
col1 col2 col3
0 0 1 2
1 3 4 5
2 6 7 8
3 9 10 11
4 12 13 14
输出:
col1 col2 col3
4 12 13 14
注意。为了更简洁,也可以这样做:
from operator import gt, ge
operator_list = [gt, ge, gt]
【讨论】:
感谢您的输入mozway以上是关于动态比较 n 多个 Pandas 列的值的主要内容,如果未能解决你的问题,请参考以下文章
Pandas / Numpy - 如何获取和比较每列与每列的计数并写入 csv?