pandas 等价于 STRING_AGG 对几列进行分组

pandas equivalent of groub by with STRING_AGG for several columns

那么有没有一种方法可以对 DataFrame 对象进行分组,然后对于剩余的列,将所有条目放入一个集合(或具有过滤的唯一值的列表)中。所以像这样

   Name        Date  Amount   purchase
0  Jack  2016-01-31      10    'apple'
1  Jack  2016-02-29       5        25
2  Jack  2016-02-29       8       'B+'
3  Jill  2016-01-31      10       'D2'
4  Jill  2016-02-29       5         E
4  Jill  2016-02-29       5         E

按前两列分组后输出

    Name        Date  Amount     purchase
 0  Jack  2016-01-31     [10]     [apple]
 1  Jack  2016-02-29    [5,8]   [25,'B+']
 3  Jill  2016-01-31     [10]      ['D2']
 4  Jill  2016-02-29      [5]       ['E']

所以我可以用 df_data = df.groupby(['Name', 'Date'])['Amount'].apply(set) 对每一列进行操作,然后将它们连接起来,但是如果列表很长,是否有更短更优雅的解决方案?

可以使用groupby的聚合函数。此外,如果想要 MultiIndexNameDate.

级别的列,则必须重置索引
df_data = df.groupby(['Name', 'Date']).aggregate(lambda x: list(x)).reset_index()

不要这样做

Pandas 从未设计为以系列/列的形式保存列表。您可以制定昂贵的变通办法,但不推荐这些。

不推荐以系列方式保存列表的主要原因是您失去了使用 NumPy 数组保存在连续内存块中的矢量化功能。您的系列将是 object dtype,代表指针序列,很像 list.

当然,objectdtype对于混合类型是不可避免的。但是,在这里,嵌套指针结构使效果更加复杂。您将失去内存和性能方面的优势,也无法访问优化的 Pandas 方法。


稍微好一点的选择

可以聚合成字符串,这样就只有一级指针了:

res = df.groupby(['Name', 'Date'], as_index=False)[['Amount', 'purchase']]\
        .agg(lambda x: ', '.join(map(str, set(x))))

print(res)
    
   Name        Date Amount  purchase
0  Jack  2016-01-31     10   'apple'
1  Jack  2016-02-29   8, 5  'B+', 25
2  Jill  2016-01-31     10      'D2'
3  Jill  2016-02-29      5         E