zl程序教程

您现在的位置是:首页 >  其他

当前栏目

大数据分析案例-基于朴素贝叶斯算法构建电信客户流失分析预警模型

案例算法数据分析 分析 基于 模型 构建 客户
2023-09-14 09:14:02 时间

 

🤵‍♂️ 个人主页:@艾派森的个人主页

✍🏻作者简介:Python学习者
🐋 希望大家多多支持,我们一起进步!😄
如果文章对你有帮助的话,
欢迎评论 💬点赞👍🏻 收藏 📂加关注+


目录

1.项目背景

2.项目简介

2.1数据说明

2.2变量介绍

 2.3技术工具

3.算法原理

4.项目实施步骤

4.1导入数据

4.2理解数据

4.3数据预处理

4.4数据可视化

4.5特征工程

4.6建立模型

5.实验结论与建议


1.项目背景

        在进入21世纪以来,中国电信业告别了20世纪最后阶段的高速发展状态,转而进入稳步发展阶段。近年来,随着通信的成本逐年下降,电信市场用户覆盖率近乎100%,几乎没有可开发的新市场,移动、联通、电信三大电信企业完全占据了电信服务市场,电信行业的不断进步,使得各大电信运营商自身服务体系不断完善,目前我国的三大运营商均实现了全业务经营 ,这意味着行业内存在产品、服务、模式等方面的高度同质化,企业间难以实现差异化竞争优势。现如今的竞争环境,迫使运营商的经营重点向有利于电信消费者的方向移动,为了维持客户的保有量,对各运营商的服务体系提出了更高的要求。      

在当今的电信市场环境下,进行客户关系管理(CRM),维系企业与客户之间的关系尤为重要。客户关系管理要求企业在开发新客户和对已有客户进行挽留两方面足够重视。相关机构在对客户满意度进行调查时,有数据表明,对于一个想要不断扩大其客户基数的企业而言,开发一个新客户企业所要花费的成本可以达到挽留一个已有客户所花费成本的五倍。然而,就电信市场而言,维系一位老客户不流失企业可以获得的利润可以达到开发新客户所带来利润的16倍。可以说电信行业通过降低客户流失率同时满足其运营成本降低和利润增加两方面的要求。因此,相较于不断开发新客户而忽视企业已有客户的重要性,维系老客户更契合于电信运营商的价值导向。               

        客户流失现象的发生是必然的,一般情况下无法避免,但可以通过采取积极的预防策略、营销方案等,抑制客户的流失意愿,进而降低客户群体的流失比率。电信企业要提前预测出可能会存在流失问题的客户,通过准确地对可能流失的客户进行定位,可以使得企业调整其决策方向,分配一定的内部资源对可能流失的客户开展积极的挽留政策,降低客户的流失率。解决现有电信服务体系相对于该目标群体存在的问题,提高客户对服务的满意度,进一步减少客户流失带来的损失。

        采用数据挖掘技术和大数据技术是实现预测的关键。利用大数据技术可以处理海量数据的特点,对客户资料、客户的行为方式,包括客户消费行为、使用行为等信息进行提取操作,从数据之间的相互关联性出发,找出不同数据之间可能存在的潜在规律,挖掘出隐藏在数据之间的潜在关系,预测和分析客户的现状和倾向,可以使企业达到及时并有针对性的对可能流失的客户进行挽留。

2.项目简介

2.1数据说明

图2-1 原始数据 

该研究数据来自公开数据集网站,集中包括了客户的21条属性,包括客户ID,性别,是否老年人,婚否等方面信息。

2.2变量介绍

下面对原始数据中的变量进行相关说明,变量说明如下所示。

表2-1相关变量说明

变量名称

变量类型

变量解释

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)

 2.3技术工具

python3.9、vscode编辑器

3.算法原理

KNN算法参考Python实现KNN算法和交叉验证

朴素贝叶斯算法参考基于朴素贝叶斯算法对肿瘤类别分类

决策树算法参考决策树原理以及在sklearn中的使用

支持向量机算法参考基于SVM-支持向量机对鸢尾花数据进行分类

随机森林、Adaboost、GradientBoosting、XGBoost算法参考集成学习之随机森林、Adaboost、Gradient Boosting、XGBoost原理及使用 

4.项目实施步骤

4.1导入数据

导入数据之前,首先把本次项目用的包也都全部导入

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.preprocessing import LabelEncoder,StandardScaler
from sklearn.metrics import recall_score,precision_score,f1_score
from sklearn.ensemble import RandomForestClassifier  # 随机森林
from sklearn.svm import SVC   # 支持向量机
from sklearn.linear_model import LogisticRegression   # 逻辑回归
from sklearn.neighbors import KNeighborsClassifier   # KNN分类算法
from sklearn.naive_bayes import GaussianNB  # 朴素贝叶斯
from sklearn.tree import DecisionTreeClassifier   # 决策树
from xgboost import XGBClassifier
from catboost import CatBoostClassifier
from sklearn.ensemble import AdaBoostClassifier
from sklearn.ensemble import GradientBoostingClassifier
from sklearn.model_selection import StratifiedShuffleSplit
import warnings
warnings.filterwarnings('ignore')
%matplotlib inline

 导入数据

