n 多个 Pandas 列的值的动态比较

Dynamic comparison of values of n multiple Pandas columns

假设用户可以输入列和值来比较 DF,因此我们可以:

column_list = ['col1', 'col2', 'col3']
value_list = [val1, val2, val3]

所以对于 select 满足 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))

但这既不具有可扩展性也不高效。我尝试在给定输入列表的情况下使用 for 循环生成字符串 df['col<>'] >= val<>),但由于 str 格式,它不适用于 Pandas。

最好的 pythonic 方法是什么?为了避免所有选项都带有 if 和 else 语句。

要对所有列使用相同的运算符进行比较,请创建一个包含值和列 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

这是处理任意长比较列表的另一种可能性(我单独发布,因为方法完全不同):

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,我们对所有列执行自定义操作,每行 return 一个布尔值,然后取对所有都为 True 的行。

输入:

   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]

有了这样的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无论是哪种,都违背了目的。如果您只需要使用一个运算符,这将变得 容易,但从您的示例来看,情况似乎并非如此。

如果您的原文 post 确实有拼写错误(所有比较应该是 >,还是全部 >=?)并且您实际上打算执行 single比较操作,见@mozway的