如何在Pandas DataFrame中创建客户状态变更为CHURNED/RESTARTED的指示列
场景说明
我现有一份客户数据DataFrame,已按CLIENT_ID和CURRENT_DATE_STATUS排序,字段如下所示:
| CLIENT_ID | CURRENT_DATE_STATUS | STATUS |
|---|---|---|
| 10002 | 2017-07-21 | STARTED |
| 10002 | 2017-07-21 | STARTED |
| 10002 | 2018-07-01 | CHURNED |
| 10002 | 2018-07-01 | CHURNED |
| 10002 | 2019-01-01 | RESTARTED |
| 11811 | 2019-08-15 | STARTED |
| 11811 | 2019-08-15 | STARTED |
| 11811 | 2019-12-31 | RESTARTED |
| 22101 | 2020-03-11 | STARTED |
| 22101 | 2020-03-11 | STARTED |
| 22101 | 2020-03-11 | STARTED |
| 22101 | 2020-11-01 | CHURNED |
| 22300 | 2018-05-06 | STARTED |
| 22300 | 2018-05-06 | STARTED |
问题需求
我需要创建一个取值为1或0的布尔类型指示列,满足如下规则:
- 针对每个
CLIENT_ID,若该行STATUS较前一条同客户记录变更为CHURNED或RESTARTED则标记为1,其余情况标记为0。
预期效果
| CLIENT_ID | CURRENT_DATE_STATUS | STATUS | STOPPED |
|---|---|---|---|
| 10002 | 2017-07-21 | STARTED | 0 |
| 10002 | 2017-07-21 | STARTED | 0 |
| 10002 | 2018-07-01 | CHURNED | 1 |
| 10002 | 2018-07-01 | CHURNED | 0 |
| 10002 | 2019-01-01 | RESTARTED | 1 |
| 11811 | 2019-08-15 | STARTED | 0 |
| 11811 | 2019-08-15 | STARTED | 0 |
| 11811 | 2019-12-31 | RESTARTED | 1 |
| 22101 | 2020-03-11 | STARTED | 0 |
| 22101 | 2020-03-11 | STARTED | 0 |
| 22101 | 2020-03-11 | STARTED | 0 |
| 22101 | 2020-11-01 | CHURNED | 1 |
| 22300 | 2018-05-06 | STARTED | 0 |
| 22300 | 2018-05-06 | STARTED | 0 |
样例数据生成代码
import pandas as pd data = {'CLIENT_ID':[10002,10002,10002,10002,10002,11811,11811,11811,22101,22101,22101,22101,22300,22300], 'CURRENT_DATE_STATUS':['2017-07-21','2017-07-21','2018-07-01','2018-07-01','2019-07-01','2019-08-15','2019-08-15','2019-12-31','2020-03-11','2020-03-11','2020-03-11','2020-11-01','2018-05-06','2018-05-06'], 'STATUS':['STARTED','STARTED','CHURNED','CHURNED','RESTARTED','STARTED','STARTED','RESTARTED','STARTED','STARTED','STARTED','CHURNED','STARTED','STARTED']} df = pd.DataFrame(data)
解决方案
通过pandas分组位移函数shift获取同客户上一行的状态,再做条件判断即可实现需求:
# 按CLIENT_ID分组,获取每条记录对应同客户上一条记录的STATUS值 df['prev_status'] = df.groupby('CLIENT_ID')['STATUS'].shift(1) # 同时满足两个条件则标记为1:1.当前状态为CHURNED或RESTARTED 2.当前状态与上一条状态不同 df['STOPPED'] = ((df['STATUS'].isin(['CHURNED', 'RESTARTED'])) & (df['STATUS'] != df['prev_status'])).astype(int) # 删除辅助列 df.drop(columns=['prev_status'], inplace=True)
执行后生成的STOPPED列与预期效果完全一致。
内容的提问来源于stack exchange,提问作者Mazil_tov998
相关产品推荐
相关产品推荐