# 导入数据
data = pd.read_csv("data.csv")
pd.set_option('display.max_columns', None)  
pd.set_option('display.max_rows', None)      

4.2理解数据

1.查看数据大小

 数据共有7043行,21列

2.查看数据基本信息

data.info()

从上述结果看出,每列数据是不存在缺失值的 ,以及可以看出他们的数据类型

3.数值型数据的描述性统计

data.describe()

 从结果中可以看出这三列特征的均值、方差、最大最小值、四分位数等数值。

4.非数值型数据的描述性统计

data.describe(include=np.object)

 上面只展示了部分的非数值型特征。

4.3数据预处理

1.缺失值处理

前面理解数据的时候,我们发现数据是没有缺失值的,再验证一下

data.isnull().sum()

经过验证,数据确实不存在缺失值

 2.重复值处理

先检验数据是否存在缺失值

any(data.duplicated()) # 检测数据是否存在重复值,结果为True则说明存在重复值,反之则不存在

结果为False ,说明数据没有重复值,如果有重复值的话,直接调用data.drop_duplicates(inplace=True)删除重复值。

3.异常值处理

先通过箱线图查看前面的数值型数据是否异常

sns.boxplot(x='Churn',y='MonthlyCharges',data=data)

 

sns.boxplot(x='Churn',y='tenure',data=data)

通过观察上面两幅图,我们发现不存在异常值,而且通过第二幅图我们可以发现流失的客户大都是使用公司服务的月数较短,分布在1-3年内,也有极少数是使用了6年多的。

4.数据类型转换

通过观察数据,我们发现TotalCharges这一列应该是数值型类型,因此我们需要进行转换

data['TotalCharges'] = data['TotalCharges'].astype(float)

结果,报错了,说的是这一列数据中存在空格的数据,先查看一下

data['TotalCharges'].value_counts()

果真出现了11个空格的数据,因此需要删除这些数据

data = data[data['TotalCharges']!=' ']
data.shape

 

 接着,重新进行数据类型转换

data['TotalCharges'] = data['TotalCharges'].astype(float)

 接着,我们将TotalCharges和MonthlyCharges数据类型转换为整数类型,能提高后面模型的准确率

data['TotalCharges'] = data['TotalCharges'].apply(lambda x:int(x))
data['MonthlyCharges'] = data['MonthlyCharges'].apply(lambda x:int(x))
data[['TotalCharges','MonthlyCharges']].head()

最后,我们将Churn是否流失这一列类型进行转换,便于后面的模型建立。

data['Churn'] = data['Churn'].map({'No':0,'Yes':1})

4.4数据可视化

1.用饼图描述流失客户比例

plt.figure(figsize=(6,6))
plt.pie(data['Churn'].value_counts(),labels=data['Churn'].value_counts().index,colors=['blue','red'],autopct='%1.2f%%',explode=(0.1,0))
plt.title('Proportions of Customer Churn')
plt.show()

 

其中,流失客户占比26.6%,未流失客户占比73.4%。

2.性别、老年人、配偶、亲属对客户流失率的影响

plt.figure(figsize=(10,10))

plt.subplot(2,2,1)
gender = sns.countplot(x='gender',hue='Churn',data=data)
plt.xlabel('gender')
plt.title('Churn by Gender')
 
plt.subplot(2,2,2)
SeniorCitizen = sns.countplot(x='SeniorCitizen',hue='Churn',data=data)
plt.xlabel('SeniorCitizen')
plt.title('Churn by SeniorCitizen')
 
plt.subplot(2,2,3)
Partner = sns.countplot(x='Partner',hue='Churn',data=data)
plt.xlabel('Partner')
plt.title('Churn by Partner')
 
plt.subplot(2,2,4)
Dependents = sns.countplot(x='Dependents',hue='Churn',data=data)
plt.xlabel('Dependents')
plt.title('Churn by Dependents')
plt.show()

 由图可知,性别男女在电信企业客户流失中几乎没有影响,老年人相较于年轻人在电信企业流失概率更大,单身客户的流失比率相较于有伴侣的客户更大,经济不独立的客户相较于经济独立的客户流失比率更大。

3.热力图显示相关系数

