在pandas中按索引和列分组

71

我有一个包含两列的数据框,分别是user_iditem_bought

其中user_id是数据框的索引。我想要按照user_iditem_bought对数据进行分组,并计算每个用户购买每种商品的次数。

请问应该如何实现?


12
你应该可以运行df.groupby([df.index, 'item_bought']).apply(pd.Series.count(level=0)),但实际上df.groupby([df.index, 'item_bought']).count()也可以得到你想要的结果。 - EdChum
为什么不把这个变成一个答案? - vumaasha
1
当我尝试按[df.index, '<col_name>']分组时,出现错误:Grouper和axis的长度必须相同。 - codekitty
我遇到了不同的错误:TypeError: unhashable type: 'Int64Index' - kuanb
@EdChum,太棒了!这甚至没有记录下来,是吗? - toliveira
4个回答

67

从版本0.20.1开始,使用更加简单:

DataFrame.groupby()by参数现在可以引用列名称或索引级别名称所表示的字符串。

arrays = [['bar', 'bar', 'baz', 'baz', 'foo', 'foo', 'qux', 'qux'],
          ['one', 'two', 'one', 'two', 'one', 'two', 'one', 'two']]

index = pd.MultiIndex.from_arrays(arrays, names=['first', 'second'])

df = pd.DataFrame({'A': [1, 1, 1, 1, 2, 2, 3, 3],
                   'B': np.arange(8)}, index=index)

print (df)

              A  B
first second      
bar   one     1  0
      two     1  1
baz   one     1  2
      two     1  3
foo   one     2  4
      two     2  5
qux   one     3  6
      two     3  7

print (df.groupby(['second', 'A']).sum())
          B
second A   
one    1  2
       2  4
       3  6
two    1  4
       2  5
       3  7

1
有没有办法也针对 pd.Series 进行操作?我试图传递系列名称,但它会出现 KeyError。我的意思是,按索引级别之一和系列的值分组一个系列。 - Konstantin

46

这应该可以运行:

>>> df = pd.DataFrame(np.random.randint(0,5,(6, 2)), columns=['col1','col2'])
>>> df['ind1'] = list('AAABCC')
>>> df['ind2'] = range(6)
>>> df.set_index(['ind1','ind2'], inplace=True)
>>> df

           col1  col2
ind1 ind2            
A    0        3     2
     1        2     0
     2        2     3
B    3        2     4
C    4        3     1
     5        0     0


>>> df.groupby([df.index.get_level_values(0),'col1']).count()

           col2
ind1 col1      
A    2        2
     3        1
B    2        1
C    0        1
     3        1

我遇到了同样的问题,使用了多级索引中的一列。在使用多级索引时,您不能使用df.index.levels[0],因为它仅具有来自该特定索引级别的唯一值,并且其大小很可能与整个数据框不同...

请参考http://pandas.pydata.org/pandas-docs/stable/generated/pandas.Index.get_level_values.html- get_level_values "返回请求级别的标签值向量,等于索引的长度"


4
import pandas as pd

import numpy as np

In [11]:

df = pd.DataFrame()

In [12]:

df['user_id'] = ['b','b','b','c']

In [13]:

df['item_bought'] = ['x','x','y','y']

In [14]:

df['ct'] = 1

In [15]:

df

Out[15]:
    user_id     item_bought     ct
0   b   x   1
1   b   x   1
2   b   y   1
3   c   y   1
In [16]:

pd.pivot_table(df,values='ct',index=['user_id','item_bought'],aggfunc=np.sum)

Out[16]:

user_id  item_bought
b        x              2
         y              1
c        y              1

为什么这个被踩了?它完全做到了他们想要的。 - howMuchCheeseIsTooMuchCheese
在你的例子中,它并没有展示如何从索引和列获取计数... user_id 是一个列。 - codekitty
1
只需重置索引 df = df.reset_index() ... 然后就可以在数据透视表中使用它了。 - howMuchCheeseIsTooMuchCheese

1

我有同样的问题 - 导入了一堆数据,想要按照索引分组。我没有多重索引之类的东西,你也没有。

我想问题在于我想要的字段是索引,所以起初我只是重置了索引 - 但这给了我一个无用的索引字段,我不想要。所以现在我做以下操作(两个级别的分组):

grouped = df.reset_index().groupby(by=['Field1','Field2'])

那么我可以在不同的报告中以各种方式使用“grouped”。
grouped[['Field3','Field4']].agg([np.mean, np.std])

这是我想要的,给我 Field1 和 Field2 分组后的 Field4 和 Field3 的平均值。

如果您只想对每个用户进行项目计数,则可以使用 groupby 中的一行简单代码:

df.reset_index().groupby(by=['user_id']).count()

如果你想做更多的事情,那么你可以(像我一样)创建“分组”,然后使用它。作为一个初学者,我发现这种方式更容易跟随。
请注意,“reset_index”不是“原地”操作,因此不会破坏您的原始数据框。

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