熊猫中唯一值的累积计数

dum*_*dad 4 pandas

我想按周累计计算熊猫框架中一列的唯一值。例如,假设我有这样的数据:

df = pd.DataFrame({'user_id':[1,1,1,2,2,2],'week':[1,1,2,1,2,2],'module_id':['A','B','A','A','B','C']})
Run Code Online (Sandbox Code Playgroud)
+---+---------+------+-----------+
|   | user_id | week | module_id |
+---+---------+------+-----------+
| 0 |       1 |    1 |         A |
| 1 |       1 |    1 |         B |
| 2 |       1 |    2 |         A |
| 3 |       2 |    1 |         A |
| 4 |       2 |    2 |         B |
| 5 |       2 |    2 |         C |
+---+---------+------+-----------+
Run Code Online (Sandbox Code Playgroud)

我想要的是一个连续的计数,直到每个星期为止,唯一的module_ids的数量,例如:

+---+---------+------+-------------------------+
|   | user_id | week | cumulative_module_count |
+---+---------+------+-------------------------+
| 0 |       1 |    1 |                       2 |
| 1 |       1 |    2 |                       2 |
| 2 |       2 |    1 |                       1 |
| 3 |       2 |    2 |                       3 |
+---+---------+------+-------------------------+
Run Code Online (Sandbox Code Playgroud)

将其作为一个循环很简单,例如,这可行:

running_tally = {}
result = {}
for index, row in df.iterrows():
    if row['user_id'] not in running_tally:
        running_tally[row['user_id']] = set()
        result[row['user_id']] = {}
    running_tally[row['user_id']].add(row['module_id'])
    result[row['user_id']][row['week']] = len(running_tally[row['user_id']])
print(result)
Run Code Online (Sandbox Code Playgroud)
running_tally = {}
result = {}
for index, row in df.iterrows():
    if row['user_id'] not in running_tally:
        running_tally[row['user_id']] = set()
        result[row['user_id']] = {}
    running_tally[row['user_id']].add(row['module_id'])
    result[row['user_id']][row['week']] = len(running_tally[row['user_id']])
print(result)
Run Code Online (Sandbox Code Playgroud)

但是我的真实数据帧很大,因此我想使用矢量化算法而不是循环。

还有一个类似的冠冕堂皇的问题在这里,但看着公认的答案(点击这里)原来的海报不希望跨越的唯一日期累积,和我一样。

我将如何在熊猫中进行矢量化?

jez*_*ael 5

想法是list通过两np.cumsum列为每个组创建一个,然后用于累积列表,最后将值转换为集合并获取长度:

df1 = (df.groupby(['user_id','week'])['module_id']
         .apply(list)
         .groupby(level=0)
         .apply(np.cumsum)
         .apply(lambda x: len(set(x)))
         .reset_index(name='cumulative_module_count'))

print (df1)
   user_id  week  cumulative_module_count
0        1     1                        2
1        1     2                        2
2        2     1                        1
3        2     2                        3
Run Code Online (Sandbox Code Playgroud)