首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

使用机器学习进行客户流失预测

本文和上一篇文章是连续的,这里是传送门,先安装好环境再看此文会更好:

提示:阅读本文预计需要8分钟,我们会用一组数据来进行机器学习客户流失分析预测。

因为接上一次的内容,所以我们默认你已经具有一套Ubuntu+Python+Anaconda的环境,接下来我们将用用实际的代码来开始分析预测工作。

再次强调,为了继续后面的代码,请关注本微信号,并回复关键字"客户流失",获取.csv的下载地址,一边做一边看才有效果。

在自己的文档目录下新建一个文件夹,比如demo-customer-churn-ann,并将下载的.csv文件放到该目录下,然后右键打开一个新的命令窗口,输入:

jupyter notebook

然后需要等大概10-20秒左右,依据你的机器性能有差异,会打开一个浏览器,并且看到这样的界面:

上一次我们已经写了如下代码,并且看到了这样的结果:

读入数据清理最常用的pandas和numpy包。

import numpy as npimport pandas as pd

从里读入数据:

df = pd.read_csv('customer_churn.csv')

看看读入效果如何:

df.head()

这里我们使用了函数,只显示前5行。

而接下来,我们要开始做更优价值的事情了:

首先是清洗数据,这也是举这个例子的好处,一般来说,并不是所有的数据都是有价值的,专业一点:并不是所有数据都对我们的预测结果有相关性价值,而是否相关当然可以通过SPSS的回归分析来计算相关性,但是我觉得更多的时候,还是需要有业务背景的专家来进行分析判断,当然本例并不难,实际上你耐心的过一下的话,会发现有一些数据是可以删除的:

RowNumber:行号,这个肯定没用,删除

CustomerID:用户编号,这个是顺序发放的,删除

Surname:用户姓名,对流失没有影响,删除

CreditScore:信用分数,这个很重要,保留

Geography:用户所在国家/地区,这个有影响,保留

Gender:用户性别,可能有影响,保留

Age:年龄,影响很大,年轻人更容易切换银行,保留

Tenure:当了本银行多少年用户,很重要,保留

Balance:存贷款情况,很重要,保留

NumOfProducts:使用产品数量,很重要,保留

HasCrCard:是否有本行信用卡,很重要,保留

IsActiveMember:是否活跃用户,很重要,保留

EstimatedSalary:估计收入,很重要,保留

Exited:是否已流失,这将作为我们的标签数据

上述数据列甄别过程,就是大名鼎鼎的“特征工程”(Feature Engineering)了,这是机器学习里面最常用的数据预处理方法。如果我们的数据量足够大,机器学习模型足够复杂,是可以跳过这一步的。但是由于我们的数据只有10000条,还需要手动筛选特征,特征工程可以提高预测质量,但就如前面说的一样,你需要的业务专家能够做出判断

选定了特征之后,我们来生成特征矩阵X,把刚才我们决定保留的特征都写进来。

X = df.loc[:,['CreditScore', 'Geography', 'Gender', 'Age', 'Tenure', 'Balance', 'NumOfProducts', 'HasCrCard', 'IsActiveMember', 'EstimatedSalary']]

看看特征矩阵的前几行:

X.head()

显示结果如下:

特征矩阵构建准确无误,下面我们构建目标数据y,也就是用户是否流失。

y = df.Exited

y.head()

0 11 02 13 04 0Name: Exited, dtype: int64

其实到了这里,该做的准备工作都差不多了,但是有一个点,机器学习说到底用的数据建模的模型,请记住这样一点,你绝大多数时候,是不能给模型算法输入字符串的,所以字符串的数值都需要处理一下,而我们的数据中,显然这两列是不符合这个标准的:

所以我们要处理一下Geogrphy列和Gender列,这里我们终于可以引入大名鼎鼎的Scikit-learn模块了:

from sklearn.preprocessing import LabelEncoder, OneHotEncoderlabelencoder1 = LabelEncoder()X.Geography= labelencoder1.fit_transform(X.Geography)labelencoder2 = LabelEncoder()X.Gender = labelencoder2.fit_transform(X.Gender)

我们需要转换两列,所以建立了两个不同的labelencoder。转换的函数叫做。

经过转换,此时我们再来看看特征矩阵的样子:

X.head()

好的,现在这两列完成了,但是。。。理智告诉我们,其实这个时候这两列并没有处理完,因为Gender当然可以是非0即1的数字表示,但是Geography显然不能这么搞,那该怎么办呢?

这里讲一个动态规划可能会讲到的概念(后续我会分享一篇读书笔记《算法图解》,里面有讲到),就是如果我们的数据是3个地区的,那我们表示的方式并不应该是0是法国,1是德国,2是西班牙,而是应该是法国变成,德国从1变成(0, 1, 0),而西班牙从2变成(0, 0, 1),这是为什么呢?

1、我们想尽可能是非0即1的表示方式

2、如果出现了0,1,2这种数值,机器学习的算法可能会人为西班牙的2大于德国的1,而实际上这并不是你要的结果。

为了解决这个问题,我们会使用到同样是Scikit-learn下的OneHotEncoder。

特征矩阵里面,我们只需要转换国别这一列。因为它在第1列的位置(从0开始计数),因而只填写它的位置信息。

