我有一个像下面这样的 pandas DataFrame:
df = pd.DataFrame({"A": [1, 1, 1, 2, 2],
"B": ["apple", "apple", "banana", "pineapple", "pineapple"],
"C": [[6, 5, 2], [2, 10, 2], [5, 37, 1], [4, 19, 2], [1, 5, 1]]})
现在我想对 A
和 B
列执行分组操作,并获取 C
列列表的平均值。多个列表的平均值被定义为逐元素平均值,因此列表第一个位置的所有第一个元素的平均值,列表第二个位置的所有第二个元素的平均值等等......
此示例所需的输出如下所示:
A B C
1 apple [4, 7.5, 2]
1 banana [5, 37, 1]
2 pineapple [2.5, 12, 1.5]
(始终保证每个组的列表具有相同的长度)
如何解决?
通常我知道如何执行 groupby 操作,无论是作为列表聚合还是作为平均值,但在比较多个列表时我找不到如何执行此操作。如果 groupby 操作不是最有效的解决方案,我也乐于接受其他建议。
最佳答案
方法一
在这里,我们从 C
列中包含的列表创建一个新数据框并将这个新创建的数据框的索引设置为列 A
和 B
.现在,通过取 mean
聚合此帧在指数中存在的水平
然后使用 .values
+ tolist
将平均值的 View 作为 numpy 数组,将此 View 转换为列表并分配给列 C
s = df.set_index(['A', 'B'])
out = pd.DataFrame(list(s['C']), s.index).mean(level=[0, 1])
out.drop(out.columns.tolist(), 1).assign(C=out.values.tolist()).reset_index()
方法二
处理大数据帧时可能较慢的朴素方法。在这里,我们按列对数据框进行分组 A
和 B
和 apply
列 C
上的 lambda 函数,然后 lambda 函数从列表中创建一个 numpy 数组,并沿 axis=0
取平均值。
out = df.groupby(['A', 'B'])['C'].apply(
lambda s: np.array(list(s)).mean(axis=0)).reset_index()
结果
A B C
0 1 apple [4.0, 7.5, 2.0]
1 1 banana [5.0, 37.0, 1.0]
2 2 pineapple [2.5, 12.0, 1.5]
性能分析
在具有 50000 行和 30000 唯一组的示例数据框中
df = pd.concat([df.assign(B=df['B'] + str(i))
for i in range(10000)], ignore_index=True)
%%timeit
s = df.set_index(['A', 'B'])
out = pd.DataFrame(list(s['C']), s.index).mean(level=[0, 1])
_ = out.drop(out.columns.tolist(), 1).assign(C=out.values.tolist()).reset_index()
# 173 ms ± 19 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
_ = df.groupby(['A', 'B'])['C'].apply(lambda s: np.array(list(s)).mean(axis=0)).reset_index()
# 2.24 s ± 68.1 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
关于python - 如何对取列表列平均值的 pandas Dataframe 执行 groupby 操作?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67649701/