查找客户在 pandas 中活跃的最大连续月数
Find max number of consecutive months a customer has been active in pandas
我正在尝试查找客户在商店中活跃的最大连续月数。这是我的数据。
+-----+---------+--------------+--------+-------------+
| Id | t_year | t_month_prx | Store | diff_months |
+-----+---------+--------------+--------+-------------+
| 1 | 2021 | 10.0 | A001 | 1.0 |
| 1 | 2022 | 1.0 | A001 | 1.0 |
| 1 | 2022 | 2.0 | A001 | 1.0 |
| 2 | 2021 | 1.0 | A001 | 1.0 |
| 2 | 2021 | 2.0 | A001 | 1.0 |
| 2 | 2021 | 3.0 | A001 | 1.0 |
| 2 | 2021 | 6.0 | A001 | 3.0 |
| 2 | 2021 | 7.0 | A001 | 1.0 |
| 2 | 2021 | 8.0 | A001 | 1.0 |
| 2 | 2021 | 9.0 | A001 | 1.0 |
| 2 | 2021 | 10.0 | A001 | 1.0 |
| 2 | 2022 | 1.0 | A001 | 1.0 |
| 2 | 2022 | 2.0 | A001 | 1.0 |
| 2 | 2021 | 1.0 | A002 | 1.0 |
| 2 | 2021 | 2.0 | A002 | 1.0 |
| 2 | 2021 | 3.0 | A002 | 1.0 |
| 2 | 2021 | 6.0 | A002 | 3.0 |
| 2 | 2021 | 7.0 | A002 | 1.0 |
| 2 | 2021 | 8.0 | A002 | 1.0 |
| 2 | 2021 | 9.0 | A002 | 1.0 |
| 2 | 2021 | 10.0 | A002 | 1.0 |
| 3 | 2021 | 10.0 | A002 | 1.0 |
| 3 | 2022 | 1.0 | A002 | 1.0 |
| 3 | 2022 | 2.0 | A002 | 1.0 |
+-----+---------+--------------+--------+-------------+
原来的问题涉及跳过两个月,所以我做了一个月的代理。所以,一年有 10 个月,而不是 12 个月。
到目前为止我尝试过的是:
df = df.sort_values(by=['Id','t_year','t_month_prx'], ascending = True).reset_index(drop=True)
df['diff_months'] = df.groupby(['Id', 't_year'])['t_month_prx'].diff()
df['diff_months'].fillna(method='bfill', inplace=True)
我得到了这个结果
df_result = pd.DataFrame({
'Id': {0: 1,1: 1,2: 1,3: 2,4: 2,5: 2,6: 2,7: 2, 8: 2,9: 2, 10: 2, 11: 2, 12: 2},
't_year': {0: 2021, 1: 2022, 2: 2022, 3: 2021,4: 2021,5: 2021,6: 2021,7: 2021,8: 2021,9: 2021,10: 2021,11: 2022,12: 2022},
't_month_prx': {0: 10.0,1: 1.0,2: 2.0,3: 1.0,4: 2.0,5: 3.0,6: 6.0,7: 7.0,
8: 8.0,9: 9.0,10: 10.0,11: 1.0,12: 2.0},
'diff_months': {0: 1.0, 1: 1.0, 2: 1.0,3: 1.0,4: 1.0,5: 1.0,6: 3.0,7: 1.0,8: 1.0,9: 1.0,10: 1.0,11: 1.0, 12: 1.0}
})
然后我终于厌倦了连续数数1s
df.groupby([df['Id'], df['diff_months'].ne(df.groupby('Id')['diff_months'].shift(1)).cumsum()])['diff_months'].sum().groupby(level=0).max().reset_index(name='consecutive_month')
它给了我以下结果
pd.DataFrame({
'Id': {0: 1,1: 2},
'counts': {0: 3.0,1: 6.0}
})
但所需的输出是:
pd.DataFrame({'Id': [1,2, 2, 3], 'Store': ['A001','A001', 'A002', 'A002'], 'counts': [3, 7, 5, 3]})
看起来像:
Id Store counts
0 1 A001 3
1 2 A001 7
2 2 A002 5
3 3 A002 3
因此,对于第二个客户,它应该是 7 个月,因为我只计算 1s
,所以它会跳过 3
。类似地,可以有多个更小的 1 序列,在这种情况下,必须 select 1 的最大数量。我的方法好吗?知道如何计算跨越不同年份的连续月份吗?[=21=]
您可以先使用 groupby
+ diff
创建组(在任何给定年份,要“连续”,差值必须为 1;跨年,差值必须为 -9 ).然后使用另一个 groupby
+ size
中的组来查找连续计数;然后再做一个 groupby
+ max
来找到每个 Id 的最大连续计数。
cols = ['Id', 'Store']
g = df.groupby(cols)
month_diff = g['t_month_prx'].diff()
year_diff = g['t_year'].diff()
nonconsecutive = ~((year_diff.eq(0) & month_diff.eq(1)) | (year_diff.eq(1) & month_diff.eq(-9)))
out = df.groupby([*cols, nonconsecutive.cumsum()]).size().droplevel(-1).groupby(cols).max().reset_index(name='counts')
输出:
Id Store counts
0 1 A001 3
1 2 A001 7
2 2 A002 5
3 3 A002 3
此代码适用于给定的示例数据集:
df = df.sort_values(['Id','t_year','t_month_prx'])
gr = (df.groupby(['Store','Id']).
apply(lambda x: (~x['t_month_prx'].diff().isin([1,-9])).cumsum()).
reset_index(name='num'))
res = (gr.groupby(['Store','Id']).
apply(lambda x: x.num.value_counts().max()).
reset_index(name='counts'))
print(res)
'''
Store Id counts
0 A001 1 3
1 A001 2 7
2 A002 2 5
3 A002 3 3
我正在尝试查找客户在商店中活跃的最大连续月数。这是我的数据。
+-----+---------+--------------+--------+-------------+
| Id | t_year | t_month_prx | Store | diff_months |
+-----+---------+--------------+--------+-------------+
| 1 | 2021 | 10.0 | A001 | 1.0 |
| 1 | 2022 | 1.0 | A001 | 1.0 |
| 1 | 2022 | 2.0 | A001 | 1.0 |
| 2 | 2021 | 1.0 | A001 | 1.0 |
| 2 | 2021 | 2.0 | A001 | 1.0 |
| 2 | 2021 | 3.0 | A001 | 1.0 |
| 2 | 2021 | 6.0 | A001 | 3.0 |
| 2 | 2021 | 7.0 | A001 | 1.0 |
| 2 | 2021 | 8.0 | A001 | 1.0 |
| 2 | 2021 | 9.0 | A001 | 1.0 |
| 2 | 2021 | 10.0 | A001 | 1.0 |
| 2 | 2022 | 1.0 | A001 | 1.0 |
| 2 | 2022 | 2.0 | A001 | 1.0 |
| 2 | 2021 | 1.0 | A002 | 1.0 |
| 2 | 2021 | 2.0 | A002 | 1.0 |
| 2 | 2021 | 3.0 | A002 | 1.0 |
| 2 | 2021 | 6.0 | A002 | 3.0 |
| 2 | 2021 | 7.0 | A002 | 1.0 |
| 2 | 2021 | 8.0 | A002 | 1.0 |
| 2 | 2021 | 9.0 | A002 | 1.0 |
| 2 | 2021 | 10.0 | A002 | 1.0 |
| 3 | 2021 | 10.0 | A002 | 1.0 |
| 3 | 2022 | 1.0 | A002 | 1.0 |
| 3 | 2022 | 2.0 | A002 | 1.0 |
+-----+---------+--------------+--------+-------------+
原来的问题涉及跳过两个月,所以我做了一个月的代理。所以,一年有 10 个月,而不是 12 个月。
到目前为止我尝试过的是:
df = df.sort_values(by=['Id','t_year','t_month_prx'], ascending = True).reset_index(drop=True)
df['diff_months'] = df.groupby(['Id', 't_year'])['t_month_prx'].diff()
df['diff_months'].fillna(method='bfill', inplace=True)
我得到了这个结果
df_result = pd.DataFrame({
'Id': {0: 1,1: 1,2: 1,3: 2,4: 2,5: 2,6: 2,7: 2, 8: 2,9: 2, 10: 2, 11: 2, 12: 2},
't_year': {0: 2021, 1: 2022, 2: 2022, 3: 2021,4: 2021,5: 2021,6: 2021,7: 2021,8: 2021,9: 2021,10: 2021,11: 2022,12: 2022},
't_month_prx': {0: 10.0,1: 1.0,2: 2.0,3: 1.0,4: 2.0,5: 3.0,6: 6.0,7: 7.0,
8: 8.0,9: 9.0,10: 10.0,11: 1.0,12: 2.0},
'diff_months': {0: 1.0, 1: 1.0, 2: 1.0,3: 1.0,4: 1.0,5: 1.0,6: 3.0,7: 1.0,8: 1.0,9: 1.0,10: 1.0,11: 1.0, 12: 1.0}
})
然后我终于厌倦了连续数数1s
df.groupby([df['Id'], df['diff_months'].ne(df.groupby('Id')['diff_months'].shift(1)).cumsum()])['diff_months'].sum().groupby(level=0).max().reset_index(name='consecutive_month')
它给了我以下结果
pd.DataFrame({
'Id': {0: 1,1: 2},
'counts': {0: 3.0,1: 6.0}
})
但所需的输出是:
pd.DataFrame({'Id': [1,2, 2, 3], 'Store': ['A001','A001', 'A002', 'A002'], 'counts': [3, 7, 5, 3]})
看起来像:
Id Store counts
0 1 A001 3
1 2 A001 7
2 2 A002 5
3 3 A002 3
因此,对于第二个客户,它应该是 7 个月,因为我只计算 1s
,所以它会跳过 3
。类似地,可以有多个更小的 1 序列,在这种情况下,必须 select 1 的最大数量。我的方法好吗?知道如何计算跨越不同年份的连续月份吗?[=21=]
您可以先使用 groupby
+ diff
创建组(在任何给定年份,要“连续”,差值必须为 1;跨年,差值必须为 -9 ).然后使用另一个 groupby
+ size
中的组来查找连续计数;然后再做一个 groupby
+ max
来找到每个 Id 的最大连续计数。
cols = ['Id', 'Store']
g = df.groupby(cols)
month_diff = g['t_month_prx'].diff()
year_diff = g['t_year'].diff()
nonconsecutive = ~((year_diff.eq(0) & month_diff.eq(1)) | (year_diff.eq(1) & month_diff.eq(-9)))
out = df.groupby([*cols, nonconsecutive.cumsum()]).size().droplevel(-1).groupby(cols).max().reset_index(name='counts')
输出:
Id Store counts
0 1 A001 3
1 2 A001 7
2 2 A002 5
3 3 A002 3
此代码适用于给定的示例数据集:
df = df.sort_values(['Id','t_year','t_month_prx'])
gr = (df.groupby(['Store','Id']).
apply(lambda x: (~x['t_month_prx'].diff().isin([1,-9])).cumsum()).
reset_index(name='num'))
res = (gr.groupby(['Store','Id']).
apply(lambda x: x.num.value_counts().max()).
reset_index(name='counts'))
print(res)
'''
Store Id counts
0 A001 1 3
1 A001 2 7
2 A002 2 5
3 A002 3 3