我见过很多类似的问题,但似乎没有一个适合我的情况。我很确定这只是一个 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
.transform
单独对每一列进行操作,因此您无法在转换操作中同时访问“pred”和“gt”。
这给你两个选择:
.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)
考虑到
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
您可以将多个列中的数据聚合到一个元组中。然后,您可以处理包含许多列数据的单个列。
我的解决方案:
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 列或更多列。