onehotencoder = OneHotEncoder(categorical_features = [1])X = onehotencoder.fit_transform(X).toarray()

我们只看转换后的第一行:

X[0]

这样,总算转换完毕了吧?

没有。

因为本例中,OneHotEncoder转换出来的3列数字,实际上是不独立的。给定其中两列的信息,你自己都可以计算出其中的第3列取值。

好比说,某一行的前两列数字是,那么第三列肯定是1。因为这是转换规则决定的。3列里只能有1个是1,其余都是0。

如果你做过多元线性回归,应该知道这种情况下,我们是需要去掉其中一列,才能继续分析的。不然会落入“虚拟变量陷阱”(dummy variable trap)。

我们删掉第0列,避免掉进坑里。

X = np.delete(X, [0], 1)

再次打印第一行:

检查完毕,现在咱们的特征矩阵处理基本完成。

但是监督式学习,最重要的是有标签(label)数据。本例中的标签就是用户是否流失。我们目前的标签数据框,它是一个行向量,我们需要把它先转换成为列向量。你可以想象成把它“竖过来”。

y = y[:, np.newaxis]y

来,和之前的结果比较一下:

这样在后面训练的时候,他就可以和前面的特征矩阵一一对应来操作计算了。

既然标签代表了类别,我们也把它用OneHotEncoder转换,这样方便我们后面做分类学习。

onehotencoder = OneHotEncoder()y = onehotencoder.fit_transform(y).toarray()

此时的标签变成两列数据,一列代表顾客存留,一列代表顾客流失。

y

总体的数据已经齐全了。但是我们不能把它们都用来训练。

这就好像老师不应该把考试题目拿来给学生做作业和练习一样。只有考学生没见过的题,才能区分学生是掌握了正确的解题方法,还是死记硬背了作业答案。

我们拿出20%的数据,放在一边,等着用来做测试。其余8000条数据用来训练机器学习模型。

from sklearn.model_selection import train_test_splitX_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0)

我们看看训练集的长度:

len(X_train)

再看看测试集的长度:

len(X_test)

确认无误。

是不是可以开始机器学习了?

可以,但是下面这一步也很关键。我们需要把数据进行标准化处理。因为原先每一列数字的取值范围都各不相同,因此有的列方差要远远大于其他列。这样对机器来说,也是很困扰的。数据的标准化处理,可以在保持列内数据多样性的同时,尽量减少不同类别之间差异的影响,可以让机器公平对待全部特征

我们调用Scikit-learn的类来完成这一过程。

from sklearn.preprocessing import StandardScalersc = StandardScaler()X_train = sc.fit_transform(X_train)X_test = sc.transform(X_test)

注意,我们只对特征矩阵做标准化,标签是不能动的。另外训练集和测试集需要按照统一的标准变化。所以你看,训练集上,我们用了函数,先拟合后转换;而在测试集上,我们直接用训练集拟合的结果,只做转换。

X_train

你会发现,许多列的方差比原先小得多。机器学习起来,会更加方便。

数据清理和转换工作至此完成,不要灰心,觉得做了这么多步才完成了数据清理和转换的工作,因为一个坏消息是,现实工作中,你要处理的复杂程度远远大于我们这个简单的例子,但是思路就是这样的。。。

不过也有一个好消息,就是接下来实际训练和预测的代码反而少得可怜

决策树

决策树是一个很简单但很实用的算法,我很喜欢那些简单但是威力无穷的算法,比如还有贝叶斯,本例这个预测很适合用决策树算法。

依然是大名鼎鼎的Scikit-learn,这个模块我太爱了,读入决策树工具:

from sklearn import treeclf = tree.DecisionTreeClassifier()clf = clf.fit(X_train, y_train)

然后,利用我们建立的决策树模型做出预测。

y_pred = clf.predict(X_test)

打印预测结果:

y_pred

array([[ 1., 0.], [ 0., 1.], [ 1., 0.], ..., [ 1., 0.], [ 1., 0.], [ 0., 1.]])

这样看不出来什么。让我们调用Scikit-learn的模块,生成分析报告。

from sklearn.metrics import classification_reportprint(classification_report(y_test, y_pred))

结果如下:

哇( ⊙o⊙ )哇~~~~

总体的准确率为0.81,召回率为0.80,f1分数为0.81,已经很高了。对10个客户做流失可能性判断,它有8次都能判断正确。

而且我没骗你吧,处理好数据后,真正的预测代码就这么5句。

所以,其实大部分工作是特征工程这样子的数据清洗和处理过程,这和大多数的数据分析工作没有差异,比如公司建立数据仓库。

81%真的是不一个不错的结果,但这样我们就能满意了吗?

当然不能,那接下来应该怎么办?是否能够进一步在这样的数据集上提高预测结果?

一方面是可以通过调整决策树的参数来达到这样的一个目的的,同时,还可以使用深度学习

那么接下来让我们进入到深度学习的领域吧,下期再见!(我争取春节前...)

编者按:(本公众号已经受邀加入了原创保护,欢迎转载,但如有转载请注明出处)。

======================

扫描关注微信号,获取更多有价值信息。

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180205G0UTW000?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券