Iris 鸢尾花数据集是一个经典数据集,在统计学习和机器学习领域都经常被用作示例。数据集内包含 3 类共 150 条记录,每类各 50 个数据,每条记录都有 4 项特征:花萼长度、花萼宽度、花瓣长度、花瓣宽度,可以通过这4个特征预测鸢尾花卉属于(Setosa, Versicolour, Virginica)中的哪一品种。本文就该数据集进行简单的机器学习入门代码操作实验,分别采用逻辑斯蒂回归模型、LDA(线性判别分析)模型训练一个Setosa 和Versicolor的线性分类器,并可视化线性分类效果,比较两种模型的精度、训练时间和分类效果。

1、熟悉训练集及参数选取

从sklearn上加载数据集,显示属性:

rides数据_数据集


rides数据_机器学习_02

注意到’DESCR’这个属性,它是description的简写,即对数据集的描述,通过它可以使我们迅速了解数据集相关信息。在工作区打开DESCR:

rides数据_数据集_03


从中可见:数据集包含150张图片,三种类型各50张,包含每种花的四个属性作为分类依据,其中分类与petal length 和 petal width 两种属性的关联性高,下边采用绘制散点图的方式,选择四个属性中的两个作为x,y轴数值,参看在这些属性确定的特征空间中数据的分布来验证这一结论:

使用index[ ]作为属性编号,4种属性选择2个,共有6种方式。
由于实验要求分类Setosa和Versicolour因此只选取属性集的前100行即可。
使用scatter函数绘制散点图。

import matplotlib.pyplot as plt 
from sklearn import datasets
plt.rcParams['font.family'] = 'SimHei'
iris = datasets.load_iris()
index=[0,1]
X=iris["data"][:,index]
y=iris["target"]
X=X[:100]
y=y[:100]
feature_name=iris["feature_names"]
plt.figure()
plt.subplot(231)
plt.scatter(X[:,0],X[:,1],c=y,marker='*')
plt.title("sepal length && sepal width", fontsize=18)
plt.xlabel(feature_name[index[0]])
plt.ylabel(feature_name[index[1]])

index=[0,2]
X=iris["data"][:,index]
X=X[:100]
plt.subplot(232)
plt.scatter(X[:,0],X[:,1],c=y,marker='*')
plt.title("sepal length && petal length",fontsize=18)
plt.xlabel(feature_name[index[0]])
plt.ylabel(feature_name[index[1]])

index=[0,3]
X=iris["data"][:,index]
X=X[:100]
plt.subplot(233)
plt.scatter(X[:,0],X[:,1],c=y,marker='*')
plt.title("sepal length && petal width",fontsize=18)
plt.xlabel(feature_name[index[0]])
plt.ylabel(feature_name[index[1]])

index=[1,2]
X=iris["data"][:,index]
X=X[:100]
plt.subplot(234)
plt.scatter(X[:,0],X[:,1],c=y,marker='*')
plt.title("sepal width && petal length",fontsize=18)
plt.xlabel(feature_name[index[0]])
plt.ylabel(feature_name[index[1]])

index=[1,3]
X=iris["data"][:,index]
X=X[:100]
plt.subplot(235)
plt.scatter(X[:,0],X[:,1],c=y,marker='*')
plt.title("sepal width && petal width",fontsize=18)
plt.xlabel(feature_name[index[0]])
plt.ylabel(feature_name[index[1]])

index=[2,3]
X=iris["data"][:,index]
X=X[:100]
plt.subplot(236)
plt.scatter(X[:,0],X[:,1],c=y,marker='*')
plt.title("petal length && petal width",fontsize=18)
plt.xlabel(feature_name[index[0]])
plt.ylabel(feature_name[index[1]])
plt.suptitle("Feature selection ",fontsize=18)

scatter散点图相关用法:

matplotlib.pyplot.scatter(x, y, c=None, marker=None)

c是color,marker是标记符号。

常见的color有:

rides数据_数据_04

常见的marker:

rides数据_数据_05

rides数据_数据集_06

从中可以看到在petal length && petal width 属性决定的特征空间中,两种花的数据分布间隔最大,因此最容易区别出,即与DESCR中的类别关联性结论相符。接下来的实验均在petal length && petal width 属性决定的特征空间中进行。

2、训练集、测试集划分

X=feature[:100]
y=target[:100]
from sklearn.model_selection import train_test_split
X_train,X_test, y_train, y_test = train_test_split(X,y,test_size=0.3, random_state=107)
print("top ten data of the training set is :\n",np.c_[X_train[:10],y_train[:10]])
print("top ten data of the testing set is :\n",np.c_[X_test[:10],y_test[:10]])

采用sklearn中提供的train_test_split函数来划分训练集和测试集,交叉验证训练结果。
test_size,设置为0.3,表示为30%为测试集,当然test_size也可为整数,表示测试集的数据数目
random_stare为随机数种子。
然后分别输出训练集和测试集前十个数据,检验划分结果。
3、模型训练时间及精度比较

