本此大数据机器学习实验从UCI机器学习数据集库中选取了经典的物种生物学abalone鲍鱼数据集,并利用该数据来建立目前比较通用的三种机器学习模型。该鲍鱼数据集是对4177个鲍鱼样本的生物学性状描述信息。
鲍鱼数据包含有4177只鲍鱼的生物学性状信息,其中将这4177只鲍鱼按照生物学性别分为三类:F(雌性),M(雄性),I(幼年)。除过鲍鱼的性别特征以外还包含着描述鲍鱼体态以及环数的描述信息。该数据集的属性信息以及变量描述如表1-1所示,表中给定的是变量名称,变量类型,度量单位和简要描述。从原始数据中删除了缺失值的例子(大多数缺失预测值),连续型变量的取值范围范围已使用生物学中的ANN处理(即除以200)得到下表的数值。
表1-1 属性变量说明表
变量 | 取值范围 | 详细说明 | 备注 |
---|---|---|---|
Type | "F","M","I" | 分类变量,有三个类别,标志着鲍鱼的三种性别 | 建模时作为自变量时利用one hot编码 |
LongestShell | 0.075-0.815 | 连续型变量,单位:mm | 描述的是鲍鱼最长外壳尺寸,自变量 |
Diameter | 0.055-0.650 | 连续型变量,单位:mm | 描述的是鲍鱼的垂直长度,自变量 |
Height | 0.000-1.130 | 连续型变量,单位:mm | 鲍鱼的生物体含壳中的高度,自变量 |
WholeWeight | 0.002-2.825 | 连续型变量,单位:g | 整只鲍鱼的重量,自变量 |
ShuckedWeight | 0.001-1.488 | 连续型变量,单位:g | 剥离壳后的肉重,自变量 |
VisceraWeight | 0.005-0.760 | 连续型变量,单位:g | 内脏重量(出血后),自变量 |
ShellWeight | 0.015-1.005 | 连续型变量,单位:g | 外壳重量(干燥后),自变量 |
Rings | 1.000-29.000 | 整型变量,单位:- | 鲍鱼环数,+1.5以年为单位给出鲍鱼年龄,因变量 |
Rings环数与年龄有着密切关系,鲍鱼年龄是环的个数加1.5。但环数的鉴定需要生物学专家用锥体切割壳体,染色,并通过显微镜计数环的数量,这是一个无聊而费时费力的任务。所以本次试验的目的希望能够利用鲍鱼的体态数据等,例如身长,重量,贝壳宽度等不需要很高的专业知识且比较容易测量的物理数据,来预测鲍鱼的环数(+1.5也就是鲍鱼的年龄),进而可以节省更多的时间和人力成本,是比较有着实际意义的机器学习回归器。
鲍鱼性别关系到鲍鱼的养殖和使用的问题。而鲍鱼的性别的确定需要的是海洋生物学家或是鲍鱼养殖者凭借大量的生物学知识或者是养殖经验,且要结果切割染色等很多工序来进一步确定,且确定过程中也是会存在偏差。这也是个费时费力的实验过程。所以自然地有一个想法,从简单易测且不需要很多生物学知识的生物表征物理量中是否能够判断出鲍鱼性别,本次利用分类机器学习算法来判断鲍鱼性别。
载入与本次试验相关的数据处理库pandas等,数据计算库numpy等,机器学习库sklean等 由于本次试验使用的Python版本为2.0,所以显示中文会有障碍所以进行字体的调整,并解决图片中出现'-'符号的问题
import sys
import numpy as np
import pandas as pd
import seaborn as sns
import matplotlib
import matplotlib.pyplot as plt
from sklearn import datasets
from sklearn.tree import DecisionTreeClassifier #分类树
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.tree import DecisionTreeRegressor #回归树
from sklearn.model_selection import cross_val_score #比较不同深度树的拟合效果,交叉检验
from collections import OrderedDict
import tensorflow as tf
import keras
matplotlib.use('qt4agg')
#指定默认字体
matplotlib.rcParams['font.sans-serif'] = ['SimHei']
matplotlib.rcParams['font.family']='sans-serif'
#解决负号'-'显示为方块的问题
matplotlib.rcParams['axes.unicode_minus'] = False
在uci机器学习数据网站上,将数据下载到本地,放置在python的工作目录并保存为csv格式。然后,利用pandas库的函数read_csv在python的读取abalone数据。本部分值进行可视化处理,所以并不进行其他的数据预处理,只将数据保存为数据框进行数据集的描述分析。
abalone=pd.read_csv('abalone.csv',header=0)
print (abalone.isnull().any()) #判断是否存在缺失值,可以看到abalone数据并没有缺失值
abalone[abalone.isnull().values==True] #确定缺失值位置
abalone= abalone.drop('Unnamed: 0',1)
Y=abalone['Rings']
X=abalone[abalone.columns[0:7]]
Y.shape #显示Y监督变量的维度,查看与样本数
plt.hist(Y,color='red',edgecolor='k')
plt.xlabel('range of perf')
plt.ylabel('Frequency')
plt.title('Histgrom of perf')
plt.show()
从图中可以发现本次试验的4177个样本鲍鱼的环数(年龄),服从的是右偏分布,为是得整体呈现集中趋势,将采用环数进行log变化
sns.distplot(np.log(Y),color='red') #画图界的整容神器log
plt.xlabel('range of ln(perf)')
plt.ylabel('Frequency')
plt.title('Histgrom of ln(perf)')
plt.show()
从图中可以明显看出经过log变化后,直方图的分布更加集中,呈现较为正态的分布。
在uci机器学习数据网站上,将数据下载到本地,放置在python的工作目录并保存为csv格式。然后,利用pandas库的函数read_csv在python的读取abalone数据。本次试验利用的是分类决策树进行鲍鱼性别的分类器的建模,是一个典型的有监督学习。因此将数据集拆分成监督变量和自变量,正如表1-1所描述的那样,监督变量本次设定为Type性别,而其他的数值变量都设定为自变量。另外为了寻找是模型达到最优的分类决策树模型,需要将原始数据划分为训练集和测试集。一般的,还需要进行几次交叉验证。处理过程如下:
abalone=pd.read_csv('abalone.csv',header=0)
print (abalone.isnull().any()) #判断是否存在缺失值,可以看到只有time和code没有缺失值
abalone[abalone.isnull().values==True] #确定缺失值位置
abalone= abalone.drop('Unnamed: 0',1)
abalone.head(5)
Y=abalone['Type'] #将代表着鲍鱼样本的性别的Tpye变量作为监督变量,来监督分类器的学习
X=abalone[abalone.columns[1:8]] #选取除过Tpye变量外的所有数值型变量作为自变量
Y.shape #显示样本数量
X_train,X_test,Y_train,Y_test=train_test_split(X,Y,random_state=14) #随机的划分为训练集和测试集
原始数据集中,分类结果为F的样本为1307个,M的样本为1342个,I的样本为1528个。查看测试集各性别类别的个数。
print (('测试集中鲍鱼数量为%d个')%(Y_test).count())
print (('测试集中性别为M的鲍鱼数量为%d个')%(Y_test=='M').sum())
print (('测试集中性别为F的鲍鱼数量为%d个')%(Y_test=='F').sum())
print (('测试集中性别为I的鲍鱼数量为%d个')%(Y_test=='I').sum())
实际抽取1045个样本作为测试集,其中的各性别分布状况与原数据的样本比例相差不大因此数据集划分比较合理。
clf=DecisionTreeClassifier(random_state=14) #构建决策树分类模型
clf.fit(X_train,Y_train) #利用训练样本数据集进行分类决策树的构建
Y_test_pred_onetree=clf.predict(X_test) #利用测试集样本来对模型进行检验
Y_test_pred_onetree
accuracy_onetree=np.mean(Y_test_pred_onetree==Y_test) * 100 #计算决策分类树的准确率
print("The test accuracy is {:.1f}%".format(accuracy_onetree))#48.6%
决策树的准确度并不是很高,只有大约50%左右,比随机预测正确概率的33%,仅仅高了12%左右,是一个弱分类器。 可以在改进时考虑boosting算法,因为变量较少无法使用随机森林算法。
def show_table(y_true,y_pred):
from sklearn.metrics import confusion_matrix #导入混淆矩阵函数
matrix=confusion_matrix(y_true,y_pred) #构成性别变量的混淆矩阵
level=np.unique(y_true).tolist() #转化为list向量
Index=['True_'+str(content) for content in level] #设置行变量名
columns=['pred_'+str(content) for content in level] #设置列变量名
return(pd.DataFrame(matrix,index=Index,columns=columns))
show_table(Y_test,Y_test_pred_onetree) #展示混淆矩阵
confusion=show_table(Y_test,Y_test_pred_onetree) #生成混淆矩阵
confusion.iloc[0,:]=confusion.iloc[0,:]/(Y_test=='F').sum()*100 #计算混淆矩阵错分百分比
confusion.iloc[1,:]=confusion.iloc[1,:]/(Y_test=='I').sum()*100
confusion.iloc[2,:]=confusion.iloc[2,:]/(Y_test=='M').sum()*100
plt.matshow(confusion)
plt.title(u'混淆矩阵')
plt.colorbar()
plt.ylabel(u'实际类型')
plt.xlabel(u'预测类型')
plt.show()
confusion #显示混淆百分比矩阵
单纯的混淆矩阵的显示并不够直观,在此将混淆矩阵进行可视化展示,如上图所示,可以清楚看到,构建的分类决策树的效果并不是很好,容易将F和M两种性别分类错误,也就是说F和M两个种类的判别混淆严重,原分类是F的在决策树的分类中错误率达到了62%,其中有43%被判定为M,被随机判断也就只好了一点点。而原分类中为M的只有44%别正确分对,只比随机蒙对高了11%所有,分类效果并不是很好,其中被判断为F的记录达到了38.6%,所以可以考虑其他的分类器来进行判断,或者利用这个弱分类器形成adaboost中的及分类器进行集成模型的构建。
在uci机器学习数据网站上,将数据下载到本地,放置在python的工作目录并保存为csv格式。然后,利用pandas库的函数read_csv在python的读取abalone数据。本次试验利用的是回归决策树进行鲍鱼环数(年龄)的分类器的建模,是一个典型的有监督学习。因此将数据集拆分成监督变量和自变量,正如表1-1所描述的那样,监督变量本次设定为环数(年龄),而其他的数值变量都设定为自变量。由于自变量数据集中存在着Type性别的分类变量,所以将该数据利用机器学习中常用的将分类变量转化为编码的one hot独热编码。另外为了寻找使模型达到最优的回归决策树模型,需要将原始数据划分为训练集和测试集。处理过程如下:
abalone=pd.read_csv('abalone.csv',header=0)
print (abalone.isnull().any()) #判断是否存在缺失值,可以看到只有time和code没有缺失值
abalone[abalone.isnull().values==True] #确定缺失值位置
abalone= abalone.drop('Unnamed: 0',1)
abalone.head(5)
Y=abalone['Rings']
X=abalone[abalone.columns[0:7]]
Y.shape
#将X矩阵的分类变量值进行onehot独热编码处理
from numpy import array
from numpy import argmax
from sklearn.preprocessing import LabelEncoder
from sklearn.preprocessing import OneHotEncoder
data=X['Type'] #首先挑选出分类变量Type进行独热编码处理,举出实例
values = array(data) #形成array数据变量
print (values)
上面已经导入了numpy模块的array和argmax模块用于数据处理,并从sklearn.preprocessing中导入了LabelEncoder和OneHotEncoder,分别用于正向转化和生成关于Type的独热编码。
# 将鲍鱼的品种类别变为整数型数字
label_encoder = LabelEncoder()
integer_encoded = label_encoder.fit_transform(values)
print (integer_encoded)
# 将整型数字变为2进制代码
onehot_encoder = OneHotEncoder(sparse=False)
integer_encoded = integer_encoded.reshape(len(integer_encoded), 1)
onehot_encoded = onehot_encoder.fit_transform(integer_encoded)
print(onehot_encoded)
# 举例利用onehot代码反向转换为标签
inverted = label_encoder.inverse_transform([argmax(onehot_encoded[0, :])])
print(inverted)
#变换因变量X矩阵中的Type变量为onehot变量
X['M']=pd.DataFrame(onehot_encoded[:,0])
X['F']=pd.DataFrame(onehot_encoded[:,1])
X['I']=pd.DataFrame(onehot_encoded[:,2])
X= X.drop('Type',1)
至此我们已经获得了数据预处理后的,不含Type性别变量的数据框,取而代之的是Type独热编码,可以用以进行回归决策树的建立。anaconda已经为我们创建好DecisionTreeRegressor环境。需要导入sklearn.tree包就可以进行回归决策树的建立了。
mse=[] #定义一个空列表用来存放回归残差数据
#进行决策回归树的生成,并通过循环来开始探索挖掘最优的决策树深度
for depth in np.arange(2,12): #绘制回归残差图直观判断回归的残差
reg=DecisionTreeRegressor(max_depth=depth)
mse.append(np.mean(abs(cross_val_score(reg,X,Y,
scoring='neg_mean_squared_error',cv=10))))
plt.plot(np.arange(2,12),mse,'o-')
plt.title('Mse of different max_depth')
plt.xlabel('max_depth')
plt.ylabel('MSE')
plt.show()
在决策树的深度挖掘的残差生成过程中,每一次的深度判断都结合了十折的交叉验证,使得获得的MSE更加可靠,模型的选取被随机性的影响更小。从不同树的深度挖掘的输出结果可以看出,但决策回归树的深度在6层时,均方误差达到最小,为6.4左右。接下来,利用所生成的训练数据集来建立层数为6层的决策回归树。并利用测试集计算回归决策树的表现预测效果。
X_train,X_test,Y_train,Y_test=train_test_split(X,Y,random_state=14) #生成一定量的模型训练集以及模型测试集
reg=DecisionTreeRegressor(max_depth=6) #按照上文的内容将回归树设定为6层
reg.fit(X_train,Y_train) #拟合模型
pred=reg.predict(X_test)
MSE=np.mean((Y_test-pred)**2) #返回测试数据的均方误差
print('MSE=%f'%MSE)
SCORE=reg.score(X_test,Y_test) #返回测试数据的平均正确率
print('SCORE=%f'%SCORE)
从输出结果中,可以看到在利用训练数据进行回归树的建模过程中,MSE均方误差5.959,SCORE训练数据的平均准确率得分0,433,并不是很理想。平均准确率并不是很高。接下来进行测试数据的回归决策树的表现。
def feature_importance(importance,feature_names,color='blue',height=1):
#feature=dict(zip(feature_names,importance_ada))
#返回从小到大的索引值用于绘制变量重要性柱状图
Index=np.argsort(importance)
#根据因变量重要性得分来按顺序进行柱状图的排序
plt.barh(left=0,bottom=np.arange(len(importance)),
width=importance[Index],color=color,height=height,edgecolor='k',
tick_label=feature_names[Index])
plt.title('Importance of Varibles')
plt.show()
importance_reg=reg.feature_importances_ #查看回归决策树模型的变量重要性得分
print(importance_reg)
feature_names=X.columns
feature_importance(importance_reg,feature_names,height=0.5) #对鲍鱼的环数预测重要性变量分布图
可以看出在6层深度的回归决策树预测鲍鱼年龄的模型建立过程中,鲍鱼的高度的重要性极强,影响系数达到0.6,然后是鲍鱼的整体重量,垂直长度等信息,关于鲍鱼的性别对年龄预测的影响较小。因此选取height高度和rings环数两个变量绘制散点图。反映连个变量的关系。
#绘制测试数据拟合差别图
def plotfigure(X,X_test,y,yp):
plt.figure()
plt.scatter(X,y,c="k",label="data")
plt.scatter(X_test,yp,c="r",label="max_depth=6",linewidth=2)
plt.xlabel("data")
plt.ylabel("target")
plt.title("Decision Tree Regression")
plt.legend(loc='upper right')
plt.xlim(-0.02,0.4) #设置坐标轴范围
plt.show()
plotfigure(X['Height'],X_test['Height'],Y,pred) #决策树的拟合效果不错预测点全部分布在样本点(黑色)之上
在Decision Tree Regression图中可以明显看出,黑色的散点是全数据的鲍鱼高度和环数的散点关系图,而红色的散点则是测试数据集的鲍鱼高度数据与环数预测值的散点关系图。测试点全部集中于黑色点中。所以可以说所构建的回归决策树已经很好的将鲍鱼环数与鲍鱼高度的关系拟合出来。所构建的决策回归树的预测效果比较不错。决策树可以通过挖掘决策树的深度,调整数的参数,可以将树优化到满足实际的生产需求。因此,决策树要想发挥其本身强大的功能,必须通过不断调整深度、进行剪枝,最终找到令人满意的结果。
由于通过分类决策树对鲍鱼的性别分类结果的正确率只有50%左右,比随机判断的效果并好不了多少,是一种弱分类器。所以想到利用决策树的弱分类器的集成算法——随机森林来进行进一步的性别种类的预测与划分。可以得到的效果比较不错,鲍鱼性别预测的正确率达到了87%以上。
本部分利用R软件进行鲍鱼性别的分类实验,详细分析代码、流程、分析结果请见附件Rmarkdown
本部分利用R软件进行鲍鱼性别的分类实验,详细分析代码、流程、以及分析结果请见附件Rmarkdown
随机森林是决策树的集成发展和算法的延伸,随机森林的测试泛化效果达到了87%左右,机器学习算法效果有了一个很好的提升。相应的支持向量机可以说是隐层为1的神经网络也就是感知机模型。由于在鲍鱼性别分类中,支持向量机的表现并不好,所以打算利用全连接的神经网络来进一步的对鲍鱼的性别分类进行尝试。本章利用架构在tensorflow库上的高质量的神经网络API——keras。keras的开发是着眼于快速实验的。一份好的研究的关键是快速的将想法转化为实践。keras可以帮我们做到这些。keras将神经网络变为全黑箱,只需要传入相应数据,告诉函数神经网络(深度学习)的层数,各层的激活函数和节点数,可以显著地减少认知困难。他所具有的优点是:
导入keras模块,并从keras.layers中导入了Dense,Dropout和Activation,分别用于添加网络层、控制dropout比例和设置激活函数。从keras.optimizers中可以导入权重优化方法,本文采用SGD(随机梯度下降)法进行优化。在这里顺便说一句,SGD并不代表只更新一回,还是基于mini-batch的。
###载入神经网络所需要tensorflow以及keras的函数,构建神经网络环境
from tensorflow.examples.tutorials.mnist import input_data
from keras.models import Sequential
from keras.layers import Dense,Dropout,Activation
from keras.optimizers import SGD
from keras.wrappers.scikit_learn import KerasClassifier
from keras.utils import np_utils
from sklearn.model_selection import train_test_split, KFold, cross_val_score
from sklearn.preprocessing import LabelEncoder
多类分类问题与二类分类问题类似,需要将类别变量(categorical function)的输出标签转化为数值变量。在多分类问题中我们将转化为虚拟变量(dummy variable):即用one hot encoding方法将输出标签的向量(vector)转化为只在出现对应标签的那一列为1,其余为0的布尔矩阵。
abalone=pd.read_csv('abalone.csv',header=0)
print (abalone.isnull().any()) #判断是否存在缺失值,可以看到只有time和code没有缺失值
abalone[abalone.isnull().values==True] #确定缺失值位置
abalone= abalone.drop('Unnamed: 0',1)
abalone = abalone.values
Y=abalone[:,0] #将代表着鲍鱼样本的性别的Tpye变量作为监督变量,来监督分类器的学习
X=abalone[:,1:9].astype(float) #选取除过Tpye变量外的所有数值型变量作为自变量
# 编码类别变量为整形
encoder = LabelEncoder()
encoded_Y = encoder.fit_transform(Y)
# 转化整形变量为one hot代码
dummy_Y = keras.utils.to_categorical(encoded_Y,3)
#将数据分成训练集和测试集。如果random_state设置为一个整数,拆分数据集是固定的。
X_train, X_test, Y_train, Y_test = train_test_split(X, dummy_Y, test_size=0.3, random_state=0)
# 定义神经网络模型以及各个层
model = Sequential() #生成模型
model.add(Dense(output_dim=64, input_dim=8, activation='relu')) #增加输入层,输出为64个神经节点,激活函数为relu
model.add(Dropout(0.5)) #每次的mini-bantch都随机去除50%的神经节点以免过拟合
model.add(Dense(64, activation='relu')) #隐层的输出节点也为64个,激活函数为relu
model.add(Dropout(0.5)) #每次的mini-bantch都随机去除50%的神经节点以免过拟合
model.add(Dense(64, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(output_dim=3, activation='softmax')) #由于本次的鲍鱼数据性别分类为3分类,所以输出为3层,激活函数为sofemax
# 编译模型
model.compile(loss='categorical_crossentropy', optimizer='sgd', metrics=['accuracy'])
model.fit(X_train,Y_train,epochs=20,batch_size=128) #建立模型,batchsize为128个数据记录,进行epoch20次训练,并计算预测得分
score = model.evaluate(X_test,Y_test,batch_size=128)
# 进行预测的测试集的鲍鱼性别
pred = model.predict(X_test)
print(pred) #输出预测性别分类变量的概率大小
print(score) #输出得分
可以看到神经网络的训练的效果也并不像预料的那样好,从预测矩阵来看,分到三类的概率到相差无几,而总的误差率为52.47%左右,虽然比支持向量机的48%提高了,但提高的并不多,所以综合以上分析可以看出,随机森林的预测效果应该是最好的。