机器学习越来越多地在企业应用,本文跟大家分享一个采用python,应用决策树算法对跨国食品超市顾客等级进行预测的具体案例。
如果想先行了解决策树算法原理,可以阅读本公众号的文章决策树-ID3算法和C4.5算法。
本文目录
一、加载数据
1 加载库
首先加载pandas库,并设置数据读取文件夹。
import os
import numpy as np
import pandas as pd
os.chdir(r'F:\公众号\4.决策树和随机森林')
2 加载数据
接着用read_csv函数读取数据。
ori_date = pd.read_csv("customer.csv") #读取数据
得到结果如下:
本文数据10281行、28列,其中每一行代表一个顾客。每一列代表一个特征,其中member_card列表示标签列。
注:如需本文数据,请到公众号中回复“决策树预测客户等级”即可免费获取。
二、数据预处理
在建模之前需要对标签列进行分析、入模特征进行挑选处理。先来看看标签列的数据特征吧。
1 分析标签列的数据分布
首先用value_counts函数看下标签列的分布情况,并查看该列是否存在缺失值和有问题的值。
ori_date['member_card'].value_counts()
得到结果如下:
说明10281个顾客中,有5703个顾客被标记为青铜客户、2420个顾客被标记为普通客户、1198个顾客被标记为金牌客户、960个顾客被标记为银牌客户。
显然这是一个多分类问题,且这一列的数据类型为int64(整形),没有缺失值,所以不需要对该列进行缺失值处理。
2 特征列数据分析
首先来看下数据框中有哪些列,具体语句如下:
ori_date.columns
得到结果如下:
可以发现第一列是顾客编号,后面的列是顾客姓名、地址、电话号码、国家、受教育程度、年收入、性别、孩子数目、拥有汽车数目等。
本文挑选年收入、受教育程度、孩子数目和拥有汽车辆数做为特征变量(自变量)进行建模。感兴趣的同学可以自己尝试增删变量,看看模型结果会有什么变化。
在建模之前先来看看入模特征的数据特点,首先是年收入列,具体语句如下:
ori_date['yearly_income'].value_counts()
得到结果如下:
从结果中可以发现,年收入这一列存在$符号、空格、-等字符,需进行特殊处理。
再来看看受教育程度列的数据特点,具体语句如下:
ori_date['education'].value_counts()
得到结果如下:
可以发现这一列是文本型,如果要入模,需转换成数值型。
接着来看看孩子数目列的数据特点,具体语句如下:
ori_date['total_children'].value_counts()
得到结果如下:
可以发现这一列是数值型,且没有空值,无需处理,可直接入模。
最后来看下拥有汽车数目列的数据特点,具体语句如下:
ori_date['num_cars_owned'].value_counts()
得到结果如下:
可以发现这一列同样是数值型,且没有空值,无需处理,可直接入模。
3 年收入列正则化处理
一种办法是只保留年收入列中的数值作为入模变量,具体语句如下:
ori_date['yearly_income'] = ori_date['yearly_income'].str.replace('[^0-9]', '')
ori_date['yearly_income'].value_counts()
得到结果如下:
其中.str.replace('[^0-9]', '')表示把年收入中非数值字符替换成空,即只保留数值字符。
另一种办法是只保留年收入下限作为入模变量,具体语句如下:
ori_date['yearly_income'] = ori_date['yearly_income'].str.split(" ").str[0].str.replace('[^0-9]', '')
ori_date['yearly_income'].value_counts()
得到结果如下:
可以发现第二种方法只保留了收入下限。
本文采用的是第一种方法,感兴趣的同学可以试试第二种办法,看看两种方法得到的变量入模后有多少区别。
4 受教育程度列One-hot编码
从上文的分析中可以发现,受教育程度列是文本列,需要转换成数值才可以入模。
有些同学可能会说,直接该列的文本转换成相应的数值即可,具体语句如下:
from sklearn.preprocessing import LabelEncoder
encoding = LabelEncoder()
encoding.fit(ori_date['education'])
education_new = encoding.transform(ori_date["education"])
education_new = pd.DataFrame(education_new)
education_new.iloc[:,0].value_counts()
得到结果如下:
对比原始数据:
可以发现Bachelors Degree(学士学历)、Graduate Degree(研究生学历)、High School Degree (高中学历)、Partial College(大学在读)、Partial High School(高中在读)分别用数值0、1、2、3、4替换。
根据常识可知在学历上,学士学历和大学在读相比学士学历和高中学历更相近。在数值上0和2相比0和3更相近。因此用数值随机替换后表现的却是高中学历和学士学历更相近,显然不合理。
所以在建模时一般采用的是One-hot编码,避免由于数值替换带来的关联性。
为了大家能更好地理解One-hot编码,给大家引入一个实例进行说明。
假设现在有8名顾客,每名顾客都有对应的受教育程度(原始列)。由于要把受教育程度入模,所以要把文本型的数据转换成数值型的。
首先找出受教育程度的所有类别(本例中是五种),把这五种受教育程度每一个都当成一列,如果顾客受教育程度是该种类别的就标记为1,否则标记为0。
从上图可以看出,顾客5的受教育程度是Graduate Degree,所以在该列标记为1,其它列标记为0,同理可得顾客6的标记方法。
One-hot编码会把原始的一列扩展成多列,在python中使用如下语句可以实现:
from sklearn.preprocessing import OneHotEncoder
encoding = OneHotEncoder()
newData = encoding.fit_transform(np.vstack(ori_date["education"].values)).todense()
frame_new = pd.DataFrame(newData)
得到结果如下:
三、模型训练
在第二节对数据进行了预处理,本节正式进入模型训练。在模型训练之前,要把特征变量(自变量)和标签变量(因变量)区分出来。
1 区分特征变量和标签变量
区分特征变量和标签变量的语句如下:
X = pd.merge(ori_date[["yearly_income", "total_children", "num_cars_owned"]],frame_new, left_index = True, right_index = True) #特征变量
y = ori_date['member_card'] #标签变量
其中特征变量X由原始数据中的年收入、孩子数目、拥有汽车辆数,以及受教育程度扩展的One-hot编码组成。
标签变量y由member_card构成。
2 模型训练与效果评估
本文采用决策树算法进行建模,并用交叉验证的方法给出模型评分,具体代码如下:
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
clf = DecisionTreeClassifier()
scores = cross_val_score(clf, X, y, scoring = 'accuracy')
print(np.mean(scores))
其中,clf=DecisionTreeClassifier表示分类器采用的决策树算法。
cross_val_score表示对自变量X和因变量y采用clf对应的算法,进行交叉验证。每一次都有一列真实值和预测值,两者进行对比算出这次训练的得分,依次保存到scores中。
最终的分数采用多次结果的加权平均来表示。
得到结果如下:
可以发现采用决策树算法进行分类,最终得分0.74左右,感兴趣的同学可以自己尝试调整入模变量和算法,看看能不能优化这个结果。
四、完整代码
本文全量代码如下:
import os
import numpy as np
import pandas as pd
from sklearn.preprocessing import OneHotEncoder
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import cross_val_score
#数据读取
os.chdir(r'F:\公众号\4.决策树和随机森林')
ori_date = pd.read_csv("customer.csv")
#年收入正则化处理
ori_date['yearly_income'] = ori_date['yearly_income'].str.replace('[^0-9]', '')
#ori_date['yearly_income'] = ori_date['yearly_income'].str.split(" ").str[0].str.replace('[^0-9]', '')
#受教育程度列One-hot编码
encoding = OneHotEncoder()
newData = encoding.fit_transform(np.vstack(ori_date["education"].values)).todense()
frame_new = pd.DataFrame(newData)
#确定特征变量和标签变量
X = pd.merge(ori_date[["yearly_income", "total_children", "num_cars_owned"]],frame_new, left_index = True, right_index = True) #特征变量
y = ori_date['member_card'] #标签变量
#模型训练和效果评估
clf = DecisionTreeClassifier()
scores = cross_val_score(clf, X, y, scoring = 'accuracy')
print(np.mean(scores))
决策树算法在python中实现已全部讲解完毕,感兴趣的同学可以跟着本文的步骤,自己用python实现。