5.4鸢尾花的分类
假设有一名植物学爱好者对她发现的鸢尾花的品种很感兴趣。她收集了每朵鸢尾花的一些测量数据:花瓣的长度和宽度以及花萼的长度和宽度,所有测量结果的单位都是厘米。
她还有一些鸢尾花分类的测量数据,这些花之前已经被植物学专家鉴定为属于setosa、versicolor或virginica三个品种之一。对于这些测量数据,她可以确定每朵鸢尾花所属的品种。
我们的目标是构建一个机器学习模型,可以从这些已知品种的鸢尾花测量数据中进行学习,从而能够预测新鸢尾花的品种。
因为我们有已知的鸢尾花的测量数据,所以这是一个监督学习问题。在这个问题中,我们要在多个选项中预测其中一个(鸢尾花的品种)。这是一个分类(classification)问题
的示例。可能的输出(鸢尾花的品种)叫做类别(class)。数据集中的每朵鸢尾花都属于三个类别之一,所以这是一个三分类问题。
单个数据点(一朵鸢尾花)的预期输出是这朵花的品种。对于一个数据点来说,它的品种叫做标签(label)。
初识数据
本例中我们用到了鸢尾花(Iris)数据集,这是机器学习和统计学中一个经典的数据集。它包含在scikit-learn的datasets模型中。我们可以调用load_iris函数来加载数据:
from sklearn.datasets import load_iris
iris_dataset=load_iris()
iris_dataset
load_iris返回的iris对象是一个Bunch对象,与字典非常相似,里面包含键和值:
print("Keys of iris_dataset:\n{}".format(iris_dataset.keys()))
Keys of iris_dataset:
dict_keys(['data', 'target', 'target_names', 'DESCR', 'feature_names', 'filename'])
DESCR键对应的是数据集的简要说明,可以查看一些数据:
print(iris_dataset['DESCR'][:139] + "\n...")
.. _iris_dataset:
Iris plants dataset
Data Set Characteristics:
:Number of Instances: 150 (50 in each of th
...
targte_names键对应的值时一个字符串数组,里面包含我们要预测的花的品种:
print("Target names:{}".format(iris_dataset['target_names']))
Target names:['setosa' 'versicolor' 'virginica']
feature_names键对应的值是一个字符串列表,对每一个特征进行了说明:
print("Feature names:\n{}".format(iris_dataset['feature_names']))
Feature names:
['sepal length (cm)', 'sepal width (cm)', 'petal length (cm)', 'petal width (cm)']
数据包含在target和data字段中。data里面是花萼长度、花萼宽度、花瓣长度、花瓣宽度的测量是,格式为Numpy数组:
print("Type of data:{}".format(type(iris_dataset['data'])))
Type of data:<class 'numpy.ndarray'>
data数组的每一行对应一朵花,列代表每朵花的四个测量数据:
print("Shape of data:{}".format(iris_dataset['data'].shape))
Shape of data150, 4)
可以看出,数组中包含150多不同的花的测量数据。前面说过,机器学习中的个体叫作样本(sample),其属性叫作特征(feature)。data数组的形状(Shape)是样本数乘以特征数。这是scikit-learn中的约定,你的数据形状应始终遵循这个约定。
我们看下前5个样本的特征数据:
print("First five rows of data:\n{}".format(iris_dataset['data'][:5]))
First five rows of data:
[[5.1 3.5 1.4 0.2]
[4.9 3. 1.4 0.2]
[4.7 3.2 1.3 0.2]
[4.6 3.1 1.5 0.2]
[5. 3.6 1.4 0.2]]
从数据中可以看出,前5朵花的花瓣宽度都是0.2cm,第一朵花的花萼最长,是5.1cm。
target数组包含的是测量过的每朵花的品种,也是一个Numpy数组:
print("Type of target:{}".format(type(iris_dataset['target'])))
Type of target:<class 'numpy.ndarray'>
target是一维数组,每朵花对应其中一个数据:
print("Shape of target:{}".format(iris_dataset['target'].shape))
Shape of target150,)
品种被转换成从0到2的整数
print("Targt:\n{}".format(iris_dataset['target']))
Targt:
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 2
2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2
2 2]
上述数字的代表含义由iris['target_names']数组给出:0代表setosa,1代表versicolor,2代表virginica。
衡量模型是否成功:训练数据与测试数据
一部分数据用于构建机器学习模型,叫作训练数据(training data)或训练集(training set)。其余的数据用来评估模型性能,叫做测试数据(test data)、测试集(test set)或留出集(hold-out set)
from sklearn.model_selection import train_test_split
X_train,X_test,y_train,y_test=train_test_split(iris_dataset['data'],iris_dataset['target'],random_state=0)
train_test_split函数利用为随机数生成器见数据集打乱,为了确保多次运行同一函数能够得到相同的输出,我们利用random_state参数指定了随机数生成器的种子,这样函数输出是固定不变的,所以这行代码的输出始终相同。
print("X_train shape:{}".format(X_train.shape))
print("y_train shape:{}".format(y_train.shape))
X_train shape112, 4)
y_train shape112,)
print("X_test shape:{}".format(X_test.shape))
print("y_test shape:{}".format(y_test.shape))
X_test shape38, 4)
y_test shape38,)
要事第一:观察数据
在构建机器小河西模型之前,通常最好检查一下数据,看看如果不用机器学习能不能轻松完成任务,或者需要的信息有没有包含在数据中。
检查数据的最佳方法之一就是将其可视化。
一种可视化方法是绘制散点图(scatter plot)。数据散点图将一个特征作为x轴,另一个特征作为y轴,将每一个数据点绘制为图上的一个点。
不幸的是,计算机屏幕只有两个维度,所以我们一次只能绘制两个特征(也可能是3个)。用这种方法难以对多于3个特征的数据集作图。解决这个问题的一种方法是绘制散点图矩阵(pair plot),从而可以两两查看所有的特征。
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
import mglearn
# 利用X_train中的数据创建DataFrame
# 利用iris_dataset.feature_names中的字符串对数据进行标记
iris_dataframe=pd.DataFrame(X_train,columns=iris_dataset.feature_names)
# 利用DataFrame创建散点图矩阵,按y_train着色
grr=pd.plotting.scatter_matrix(iris_dataframe,c=y_train,figsize=(15,15),marker='o',hist_kwds={'bins':20},s=60,alpha=0.8,cmap=mglearn.cm3