机器学习实训:鸢尾花识别

作者:欧新宇(Xinyu OU)

本文档所展示的测试结果,均运行于:Intel Core i7-7700K CPU 4.2GHz

任务说明


1. 任务说明

构建一个模型,根据鸢尾花的花萼长度、花萼宽度、花瓣长度和花瓣宽度将一朵鸢尾花分为三种不同的品种。

鸢尾花

具体任务包括:

  1. 构建一个模型,根据鸢尾花的花萼长度、花萼宽度、花瓣长度和花瓣宽度,使用训练集对鸢尾花进行建模
  2. 对模型进行评分,输出测试集的精度
  3. 使用模型将一朵鸢尾花分为三种不同的品种
  4. 完善给出的代码
  5. 尽量对整个代码进行调优,获得你所能达到的最佳性能。注意可以尝试多种模型,最终保留最优模型进行提交
  6. 完整的代码和运行结果在AIStudio平台进行提交

2. 数据集说明

鸢尾花数据集总共包含150个数据,每个种类的鸢尾花都是50个样本,每个样本都包含4个特征:花萼长度、花萼宽度、花瓣长度和花瓣宽度。目标值为3种不同的鸢尾花:{0:山鸢尾, 1:变色鸢尾, 2: 维吉尼亚鸢尾}

3. 必要依赖库

  1. numpy: Python第三方库计算库,用于进行科学计算
  2. pandas: Python第三方数据分析库,用于处理数据
  3. matplotlib: Python第三方绘图库,用于实现数据可视化
  4. sklearn: Python机器学习库,其中封装了大量机器学习算法,例如:SVM、KMeans、NLP、决策树、KNN等。

4. 基本要求

  1. 将数据集按照2:8的比例分割为训练集和测试集。
  2. 建议设置random_state=1,以固定随机数生成的结果

示例代码


Step0: 导入依赖库

In [1]:
import numpy as np  
import pandas as pd

from sklearn.model_selection import train_test_split
from sklearn import svm             # 导入SVM支持向量机包 
from sklearn import neural_network  # 导入MLP神经网络包

Step1: 数据准备

(1) 下载鸢尾花数据集(百度AI Studio - 数据集 - 鸢尾花数据集(完整版)“宇宙骑士, 2020-05-02,iris.csv”)

(2) 观察鸢尾花数据集的构成和特点,并将数据集按照训练集和测试集的模式进行分割。分割比例要求2:8。

In [2]:
def prepare_datasets(show_examples = False):
    # 使用pandas载入数据集
    data = pd.read_csv('../Datasets/iris.csv')
    
    # 将类别名称转换成编码
    data.loc[data.Species=='Iris-setosa', 'Species']='0'
    data.loc[data.Species=='Iris-versicolour', 'Species']='1'
    data.loc[data.Species=='Iris-virginica', 'Species']='2'

    if show_examples == True:
        # 观察数据集,取前5个样本
        print(data.head())

    # 将数据中的特征和标签进行分离,其中第0位位索引号,第1-8位位特征,第9位为标签
    X = data.iloc[:, 0:4]
    y = data.iloc[:, 4]

    # 以 20%:80%的比例对训练集和测试集进行拆分
    X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.8, random_state=1)
    
    return X_train, X_test, y_train, y_test 
In [3]:
# X_train, X_test, y_train, y_test = prepare_datasets(show_examples=True)

Step2:创建模型

- SVM支持向量机

C越大,相当于惩罚松弛变量,希望松弛变量接近0,即对误分类的惩罚增大,趋向于对训练集全分对的情况,这样对训练集测试时准确率很高,但泛化能力弱。 C值小,对误分类的惩罚减小,允许容错,将他们当成噪声点,泛化能力较强。

kernel='linear'时,为线性核

decision_function_shape='ovr'时,为one v rest,即一个类别与其他类别进行划分,

decision_function_shape='ovo'时,为one v one,即将类别两两之间进行划分,用二分类的方法模拟多分类的结果。

In [4]:
def SVM():
    model_name = 'SVM'
    #model = svm.SVC(C=0.8,kernel='rbf', gamma=50,decision_function_shape='ovr')
    model = svm.SVC(C=0.5,                           #误差项惩罚系数,默认值是1
                    kernel='rbf',                    #kernel= {线性核: 'linear', 高斯核: kenrel="rbf"}
                    decision_function_shape='ovr',   #决策函数
                    gamma='auto')
    return model, model_name
In [5]:
#  model

