前言:Customer Attribution——客户流失
Customerattribution ,又叫做Customer churn, Customer turnover或则Customer defection(客户流失), 是客户、消费者流失的意思。
电话运营商、网络服务上、付费电视公司、保险公司和预警监控服务公司,通常使用客户流失分析和客户流失率作为公司的关键运营指标之一,因为维护客户的成本比获取一个新客户的成本要低得多。这些公司一般开设有客户服务部门,部门工作之一是企图赢回已经流失的客户,因为从长远的角度来看,一个忠实客户的价值远高于一个新客户的价值。
公司一般将流失客户分为主动流失和被动流失两类。主动流失的客户是指那些自己决定转投其他公司或者使用其他服务的客户;被动流失的客户则多是由于受到跟基础环境变化、死亡或者搬家等外界话环境的影响而不得不放弃使用。通常,被动流失的客户不纳入分析模型里。客户流失分析倾向于专注对主动流失客户的分析,因为主动流失客户的流失原因一般跟公司-客户关系有关,而公司在某种程度上客户控制这种关系。比如,要如何控制账单或者如何继续宁售后服务。
通过使用客户流失模型可以评估客户的流失风险,从而进行客户流失分析。客户流失模型能够对潜在流失客户的优先级进行排序,因而模型能够对可能流失的客户群体实施有效的监控。
变量说明
变量 | 类型 | 变量内容 |
---|---|---|
customerID | 字符串 | 客户ID |
gender | 字符串 | 性别 |
SeniorCitizen | 数值型 | 客户是否老年人(是:1;否:0) |
Partner | 字符串 | 客户是否有合伙人(是:Yes;否:No) |
Dependents | 字符串 | 客户所使用服务是否有附属用户(是:Yes;否:No) |
tenure | 字符串 | 客户使用公司服务的月数(0-72之间) |
PhoneService | 字符串 | 客户是否办有电话服务(是:Yes;否:No) |
MultipleLines | 字符串 | 客户是否办理了多条电话服务渠道(是:Yes;否:No) |
InternetService | 字符串 | 客户的网络服务提供线路(DSL:数字用户线路, Fiber optic:光纤线路, No:未办理网络服务) |
OnlineSecurity | 字符串 | 客户是否使用网络安全服务(是:Yes;否:No;未开通网络:No internet service) |
OnlineBackup | 字符串 | 用户是否使用网络备份功能(是:Yes;否:No;未开通网络:No internet service) |
DeviceProtection | 字符串 | 客户是否开启设备保护(是:Yes;否:No;未开通网络:No internet service) |
TechSupport | 字符串 | 客户是否使用技术支持功能(是:Yes;否:No;未开通网络:No internet service) |
SteamingTV | 字符串 | 客户是否办理 数字电视功能(是:Yes;否:No;为开通网络:No internet service) |
SteamingMovies | 字符串 | 客户是否办理数字电影功能(是:Yes;否:No;为开通网络:No internet service) |
Contract | 字符串 | 客户的合约方式(每月签约:Month-to-month;一年:One year;两年:Two year) |
PaperlessBilling | 字符串 | 客户是否使用无纸化账单(是:Yes;否:No) |
PaymentMethod | 字符串 | 客户的付款方式(电子支票:Electronic check;邮寄支票:Mailed check;银行自动转账:Bank transfer(automatic);信用卡自动扣款:Credit card(automatic)) |
MonthlyuCharges | 数值型 | 客户的每月支出情况 |
TotalCharges | 数值型 | 客户从使用至今的总支出情况 |
Churn | 字符串 | 客户是否流失(已流失:Yes;未流失:No) |
1 Data:导入数据
导入所需库:
# import libraries
import numpy as np # 线性代数功能
import pandas as pd # 数据处理,加载csv文件
import os
import matplotlib.pyplot as plt # 数据可视化
from PIL import Image
%matplotlib inline
import seaborn as sns # 数据可视化
import itertools
import warnings
warnings.filterwarnings('ignore')
import io
import plotly.offline as py # 数据可视化
py.init_notebook_mode(connected=True) #数据可视化
import plotly.graph_objs as go # 数据可视化
import plotly.tools as tls # 数据可视化
import plotly.figure_factory as ff # 数据可视化
导入数据:
telcom = pd.read_csv('...WA_Fn-UseC_-Telco-Customer-Churn.csv')
# 查看前五行数据
telcom.head()
- 也可以用to_csv的方法,将head()的结果导入到一个文件种,方便查看。
1.1 Data overview:数据总览
# 数据总览:
print('Rows :', telcom.shape[0]) # 返回行数
print('Columns :', telcom.shape[1]) # 返回列数
print('\nFeatures:\n', telcom.columns.tolist()) # tolist()以列表的形式存储值
print('\nMissing values:\n', telcom.isnull().sum().values.sum())
print('\nUnique values: \n', telcom.nunique()) # 查看变量的唯一值个数
2 Data Manipulation:数据处理
# 2 数据预处理
# 将TotalCharges列中的空值全部替换为nan
telcom['TotalCharges'] = telcom['TotalCharges'].replace(' ', np.nan)
# 将TotalCharges列中的空值行全部删除,空值行占总行数的0.15%,予以删除
telcom = telcom[telcom['TotalCharges'].notnull()]
telcom = telcom.reset_index()[telcom.columns]
# 将值转变为浮点型
telcom['TotalCharges'] = telcom['TotalCharges'].astype(float)
# 将以下列中的‘No internet service’变为‘No’。
replace_cols = ['OnlineSecurity', 'OnlineBackup', 'DeviceProtection',
'TechSupport', 'StreamingTV', 'StreamingMovies']
for i in replace_cols:
telcom[i] = telcom[i].replace({
'No internet service': 'No'})
# 替换值
telcom['SeniorCitizen'] = telcom['SeniorCitizen'].replace({
1:'Yes', 0:'No'})
# 将Tenure变量的值转变为分类值
def tenure_lab(telcom):
if telcom['tenure'] <= 12:
return 'Tenure_0_12'
elif (telcom['tenure'] > 12) & (telcom['tenure'] <= 24):
return 'Tenure_12_24'
elif (telcom['tenure'] > 24) & (telcom['tenure'] <= 48):
return 'Tenure_24_48'
elif (telcom['tenure'] > 48) & (telcom['tenure'] <= 60):
return 'Tenure_48_60'
elif telcom['tenure'] > 60:
return 'Tenure_gt_60'
telcom['tenure_group'] = telcom.apply(lambda telcom: tenure_lab(telcom), axis=1)
# 将流失与非流失客户分开为两个数据集
churn = telcom[telcom['Churn'] == 'Yes']
not_churn = telcom[telcom['Churn'] == 'No']
# 将分类变量与数值型变量分开
Id_col = ['customerID']
target_col = ['Churn']
cat_cols = telcom.nunique()[telcom.nunique()<6].keys().tolist()
cat_cols = [x for x in cat_cols if x not in target_col]
num_cols = [x for x in telcom.columns if x not in cat_cols+target_col+Id_col]
# 二元类型列
bin_cols = telcom.nunique()[telcom.nunique()==2].keys().tolist()
# 多元类型列
multi_cols = [i for i in cat_cols if i not in bin_cols]
- 此部分代码无输出,可以用head()来看看处理之后的情况。
3 Exploration Data Analysis(EDA):描述性统计分析
3.1 客户流失情况
# 客户流失标签
lab = telcom['Churn'].value_counts().keys().tolist()
# 相应值
val = telcom['Churn'].value_counts().values.tolist()
trace = go.Pie(labels=lab, values=val,
marker=dict(
colors=['royalblue', 'lime'],
line=dict(color='white',
width=1.3)
),
rotation=90, hoverinfo='label+value+text',
hole=0.5)
layout = go.Layout(
dict(
title='Customer attribution in data',
plot_bgcolor='rgb(243, 243, 243)',
paper_bgcolor='rgb(243, 243, 243)', # 这是白色的意思
))
data = [trace]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
- 绿色是已流失客户,占比26.6%;未流失客户占比73.4%;
- 可见,这是一个不平衡数据集,后期建模需要采用适当的抽样技术进行抽样。
3.2 变量分布情况(饼图、柱形图和散点图)
- 饼图、柱形图和散点图都是数据描述分析的基本图表
- 饼图和柱形图均可以显示分类数据各分类的分布情况
- 散点图方便观察数值型数据的趋势分布情况
** 以下代码分别定义用于绘制饼图、直方图和散点图的函数**
# 定义一个用于绘制客户分类占比的饼图的函数
def plot_pie(column):
trace1 = go.Pie(values=churn[column].value_counts().values.tolist(),
labels=churn[column].value_counts().keys().tolist(),
hoverinfo='label+percent+name',
domain=dict(x=[0, 0.48]),
name='Churn Customer',
marker=dict(line=dict(width=2,
color='rgb(243, 243, 243)')),
hole=0.6,
)
trace2 = go.Pie(values=not_churn[column].value_counts().values.tolist(),
labels=not_churn[column].value_counts().keys().tolist(),
hoverinfo='label+percent+name',
marker=dict(line=dict(width=2,
color='rgb(243, 243, 243)')),
domain=dict(x=[0.52, 1]),
hole=0.6,
name='Non churn customers'
)
layout = go.Layout(
dict(
title=column+'distribution in customer attrition',
plot_bgcolor='rgb(243, 243, 243)',
paper_bgcolor='rgb(243, 243, 243)',
annotations=[dict(
text='churn customers',
font=dict(size=13),
showarrow=False,
x=0.15, y=0.5,
)]
)
)
data=[trace1, trace2]
fig=go.Figure(data=data, layout=layout)
py.iplot(fig)
# 定义用于绘制客户流失类型的直方图
def histogram(column):
trace1 = go.Histogram(x=churn[column],
histnorm='percent',
name='Churn Customers',
marker=dict(
line=dict(width=0.5,
color='black')
),
opacity=0.9)
trace2 = go.Histogram(x=not_churn[column],
histnorm='percent',
name='Non Churn Customers',
marker=dict(
line=dict(width=0.5,
color='black')
),
opacity=0.9
)
data = [trace1, trace2]
layout = go.Layout(
dict(
title=column+'distribution in customer attrition',
plot_bgcolor='rgb(243, 243, 243)',
paper_bgcolor='rgb(243, 243, 243)',
xaxis=dict(
gridcolor='rgb(255, 255, 255)',
title=column,
zerolinewidth=1,
ticklen=5,
gridwidth=2
),
yaxis=dict(
gridcolor='rgb(255, 255, 255)',
title='percent',
zerolinewidth=1,
ticklen=5,
gridwidth=2
)
)
)
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
# 定义用于绘制数值型变量的散点图矩阵的函数
def scatter_matrix(df):
df = df.sort_values(by='Churn', ascending=True)
classes = df['Churn'].unique().tolist()
classes
classes_code = {
classes[k]: k for k in range(2)}
classes_code
color_vals = [classes_code[cl] for cl in df['Churn']]
color_vals
pl_colorscale = 'Portland'
pl_colorscale
text = [df.loc[k, 'Churn'] for k in range(len(df))]
text
trace = go.Splom(
dimensions=[
dict(label='tenure',
values=df['tenure']),
dict(label='MonthlyCharges',
values=df['MonthlyCharges']),
dict(label='TotalCharges',
values=df['TotalCharges']),
],
text=text,
marker=dict(
color=color_vals,
colorscale=pl_colorscale,
size=3,
showscale=False,
line=dict(width=0.1,
color='rgb(230, 230, 230)')
)
)
axis = dict(showline=True,
zeroline=False,
gridcolor='#fff',
ticklen=4)
layout = go.Layout(
dict(title='Scatter plot matrix for Numerical columns for customer attrition',
autosize=False, height=800, width=800,
dragmode='select', hovermode='closest',
plot_bgcolor='rgba(240, 240, 240, 0.95)',
xaxis1 = dict(axis),
yaxis1 = dict(axis),
xaxis2 = dict(axis),
yaxis2 = dict(axis),
xaxis3 = dict(axis),
yaxis3 = dict(axis)
)
)
data = [trace]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
3.2.1 调用函数绘制饼图
# 使用for循环绘制饼图
for i in cat_cols:
plot_pie(i)
** 按照是否流失进行分组,各分类变量的分类占比情况**
emmm…暂时搞不清楚为什么未流失客户的title显示不出来…先这样吧!!!不好意思了!!!
- 按照客户是否流失进行分类后发现,不管客户是否流失,客户的性别比例分布都比较均衡。
- 说明客户是否选择使用产品跟性别的关系不太大。
-首先,不论是已流失还是未流失客户,老年客户的占比均比较小。
- 已流失客户中,老年客户占比25.5%;未流失客户中,老年客户占比12.9%
- 再用客户中(未流失客户)老年客户的占比为12.9%
- 说明,产品对于老年客户可能不太友好
- 未流失客户中合伙客户占比较大,一流失客户中非合伙客户的占比较大
- 说明如果跟别人一同使用公司产品,那么流失的可能性会减小。能过够增加关联客户数量的产品有利于增加客户的忠诚度,减小客户流失。
- 不论何种情况,未办理附属业务的客户均沾大多数;
- 已流失客户中,82.6%的客户为办理服务业务。此占比较为流失客户中办理未办理附属业务的比例——65.7%要大。
- 说明,办理附属业务的客户忠诚度较高。
- 不论是否为流失客户,开通和未开通的通话服务的比例差不多。
- 说明通话服务是公司的基本业务,业务较为成熟,对客户流失的影响不大
- 不论是否为流失客户,未开通电话服务的占比差不多。
- 未流失客户中拥有多条通话渠道的客户占比较少
- 拥有多条通话渠道的客户流失的比例比较大,可能是因为多条通话渠道导致的费用升高而且功能过剩。
- 为流失客户中未开通网络服务的人数占比为27.3%,而已流失客户中为开通网络服务的占比为6.05%。
- 未流失客户中开通数字线路和光纤线路的客户占比差不多,分别为37.9%和34.8%。
- 已流失客户中开通光纤线路的客户占比为69.4%,远高于开通数字电路的流失客户(占比24.6%)。
- 说明,光纤服务是导致开通网络服务的客户流失的主要原因,需要进一步调查客户对于公司光纤渠道网络服务的反馈。
- 已流失客户中未开通网络安全服务的占比为84.2%,高于未流失客户中未开通网络安全服务的占比(66.7%)。
- 说明,部分客户流失的原因是觉得公司提供的网络服务不够安全,需要进一步调查原因。
- 已流失客户中未开通线上备份(云备份,应该可以这样翻译吧)的占比为72%, 未流失客户的这一比例为63.2%, 前者高于后者。
- 说明开通网络备份服务的客户忠诚度较高,不过,已流失客户中有28%的客户开通了网络备份服务,需要调查这一部分客户对于网络备份服务的反馈。
- 另一方面,未流失客户中只有少于37%的客户开通了线上备份功能,需要调查客户对于备份服务的反馈,通过完线上备份服务,提高客户粘性。
- 已流失客户中有70.8%的客户未开通设备保护功能,未流失客户中有63.7%的客户未开通设备保护功能。
- 说明,未开通设备保护功能客户流失的可能性较大。
- 由于未流失客户中,未开通设备保护的客户占比较高,应进一步思考该服务对于增加客户粘性的贡献度,调查客户对于该项服务的反馈,改进服务。
- 已流失客户中未开通技术支持服务的占比为83.4%, 未流失客户中未开通技术支持服务的占比为66.5%,前者较后者大很多
- 说明技术服务业务对于增加客户粘性具有较大影响,未开通技术服务的客户更容易流失。
- 可以通过推广技术支持业务增加客户忠诚度
- 已流失客户中开通了数字电视服务的客户占比为43.6%,未流失客户中开通了此服务的客户占比为36.6%, 前者略高于后者。
- 说明开通数字电视服务的客户更容易流失,改进该业务能够对减少客户流失有贡献。
- 需要进一步调查客户对于数据电视服务的反馈。
- 与数字电视服务相同,已流失客户中开通此项业务的客户占比(43.8%)略高于未流失客户中开通此项业务的占比(37.1%)
- 同样需要调查客户对于数字电影服务的反馈情况。
- 已流失客户中88.6%为按月签约的客户, 而在未流失客户中,此类别占比为43%,远低于已流失客户中按月签约客户的占比。
- 说明,按月签约的客户更容易流失,对于产品的粘性不高。
- 已流失客户中,使用无纸化账单的占比为74.9%, 高于未流失客户中53.6%的无纸化账单客户占比。
- 需要调查流失客户对无纸化账单看法。
- 流失客户中使用电子支票付款的客户占比为57.39%,高于未流失客户的25.1%。
- 未流失客户中,四种支付方式的占比差别不大。
- 需要进一步调查使用电子支票的客户,了解其中原因。
- 已流失客户中使用期限在0-12个月占比为55.5%, 使用期限在1-4年之间的客户占比为33.1%(15.7%+17.4%)。
- 说明,使用期限增长,客户懒得跟换产品或者忠诚度提升。
3.2.2 调用函数绘制柱形图
# 使用for循环绘制柱形图
for i in num_cols:
histogram(i)
** 柱形图适用于描绘数值型数据的分布情况**
3.2.3 调用函数绘制散点图
绘制不同数值型变量之间的组合散点图,能十分方便的观察不同变量之间的关系。
# 绘制散点图矩阵
scatter_matrix(telcom)
这里直接使用relcom数据集,因为绘制散点图只是用数值型数据。也就是tenure, MonthlyCharges和TotalCharges三列。
不知道为社么,pycharm显示不出这个散点图,检查代码也没有发现问题,这里直接贴上原贴的图
- 这段代码看得不太懂,继续研究之后再来修改,不好意思
3.3 按照tenure变量进行分组的客户流失情况
** 提取绘图所需数据**
# 按照tenure分组的客户流失情况
tg_ch = churn['tenure_group'].value_counts().reset_index()
tg_ch.columns = ['tenure_group', 'count']
tg_nch = not_churn['tenure_group'].value_counts().reset_index()
tg_nch.columns = ['tenure_group', 'count']
- 构建tg_ch数据表,存放已流失客户的tenure_group列的计数值。
- 构建tg_nch数据表,存放的未流失客户的tenure_group列的计数值。
** 绘制条形图**
# 使用条形图展现
# 对于流失客户
trace1 = go.Bar(x=tg_ch['tenure_group'], y=tg_ch['count'],
name='Churn Customers',
marker=dict(line=dict(width=0.5,
color='black')),
opacity=0.9)
# 对于未流失客户
trace2 = go.Bar(x=tg_nch['tenure_group'], y=tg_nch['count'],
name='Non Churn Customers',
marker=dict(line=dict(width=0.5,
color='black')),
opacity=0.9)
layout = go.Layout(dict(
title='Customer Attrition in tenure groups',
plot_bgcolor='rgb(243, 243, 243)',
paper_bgcolor='rgb(243, 243, 243)',
xaxis=dict(gridcolor='rgb(255, 255, 255)',
title='count',
zerolinewidth=1,
ticklen=5,
gridwidth=2)
))
data = [trace1, trace2]
fig = go.Figure(data=data, layout=layout)
py.iplot(fig)
结果输出
- 随着存续期限的增长,已流失客户的数量逐渐减少。
- 未流失客户中,存续期限为0-12个月,24-48个月和60个月以上的(即2-4年和5年以上)的客户数量较多,其中存续期限为60个月以上的客户数量最多。此外,1-2年和4-5年的客户数量较少。
- 说明,短期合约客户更容易流失。
3.4 按照tennure和Churn变量进行分组的月支出和总支出情况
# 提取数据
telcom[['MonthlyCharges', 'TotalCharges', 'tenure', 'tenure_group']]
# 使用散点图来展现按照tenure分组的每月开支和总开支情况
def plot_tenure_scatter(tenure_group, color):
tracer = go.Scatter(x=telcom[telcom['tenure_group']==tenure_group]['MonthlyCharges'],
y=telcom[telcom['tenure_group']==tenure_group]['TotalCharges'],
mode='markers', marker=dict(line=dict(width=0.2, color='black'),
size=4, color=color, symbol='diamond-dot'),
name=tenure_group, opacity=0.9
)
return tracer
# 用散点图绘制按照churn分组的每月开支和总开支
def plot_churn_scatter(churn, color):
tracer = go.Scatter(x=telcom[telcom['Churn']==churn]['MonthlyCharges'], # 进提取已流失客户数据
y=telcom[telcom['Churn']==churn]['TotalCharges'], # 进提取已流失客户数据
mode='markers', marker=dict(line=dict(width=0.2, color='black'),
size=4, color=color, symbol='diamond-dot'),
name='Churn'+churn,
opacity=0.9)
return tracer
trace1 = plot_tenure_scatter('Tenure_0_12', '#FF3300')
trace2 = plot_tenure_scatter('Tenure_12_24', '#6666FF')
trace3 = plot_tenure_scatter('Tenure_24_48', '#99FF00')
trace4 = plot_tenure_scatter('Tenure_48_60', '#996600')
trace5 = plot_tenure_scatter('Tenure_gt_60', 'grey')
trace6 = plot_churn_scatter('Yes', 'red')
trace7 = plot_churn_scatter('No', 'blue')
data1 = [trace1, trace2, trace3, trace4, trace5]
data2 = [trace7, trace6]
# layout
def layout_title(title):
layout = go.Layout(dict(
title=title, plot_bgcolor='rgb(243, 243, 243)', paper_bgcolor='rgb(243, 243, 243)',
xaxis=dict(gridcolor='rgb(255, 255, 255)', title='Monthly charges',
zerolinewidth=1, ticklen=5, gridwidth=2),
yaxis=dict(gridcolor='rgb(255, 255, 255)', title='Total charges',
zerolinewidth=1, ticklen=5, gridwidth=2),
height=600
))
return layout
layout1 = layout_title('Monthly Charges & Total Charges by Tenure group')
layout2 = layout_title('Monthly Charges & Total Charges by Churn group')
fig1 = go.Figure(data=data1, layout=layout1)
fig2 = go.Figure(data=data2, layout=layout2)
py.iplot(fig1)
py.iplot(fig2)
fig1 结果输出
- 不论存续期限长短,已流失客户月消费和总消费较低的密度比较大。说明低消费群体是更容易流失。可能是由于购买的增值服务较少,粘性较小;或者流失的成本不高。
- 存续期限为60个月以上的已流失客户的总消费的趋势最陡,变动幅度最大。扇区两头的密度较大,中间部分的密度较小。
fig2结果输出
3.5 按照tenure进行分组的平均支出情况
avg_tgc = telcom.groupby(['tenure_group', 'Churn'])[['MonthlyCharges', 'TotalCharges']].mean().reset_index()
# 为获得绘图参数构建函数
def mean_charges(column, aggregate):
tracer = go.Bar(x=avg_tgc[avg_tgc['Churn']==aggregate]['tenure_group'],
y=avg_tgc[avg_tgc['Churn']==aggregate][column],
name=aggregate, marker=dict(line=dict(width=1)),
text='Churn')
return tracer
def layout_plot(title, xaxis_lab, yaxis_lab):
layout = go.Layout(title = title, plot_bgcolor='rgb(243, 243, 243)',
paper_bgcolor='rgb(243, 243, 243)',
xaxis=dict(gridcolor='rgb(255, 255, 255)', title=xaxis_lab,
zerolinewidth=1, ticklen=5, gridwidth=2),
yaxis=dict(gridcolor='rgb(255, 255, 255)', title=yaxis_lab,
zerolinewidth=1, ticklen=5, gridwidth=2))
return layout
# 第一个图,按照tenure进行分组的每月平均支出
trace1 = mean_charges('MonthlyCharges', 'Yes')
trace2 = mean_charges('MonthlyCharges', 'No')
layout1 = layout_plot('Average Monthly Charges by Tenure groups', 'Tenure group', 'Monthly Charges')
data1 = [trace1, trace2]
fig1 = go.Figure(data=data1, layout=layout1)
# 第二个图,绘制按照tenure变量进行分组的平均总支出
trace3 = mean_charges('TotalCharges', 'Yes')
trace4 = mean_charges('TotalCharges', 'No')
layout2 = layout_plot('Average Total Charges by Tenure groups', 'Tenure group', 'Total Charges')
data2 = [trace3, trace4]
fig2 = go.Figure(data=data2, layout=layout2)
py.iplot(fig1)
py.iplot(fig2)
fig1结果输出
- 不论是否流失,随着存续期限上升,客户的平均月消费均平缓增多。
- 不论哪个存续期限,未流失客户的平均月消费均低于已流失客户的平均月消费。
- 说明,不论存续期限长短,客户流失的原因可能是因为觉得资费不合理。
fig2结果输出
- 与常理相符,不论客户是否流失,随着存续期限增加,客户的总消费也增加。
- 随着存续期限增加,流失客户的总消费逐渐高于未流失客户的总消费。
- 说明,客户流失原因之一是资费过高。