动态比较 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,哪种达不到目的。如果您只需要使用单个运算符,这将变得更加容易,但从您的示例来看,情况似乎并非如此。

如果您的原始帖子确实有拼写错误(所有比较应该是&gt;,还是都应该是&gt;=?)并且您确实打算执行单个比较操作,请参阅@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?

pandas比较两个dataframe特定数据列的数值是否相同并给出差值:使用np.where函数

使用 pandas 比较不同块中的值

动态比较 MySQL 中的版本号

如何比较多列,并在单个新列中生成值,在 Pandas 中使用 Apply 函数