pandas 如何计算最近n天内每组唯一值的数量

xzv2uavs  于 2023-01-24  发布在  其他
关注(0)|答案(2)|浏览(142)

我有下面的Pandas数据框:
| 组ID|日期|价值|
| - ------|- ------|- ------|
| 1个|2023年1月1日|A类|
| 1个|2023年1月5日|B|
| 1个|2023年1月17日|C级|
| 第二章|2023年1月1日|A类|
| 第二章|2023年1月20日|B|
| 三个|2023年1月1日|A类|
| 三个|2023年1月10日|B|
| 三个|2023年1月12日|C级|
我想执行groupby并计算每个groupId的唯一值的数量,但只查看最后n=14天,相对于该行的date
我想要的结果是这样的:
| 组ID|日期|价值|新列|
| - ------|- ------|- ------|- ------|
| 1个|2023年1月1日|A类|1个|
| 1个|2023年1月5日|B|第二章|
| 1个|2023年1月17日|C级|第二章|
| 第二章|2023年1月1日|A类|1个|
| 第二章|2023年1月20日|B|1个|
| 三个|2023年1月1日|A类|1个|
| 三个|2023年1月10日|B|第二章|
| 三个|2023年1月12日|C级|三个|
我确实尝试过使用groupby(...).rolling('14d').nunique(),虽然rolling函数适用于数字字段来计数和计算平均值等...但当与nunique一起用于字符串字段来计数唯一字符串/对象值的数量时,它就不起作用了。
您可以使用下面的代码生成 Dataframe 。

pd.DataFrame(
{
 'groupId': [1, 1, 1, 2, 2, 3, 3, 3],
 'date': ['2023-01-01', '2023-01-05', '2023-01-17', '2023-01-01', '2023-01-20', '2023-01-01', '2023-01-10', '2023-01-12'], #YYYY-MM-DD
 'value': ['A', 'B', 'C', 'A', 'B', 'A', 'B', 'C'],
 'newColumn': [1, 2, 2, 1, 1, 1, 2, 3]
}


你知道如何解决这个问题吗,即使不使用rolling函数?非常感谢!

igetnqfo

igetnqfo1#

您也可以使用count代替nunique

>>> (df.groupby('groupId').rolling('14D', on='date')['value'].count()
       .astype(int).rename('newColumn').reset_index())

   groupId       date  newColumn
0        1 2023-01-01          1
1        1 2023-01-05          2
2        1 2023-01-17          2
3        2 2023-01-01          1
4        2 2023-01-20          1
5        3 2023-01-01          1
6        3 2023-01-10          2
7        3 2023-01-12          3
    • 注意事项**:除非(groupId,date)是唯一组合,否则将此输出与原始 Dataframe 合并可能会很复杂。
    • 更新**

如果您的索引是数值型的(或者创建一个单调递增的虚拟列),您可以使用以下技巧:

sr = (df.reset_index().groupby('groupId').rolling('14D', on='date')
        .agg({'value': 'count', 'index': 'max'}).astype(int)
        .set_index('index')['value'])
df['newColumn'] = sr
print(df)

# Output
   groupId       date value  newColumn
0        1 2023-01-01     A          1
1        1 2023-01-05     B          2
2        1 2023-01-17     C          2
3        2 2023-01-01     A          1
4        2 2023-01-20     B          1
5        3 2023-01-01     A          1
6        3 2023-01-10     B          2
7        3 2023-01-12     C          3
    • 更新2**

您可以使用pd.factorizevalue列转换为数值列:

>>> (df.assign(value=pd.factorize(df['value'])[0])
       .groupby('groupId').rolling('14D', on='date')['value']
       .apply(lambda x: x.nunique())
       .astype(int).rename('newColumn').reset_index())

   groupId       date  newColumn
0        1 2023-01-01          1
1        1 2023-01-05          2
2        1 2023-01-17          2
3        2 2023-01-01          1
4        2 2023-01-20          1
5        3 2023-01-01          1
6        3 2023-01-10          2
7        3 2023-01-12          3
ecfsfe2w

ecfsfe2w2#

另一种可能的解决方案(不使用rolling):

df['date'] = pd.to_datetime(df['date'])
df['new2'] = df.groupby('groupId')['date'].transform(
    lambda x: x.diff().dt.days.cumsum().le(14).mul(~x.duplicated()).cumsum()+1)

输出:

groupId       date value  new2
0        1 2023-01-01     A     1
1        1 2023-01-05     B     2
2        1 2023-01-17     C     2
3        2 2023-01-01     A     1
4        2 2023-01-20     B     1
5        3 2023-01-01     A     1
6        3 2023-01-10     B     2
7        3 2023-01-12     C     3

相关问题