如果满足m个条件中的任何一个,则为熊猫

时间:2020-01-22 19:57:50

标签: python pandas

示例。

假设我的数据框包含几列,并且我想选择与所有4个条件匹配的行,我会这样写:

condition = (df['A'] < 10) & (df['B'] < 10) & (df['C'] < 10) & (df['D'] < 10)
df.loc[condition]

与之相反,如果我要选择与以下四个条件中的任何一个相匹配的行,我会写:

condition = (df['A'] < 10) | (df['B'] < 10) | (df['C'] < 10) | (df['D'] < 10)
df.loc[condition]

现在,如果我想选择与这4个条件中的任何两个条件匹配的行怎么办?那将是与列(A和B),(A和C),(A和D),(B和C)或(C和D)的任何组合匹配的行。很明显,我可以使用所有这些组合来编写复杂的条件:

condition = ((df['A'] < 10) & (df['B'] < 10)) |\
            ((df['A'] < 10) & (df['C'] < 10)) |\
            ((df['A'] < 10) & (df['D'] < 10)) |\
            ((df['B'] < 10) & (df['C'] < 10)) |\
            ((df['C'] < 10) & (df['D'] < 10))
df.loc[condition]

但是,如果有50列,而我想匹配这50列中的任何20列,那么就不可能将所有可能的组合都列为条件。有办法更好地做到这一点吗?

2 个答案:

答案 0 :(得分:5)

True == 1False == 0起,您可以通过检查总和找到满足至少N个条件的行。系列具有大多数基本比较作为属性,因此您可以制作带有多个检查的单个条件列表,然后使用getattr使其整洁。

import pandas as pd
import numpy as np

np.random.seed(123)
df = pd.DataFrame(np.random.randint(0, 20, (5,4)), columns=list('ABCD'))

# can check `eq`, `lt`, `le`, `gt`, `ge`, `isin`
cond_list = [('A', 'lt', 10), ('B', 'ge', 10), ('D', 'eq', 4), 
             ('C', 'isin', [2, 4, 6])]
df_c = pd.concat([getattr(df[col], attr)(val).astype(int) 
                  for col,attr,val in cond_list], axis=1)
#   A  B  D  C
#0  0  0  0  1
#1  0  1  0  0
#2  1  1  0  0
#3  1  1  0  0
#4  0  1  0  1

# Each row satisfies this many conditions
df_c.sum(1)
#0    1
#1    1
#2    2
#3    2
#4    2
#dtype: int64

#Select those that satisfy at least 2.
df[df_c.sum(1).ge(2)]
#    A   B   C   D
#2   0  17  15   9
#3   0  14   0  15
#4  19  14   4   0

如果您需要使用.getattr无法进行的一些更复杂的比较,则可以自行编写并合并该系列列表。

df_c = pd.concat([df['A'].lt(10), df['B'].ge(10), df['D'].eq(4), 
                  df['C'].isin([2,4,6])], 
                 axis=1).astype(int)

答案 1 :(得分:3)

这是使用itertools.combinations的方法,因此我们可以获得条件的所有必要组合。然后我们检查条件1和条件2的“数量”为True

# test dataframe
np.random.seed(10)
df = pd.DataFrame(np.random.randint(20, size=(10,5)), columns=list('ABCDE'))
print(df)

    A   B   C   D   E
0   9   4  15   0  17
1  16  17   8   9   0
2  10   8   4  19  16
3   4  15  11  11   1
4   8   4  14  17  19
5  13   5  13  19  13
6  12   1   4  18  13
7  11  10   9  15  18
8  16   7  11  17  14
9   7  11   1   0  12
from itertools import combinations

conditions = [(df['A'] < 10), (df['B'] < 15), (df['C'] >= 5), (df['D'] <= 9)]
mask = pd.concat([x&y for x, y in combinations(conditions, 2)], axis=1).sum(axis=1).ge(2)

df[mask]

   A   B   C   D   E
0  9   4  15   0  17
4  8   4  14  17  19
9  7  11   1   0  12