机器学习项目实践——鸢尾花分类

基于SVM算法实现鸢尾花分类

摘要:支持向量机,因其英文名为support vector machine,故一般简称SVM,通俗来讲,它是一种二类分类模型,其基本模型定义为特征空间上的间隔最大的线性分类器,其学习策略便是间隔最大化,最终可转化为一个凸二次规划问题的求解。最基础的便是二分类问题,给定一个数据集,含有多个属性,通过这些属性,建立超平面,使得这些点分为2类,定义标签1与-1,然后对其他的点进行预测。本实验实现svm分类程序对鸢尾花数据集进行分类,并分析结果与得出相关的结论。

一、问题介绍:

在这里插入图片描述
构建一个模型,根据鸢尾花的花萼和花瓣大小将其分为三种不同的品种。
iris数据集总共包含150行数据
每一行数据由 4 个特征值及一个目标值组成。
4 个特征值分别为:萼片长度、萼片宽度、花瓣长度、花瓣宽度
目标值为三种不同类别的鸢尾花,分别为: Iris Setosa、Iris Versicolour、Iris Virginica
通过数据完成模型建立和评估

二、解题步骤:

1.数据准备
(1)从指定路径下加载数据,将字符型转化为整型
(2)对加载的数据进行分割,x_train,x_test,y_train,y_test分别表示训练集特征、训练集标签、测试集特征、测试集标签
(3)一部分数据用于构建模型,称为训练数据,另一部分用于评估模型性能,称为测试数据。可以利用scikit-learn中train_test_split函数可以实现这个功能。

导入项目所需要的包:

import numpy as np
from sklearn import model_selection
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import colors
from sklearn import svm, datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve, auc
from sklearn.preprocessing import label_binarize #标签二值化LabelBinarizer,可以把yes和no转化为0和1,或是把incident和normal转化为0和1。
from sklearn.multiclass import OneVsRestClassifier

将字符型转为整形,便于数据加载:

def iris_type(s):
    class_label={b'setosa':0,b'versicolor':1,b'virginica':2}
    return class_label[s]

2.加载数据:
使用numpy中的loadtxt读入数据文件
注意数据的读取,delimiter参数是根据txt文件中的分隔符来设置的!

#使用numpy中的loadtxt读入数据文件
filepath='iris.txt'  # 数据文件路径
#注意数据的读取,delimiter参数是根据txt文件中的分隔符来设置的!
data=np.loadtxt(filepath,dtype=float,delimiter=None,converters={4:iris_type})

3.数据分割:
np.split 按照列(axis=1)进行分割,从第四列开始往后的作为y 数据,之前的作为X 数据。函数 split(数据,分割位置,轴=1(水平分割) or 0(垂直分割))。
x = X[:,0:2]
在 X中取前两列作为特征(为了后期的可视化画图更加直观,故只取前两列特征值向量进行训练)
用train_test_split将数据随机分为训练集和测试集,测试集占总数据的30%(test_size=0.3),random_state是随机数种子
参数解释:
x:train_data:所要划分的样本特征集。
y:train_target:所要划分的样本结果。
test_size:样本占比,如果是整数的话就是样本的数量。
random_state:是随机数的种子。(随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。
随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。)

X, y = np.split(data, (4,),axis=1)  # np.split 按照列(axis=1)进行分割,从第四列开始往后的作为y 数据,之前的作为X 数据。函数 split(数据,分割位置,轴=1(水平分割) or 0(垂直分割))。
x = X[:,0:2]  # 在 X中取前两列作为特征(为了后期的可视化画图更加直观,故只取前两列特征值向量进行训练)

x_train,x_test,y_train,y_test=model_selection.train_test_split(x,y,random_state=1,test_size=0.3)

4.定义模型:
搭建模型,训练SVM分类器

classifier=svm.SVC(kernel='rbf',gamma=0.1,decision_function_shape='ovo',C=0.8)
train(classifier, x_train, y_train)

kernel='linear’时,为线性核函数,C越大分类效果越好,但有可能会过拟合(defaul C=1)。
kernel=‘rbf’(default)时,为高斯核函数,gamma值越小,分类界面越连续;gamma值越大,分类界面越“散”,分类效果越好,但有可能会过拟合。
decision_function_shape='ovo’时,为one v one分类问题,即将类别两两之间进行划分,用二分类的方法模拟多分类的结果。
decision_function_shape='ovr’时,为one v rest分类问题,即一个类别与其他类别进行划分。

