如何在熊猫中比较行值和组值

时间:2020-10-22 13:54:50

标签: python pandas pandas-groupby

我有一个看起来像这样的数据框

pd.DataFrame({'A': ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H'],
   ...:                    'B': ['C1', 'C1', 'C1', 'C1', 'C2', 'C2', 'C2', 'C2'],
   ...:                    'X': [0, 0, 1, 1, 0, 1, 0, 0],
   ...:                    'Y': [1, 1, 1, 0, 1, 1, 0, 1],
   ...:                    'Z': [4, 5, 2, 1, 2, 1, 3, 5]})
Out[35]: 
   A   B  X  Y  Z
0  A  C1  0  1  4
1  B  C1  0  1  5
2  C  C1  1  1  2
3  D  C1  1  0  1
4  E  C2  0  1  2
5  F  C2  1  1  1
6  G  C2  0  0  3
7  H  C2  0  1  5

我想按组(B列)选择所有行,其中Y列等于1 AND

(Z列的总和)<(10-X = 1的Z列的总和)

我尝试过

(df.Y==1) & ((df[df.Y==1].groupby('B')['Z'].cumsum()) <= (10 - df[df.X==1].groupby('B')['Z'].sum()))
Traceback (most recent call last):
  File "C:\ProgramData\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py", line 2963, in run_code
    exec(code_obj, self.user_global_ns, self.user_ns)
  File "<ipython-input-36-5be310568c09>", line 1, in <module>
    df['S'] = (df.Y==1) & ((df[df.Y==1].groupby('B')['Z'].cumsum()) <= (10 - df[df.X==1].groupby('B')['Z'].sum()))
  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\ops\common.py", line 64, in new_method
    return method(self, other)
  File "C:\ProgramData\Anaconda3\lib\site-packages\pandas\core\ops\__init__.py", line 524, in wrapper
    raise ValueError("Can only compare identically-labeled Series objects")
ValueError: Can only compare identically-labeled Series objects

这有效

(df.Y==1) & ((df[df.Y==1].groupby('B')['Z'].cumsum()) <= 10)
Out[39]: 
0     True
1     True
2    False
3    False
4     True
5     True
6    False
7     True
dtype: bool

但这只是检查是否(cumsum <= 10),而不是(10减去df.Z,其中df.X == 1)

什么是正确的方法?

2 个答案:

答案 0 :(得分:0)

让我们使用groupby().apply()并使用您的逻辑:

mask = (df.loc[df['Y']==1]
   .groupby('B')
   .apply(lambda x: x['Z'].cumsum() + x['Z']*x['X'].eq(1) < 10)
   .reset_index('B', drop=True)
    & df['Y'].eq(1)
)

输出:

0     True
1     True
2    False
3    False
4     True
5     True
6    False
7     True
dtype: bool

答案 1 :(得分:0)

此方法创建2个新列,然后使用其中的值来过滤数据框。新列:

•'Z_cumsum':当'Y'= 1时,按'B'中的组的'Z'累积总和

•'Z_sum':'B'中每个组的Z值之和,仅包括Z其中的值

df['Z_cumsum'] = np.nan
df.loc[df.Y==1, 'Z_cumsum'] = df[df.Y==1].groupby('B')['Z'].cumsum()

df['Z_sum'] = np.nan
for b in set(df['B']):
    df.loc[df.B==b,'Z_sum'] = df.loc[df['X']==1].groupby('B')['Z'].sum()[b]
df

新数据框:

    A   B   X   Y   Z   Z_cumsum    Z_sum
0   A   C1  0   1   4   4.0         3.0
1   B   C1  0   1   5   9.0         3.0
2   C   C1  1   1   2   11.0        3.0
3   D   C1  1   0   1   NaN         3.0
4   E   C2  0   1   2   2.0         1.0
5   F   C2  1   1   1   3.0         1.0
6   G   C2  0   0   3   NaN         1.0
7   H   C2  0   1   5   8.0         1.0

现在,您可以更轻松地过滤数据框:

(df.Y==1) & (df['Z_cumsum'] <= (10- df['Z_sum']))

0     True
1    False
2    False
3    False
4     True
5     True
6    False
7     True
dtype: bool

我知道这是一种相当麻烦的方法,但这是我能够得到的。