# 提取特征
charges = data.iloc[:,1:20]
corrDf = charges.apply(lambda x:pd.factorize(x)[0])
# 构造相关性矩阵
corr = corrDf.corr()
# 使用热力图显示相关系数
plt.figure(figsize=(20,16))
sns.heatmap(corr,linewidths=0.2,cmap='YlGnBu',annot=True,cbar=False,annot_kws={'fontsize':13})
plt.title('Correlation between variables',fontdict={'fontsize':16})
plt.show()

由图可知,颜色越深达标相关性越强电话服务与多线业务之间存在较强的正相关性,设备保护,技术服务支持,网络电视,网络电影之间也存在较强的正相关性。

4.电信用户是否流失与各变量之间的相关性

# 进行one-hot编码
tel_dummies = pd.get_dummies(data.iloc[:,1:21])
plt.figure(figsize=(15,8))
tel_dummies.corr()['Churn'].sort_values(ascending=False).plot(kind='bar')
plt.title('Correlations between Churn and variables')
plt.show()

由图可知,变量性别与变量电话服务的值接近于0,表明这两个变量对电信企业客户流失的影响特别小,在进行预测研究时,可不考虑。

5.网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视、网络电影和无互联网服务对客户流失率的影响

# 网络安全服务、在线备份业务、设备保护业务、技术支持服务、网络电视、网络电影和无互联网服务对客户流失率的影响
covariables = ['OnlineSecurity','OnlineBackup','DeviceProtection','TechSupport','StreamingTV','StreamingMovies']
plt.figure(figsize=(16,10))
for i,item in enumerate(covariables,1):
    plt.subplot(2,3,i)
    sns.countplot(x=item,hue='Churn',data=data,order=['Yes','No','No internet service'])
    plt.title('Churn by '+str(item))
    i+=1
plt.show()

 6.签订合同方式对客户流失率的影响

sns.barplot(x='Contract',y='Churn',data=data)
plt.title('Churn by Contract type')
plt.show()

由上图可以看出,签订合同方式对客户流失率影响为:按月签订>按一年签订>按两年签订,这可能标明,设定长期合同对留住现有客户更有效。

7.付款方式对客户流失率的影响 

plt.figure(figsize=(10,6))
sns.barplot(x='PaymentMethod',y='Churn',data=data)
plt.title('Churn by PaymentMethod')
plt.show()

 有上图可以看出,在四种支付方式中,使用Electronic check的用户流失率最高,而其他三种支付方式基本持平,因此可以推断电子账单在设计上影响用户体验。

4.5特征工程

数据标准化

telcomvar = data.iloc[:,2:20]
telcomvar.drop('PhoneService',axis=1,inplace=True)
# 数据标准化
scaler = StandardScaler(copy=False)
telcomvar[['tenure','MonthlyCharges','TotalCharges']] = scaler.fit_transform(telcomvar[['tenure','MonthlyCharges','TotalCharges']])

使用箱线图查看数据是否存在异常值 

# 使用箱线图查看数据是否存在异常值
plt.figure(figsize=(8,4))
sns.boxplot(data=telcomvar[['tenure','MonthlyCharges','TotalCharges']])
plt.show()

 

从结果看出,三个变量不存在明显的异常值 

 查看对象类型字段中存在的值:

# 查看对象类型字段中存在的值
def uni(col):
    print(col,'--',telcomvar[col].unique())
telcomobject = telcomvar.select_dtypes(['object'])
for i in range(0,len(telcomobject.columns)):
    uni(telcomobject.columns[i])

 

综合之前的结果来看,在这六个变量中存在NO internet service,即无互联网服务对客户流失率影响很小,这些客户不使用任何互联网产品,因此它和NO是一样的效果,可以使用no进行代替。

# 替换值
telcomvar.replace(to_replace={'No internet service':'No','No phone service':'No'},inplace=True)
for i in range(0,len(telcomobject.columns)):
    uni(telcomobject.columns[i])

然后使用sklearn标签进行编码,将分类数据转换为整数编码:

# 使用sklearn标签编码,将分类数据转换为整数编码
def labelencode(col):
    telcomvar[col] = LabelEncoder().fit_transform(telcomvar[col])
for i in range(0,len(telcomobject.columns)):
    labelencode(telcomobject.columns[i])
for i in range(0,len(telcomobject.columns)):
    uni(telcomobject.columns[i])

 

4.6建立模型

1.建立训练集和测试集

'''
由于我们所使用的数据集是不平衡的,所以最好使用分层交叉验证来确保训练集和测试集都包含每个类样本的保留函数。
交叉验证函数StratifiedShuffleSplit,功能是从样本数据中随机按比例选取训练数据和测试数据
params:
    n_splits:将训练数据分成train/test对的组数,可根据需要进行设置,默认为10
    test_size/train_size:设置train/test所占比例
'''
X = telcomvar
y = data['Churn']
sss = StratifiedShuffleSplit(n_splits=5,test_size=0.2,random_state=666)
# 建立训练数据和测试数据
for train_index,test_index in sss.split(X,y):
    print('train:',train_index,'test:',test_index)
    X_train,X_test = X.iloc[train_index],X.iloc[test_index]
    y_train,y_test = y.iloc[train_index],y.iloc[test_index]