5.模型评估:
计算决策函数的值,可以通过decision_function()实现decision_function中每一列的值代表距离各类别的距离。只需要调用该函数即可。

def print_accuracy(model, x_train, y_train,x_test, y_test ):
    print('SVM-输出训练集的准确率为:', model.score(x_train, y_train))
    print("SVM-输出测试集的准确率为:", model.score(x_test, y_test))
    #原始结果与预测结果进行对比
    show_accuracy(model.predict(x_train), y_train, 'traing data')
    show_accuracy(model.predict(x_test), y_test, 'testing data')
    #计算决策函数的值,可以通过decision_function()实现。decision_function中每一列的值代表距离各类别的距离。
    print('decision_function:\n', model.decision_function(x_train))

6.模型可视化:
通过matplotlib函数可直接引用画出测试集的散点图

def draw(model, x):
    x1_min, x1_max = x[:, 0].min(), x[:, 0].max()  # 第0列的范围  x[:, 0] ":"表示所有行,0表示第1列
    x2_min, x2_max = x[:, 1].min(), x[:, 1].max()  # 第1列的范围  x[:, 0] ":"表示所有行,1表示第2列
    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]  # 生成网格采样点(用meshgrid函数生成两个网格矩阵X1和X2)
    grid_test = np.stack((x1.flat, x2.flat), axis=1)  # 测试点,再通过stack()函数,axis=1,生成测试点
    # .flat 将矩阵转变成一维数组 (与ravel()的区别:flatten:返回的是拷贝

    grid_hat = model.predict(grid_test)  # 预测分类值
    grid_hat = grid_hat.reshape(x1.shape)  # 使之与输入的形状相同

7.绘制ROC曲线
ROC的全称是Receiver Operating Characteristic Curve,中文名字叫“受试者工作特征曲线”首先是由二战中的电子工程师和雷达工程师发明的,用来侦测战场上的敌军载具(飞机、船舰),也就是信号检测理论。之后很快就被引入了心理学来进行信号的知觉检测。此后被引入机器学习领域,用来评判分类、检测结果的好坏。
ROC曲线的横坐标为FPR(假正率),纵坐标为TPR(真正率)。有了ROC曲线需要对模型有一个定量的分析,这里就需要引入AUC(Area under ROC Curve)面积,AUC指的就是ROC曲线下方的面积,计算AUC只需要沿着ROC的横轴做积分即可,真实场景下ROC曲线一般在y=x直线的上方,所以AUC的取值一般在0.5~1之间,AUC值越大说明模型的性能越好。

iris = datasets.load_iris()
# 鸢尾花数据导入
X = iris.data
# 每一列代表了萼片或花瓣的长宽,一共4列,每一列代表某个被测量的鸢尾植物,iris.shape=(150,4)
y = iris.target
# target是一个数组,存储了data中每条记录属于哪一类鸢尾植物,所以数组的长度是150,所有不同值只有三个
random_state = np.random.RandomState(0)
# 给定状态为0的随机数组
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]

n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]
# 添加合并生成特征测试数据集
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.25,
                                                    random_state=0)

三、结果分析:

1.采用SVM模型得到训练集和测试集的准确率如下:在这里插入图片描述
2.计算得到决策函数的值:
在这里插入图片描述
3.可视化展示散点图:
在这里插入图片描述
4.ROC曲线的绘制:
在这里插入图片描述

总结:
通过散点图及ROC曲线图和准确率的表现来看,该实验基于SVM模型实现鸢尾花的分类识别中,模型的训练效果比较满意,识别率可以达到80%。但有些地方还可以继续完善,完善后的效果应该可以达到90%。

四、源代码:

import numpy as np
from sklearn import model_selection
import matplotlib as mpl
import matplotlib.pyplot as plt
from matplotlib import colors
from sklearn import svm, datasets
from sklearn.model_selection import train_test_split
from sklearn.metrics import roc_curve, auc
from sklearn.preprocessing import label_binarize #标签二值化LabelBinarizer,可以把yes和no转化为0和1,或是把incident和normal转化为0和1。
from sklearn.multiclass import OneVsRestClassifier

