Pandas 基于多列进行分组和转换

问题描述 投票:0回答:3

我见过很多类似的问题,但似乎没有一个适合我的情况。我很确定这只是一个 groupby 转换,但我不断遇到

KeyError
axis
问题。我正在尝试按
filename
进行分组并检查
pred != gt
的位置。

例如,索引 2 是

f1.wav
的唯一索引,因此为 1,索引 (13,14,18) 是
f2.wav
的唯一索引,因此为 3。

df = pd.DataFrame([{'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 2, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f1.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f2.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f2.wav'}, {'pred': 2, 'gt': 2, 'filename': 'f2.wav'}, {'pred': 0, 'gt': 2, 'filename': 'f2.wav'}, {'pred': 0, 'gt': 2, 'filename': 'f2.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f2.wav'}, {'pred': 0, 'gt': 0, 'filename': 'f2.wav'}, {'pred': 2, 'gt': 2, 'filename': 'f2.wav'}, {'pred': 0, 'gt': 2, 'filename': 'f2.wav'}, {'pred': 2, 'gt': 0, 'filename': 'f2.wav'}])
    pred  gt filename
0      0   0   f1.wav
1      0   0   f1.wav
2      2   0   f1.wav
3      0   0   f1.wav
4      0   0   f1.wav
5      0   0   f1.wav
6      0   0   f1.wav
7      0   0   f1.wav
8      0   0   f1.wav
9      0   0   f1.wav
10     0   0   f2.wav

预期产量

    pred  gt filename  counts
0      0   0   f1.wav       1
1      0   0   f1.wav       1
2      2   0   f1.wav       1
3      0   0   f1.wav       1
4      0   0   f1.wav       1
5      0   0   f1.wav       1
6      0   0   f1.wav       1
7      0   0   f1.wav       1
8      0   0   f1.wav       1
9      0   0   f1.wav       1
10     0   0   f2.wav       3
11     0   0   f2.wav       3
12     2   2   f2.wav       3
13     0   2   f2.wav       3
14     0   2   f2.wav       3
15     0   0   f2.wav       3
16     0   0   f2.wav       3
17     2   2   f2.wav       3
18     0   2   f2.wav       3
19     2   0   f2.wav       3

我在想

df.groupby('filename').transform(lambda x: x['pred'].ne(x['gt']).sum(), axis=1)
但我明白了
TypeError: Transform function invalid for data types

python pandas dataframe group-by transform
3个回答
7
投票

.transform
单独对每一列进行操作,因此您无法在转换操作中同时访问“pred”和“gt”。

这给你两个选择:

  1. 聚合并重新索引或连接回原始形状
  2. 预先计算布尔数组并
    .transform

方法 2 可能是最快的:

df['counts'] = (
    (df['pred'] != df['gt'])
    .groupby(df['filename']).transform('sum')
)

print(df)
    pred  gt filename  counts
0      0   0   f1.wav       1
1      0   0   f1.wav       1
2      2   0   f1.wav       1
3      0   0   f1.wav       1
4      0   0   f1.wav       1
5      0   0   f1.wav       1
6      0   0   f1.wav       1
7      0   0   f1.wav       1
8      0   0   f1.wav       1
9      0   0   f1.wav       1
10     0   0   f2.wav       4
11     0   0   f2.wav       4
12     2   2   f2.wav       4
13     0   2   f2.wav       4
14     0   2   f2.wav       4
15     0   0   f2.wav       4
16     0   0   f2.wav       4
17     2   2   f2.wav       4
18     0   2   f2.wav       4
19     2   0   f2.wav       4

请注意

f2.wav
有 4 个实例,其中 'pre' != 'gt' (索引 13, 14, 18, 19)


1
投票

考虑到

df
是问题中的数据框 OP 共享,为了按
filename
分组并检查
pred
!=
gt
的计数,可以使用
pandas.DataFrame.groupby
pandas.DataFrame.apply
如下

df2 = df.groupby('filename').apply(lambda x: x[x['pred'] != x['gt']])

[Out]:
             pred  gt filename
filename                      
f1.wav   2      2   0   f1.wav
f2.wav   13     0   2   f2.wav
         14     0   2   f2.wav
         18     0   2   f2.wav
         19     2   0   f2.wav

假设想要统计每个

filename
出现的次数,因为经过上一次操作,
filename
既是索引级别又是列标签,这是不明确的,并且考虑到OP想要有一个列名为
count
来计算每组中每个项目的数量,必须达到
groupby
级别(可以传递的各种参数之一),最后使用
pandas.core.groupby.GroupBy.cumcount
。 (注意:与接受的答案相反,这种方法将按顺序计数)

df2['count'] = df2.groupby(level=0).cumcount() + 1 # The +1 is to make the count start at 1 instead of 0.

[Out]:
             pred  gt filename  count
filename                             
f1.wav   2      2   0   f1.wav      1
f2.wav   13     0   2   f2.wav      1
         14     0   2   f2.wav      2
         18     0   2   f2.wav      3
         19     2   0   f2.wav      4

单行代码如下所示

df2['count'] = df.groupby('filename').apply(lambda x: x[x['pred'] != x['gt']]).groupby(level=0).cumcount() + 1

[Out]:
             pred  gt filename  count
filename                             
f1.wav   2      2   0   f1.wav      1
f2.wav   13     0   2   f2.wav      1
         14     0   2   f2.wav      2
         18     0   2   f2.wav      3
         19     2   0   f2.wav      4

如果不需要将计数放在单独的列中,则将

df2
视为本答案中提到的第一个操作之后的数据帧(当创建
df2
时),那么可以简单地使用以下内容(这给出了更多信息)高级概述)

df3 = df2.groupby(level=0).count().iloc[:, 0]

[Out]:
filename
f1.wav    1
f2.wav    4
Name: pred, dtype: int64

0
投票

您可以将多个列中的数据聚合到一个元组中。然后,您可以处理包含许多列数据的单个列。

我的解决方案:

df["pred_gt"] = list(zip(*[df["pred"], df["gt"]]))
df["counts"] = df.groupby("filename")["pred_gt"].transform(
    lambda x: x.apply(lambda y: y[0] != y[1]).sum()
)
print(df)
    pred  gt filename pred_gt  counts
0      0   0   f1.wav  (0, 0)       1
1      0   0   f1.wav  (0, 0)       1
2      2   0   f1.wav  (2, 0)       1
3      0   0   f1.wav  (0, 0)       1
4      0   0   f1.wav  (0, 0)       1
5      0   0   f1.wav  (0, 0)       1
6      0   0   f1.wav  (0, 0)       1
7      0   0   f1.wav  (0, 0)       1
8      0   0   f1.wav  (0, 0)       1
9      0   0   f1.wav  (0, 0)       1
10     0   0   f2.wav  (0, 0)       4
11     0   0   f2.wav  (0, 0)       4
12     2   2   f2.wav  (2, 2)       4
13     0   2   f2.wav  (0, 2)       4
14     0   2   f2.wav  (0, 2)       4
15     0   0   f2.wav  (0, 0)       4
16     0   0   f2.wav  (0, 0)       4
17     2   2   f2.wav  (2, 2)       4
18     0   2   f2.wav  (0, 2)       4
19     2   0   f2.wav  (2, 0)       4

此方法也适用于 3 列或更多列。

© www.soinside.com 2019 - 2024. All rights reserved.