pandas 如何在python中选择按不同列分组的特定条件以上的行?

s3fp2yjn  于 2023-04-19  发布在  Python
关注(0)|答案(2)|浏览(119)

我有以下 Dataframe :

A   B   C
1   3   2
1   7   7
1   7   7
1   5   4
2   2   1
2   8   8
2   4   5
3   5   3
3   1   9
3   4   4

我试图做的是,对于A列中的每一组相同的值,找到B列中的值等于C列中的值的最后一行,然后返回B = C的LAST行之前的行,包括行本身。所以预期的结果是:

A   B   C
1   3   2
1   7   7
1   7   7
2   2   1
2   8   8
3   5   3
3   1   9
3   4   4

我已经尝试了下面的代码,但它返回的是B = C的第一行之前的行,而不是最后一行之前的行。

mask = df['B'] == df['C']
df.loc[mask[::-1].groupby(df['A']).cummax()]
carvr3hs

carvr3hs1#

使用反向的groupby.cummax按预期工作:

m = df['B'].eq(df['C'])
out = df[m[::-1].groupby(df['A']).cummax()]

输出:

A  B  C
0  1  3  2
1  1  7  7
2  1  7  7
4  2  2  1
5  2  8  8
7  3  5  3
8  3  1  9
9  3  4  4

可复制输入:

df = pd.DataFrame({'A': [1, 1, 1, 1, 2, 2, 2, 3, 3, 3],
                   'B': [3, 7, 7, 5, 2, 8, 4, 5, 1, 4],
                   'C': [2, 7, 7, 4, 1, 8, 5, 3, 9, 4]})

错误可能来自具有重复值的索引,在这种情况下,您可以使用底层numpy数组绕过索引对齐,并手动反转输出:

grouper = df.loc[::-1, 'A'].values
out = df.loc[m[::-1].groupby(grouper).cummax()[::-1]]

备选输入:

df = pd.DataFrame({'A': [1, 1, 1, 1, 2, 2, 2, 3, 3, 3],
                   'B': [3, 7, 7, 5, 2, 8, 4, 5, 1, 4],
                   'C': [2, 7, 7, 4, 1, 8, 5, 3, 9, 4]},
                 index=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
                 )
选择第一个相等之前(包括)的所有行
tmp = df.assign(m=df['B'].ne(df['C']))
# rows before the first equality
m1 = tmp.groupby('A')['m'].cummin()
# first equality
m2 = ~tmp.duplicated(['A', 'm'])

out = df[m1|m2]
  • 注意,如果不想包含第一个等式,只需使用out = df[m1]。*

输出:

A  B  C
0  1  3  2
1  1  7  7
4  2  2  1
5  2  8  8
7  3  5  3
8  3  1  9
9  3  4  4
yx2lnoni

yx2lnoni2#

对于我正确的解决方案,这里有一个创建助手列的替代方案:

mask = df['B'] == df['C']
df = df[df.assign(m=mask).iloc[::-1].groupby('A')['m'].cummax()]
#or
#df = df[df.assign(m=mask).iloc[::-1].groupby('A')['m'].cummax().iloc[::-1]]
print (df)
   A  B  C
0  1  3  2
1  1  7  7
2  1  7  7
4  2  2  1
5  2  8  8
7  3  5  3
8  3  1  9
9  3  4  4

另一个想法是创建默认索引:

df = df.reset_index(drop=True)

#OP solution
mask = df['B'] == df['C']
df.loc[mask[::-1].groupby(df['A']).cummax()]

编辑:如果需要所有行在第一个相同的B之前,C列用途:

#sample data
print (df)
    A  B  C
0   1  3  2
1   1  7  7
2   1  7  7
3   1  5  4
4   1  7  7
5   1  2  2
6   2  2  1
7   2  8  8
8   2  4  5
9   3  5  3
10  3  1  9
11  3  4  4
12  4  7  7
13  4  7  7
14  4  7  5
15  5  4  4
16  5  4  4
17  5  1  1
18  5  1  1
19  6  8  4
#compare columns
m = df['B'] == df['C']
#create groups by consecutive B, C columns
df1 = df.assign(g = df[['B','C']].ne(df[['B','C']].shift()).any(axis=1).cumsum())
print (df1)
    A  B  C   g
0   1  3  2   1
1   1  7  7   2
2   1  7  7   2
3   1  5  4   3
4   1  7  7   4
5   1  2  2   5
6   2  2  1   6
7   2  8  8   7
8   2  4  5   8
9   3  5  3   9
10  3  1  9  10
11  3  4  4  11
12  4  7  7  12
13  4  7  7  12
14  4  7  5  13
15  5  4  4  14
16  5  4  4  14
17  5  1  1  15
18  5  1  1  15
19  6  8  4  16
#filter only matched B, C and aggregate min
s = df1[m].groupby('A')['g'].min()

#compare mapped A groups and filter if less or equal values
df2 = df[df1['g'].le(df['A'].map(s))]
print (df2)
    A  B  C
0   1  3  2
1   1  7  7
2   1  7  7
6   2  2  1
7   2  8  8
9   3  5  3
10  3  1  9
11  3  4  4
12  4  7  7
13  4  7  7
15  5  4  4
16  5  4  4
#if need only first row with same B, C chain duplicated
df3 = df[df1['g'].le(df['A'].map(s)) & ~df1['g'].duplicated()]
print (df3)
    A  B  C
0   1  3  2
1   1  7  7
6   2  2  1
7   2  8  8
9   3  5  3
10  3  1  9
11  3  4  4
12  4  7  7
15  5  4  4

相关问题