# # 当使用numpy中的loadtxt函数导入该数据集时,假设数据类型dtype为浮点型,但是很明显数据集的第五列的数据类型是字符串并不是浮点型。
# # 因此需要额外做一个工作,即通过loadtxt()函数中的converters参数将第五列通过转换函数映射成浮点类型的数据。
# # 首先,我们要写出一个转换函数:
# # 定义一个函数,将不同类别标签与数字相对应
def iris_type(s):
    class_label={b'setosa':0,b'versicolor':1,b'virginica':2}
    return class_label[s]

def train(model, x_train, y_train):
    model.fit(x_train,y_train.ravel())

def show_accuracy(a, b, tip):
    acc = (a.ravel() == b.ravel())
    print("%s Accuracy:%.3f"%(tip, np.mean(acc)))

def print_accuracy(model, x_train, y_train,x_test, y_test ):
    print('SVM-输出训练集的准确率为:', model.score(x_train, y_train))
    print("SVM-输出测试集的准确率为:", model.score(x_test, y_test))
    #原始结果与预测结果进行对比
    show_accuracy(model.predict(x_train), y_train, 'traing data')
    show_accuracy(model.predict(x_test), y_test, 'testing data')
    #计算决策函数的值,可以通过decision_function()实现。decision_function中每一列的值代表距离各类别的距离。
    print('decision_function:\n', model.decision_function(x_train))

def draw(model, x):
    x1_min, x1_max = x[:, 0].min(), x[:, 0].max()  # 第0列的范围  x[:, 0] ":"表示所有行,0表示第1列
    x2_min, x2_max = x[:, 1].min(), x[:, 1].max()  # 第1列的范围  x[:, 0] ":"表示所有行,1表示第2列
    x1, x2 = np.mgrid[x1_min:x1_max:200j, x2_min:x2_max:200j]  # 生成网格采样点(用meshgrid函数生成两个网格矩阵X1和X2)
    grid_test = np.stack((x1.flat, x2.flat), axis=1)  # 测试点,再通过stack()函数,axis=1,生成测试点
    # .flat 将矩阵转变成一维数组 (与ravel()的区别:flatten:返回的是拷贝

    grid_hat = model.predict(grid_test)  # 预测分类值
    grid_hat = grid_hat.reshape(x1.shape)  # 使之与输入的形状相同

    # # 2.指定默认字体
    # mpl.rcParams['font.sans-serif'] = [u'SimHei']
    # mpl.rcParams['axes.unicode_minus'] = False

    # 3.绘制
    cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
    cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])

    # alpha = 0.5
    plt.pcolormesh(x1, x2, grid_hat, cmap=cm_light)  # 预测值的显示
    # plt.plot(x[:, 0], x[:, 1], 'o', alpha=alpha, color='blue', markeredgecolor='k')
    plt.scatter(x[:, 0], x[:, 1], c=np.squeeze(y), edgecolor='k', s=50, cmap = cm_dark )  # 圈中测试集样本
    plt.scatter(x_test[:, 0], x_test[:, 1], s=120, facecolors='none', zorder=10)  # 圈中测试集样本
    plt.xlabel('sepal length', fontsize=13)
    plt.ylabel('sepal width', fontsize=13)
    plt.xlim(x1_min, x1_max)
    plt.ylim(x2_min, x2_max)
    plt.title('SVM feature', fontsize=15)
    #plt.grid()
    plt.show()

#1.数据准备
#1.1加载数据
#使用numpy中的loadtxt读入数据文件
filepath='iris.txt'  # 数据文件路径
#注意数据的读取,delimiter参数是根据txt文件中的分隔符来设置的!
data=np.loadtxt(filepath,dtype=float,delimiter=None,converters={4:iris_type})

#1.2数据分割
X, y = np.split(data, (4,),axis=1)  # np.split 按照列(axis=1)进行分割,从第四列开始往后的作为y 数据,之前的作为X 数据。函数 split(数据,分割位置,轴=1(水平分割) or 0(垂直分割))。
x = X[:,0:2]  # 在 X中取前两列作为特征(为了后期的可视化画图更加直观,故只取前两列特征值向量进行训练)

