如何编写函数识别流失客户、回流客户、新客户等类型?
客户状态分类:流失、回流、新客户判定实现
需求与规则
需要基于address_id和时间维度(my_date),将客户分为以下状态:
- 流失客户(Left):按
address_id分组并按日期排序后,出现连续的「Verizon → Verizon → 非Verizon → 非Verizon」模式,即客户从Verizon转投其他运营商 - 回流客户(Boomerang):客户从Verizon转出后,再次转回Verizon;或过去曾是Verizon客户,再次成为Verizon客户
- 新客户(New Client):首次成为Verizon客户的用户
- Never Client:从未成为Verizon客户的用户
- Never Left:一直是Verizon客户的用户
- Other:不符合上述模式的特殊情况
测试数据
import pandas as pd import numpy as np # 测试数据 details = { 'address_id': [111,111,111,111,111,111,222,222,222,222,222,222,333,333,333,333,333,333,444,444,444,444,444,444,555,555,555,555,555,555,777,777,777], 'my_company':['Comcast','Verizon','Other','Other','Comcast','Comcast','Spectrum','Spectrum','Spectrum','Spectrum','Spectrum','Spectrum','Verizon','Verizon','Verizon','Verizon','Verizon','Verizon','Spectrum','Spectrum','Spectrum','Spectrum','Verizon','Spectrum','Spectrum','Spectrum','Spectrum','Spectrum','Verizon','Other','Verizon','Comcast','Comcast'], 'my_date':['2022-01-24','2022-02-21','2022-03-28','2022-04-25','2022-05-23','2022-06-27','2022-01-24','2022-02-21','2022-03-28','2022-04-25','2022-05-23','2022-06-27','2022-01-24','2022-02-21','2022-03-28','2022-04-25','2022-05-23','2022-06-27','2022-01-24','2022-02-21','2022-03-28','2022-04-25','2022-05-23','2022-06-27','2022-01-24','2022-02-21','2022-03-28','2022-04-25','2022-05-23','2022-06-27','2022-01-24','2022-02-21','2022-03-28'] } df = pd.DataFrame(details)
现有尝试的问题
之前的代码仅检查了Verizon是否存在,未结合日期排序后的时间序列变化,无法捕捉状态的先后顺序,因此无法准确判定客户类型:
# 尝试1:仅判断Verizon是否存在,无时间维度 def f(ser): if 'Verizon' not in ser.unique(): return False if 'Verizon' in ser.unique(): return True return False df['gone_client'] = df.groupby('address_id')['my_company'].transform(f) # 尝试2:仅查找Verizon字符串,未处理状态变化 sub ='Verizon' df["Indexes"]= df["my_company"].str.find(sub)
期望输出
| address_id | my_company | my_date | status |
|---|---|---|---|
| 111 | Comcast | 1/24/2022 | Left |
| 111 | Verizon | 2/21/2022 | Left |
| 111 | Other | 3/28/2022 | Left |
| 111 | Other | 4/25/2022 | Left |
| 111 | Comcast | 5/23/2022 | Left |
| 111 | Comcast | 6/27/2022 | Left |
| 222 | Spectrum | 1/24/2022 | Never Client |
| 222 | Spectrum | 2/21/2022 | Never Client |
| 222 | Spectrum | 3/28/2022 | Never Client |
| 222 | Spectrum | 4/25/2022 | Never Client |
| 222 | Spectrum | 5/23/2022 | Never Client |
| 222 | Spectrum | 6/27/2022 | Never Client |
| 333 | Verizon | 1/24/2022 | Never Left |
| 333 | Verizon | 2/21/2022 | Never Left |
| 333 | Verizon | 3/28/2022 | Never Left |
| 333 | Verizon | 4/25/2022 | Never Left |
| 333 | Verizon | 5/23/2022 | Never Left |
| 333 | Verizon | 6/27/2022 | Never Left |
| 444 | Spectrum | 1/24/2022 | Left |
| 444 | Spectrum | 2/21/2022 | Left |
| 444 | Spectrum | 3/28/2022 | Left |
| 444 | Spectrum | 4/25/2022 | Left |
| 444 | Verizon | 5/23/2022 | Left |
| 444 | Spectrum | 6/27/2022 | Left |
| 555 | Verizon | 1/24/2022 | Boomerang |
| 555 | Spectrum | 2/21/2022 | Boomerang |
| 555 | Spectrum | 3/28/2022 | Boomerang |
| 555 | Spectrum | 4/25/2022 | Boomerang |
| 555 | Verizon | 5/23/2022 | Boomerang |
| 555 | Verizon | 6/27/2022 | Boomerang |
| 777 | Comcast | 1/24/2022 | New Client |
| 777 | Comcast | 2/21/2022 | New Client |
| 777 | Verizon | 1/24/2022 | New Client |
| 888 | Verizon | 2/21/2022 | Other |
| 888 | Comcast | 3/28/2022 | Other |
| 888 | Verizon | 4/25/2022 | Other |
| 888 | Comcast | 5/23/2022 | Other |
| 888 | Comcast | 6/27/2022 | Other |
解决方案
核心思路是先按address_id和my_date排序,再对每个客户的运营商序列进行时间维度的状态分析:
# 1. 转换日期格式并排序 df['my_date'] = pd.to_datetime(df['my_date']) df = df.sort_values(['address_id', 'my_date']).reset_index(drop=True) # 2. 定义状态判定函数 def determine_status(series): company_list = series.tolist() has_verizon = 'Verizon' in company_list # 从未是Verizon客户 if not has_verizon: return 'Never Client' # 一直是Verizon客户 all_verizon = all(c == 'Verizon' for c in company_list) if all_verizon: return 'Never Left' # 检查回流:存在离开后又返回的情况 has_return = False for i in range(len(company_list)): if company_list[i] != 'Verizon': # 前面有Verizon,后面也有Verizon any_before = any(c == 'Verizon' for c in company_list[:i]) any_after = any(c == 'Verizon' for c in company_list[i+1:]) if any_before and any_after: has_return = True break if has_return: return 'Boomerang' # 检查流失模式:连续两个Verizon后接两个非Verizon for i in range(len(company_list)-3): if (company_list[i] == 'Verizon' and company_list[i+1] == 'Verizon' and company_list[i+2] != 'Verizon' and company_list[i+3] != 'Verizon'): return 'Left' # 检查新客户:首次出现Verizon,且之前没有过 first_verizon_idx = next(i for i, c in enumerate(company_list) if c == 'Verizon') no_past_verizon = all(c != 'Verizon' for c in company_list[:first_verizon_idx]) if no_past_verizon: return 'New Client' # 其他特殊情况 return 'Other' # 3. 分组应用函数并合并结果 df['status'] = df.groupby('address_id')['my_company'].transform(determine_status) # 查看结果 print(df[['address_id', 'my_company', 'my_date', 'status']])
代码说明
- 先将日期转换为datetime格式并排序,确保时间序列的正确性
- 针对每个客户的运营商序列,依次判定:从未是Verizon客户→一直是Verizon客户→回流客户→流失客户→新客户→其他情况
- 通过遍历序列分析运营商的时间变化,准确捕捉状态转换逻辑
内容的提问来源于stack exchange,提问作者ASH
相关产品推荐
相关产品推荐

