如何按月获取 pandas 中不同类别的唯一计数?

How to get unique count by month for different categories in pandas?

我有一个这样的 pandas 数据框:

Month      ID
Sep 21     ID_1
Sep 21     ID_2
Sep 21     ID_3
Oct 21     ID_1
Oct 21     ID_2
Oct 21     ID_4
Oct 21     ID_5
Nov 21     ID_1
Nov 21     ID_2
Nov 21     ID_3
Nov 21     ID_4
Dec 21     ID_2
Dec 21     ID_3
Dec 21     ID_4
Dec 21     ID_5
Jan 22     ID_3
Jan 22     ID_4
Jan 22     ID_5

并且我想要像这样的格式的 ID 计数作为输出 pandas 数据帧:

作为值,我可以获得每个月的 ID 的唯一计数,例如 10 月 2 日的 ID1 应该被计算在 2 个月以内,因为它现在出现了 2 个月,而在 11 月 ID2 将被计算在 3 个月以内,因为它是持续出现 3 个月。但由于 ID5 在 10 月首次出现,因此在 10 月将被计算在 1 个月以内,依此类推。任何出现超过4次的ID都应计入4个月+类别。

在 pandas 中,我不确定如何使用这种方法来获得这个独特的计数并拥有一个枢轴 table。

首先,这将创建一个发生矩阵。请注意,我对 easy-sorting.

使用 date-time 格式 Month
step1 = pd.crosstab(
    df['ID'], 
    pd.to_datetime(df['Month'], format='%b %y')
)

Month   2021-09-01  2021-10-01  2021-11-01  2021-12-01  2022-01-01
ID                  
ID_1    1   1   1   0   0
ID_2    1   1   1   1   0
ID_3    1   0   1   1   1
ID_4    0   1   1   1   1
ID_5    0   1   0   1   1

然后,做满足连续性条件的累加和

for month_prev, month_next in zip(step1.columns, step1.columns[1:]):
    step1[month_next] = (step1[month_next] + step1[month_prev]) * step1[month_next]

Month   2021-09-01  2021-10-01  2021-11-01  2021-12-01  2022-01-01
ID                  
ID_1    1   2   3   0   0
ID_2    1   2   3   4   0
ID_3    1   0   1   2   3
ID_4    0   1   2   3   4
ID_5    0   1   0   1   2

然后,我们应用meltgroupbyvalue_counts来计算每个月的cumsum-values,unstack移动Month到列,其余 3 种方法来处理格式。

step2 = pd.melt(step1)\
    .groupby('Month')['value']\
    .value_counts()\
    .unstack(level=0)\
    .fillna(0)\
    .drop(0)\
    .astype(int)

Month   2021-09-01  2021-10-01  2021-11-01  2021-12-01  2022-01-01
value                   
1   3   2   1   1   0
2   0   2   1   1   1
3   0   0   2   1   1
4   0   0   0   1   1

进一步格式化的最后一步:

step2.columns = step2.columns.strftime('%b %y')
step2.loc[4] = step2.loc[step2.index>=4].sum()
step2.index = (step2.index.astype(str) + ' Month').str.replace('4 Month', '4 Month+')

Month   Sep 21  Oct 21  Nov 21  Dec 21  Jan 22
value                   
1 Month 3   2   1   1   0
2 Month 0   2   1   1   1
3 Month 0   0   2   1   1
4 Month+    0   0   0   1   1