x_train,x_test,y_train,y_test=model_selection.train_test_split(x,y,random_state=1,test_size=0.3)
#
#用train_test_split将数据随机分为训练集和测试集,测试集占总数据的30%(test_size=0.3),random_state是随机数种子
# 参数解释:
# x:train_data:所要划分的样本特征集。
# y:train_target:所要划分的样本结果。
# test_size:样本占比,如果是整数的话就是样本的数量。
# random_state:是随机数的种子。
# (随机数种子:其实就是该组随机数的编号,在需要重复试验的时候,保证得到一组一样的随机数。比如你每次都填1,其他参数一样的情况下你得到的随机数组是一样的。但填0或不填,每次都会不一样。
# 随机数的产生取决于种子,随机数和种子之间的关系遵从以下两个规则:种子不同,产生不同的随机数;种子相同,即使实例不同也产生相同的随机数。)

#2.定义模型:SVM模型定义
#搭建模型,训练SVM分类器
# classifier=svm.SVC(kernel='linear',gamma=0.1,decision_function_shape='ovo',C=0.1)
# kernel='linear'时,为线性核函数,C越大分类效果越好,但有可能会过拟合(defaul C=1)。
classifier=svm.SVC(kernel='rbf',gamma=0.1,decision_function_shape='ovo',C=0.8)
# kernel='rbf'(default)时,为高斯核函数,gamma值越小,分类界面越连续;gamma值越大,分类界面越“散”,分类效果越好,但有可能会过拟合。
# decision_function_shape='ovo'时,为one v one分类问题,即将类别两两之间进行划分,用二分类的方法模拟多分类的结果。
# decision_function_shape='ovr'时,为one v rest分类问题,即一个类别与其他类别进行划分。
train(classifier, x_train, y_train)
#调用ravel()函数将矩阵转变成一维数组

#4.模型评估
print_accuracy(classifier, x_train, y_train, x_test, y_test)
# SVM-输出训练集的准确率为: 0.838095238095
# SVM-输出测试集的准确率为: 0.777777777778

#5.模型可视化
draw(classifier, x)

#6.绘制ROC曲线
iris = datasets.load_iris()
# 鸢尾花数据导入
X = iris.data
# 每一列代表了萼片或花瓣的长宽,一共4列,每一列代表某个被测量的鸢尾植物,iris.shape=(150,4)
y = iris.target
# target是一个数组,存储了data中每条记录属于哪一类鸢尾植物,所以数组的长度是150,所有不同值只有三个
random_state = np.random.RandomState(0)
# 给定状态为0的随机数组
y = label_binarize(y, classes=[0, 1, 2])
n_classes = y.shape[1]

n_samples, n_features = X.shape
X = np.c_[X, random_state.randn(n_samples, 200 * n_features)]
# 添加合并生成特征测试数据集
X_train, X_test, y_train, y_test = train_test_split(X, y,
                                                    test_size=0.25,
                                                    random_state=0)
# 根据此模型训练简单数据分类器
classifier = OneVsRestClassifier(svm.SVC(kernel='linear', probability=True,
                                         random_state=random_state))  # 线性分类支持向量机
y_score = classifier.fit(X_train, y_train).decision_function(X_test)
# 用一个分类器对应一个类别, 每个分类器都把其他全部的类别作为相反类别看待。
fpr = dict()
tpr = dict()
roc_auc = dict()
for i in range(n_classes):
    fpr[i], tpr[i], _ = roc_curve(y_test[:, i], y_score[:, i])
    # 计算ROC曲线面积
    roc_auc[i] = auc(fpr[i], tpr[i])

fpr["micro"], tpr["micro"], _ = roc_curve(y_test.ravel(), y_score.ravel())
roc_auc["micro"] = auc(fpr["micro"], tpr["micro"])

plt.figure()
lw = 2
plt.plot(fpr[2], tpr[2], color='darkorange',
         lw=lw, label='ROC curve (area = %0.4f)' % roc_auc[2])
plt.plot([0, 1], [0, 1], color='navy', lw=lw, linestyle='--')
plt.xlabel('FPR')
plt.ylabel('TPR')
plt.ylim([0.0, 1.0])
plt.xlim([0.0, 1.0])
plt.legend(loc="lower right")
plt.title("Precision-Recall")
plt.show()
  • 17
    点赞
  • 215
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

来杯橙汁压惊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值