#Logistic Regression training
import  time
from sklearn.linear_model import LogisticRegression
tic=time.time()
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
toc=time.time()
score=log_reg.score(X_test,y_test)
print("LogistRegression cost",(toc-tic)*1e3,"ms" )
print("LogistRegression model accuracy:",score)

引入线性模型中的逻辑斯蒂回归模型。进行逻辑斯蒂模型训练。

time.time.()的用法类似matlab的tic,toc,意思是获取当前CPU时钟。

模型自带的.score()函数,可以直接对测试集进行测试,返回测试正确率。

LDA训练模型使用与此类似。

当然在机器学习中,我们常常利用一种更加直观的误差分析方法:混淆矩阵

它主要是基于查准率和查全率的概念的一个矩阵。

rides数据_机器学习_07

sklearn中也提供了混淆矩阵相关的函数:

#confusion matrix
from sklearn.metrics import confusion_matrix
y_pre=log_reg.predict(X_test)
confusion=confusion_matrix(y_test,y_pre)
print("confusion matrix of Logist is :\n",confusion)
plt.figure()
plt.imshow(confusion, cmap=plt.cm.gray)
classes = list(set(y_test))
classes.sort()
indices = range(len(confusion))
plt.title("Confusion matrix of Logist",fontsize=18)
plt.xticks(indices, classes)
plt.yticks(indices, classes)
plt.xlabel('prediction',fontsize=18)
plt.ylabel('reality',fontsize=18)

confusion_matrix()函数直接根据测试集标注和测试集预测结果返回混淆矩阵。

rides数据_数据集_08


矩阵的结果还可以直接使用imshow()函数显示出来,颜色越深代表数值越大,主对角线上的数据都是判断正确的数据。

rides数据_数据集_09


4、分类结果可视化

等高线图是非常常用的分类可视化表示方式,在此我们也采用这种方式。

rides数据_数据集_10

首先标定我们的绘图范围为数据集中的数据最值决定的范围下向四周拓展一个单位。

在这个范围空间中,使用meshgrid( )函数,构建坐标网点,分别将横纵坐标集合转为列向量组,然后使用np.c_[ ]函数,把两个列向量组按列整合起来,这样就使坐标点表示的属性值的形式和我们训练集中的属性形式统一起来了,利用训练好的分类器,坐标点的分类结果可能性。

使用contourf( )函数,将分类结果以等高线图的形式输入。

然后把我们训练集的点和测试集的点的分别也显示在图上。

Setosa使用蓝色的点,其中训练集数据以圆点表示,测试集为五角星。

Versicolour使用绿色的点,其中训练集数据以三角形表示,测试集为加号。

将预测分类可能性结果为0.5的位置的等高线作为边界线,视为最终的分类边界,使用黑色虚线鲜明地标注出来。

rides数据_机器学习_11

rides数据_ico_12

从分类器的可视化结果来看,对数几率回归模型和LDA模型的分类器均可以正确划分两种花,但是对数几率回归模型的不定范围(预测可能性在0到1之间)更大,而LDA模型的不定范围大大缩小。这是由于对数几率回归本身所采取的预测模型就是一个具有弹性的线性模型,有一定的冗余度,预测结果也就是一个渐变的过程,然后在两端迅速收缩。而LDA模型则是求的一个最优解,即保证分类使得两组数据在特征空间上分隔最大化,因此由它得到的二分类器有点非黑即白的意味,因为它要保证的同类间距离尽可能小,不同类间的分隔尽可能大,因此在其他特征空间上收缩很快,不定空间范围小。

最后贴个训练的代码吧。

# -*- coding: utf-8 -*-
"""
Created on Sun Jun 14 16:44:23 2020

@author: Flower unbeaten
"""
#data preparation and preview 
import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
list(iris.keys())
data=iris["data"]
target=iris["target"]
target_names=iris["target_names"]
describe=iris["DESCR"]

#data split
feature = iris["data"][:, 2:] # petal length & petal width
X=feature[:100]
y=target[:100]
from sklearn.model_selection import train_test_split
X_train,X_test, y_train, y_test = train_test_split(X,y,test_size=0.3, random_state=107)
print("top ten data of the training set is :\n",np.c_[X_train[:10],y_train[:10]])
print("top ten data of the testing set is :\n",np.c_[X_test[:10],y_test[:10]])

#Logistic Regression training
import  time
from sklearn.linear_model import LogisticRegression
tic=time.time()
log_reg = LogisticRegression()
log_reg.fit(X_train, y_train)
toc=time.time()
score=log_reg.score(X_test,y_test)
print("LogistRegression cost",(toc-tic)*1e3,"ms" )
print("LogistRegression model accuracy:",score)