- 多层感知机

  • solver: 优化器,可选参数{'lbfgs', 'sgd', 'adam'},默认值'adam'. lbfgs拟牛顿算法,适合较小数据集,一般会使用整个数据集来进行运算和优化;sgd随机梯度下降算法,是神经网络广泛使用的优化算法,结合mini-batch方法,可以实现对大规模和超大规模数据集的优化;adam是对sgd算法的改进,它通过计算梯度的一阶矩估计和二阶矩估计而自动调节学习率。
  • activation: 激活函数,可选参数{'identity', 'logistic', 'tanh', 'relu'},默认值'relu'. 其中identity表示恒等,不对样本特征做处理,返回值$f(x)=x$;logistic就是sigmoid激活函数,返回值$f(x) = \frac{1}{1+e^{-x}}$;relu是限制线性激活,是目前深度学习应用最广的一种激活函数,返回值$f(x) = max(0, x)$。
  • hidden_layer_sizes: 表示隐藏层的数量,数组形式.[100, 100, 100],表示包含三层,每层100个神经元。
  • alpha: 正则化参数,默认值为0.0001
  • batch_size: 批处理时,每批数据的大小。当数据集较大时,通常会设置为mini-batch模式进行优化。lbfgs由于是对所有样本进行统一处理,所以无法使用mini-batch模式。一般来说,批大小的设置以设备所支持的最大性能为依据,例如:GPU的显存的大小,内存所能支持的最大容量。
  • max_iter: 最大迭代次数
  • learning_rate:学习率,用于设置每次权重更新的大小,它决定了权重更新的速度。在sklearn中只有使用随机梯度算法(SGD)时需要设置,可选参数{'constant', 'invscaling', 'adaptive'},默认值为'constant'.
  • learning_rate_init: 学习率初始值,默认为0.001. 在使用深度卷积神经网络进行训练时,学习率的设置非常有讲究,一般会根据迭代次数进行手动调整。通常情况会使用一个较小的学习率(例如0.001)做模型激活(慢启动),然后随着迭代次数设置3个不同的学习率,这三个学习率一般采用从大到小的方式设置,例如一个典型值:{0.01, 0.001, 0.0001}(注意,典型值并不是绝对实用所有情况)
  • momentum: 动量,默认值0.9, 一般是在SGD算法中使用
  • shuffle: 设置是否在每次迭代时都打乱数据,该超参数只能引用与SGD和ADAM。为了增加多样性,一般设置为True。通常在深度学习中,每次迭代都打乱数据是非常重要的设置。
  • 其他在参数在真实应用中再进行讲解和设置
In [6]:
def MLP():
    model_name = 'MLP'
    model = neural_network.MLPClassifier(
        solver='lbfgs',                      # 优化器solver={'lbfgs', 'sgd', 'adam'}
        hidden_layer_sizes=[128,64,128],     # 隐层单元
        activation='relu',                   # 激活函数activation={'identity', 'logistic', 'tanh', 'relu'}
        alpha=1e-5)                          # 正则化参数
    
    return model, model_name

Step3: 模型训练

In [7]:
def train(model, x_train,y_train):
    model.fit(X_train,         #训练集特征向量
              y_train.ravel()) #训练集目标值
In [8]:
# train(model, X_train, y_train)

Step4: 模型评估

In [9]:
def print_results(model, model_name, X_train, y_train, X_test, y_test):
    print('{}模型:'.format(model_name))
    
    #分别打印训练集和测试集的准确率  score(X_train,y_train):表示输出X_train,y_train在模型上的准确率
    print('训练集评分: {:.3f}'.format(model.score(X_train, y_train)))
    print('测试集评分: {:.3f}'.format(model.score(X_test, y_test)))
    
    #计算决策函数的值,表示x到各分割平面的距离(该函数只支持SVM)
#     print('decision_function:\n', clf.decision_function(X_train))
In [10]:
#  print_results(model,X_train,y_train,X_test,y_test)

Step5: 预测样本

In [11]:
def predict(model, test_id):
    print('待预测样本编号为:{},原始标签为:{},预测标签为:{}。'.format(
        test_id,                                       # 基于测试集的id,值得注意的是测试集的划分是随机的,因此与原编号不一致
        np.array(y_test)[test_id],                     # 将df数据转换成numpy数组,并通过新的索引获取数据
        model.predict([np.array(X_test)[test_id]])[0]))   # 将测试样本也转换成2Dnumpy数组,实现新索引关联。注意需要将样本转换为2D数组。

Step6: 执行主函数Main

In [12]:
if __name__ == '__main__':
    
# Step0. 全局超参数配置
    test_id    = 113     #测试集样本编号   
    
    
# Step1. 准备数据集
#     X_train, X_test, y_train, y_test = prepare_datasets(show_examples = True)
    X_train, X_test, y_train, y_test = prepare_datasets()
    
# Step2. 定义模型:SVM模型定义
    model, model_name = SVM()
#    model, model_name = MLP()

# Step3. 启动训练过程
    train(model, X_train, y_train)

# Step4. 模型评估
    print_results(model, model_name, X_train, y_train, X_test, y_test)
    
# Step5: 样本预测
    predict(model, test_id)
SVM模型:
训练集评分: 1.000
测试集评分: 0.925
待预测样本编号为:113,原始标签为:0,预测标签为:0。
In [13]:
# MLP模型:
# 训练集评分: 1.000
# 测试集评分: 0.942
# 待预测样本编号为:113,原始标签为:0,预测标签为:0。

# SVM模型:
# 训练集评分: 1.000
# 测试集评分: 0.925
# 待预测样本编号为:113,原始标签为:0,预测标签为:0。