Python Pandas-聚合不一致的值类型(字符串与列表)

Python Pandas-聚合不一致的值类型(字符串与列表),python,pandas,dataframe,pandas-groupby,Python,Pandas,Dataframe,Pandas Groupby,给定以下数据帧,我尝试对'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']], '

给定以下数据帧,我尝试对
'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'和'd
,对于
'ID'=2
,我们有
'a','b','c'
一个解决方案是将问题分成两部分。首先展平数据帧,以确保
df['A']
仅由字符串组成。然后连接两个
GroupBy
操作

步骤1:展平数据帧 您可以使用
itertools.chain
numpy.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
lambda x:x.apply(pd.Series).stack().nunique()
do吗?@JonClements是的!把它作为一个答案,这样我就可以吻你了,如果你解释一下这个lambda中的细节,我会非常感激
apply(pd.Series)
+
stack
可以工作,但也可能会非常慢。@jp确实。。。这就是为什么我没有发布答案的原因。。。现在一定有更好的熊猫式的方式来做…:)@琼克莱门茨,是的,这是一个很常见的问题。我最喜欢的(对于少量的列)是
np.repeat
+
it.chain
,但我觉得我们重复的食谱应该内置在Pandas中,可能是通用的。在我最初的问题中,有更多的列(除了'A'和'C')是我聚合的。这个比例如何?@EranMoshe,取决于“更多”,如果<10列,这个比例可能很好。在这里,您可以对任意列使用相同的逻辑,而无需分别为每个列键入逻辑。如果您不关心中间结果,那么可以使用
apply(pd.Series)
+
stack
方法
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