You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何编写函数识别流失客户、回流客户、新客户等类型?

客户状态分类:流失、回流、新客户判定实现

需求与规则

需要基于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_idmy_companymy_datestatus
111Comcast1/24/2022Left
111Verizon2/21/2022Left
111Other3/28/2022Left
111Other4/25/2022Left
111Comcast5/23/2022Left
111Comcast6/27/2022Left
222Spectrum1/24/2022Never Client
222Spectrum2/21/2022Never Client
222Spectrum3/28/2022Never Client
222Spectrum4/25/2022Never Client
222Spectrum5/23/2022Never Client
222Spectrum6/27/2022Never Client
333Verizon1/24/2022Never Left
333Verizon2/21/2022Never Left
333Verizon3/28/2022Never Left
333Verizon4/25/2022Never Left
333Verizon5/23/2022Never Left
333Verizon6/27/2022Never Left
444Spectrum1/24/2022Left
444Spectrum2/21/2022Left
444Spectrum3/28/2022Left
444Spectrum4/25/2022Left
444Verizon5/23/2022Left
444Spectrum6/27/2022Left
555Verizon1/24/2022Boomerang
555Spectrum2/21/2022Boomerang
555Spectrum3/28/2022Boomerang
555Spectrum4/25/2022Boomerang
555Verizon5/23/2022Boomerang
555Verizon6/27/2022Boomerang
777Comcast1/24/2022New Client
777Comcast2/21/2022New Client
777Verizon1/24/2022New Client
888Verizon2/21/2022Other
888Comcast3/28/2022Other
888Verizon4/25/2022Other
888Comcast5/23/2022Other
888Comcast6/27/2022Other

解决方案

核心思路是先按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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.19 23:00:54