首页 > 解决方案 > 如何对采用列表列平均值的熊猫数据框执行 groupby 操作?

问题描述

我有一个如下所示的熊猫数据框:

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。多个列表的平均值被定义为按元素的平均值,因此列表第 1 位的所有第 1 个元素的平均值,列表第 2 位的所有第 2 个元素的平均值等等......

此示例所需的输出如下所示:

A        B            C
1        apple        [4, 7.5, 2]
1        banana       [5, 37, 1]
2        pineapple    [2.5, 12, 1.5]

(始终保证每个组的列表具有相同的长度)

如何解决这个问题?

通常我知道如何执行 groupby 操作,无论是作为列表聚合还是作为平均值,但是在比较多个列表时我找不到如何执行此操作。如果 groupby 操作不是最有效的解决方案,我也愿意接受其他建议。

标签: pythonpandasdataframegroup-by

解决方案


方法一

在这里,我们从 column 中包含的列表创建一个新的数据框,C并将这个新创建的数据框的索引设置为 columnsABmean现在,通过采用索引中存在的级别来聚合此框架

然后使用.values+tolist将平均值的视图作为 numpy 数组,将此视图转换为列表并分配给列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并在 column 上使用 lambda 函数,B然后lambda 函数从列表中创建一个 numpy 数组并取平均值applyCaxis=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)

推荐阅读