【问题标题】:Pandas - aggregate over inconsistent values types (string vs list)Pandas - 聚合不一致的值类型(字符串与列表)
【发布时间】:2019-01-27 12:57:02
【问题描述】:

鉴于以下 DataFrame,我尝试聚合列 'A''C'。对于'A',计算字符串的唯一出现次数,对于'C',求和。

'A' 中的一些样本实际上是这些字符串的列表时,就会出现问题。

这是一个简化的例子:

df = pd.DataFrame({'ID': [1, 1, 1, 1, 1, 2, 2, 2], 
               'A' : ['a', 'a', 'a', 'b', ['b', 'c', 'd'], 'a', 'a', ['a', 'b', 'c']],
               'C' : [1, 2, 15, 5, 13, 6, 7, 1]})
df
Out[100]: 
   ID          A   C
0   1          a   1
1   1          a   2
2   1          a  15
3   1          b   5
4   1  [b, c, d]  13
5   2          a   6
6   2          a   7
7   2  [a, b, c]   1

aggs = {'A' : lambda x: x.nunique(dropna=True),
        'C' : 'sum'}

# This will result an error: TypeError: unhashable type: 'list'
agg_df = df.groupby('ID').agg(aggs)

我想要以下输出:

print(agg_df)
    A   C
ID       
1   4  36
2   3  14

这是因为对于 'ID' = 1,我们有 'a', 'b', 'c' and 'd',对于 'ID' = 2,我们有 'a', 'b', 'c'

【问题讨论】:

  • lambda x: x.apply(pd.Series).stack().nunique() 会这样做吗?
  • @JonClements 是的!把它作为答案,这样我就可以吻你了,如果你在这个 lambda 中解释细节,我将非常感激
  • apply(pd.Series) + stack 会起作用,但也可能会很慢。
  • @jpp 确实......这就是为什么我没有发布答案......这些天必须有一种更好的熊猫风格的方法... :)
  • @JonClements,是的,它这样是一个常见问题。我最喜欢(对于少数列)是np.repeat + it.chain,但我觉得我们重复的食谱应该内置在 Pandas 中,可能是 Cythonised 用于一般用途。

标签: python pandas dataframe pandas-groupby


【解决方案1】:

一种解决方案是将您的问题分成两部分。首先展平您的数据框以确保 df['A'] 仅包含字符串。然后连接几个GroupBy 操作。

第 1 步:扁平化数据框

您可以根据需要使用itertools.chainnumpy.repeat 链接和重复值。

from itertools import chain

A = df['A'].apply(lambda x: [x] if not isinstance(x, list) else x)
lens = A.map(len)

res = pd.DataFrame({'ID': np.repeat(df['ID'], lens),
                    'A': list(chain.from_iterable(A)),
                    'C': np.repeat(df['C'], lens)})

print(res)

#    A   C  ID
# 0  a   1   1
# 1  a   2   1
# 2  a  15   1
# 3  b   5   1
# 4  b  13   1
# 4  c  13   1
# 4  d  13   1
# 5  a   6   2
# 6  a   7   2
# 7  a   1   2
# 7  b   1   2
# 7  c   1   2

第 2 步:在原始和扁平化上连接 GroupBy

agg_df = pd.concat([res.groupby('ID')['A'].nunique(),
                    df.groupby('ID')['C'].sum()], axis=1)

print(agg_df)

#     A   C
# ID       
# 1   4  36
# 2   3  14

【讨论】:

  • 在我原来的问题中,我汇总了更多列(除了“A”和“C”)。这个规模如何?
  • @EranMoshe,取决于“更多”,如果它是 an example,您可以在其中对任意列使用相同的逻辑,而无需分别为每一列输入逻辑。如果不关心中间结果,那么可以使用apply(pd.Series)+stack方法
猜你喜欢
  • 1970-01-01
  • 2018-03-01
  • 2016-10-31
  • 2017-10-11
  • 1970-01-01
  • 2015-01-02
  • 1970-01-01
  • 2023-01-17
  • 2017-06-20
相关资源
最近更新 更多