2.选择机器学习算法

# 使用分类算法,这里选用10中分类算法
Classifiers = [
    ['Random Forest',RandomForestClassifier()],
    ['SVC',SVC()],
    ['LogisticRegression',LogisticRegression()],
    ['KNN',KNeighborsClassifier()],
    ['Naive Bayes',GaussianNB()],
    ['Decision Tree',DecisionTreeClassifier()],
    ['AdaBoostClassifier',AdaBoostClassifier()],
    ['GradientBoostingClassifier',GradientBoostingClassifier()],
    ['XGB',XGBClassifier()],
    ['CatBoost',CatBoostClassifier()]
]

 3.训练模型

Classify_result = []
names = []
prediction = []
for name,classifier in Classifiers:
    classifier.fit(X_train,y_train)
    y_pred = classifier.predict(X_test)
    recall = recall_score(y_test,y_pred)
    precision = precision_score(y_test,y_pred)
    f1score = f1_score(y_test,y_pred)
    class_eva = pd.DataFrame([recall,precision,f1score])
    Classify_result.append(class_eva)
    names.append(pd.Series(name))
    prediction.append(pd.Series(y_pred))

4.评估模型

召回率(recall)的含义是:原本为对的当中,预测为对的比例(值越大越好,1为理想状态)

精确率、精度(precision)的含义是:预测为对的当中,原本为对的比例(值越大越好,1为理想状态)。

F1分数(F1-Score)指标综合了Precision与Recall的产出的结果。

F1-Score的取值范围为0-1,1代表模型的输出最好,0最差。

# 评估模型
names = pd.DataFrame(names)[0].tolist()
result = pd.concat(Classify_result,axis=1)
result.columns = names
result.index = ['recall','precision','f1score']
result

 综上所述,在10中分类算法中朴素贝叶斯(Naive Bayes)的F1分数最大为63.8%,所有使用朴素贝叶斯模型效果最好。

5.结果预测

# 预测数据集特征(由于没有提供数据集,这里选取后10行作为需要预测的数据集)
pred_x = telcomvar.tail(10)
# 提取id
pred_id = data['customerID'].tail(10)
# 使用朴素贝叶斯算法进行预测
model = GaussianNB()
model.fit(X_train,y_train)
pred_y = model.predict(pred_x)
# 预测结果
predDf = pd.DataFrame({'customerID':pred_id,'Churn':pred_y})
predDf

 后十位客户中,预测有三位流失,七位不流失。

5.实验结论与建议

  针对此研究,目前将电信行业客户流失的原因大体分为五大类,分别为:资费敏感、终端原因、服务原因、竞争对手、客户流动。现就这五大类流失原因进行分析如下:

(1)资费敏感

资费敏感的客户可能会由于运营商提供的资费过于昂贵,或者强制被捆绑购买了不需要的套餐或服务而导致流失,转投向资费更便宜实惠的运营商。

(2)终端原因

由于终端原因流失的客户大都是最求高端靓机的客户,原电信运营商不能满足这部分客户追求潮流,追求更新技术的需求,造成了客户流失。

(3)服务原因

由于电信运营商的服务水平造成的客户流失反映在客户投诉上,运营商是否及时对客户的投诉信息进行处理,处理结果是否令客户满意极大影响着客户是否流失。

(4)竞争对手影响

在竞争市场上,如果竞争对手存在更好的服务,更优惠的政策将在一定程度上影响客户在本公司的流失。

(5)客户流动

由于客户搬迁或工作原因,也有可能会造成客户的流失。

客户流失预测研究最大的目的在于为营销部门提供有效的营销方案。对于不同原因流失的客户,企业应当采取不同的营销策略,对其进行挽留,以达到资源节约,效益最大的目的。

具体针对措施如下:

1.对于资费敏感的客户,可进行话费赠送或优惠充值的活动,降低资费,挽留客户。

2.对于由于终端原因流失的客户,定期为其发送最新的购机信息,包括性能,活动,价格优惠等政策。

3.对于由于服务原因流失的客户,运营商应该对这类客户进行充分的调研,了解客户的需求,最大程度地满足客户的需求。

4.对于由于竞争对手流失的客户,企业应调研竞争公司的业务体系,找到自身不足之处,优化自身的业务流程,提升对于客户的服务质量。

5.对于由于客户流动造成的流失,运营商可以推出异地优惠政策等,全方位提升业务跨度。