4

我有很多用户/项目/时间戳数据。我想知道所有用户首先消费了哪些项目,其次是第三,等等。

我的问题是:如果我有一个已经按时间排序(降序)的数据框,它会在整个groupby过程中默认保持排序吗?而且,即使用户没有消费过两个项目,我如何才能提取任何用户消费的前两个项目?

import pandas as pd
df = pd.DataFrame({'item_id': ['b', 'b', 'a', 'c', 'a', 'b'], 'user_id': [1,2,1,1,3,1], 'time': range(6)})

print df
pd.get_dummies(df['item_id'])

gp = df.groupby('user_id').head()
print gp

# Return item_id of first one installed in each case ??

这给出了:

  item_id  time  user_id
0       b     0        1
1       b     1        2
2       a     2        1
3       c     3        1
4       a     4        3
5       b     5        1

          item_id  time  user_id
user_id                         
1       0       b     0        1
        2       a     2        1
        3       c     3        1
        5       b     5        1
2       1       b     1        2
3       4       a     4        3

现在,我需要提取前两个 item_id 值,如下所示(但保留 user_id 列不是必需的):

user_id    order    item_id
      1        0          b
      1        1          a
      2        0          b
      3        0          a
4

2 回答 2

4

这是一个黑客:

In [75]: def nth_order(x, n):
   ....:     xn = x[:n]
   ....:     return xn.join(Series(arange(len(xn)), name='order', index=xn.index))
   ....:

In [76]: df.groupby('user_id').apply(lambda x: nth_order(x, 2))
Out[76]:
          item_id  time  user_id  order
user_id
1       0       b     0        1      0
        2       a     2        1      1
2       1       b     1        2      0
3       4       a     4        3      0

请注意,您不能只使用n,因为您可能有一个组 where len(group) < 2,因此

len(x[:n]) != n

在每种情况下(根据您的问题)。

这是 pandas 中这种特殊切片的一个特性:如果您在此处切片通过末尾,您将只得到每一行(并且可能没有n行),而使用ilocindexing,这是不正确的。也就是说,如果您尝试切片超出数组的末尾,则会引发异常。

于 2013-08-22T23:34:37.410 回答
2

您可以直接使用head来执行此操作,从而获得最佳n结果):

In [11]: g = df.groupby('user_id')

In [12]: g.head(2)
Out[12]:
          item_id  time  user_id
user_id
1       0       b     0        1
        2       a     2        1
2       1       b     1        2
3       4       a     4        3

从 0.13 IIRC 开始,这比任何基于应用的解决方案 head都快得多(调用 head 曾经是.apply(lambda x: x.head()).

实现使用cumcountso 在精神上与 PhilipCloud 的解决方案相似。

于 2013-08-22T23:43:44.610 回答