Pandas groupby - 不同值的集合

4

我有这个数据框

x = pd.DataFrame.from_dict({'cat1':['A', 'A', 'A', 'B', 'B', 'C', 'C', 'C'], 'cat2':['X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z']})

  cat1 cat2
0    A    X
1    A    X
2    A    Y
3    B    Y
4    B    Y
5    C    Y
6    C    Z
7    C    Z

我希望按 cat1 进行分组,然后将 cat2 聚合为不同值的集合,例如:

  cat1 cat2
0    A    (X, Y)
1    B    (Y,)
2    C    (Y, Z)

这是一个更大的数据框,有更多列,每列都有自己的聚合函数,那么我该如何将此功能传递给聚合字典?

5个回答

6

使用lambda函数与setunique,并将输出转换为tuple

x = pd.DataFrame.from_dict({'cat1':['A', 'A', 'A', 'B', 'B', 'C', 'C', 'C'], 
                            'cat2':['X', 'X', 'Y', 'Y', 'Y', 'Y', 'Z', 'Z'],
                             'col':range(8)})
print (x)
  cat1 cat2  col
0    A    X    0
1    A    X    1
2    A    Y    2
3    B    Y    3
4    B    Y    4
5    C    Y    5
6    C    Z    6
7    C    Z    7

a = x.groupby('cat1').agg({'cat2': lambda x: tuple(set(x)), 'col':'sum'})
print (a)
        cat2  col
cat1             
A     (Y, X)    3
B       (Y,)    7
C     (Y, Z)   18

或者:

a = x.groupby('cat1').agg({'cat2': lambda x: tuple(x.unique()), 'col':'sum'})
print (a)
        cat2  col
cat1             
A     (X, Y)    3
B       (Y,)    7
C     (Y, Z)   18

编辑:

f = lambda x: tuple(x.unique())
f.__name__ = 'my_name'
a = x.groupby('cat1')['cat2'].agg(['min', 'max', 'nunique', f])
print (a)
     min max  nunique my_name
cat1                         
A      X   Y        2  (X, Y)
B      Y   Y        1    (Y,)
C      Y   Z        2  (Y, Z)

如果只有一个lambda函数或者列名<lambda>没有问题:
a = x.groupby('cat1')['cat2'].agg(['min', 'max', 'nunique', lambda x: tuple(x.unique())])
print (a)
     min max  nunique <lambda>
cat1                          
A      X   Y        2   (X, Y)
B      Y   Y        1     (Y,)
C      Y   Z        2   (Y, Z)

所以我已经有了像'cat2': ['min', 'max', 'nunique']这样的东西,也就是说,我已经在多个方面对这一列进行了聚合。你的解决方案如何修改以适应这种情况?谢谢。 - Baron Yugovich
可以使用自定义函数并通过 __name__ 设置名称,请查看最后一次编辑。 - jezrael

3

按组分组并筛选唯一值,可以得到不重复的结果

x.groupby('cat1').cat2.unique()

A    [X, Y]
B       [Y]
C    [Y, Z]

如果您想以元组形式输出,请尝试

x.groupby('cat1').cat2.unique().apply(tuple)

A    (X, Y)
B      (Y,)
C    (Y, Z)

请查看我对上面问题的编辑。我需要将其作为更大聚合字典的一部分完成。 - Baron Yugovich

3
x.groupby('cat1')['cat2'].unique().reset_index()

# Returns 
  cat1    cat2
0    A  [X, Y]
1    B     [Y]
2    C  [Y, Z]

此代码首先按照'cat1'列对整个数据框进行分组,仅选择'cat2'列,并将每个分组简化为唯一的'cat2'值集合。结果将'cat1'值放在索引中,因此如果需要以列的格式输出,则reset_index()可以将这些值取回。


请查看我对上面问题的编辑。我需要将其作为更大聚合字典的一部分完成。 - Baron Yugovich

2
x.groupby('cat1')['cat2'].agg(lambda x: set(x))

输出

enter image description here

关于评论中提出的简化,以下内容至少适用于Python 3.6.5和Pandas 0.23.0(但不适用于Python 3.6.2和Pandas 0.20.3):

x.groupby('cat1')['cat2'].agg(set)

1
这里其实不需要 lambda,因为 set 是可调用的。所以 x.groupby('cat1').agg(set) 也能达到同样的效果,是吧? - Simon Bowly
1
尽管我认为它应该可以工作,但在这种情况下它并没有起作用。 - Alter
请查看我对上述问题的编辑。 我需要将其作为更大的聚合字典的一部分完成。 - Baron Yugovich
1
这个解决方案比基于“unique”和“apply”的解决方案快得多。 - Skippy le Grand Gourou

2

或者我们可以在进行分组之前对数据框进行筛选

x.drop_duplicates().groupby('cat1').cat2.apply(tuple)
Out[777]: 
cat1
A    (X, Y)
B      (Y,)
C    (Y, Z)
Name: cat2, dtype: object

请查看我对上面问题的编辑。我需要将其作为更大聚合字典的一部分完成。 - Baron Yugovich

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接