《python数据分析与挖掘实战》学习笔记2
———————————————————————————————————
线性回归——因、自变量是线性关系,对一个或多个自、因变量线性建模,用最小二乘法求系数。
非线性回归——因、自变量是非线性,非线性建模。
Logistic回归——因变量为0或1二分类,广义线性回归特例,利用Logistic函数将因变量控制0-1内表示取值为1的概率。
岭回归——参与建模的自变量间具有多重共线性,用改进的最小二乘法估计。
主成分回归——自变量间含有多重共线性,根据PCA提出,是参数估计的一种有偏估计。
———————————————————————————————————
本小节只对二分类Logistic回归模型的相关原理进行介绍:
#-*- coding: utf-8 -*-
#逻辑回归,自动建模
import pandas as pd
#参数初始化
filename =r'E:\..\demo\data\bankloan.xls'
data = pd.read_excel(filename)
x = data.iloc[:,:8].as_matrix()
y = data.iloc[:,8].as_matrix()
from sklearn.linear_model import LogisticRegression as LR
from sklearn.linear_model import RandomizedLogisticRegression as RLR
rlr = RLR() #稳定性选择方法中的随机逻辑回归进行特征筛选
rlr.fit(x, y) #训练模型
rlr.get_support() #获取筛选结果
print('特征筛选结束')
print('有效特征为:%s' % ','.join(data.iloc[:,:8].columns[rlr.get_support()]))
x=data[data.iloc[:,:8].columns[rlr.get_support()]].as_matrix()#筛选好特征
lr = LR() #建立逻辑回归模型
lr.fit(x, y) #用筛选后的特征数据来训练模型
print('逻辑回归模型训练结束')
print('模型的平均正确率为:%s' % lr.score(x, y))
结果为:
特征筛选结束
有效特征为:工龄,地址,负债率,信用卡负债
逻辑回归模型训练结束
模型的平均正确率为:0.814285714286
———————————————————————————————————
———————————————————————————————————
决策树是一种基本的分类与回归方法,一般多用于分类问题中,表示基于特征对实例进行分类的过程,可以认为是if-then规则的集合,或者说是定义在特征空间与类空间上的条件概率分布。
其主要分为2个大的模块,学习时,利用训练数据,根据损失函数最小化的原则建立决策树模型;预测时,对于给出的未知数据,利用之前所建立的决策树模型进行分类预测。
具体包括3个步骤:特征选择;决策树生成;决策树剪枝。
决策树算法的分类:
ID3计算步骤:(1)对当前样本集合,计算所有属性的信息增益;(2)选择信息增益最大的属性作为测试属性,把测试属性取值相同的样本划为同一子样本集;(3)若子样本集的类别属性只含有单个属性,则分支为叶子节点,判断其属性值并标上相应的符号,然后返回调用处;否则对子样本集递归调用本算法。
原理为:(1)总的信息熵,共m个类别。其概率为给类别个数占总个数的比值。
I ( s 1 , s 2 , . . . , s m ) = − ∑ i m P i l o g 2 ( P i ) I(s_1,s_2,...,s_m)=-\sum_{i}^{m}P_ilog_2(P_i) I(s1,s2,...,sm)=−i∑mPilog2(Pi)
(2)计算各属性的信息熵值:A属性的信息熵值。
E ( A ) = ∑ j = i k s 1 j + s 2 j + . . . + s m j s I ( s 1 j , . . . , s m j ) E(A)=\sum_{j=i}^{k}\frac{s_{1j}+s_{2j}+...+s_{mj}}{s}I(s_{1j},...,s_{mj}) E(A)=j=i∑kss1j+s2j+...+smjI(s1j,...,smj)
(3)计算该属性划分样本集的信息增益为:
G a i n ( A ) = I ( s 1 , s 2 , . . . , s m ) − E ( A ) Gain(A)=I(s_1,s_2,...,s_m)-E(A) Gain(A)=I(s1,s2,...,sm)−E(A)
其中E(A)越小越好,Gain(A)越大越好,即说明选择A属性对于分类所提供的信息越大,其对分类的不确定程度越小。
举例对某餐饮企业的相关销售数据,分析出对销量有影响的因素。
# 决策树算法预测销量高低代码
import pandas as pd
filename=r'E:...\Python数据分析与挖掘实战\chapter5\demo\data\sales_data.xls' #文件路径根据自己设置,可以是绝对的,也可以是相对的。
data=pd.read_excel(filename,index_col='序号')
data[data=='好']=1
data[data=='是']=1
data[data=='高']=1
data[data !=1]=-1#将类别标签数据转化为数据,用1表示好,是,高,用-1表示坏,否,低
x=data.iloc[:,:3].as_matrix().astype(int)
y=data.iloc[:,3].as_matrix().astype(int)
from sklearn.tree import DecisionTreeClassifier as DTC
dtc=DTC(criterion='entropy')#基于信息熵建立决策树
dtc.fit(x,y)#训练模型
from sklearn.tree import export_graphviz
from sklearn.externals.six import StringIO#导入相关函数,可视化决策树
x=pd.DataFrame(x)
with open("tree.dot",'w') as f:
f=export_graphviz(dtc,feature_names=x.columns,out_file=f)
#dot -Tpdf tree.dot -o tree.pdf #将结果可视化,不知道为什么不行
#dot -Tpng tree.dot -o tree.pdf
结果为:
———————————————————————————————————
———————————————————————————————————
各类神经网络算法
BP算法的学习过程由信号的正向传播与误差的逆向传播两个过程组成。正向传播时,输入信号经过隐层的处理后,传向输入层。若输出层节点未能得到期望的输出,则转入误差的逆向传播阶段,将输出误差按某种子形式,通过隐层向输入层返回,从而获得各层单元的参考误差或称误差信号,作为修改各单元权值的依据。此过程一直进行到网络输出的误差逐渐减少到可接受的程度或达到设定的学习次数为止。
神经网络算法预测销量高低的相关代码及结果:
import pandas as pd
filename=r'E:\...\Python数据分析与挖掘实战\chapter5\demo\data\sales_data.xls'
data=pd.read_excel(filename,index_col='序号')
data[data=='好']=1
data[data=='是']=1
data[data=='高']=1
data[data !=1]=0#将类别标签数据转化为数据,用1表示好,是,高,用0表示坏,否,低
x=data.iloc[:,:3].as_matrix().astype(int)
y=data.iloc[:,3].as_matrix().astype(int)
# from tensorflow import
from keras.models import Sequential
from keras.layers.core import Dense,Activation
model=Sequential()#建立模型
model.add(Dense(input_dim=3,output_dim=10))
model.add(Activation('relu'))#用relu函数作为激活函数,提高准确度
model.add(Dense(input_dim=10,output_dim=1))
model.add(Activation('sigmoid'))#由于是0-1输出,用sigmoid函数作为激活函数
model.compile(loss='binary_crossentropy',optimizer='adam',class_mode='binary')#编译模型,指定损失函数为binary_crossentropy,模式为binary,求解方法为adam。
model.fit(x,y,nb_epoch=1000,batch_size=10)#训练模型,学习1000次
yp=model.predict_classes(x).reshape(len(y))#分类预测
# from cm_plot import *#导入混淆矩阵可视化函数
# cm_plot(y,yp).show()
def cm_plot(y, yp):
from sklearn.metrics import confusion_matrix # 导入混淆矩阵函数
cm = confusion_matrix(y, yp) # 混淆矩阵
import matplotlib.pyplot as plt
plt.matshow(cm, cmap=plt.cm.Greens) # 画混淆矩阵图,配色风格使用cm.Greens,更多风格请参考官网。
plt.colorbar() # 颜色标签
for x in range(len(cm)): # 数据标签
for y in range(len(cm)):
plt.annotate(cm[x, y], xy=(x, y), horizontalalignment='center', verticalalignment='center')
plt.ylabel('True label') # 坐标轴标签
plt.xlabel('Predicted label') # 坐标轴标签
return plt
cm_plot(y, yp).show()
结果报错:没能得到解决。后续在更改。
———————————————————————————————————
———————————————————————————————————
实例问题阐述:如餐饮企业
(1)通过客户的消费行为挖掘有价值的客户群;
(2)如何合理对菜品进行分析,挖掘毛利润较高的菜品。
本次分析主要运用了K-Means聚类算法,所以对其做一个大致的阐述。K-Means聚类算法是一种典型的基于距离的非层次聚类算法,在保证最小化误差函数的基础上将数据划分为预定的类数K,采用距离作为相似性的评价指标,也就是说两个对象的距离越近,其相似度就越高。
本题选取了以餐饮客户消费情况为例的940个客户,3个消费特征为研究背景的数据,其中第一个特征为最近一次消费的时间间隔,第二个为消费频率,第三个为消费的总金额。根据这些数据将客户划分为不同的客户群,并对所得到的客户群体进行价值评价。
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
# 参数初始化
inputfile = 'consumption_data.xls' # 销量及其他属性数据
outputfile = 'data_type.xls' # 保存结果的文件名
k = 3 # 聚类的类别
iteration = 600 # 聚类最大循环次数
data = pd.read_excel(inputfile, index_col='Id') # 读取数据
data_zs = 1.0 * (data - data.mean()) / data.std() # 数据标准化
model = KMeans(n_clusters=k, n_jobs=4, max_iter=iteration, random_state=1234) # 分为k类,并发数4
model.fit(data_zs) # 开始聚类
# 简单打印结果
r1 = pd.Series(model.labels_).value_counts() # 统计各个类别的数目
r2 = pd.DataFrame(model.cluster_centers_) # 找出聚类中心
r = pd.concat([r2, r1], axis=1) # 横向连接(0是纵向),得到聚类中心对应的类别下的数目
r.columns = list(data.columns) + ['类别数目'] # 重命名表头
print(r)
# 详细输出原始数据及其类别
r = pd.concat([data, pd.Series(model.labels_, index=data.index)], axis=1) # 详细输出每个样本对应的类别
r.columns = list(data.columns) + ['聚类类别'] # 重命名表头
r.to_excel(outputfile) # 保存结果
def density_plot(data): # 自定义作图函数
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
p = data.plot(kind='kde', linewidth=2, subplots=True, sharex=False)
[p[i].set_ylabel(u'密度') for i in range(k)]
plt.legend()
return plt
pic_output = 'pd' # 概率密度图文件名前缀
for i in range(k):
density_plot(data[r[u'聚类类别'] == i]).savefig(u'%s%s.png' % (pic_output, i))
import pandas as pd
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
# 参数初始化
inputfile = 'consumption_data.xls' # 销量及其他属性数据
inputfile1 = 'data_type.xls'
data = pd.read_excel(inputfile, index_col = 'Id') # 读取数据
data_zs = 1.0*(data - data.mean())/data.std()
r = pd.read_excel(inputfile1,index_col='Id')
tsne = TSNE(random_state=105)
tsne.fit_transform(data_zs) # 进行数据降维
tsne = pd.DataFrame(tsne.embedding_, index = data_zs.index) # 转换数据格式
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
# 不同类别用不同颜色和样式绘图
d = tsne[r['聚类类别'] == 0]
plt.plot(d[0], d[1], 'r+',label='低价值客户群', linewidth=2)
d = tsne[r['聚类类别'] == 1]
plt.plot(d[0], d[1], 'yo',label="高价值客户群", linewidth=2)
d = tsne[r['聚类类别'] == 2]
plt.plot(d[0], d[1], 'b*',label="一般价值客户群", linewidth=2)
plt.legend()
plt.show()
图4聚类效果图
从上图可以看出,大部分都聚合在了一起,聚合效果较好。
为了进一步确定其分类的准确性,在spss21.0中也进行了相关的聚类操作,其中采用k-means聚类和系统聚类的结果都是相同的,但与上述的python结果有所出入。
SPSS21.0聚类过程和结果如下所示:
①分析—分类—k-均值/系统聚类。
②迭代选择600次,产生3类。
③结果如下所示:
从上面的结果来看,与python中的结果有所出入,且从方差分析表的结果来看,其结果更为显著,准确性更高一些。
关联规则分析又称购物篮分析,最早为了发现超市销售数据库中不同的商品之间的关联关系。例如:某顾客在购买了面包之后,很可能也会购买牛奶;购买了啤酒的顾客很可能也会购买尿不湿等。这样就可以提取其中的关联规则:“面包—牛奶”,“啤酒—尿不湿”。前项—后项的规则,这时,商店管理者就可制定相应的政策,如,降低面包的售价,适当提高牛奶的售价,进而增加超市整体的利润。
1、Apriori:关联规则最常用的挖掘频繁项集的算法,核心思想是通过连接产生选项及其支持度然后通过剪枝生成频繁项集。
2、FP-Tree:针对Apriori固有的多次扫描事务数据集的缺项,提出不产生候选频繁项集的方法。
3、Eclat:是一种深度优先算法,采用垂直数据表示形式,在概念和理论的基础上利用基于前缀的等价关系将搜索空间划分为较小的子空间。
4、灰色关联法:分析和确定各因素之间的影响程度或是若干子因素对主因素的贡献度进行分析的方法。
下面重点阐述Apriori算法的应用。
关联规则:形如X->Y的蕴涵表达式,其中X和Y是不相交的项集。关联规则的强度可以用支持度(support)、置信度(confidence)、提升度(lift)度量。
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
def connect_string(x, ms):
x = list(map(lambda i:sorted(i.split(ms)), x))
l = len(x[0])
r = []
for i in range(len(x)):
for j in range(i,len(x)):
if x[i][:l-1] == x[j][:l-1] and x[i][l-1] != x[j][l-1]:
r.append(x[i][:l-1]+sorted([x[j][l-1],x[i][l-1]]))
return r
#寻找关联规则的函数
def find_rule(d, support, confidence, ms = u'--'):
result = pd.DataFrame(index=['support', 'confidence']) #定义输出结果
support_series = 1.0*d.sum()/len(d) #支持度序列
column = list(support_series[support_series > support].index) #初步根据支持度筛选
k = 0
while len(column) > 1:
k = k+1
print(u'\n正在进行第%s次搜索...' %k)
column = connect_string(column, ms)
print(u'数目:%s...' %len(column))
sf = lambda i: d[i].prod(axis=1, numeric_only = True) #新一批支持度的计算函数
#创建连接数据,这一步耗时、耗内存最严重。当数据集较大时,可以考虑并行运算优化。
d_2 = pd.DataFrame(list(map(sf,column)), index = [ms.join(i) for i in column]).T
support_series_2 = 1.0*d_2[[ms.join(i) for i in column]].sum()/len(d) #计算连接后的支持度
column = list(support_series_2[support_series_2 > support].index) #新一轮支持度筛选
support_series = support_series.append(support_series_2)
column2 = []
for i in column: #遍历可能的推理,如{A,B,C}究竟是A+B-->C还是B+C-->A还是C+A-->B?
i = i.split(ms)
for j in range(len(i)):
column2.append(i[:j]+i[j+1:]+i[j:j+1])
cofidence_series = pd.Series(index=[ms.join(i) for i in column2]) #定义置信度序列
for i in column2: #计算置信度序列
cofidence_series[ms.join(i)] = support_series[ms.join(sorted(i))]/support_series[ms.join(i[:len(i)-1])]
for i in cofidence_series[cofidence_series > confidence].index: #置信度筛选
result[i] = 0.0
result[i]['confidence'] = cofidence_series[i]
result[i]['support'] = support_series[ms.join(sorted(i.split(ms)))]
result = result.T.sort_values(['confidence','support'], ascending = False) #结果整理,输出
print(u'\n结果为:')
print(result)
return result
将上述代码命名为:apriori.py.
# -*- coding: utf-8 -*-
from __future__ import print_function
import pandas as pd
from apriori import * # 导入自行编写的apriori函数
inputfile = '../data/shopping_data.xls'
outputfile = '../tmp/apriori_rules1.xls' # 结果文件
data = pd.read_excel(inputfile, header = None)
print(u'\n转换原始数据至0-1矩阵...')
ct = lambda x : pd.Series(1, index=x[pd.notnull(x)]) # 转换0-1矩阵的过渡函数
b = map(ct, data.as_matrix()) # 用map方式执行
data = pd.DataFrame(list(b)).fillna(0) # 实现矩阵转换,空值用0填充
print(data)
print(u'\n转换完毕。')
del b # 删除中间变量b,节省内存
support = 0.1 # 最小支持度
confidence = 0.5 # 最小置信度
ms = '---' # 连接符,默认'--',用来区分不同元素,如A--B。需要保证原始表格中不含有该字符
find_rule(data, support, confidence, ms).to_excel(outputfile) # 保存结果
该模块我在另一篇博客中有详细的阐述。详见:《统计案例分析之预测社会消费品零售总额》。
就餐饮企业而言,经常会碰到如下问题。
1)如何根据客户的消费记录检测是否为异常刷卡消费?
2)如何检测是否有异常订单?
这一类异常问题可以通过离群点检测来解决。
离群点检测是数据挖掘中重要的一部分。
下面主要介绍基于聚类方法的离群点检测的应用。
(1)丢弃远离其他簇的小簇:该过程可以简化为丢弃小于某个阈值的所有簇
(2)基于原型的聚类:首先聚类所有对象,然后评估对象属于簇的程度。可以用对象到他的簇中心的距离来度量属于簇的程度。
选择之前所提到的消费数据,找出数据中含有的离群点。具体代码示例如下:
# -*- coding: utf-8 -*-
import numpy as np
import pandas as pd
# 参数初始化
inputfile = '../data/consumption_data.xls' # 销量及其他属性数据
k = 3 # 聚类的类别
threshold = 2 # 离散点阈值
iteration = 500 # 聚类最大循环次数
data = pd.read_excel(inputfile, index_col = 'Id') # 读取数据
data_zs = 1.0*(data - data.mean())/data.std() # 数据标准化
from sklearn.cluster import KMeans
model = KMeans(n_clusters = k, n_jobs = 4, max_iter = iteration) # 分为k类,并发数4
model.fit(data_zs) # 开始聚类
# 标准化数据及其类别
r = pd.concat([data_zs, pd.Series(model.labels_, index = data.index)], axis = 1) # 每个样本对应的类别
r.columns = list(data.columns) + ['聚类类别'] # 重命名表头
norm = []
for i in range(k): # 逐一处理
norm_tmp = r[['R', 'F', 'M']][r['聚类类别'] == i]-model.cluster_centers_[i]
norm_tmp = norm_tmp.apply(np.linalg.norm, axis = 1) # 求出绝对距离
norm.append(norm_tmp/norm_tmp.median()) # 求相对距离并添加
norm = pd.concat(norm) # 合并
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei'] # 用来正常显示中文标签
plt.rcParams['axes.unicode_minus'] = False # 用来正常显示负号
norm[norm <= threshold].plot(style = 'go') # 正常点
discrete_points = norm[norm > threshold] # 离群点
discrete_points.plot(style = 'ro')
for i in range(len(discrete_points)): # 离群点做标记
id = discrete_points.index[i]
n = discrete_points.iloc[i]
plt.annotate('(%s, %0.2f)'%(id, n), xy = (id, n), xytext = (id, n))
plt.xlabel('编号')
plt.ylabel('相对距离')
plt.show()
结果如下:
离散点检测距离误差图
从上图可以看出,该数据中8个红点表示有8个离群点。在之后的聚类中应将这些数据予以剔除。操作之后,聚类结果如下所示:
从上图来看,聚类效果仍然不是特别理想,需要对数据作进一步处理。