#visualization results
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'SimHei'
x_min,x_max=[feature[:,0].min()-1,feature[:,0].max()+1]
y_min,y_max=[feature[:,1].min()-1,feature[:,1].max()+1]
x0 , y0 = np.meshgrid(np.linspace(x_min,x_max,500).reshape(-1,1),
                      np.linspace(y_min,y_max,500).reshape(-1,1))
X_new = np.c_[x0.ravel(),y0.ravel()]
y_proba = log_reg.predict_proba(X_new)
plt.figure()
plt.plot(X_train[y_train==0,0],X_train[y_train==0,1],"b.")
plt.plot(X_train[y_train==1,0],X_train[y_train==1,1],"g^")
plt.plot(X_test[y_test==0,0],X_test[y_test==0,1],"b*")
plt.plot(X_test[y_test==1,0],X_test[y_test==1,1],"g+")
z_train=y_proba[:,1].reshape(x0.shape)
contour=plt.contourf(x0,y0,z_train,alpha=0.2,cmap=plt.cm.brg)
plt.clabel(contour, inline=1, fontsize=12)

left_right = np.array([x_min,x_max])
boundary = -(log_reg.coef_[0][0] * left_right + log_reg.intercept_[0]) / log_reg.coef_[0][1]
plt.plot(left_right, boundary, "k--", linewidth=3)
plt.axis([x_min,x_max, y_min, y_max])
plt.title("LogistRegression",fontsize=18)
plt.xlabel("petal length",fontsize=18)
plt.ylabel("petal width",fontsize=18)
plt.legend(("train_Setosa","train_Versicolour","test_Setosa","test_Versicolour",
            "boundary"),loc='best',fontsize=18)

#confusion matrix
from sklearn.metrics import confusion_matrix
y_pre=log_reg.predict(X_test)
confusion=confusion_matrix(y_test,y_pre)
print("confusion matrix of Logist is :\n",confusion)
plt.figure()
plt.imshow(confusion, cmap=plt.cm.Blues)
classes = list(set(y_test))
classes.sort()
indices = range(len(confusion))
plt.title("Confusion matrix of Logist",fontsize=18)
plt.xticks(indices, classes)
plt.yticks(indices, classes)
plt.xlabel('prediction',fontsize=18)
plt.ylabel('reality',fontsize=18)

#LDA
from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA
lda = LDA()
tic=time.time()
lda.fit(X_train, y_train)
toc=time.time()
score=log_reg.score(X_test,y_test)
print("LDA cost",(toc-tic)*1e3,"ms" )
print("LDA model accuracy:",score)
#visualization results
import matplotlib.pyplot as plt
plt.rcParams['font.family'] = 'SimHei'
x_min,x_max=[feature[:,0].min()-1,feature[:,0].max()+1]
y_min,y_max=[feature[:,1].min()-1,feature[:,1].max()+1]
x0 , y0 = np.meshgrid(np.linspace(x_min,x_max,500).reshape(-1,1),
                      np.linspace(y_min,y_max,500).reshape(-1,1))
X_new = np.c_[x0.ravel(),y0.ravel()]
y_proba = lda.predict_proba(X_new)
plt.figure()
plt.plot(X_train[y_train==0,0],X_train[y_train==0,1],"b.")
plt.plot(X_train[y_train==1,0],X_train[y_train==1,1],"g^")
plt.plot(X_test[y_test==0,0],X_test[y_test==0,1],"b*")
plt.plot(X_test[y_test==1,0],X_test[y_test==1,1],"g+")
z_train=y_proba[:,1].reshape(x0.shape)
contour=plt.contourf(x0,y0,z_train,alpha=0.2,cmap=plt.cm.brg)
plt.clabel(contour, inline=1, fontsize=12)

left_right = np.array([x_min,x_max])
boundary = -(lda.coef_[0][0] * left_right + lda.intercept_[0]) / lda.coef_[0][1]
plt.plot(left_right, boundary, "k--", linewidth=3)
plt.axis([x_min,x_max, y_min, y_max])
plt.title("LDA",fontsize=18)
plt.xlabel("petal length",fontsize=18)
plt.ylabel("petal width",fontsize=18)
plt.legend(("train_Setosa","train_Versicolour","test_Setosa","test_Versicolour","boundary"),
           loc='best',fontsize=18)

#confusion matrix
from sklearn.metrics import confusion_matrix
y_pre=lda.predict(X_test)
confusion=confusion_matrix(y_test,y_pre)
print("confusion matrix is of LDA :\n",confusion)
plt.figure()
plt.imshow(confusion, cmap=plt.cm.Blues)
classes = list(set(y_test))
classes.sort()
indices = range(len(confusion))
plt.title("Confusion matrix of LDA",fontsize=18)
plt.xticks(indices, classes)
plt.yticks(indices, classes)
plt.xlabel('prediction',fontsize=18)
plt.ylabel('reality',fontsize=18)