前言
本博客主要是记录一些学习《python 机器学习基础》的心得 ,通过记录博客来作为输出,希望能够和大家一起分享知识。代码编写环境是直接安装的Anaconda,在 Jupyter Notebook上实现的,对于小白来说很友好,省事
后面的内容主要是从书中的 1.7 第一个应用:鸢尾花分类
开始记录,因为之前都是一些简单的介绍,比如使用的代码包和版本,大家可以自己去了解就行。那么废话不多说,就开始吧
1.7 第一个应用:鸢尾花分类
这个小节主要是介绍如何去实现一个简单的模型还有一些核心概念和术语。
问题分析
1.场景
有一名植物学爱好者对她发现的鸢尾花品种很感兴趣,她就收集了每朵鸢尾花的一些测量数据:花瓣的长度和宽度以及花萼的长度和宽度,所有测量结果的单位都是厘米。这些花之前已经被植物学专家鉴定为属于 setosa、 versicolor 或 virginica 三个品种之一。
2.目标
现在的目标就是构建一个机器学习模型,可以从这些已知的品种的鸢尾花测量数据中进行学习,从而能够预测新鸢尾花的品种。
3.问题定位
我们有已知品种的鸢尾花的测量数据,所以这是一个监督学习问题,同时在这个场景中我们是要预测出属于哪一种鸢尾花品种,所以这还是一个分类问题。这其中有两个基本概念,类别与标签。
-
类别:鸢尾花的不同品种
1.7.1 初识数据
本例中使用到的数据,是机器学习和统计学中一个经典的数据集,它包含在scikit-learn 的 datasets 模块中,引入方式如下:
from sklearn.datasets import load_iris
iris_dataset = load_iris()
load_iris 返回的 iris 对象是一个 Bunch 对象,与字典非常相似,里面包含键和值,可以使用iris_dataset.keys()查看
其中有一些关键字段需要说明:
DESCR 键对应的值是数据集的简要说明:可以使用如下方式查看
print(iris_dataset['DESCR'][:193] + "\n...")
target_names 键对应的值是一个字符串数组,里面包含我们要预测的花的品种:
print("Target names: {}".format(iris_dataset['target_names']))
feature_names 键对应的值是一个字符串列表,对每一个特征进行了说明:
print("Feature names: \n{}".format(iris_dataset['feature_names']))
target 和 data 字段包含着训练使用的数据,data里面是花萼长度、花萼宽度、花瓣长度、花瓣宽
度的测量数据,格式为 NumPy 数组;data 数组的每一行对应一朵花,列代表每朵花的四个测量数据。
使用如下语法查看数据的情况:
print("Shape of data: {}".format(iris_dataset['data'].shape))
###会输出 Shape of data: (150, 4)
可以看出,数组中包含 150 朵不同的花的测量数据。这里补充一些概念,机器学习汇总,个体叫样本(sample)
,其属性叫做特征(feature)
。下面给出前 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]]
target是一维数组,每朵花对应其中一个数据:(品种被转换成从 0 到 2 的整数)
print("Target:\n{}".format(iris_dataset['target']))
输出如下:
Target:
[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 000000000000111111111111111111111111 1
111111111111111111111111122222222222 2
222222222222222222222222222222222222 2 2]
上述数字的代表含义由 iris['target_names'] 数组给出:
0 代表 setosa,1 代表 versicolor, 2 代表 virginica。
1.7.2 衡量模型是否成功:训练数据与测试数据
当评估一个模型的效果时,我们是不能用构建模型的数据用于评估模型的,因为我们的模型会一直记住这个数据,他就总是能预测正确,这样会导致我们无法判断它的预测结果是否可信。因此我们需要使用新的数据来评估模型性能。
通常的做法通常的做法是将收集好的带标签数据(此例中是 150 朵花的测量数据) 分成两部分。一部分数据用于构建机器学习模型,叫作训练数据(training data)或训练 集(training set)。其余的数据用来评估模型性能,叫作测试数据(test data)、测试集(test set)或留出集(hold-out set)
如何实现数据划分
scikit-learn 中的 train_test_split 函数可以打乱数据集并进行拆分。这个函数将 75% 的 行数据及对应标签作为训练集,剩下 25% 的数据及其标签作为测试集。训练集与测试集的 分配比例可以是随意的,但使用 25% 的数据作为测试集是很好的经验法则。
基本原则
scikit-learn 中的数据通常用大写的 X 表示,而标签用小写的 y 表示。这是受到了数学 标准公式 f(x)=y 的启发,其中 x 是函数的输入,y 是输出。我们用大写的 X 是因为数据是 一个二维数组(矩阵),用小写的 y 是因为目标是一个一维数组(向量),这也是数学中 的约定。
代码样例
###在对数据进行拆分之前,train_test_split 函数利用伪随机数生成器将数据集打乱。
###为了确保多次运行同一函数能够得到相同的输出,我们利用 random_state 参数指定了随机数生成器的种子。
##这样函数输出就是固定不变的,所以这行代码的输出始终相同。
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 函数的输出为 X_train、X_test、y_train 和 y_test,它们都是 NumPy 数组。
X_train 包含 75% 的行数据,X_test 包含剩下的 25%
1.7.3 观察数据
在构建机器学习模型之前,通常最好检查一下数据,看看如果不用机器学习能不能轻松完
成任务,或者需要的信息有没有包含在数据中。比如数据中是否包含异常值和特殊值。
观察数据可以绘制散点图,对于多于 3 个维度的数据集,可以绘制散点矩阵图
代码实现
注意:需要先执行以下代码引入相关包,其中因为 python3 的版本原因,引入 mglearn 会有警告,scatter_matrix()方法在 pandas.plotting 下。
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=.8,cmap=mglearn.cm3)
Iris 数据集的散点图矩阵,按类别标签着色
1.7.4 构建第一个模型:k 近邻算法
现在开始构建机器学习的模型,对于这个场景我们使用的是 k 近邻分类器。这是一个很容易理解的算法。构建此模型只需要保存训练 集即可。要对一个新的数据点做出预测,算法会在训练集中寻找与这个新数据点距离最近 的数据点,然后将找到的数据点的标签赋值给这个新数据点。
scikit-learn 中所有的机器学习模型都在各自的类中实现,这些类被称为 Estimator 类。k 近邻分类算法是在 neighbors 模块的 KNeighborsClassifier 类中实现的。我们需 要将这个类实例化为一个对象,然后才能使用这个模型。这时我们需要设置模型的参数。 KNeighborsClassifier 最重要的参数就是邻居的数目,这里我们设为 1:
代码实现
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)
想要基于训练集来构建模型,需要调用 knn 对象的 fit 方法,输入参数为 X_train 和 y_ train,二者都是 NumPy 数组,前者包含训练数据,后者包含相应的训练标签
knn.fit(X_train, y_train)
输出如下:
KNeighborsClassifier(algorithm='auto', leaf_size=30, metric='minkowski',
metric_params=None, n_jobs=1, n_neighbors=1, p=2,
weights='uniform')
1.7.5 做出预测
现在我们可以用这个模型对新数据进行预测了,我们可能并不知道这些新数据的正确标签,先模拟一份数据看看
In[27]:
X_new = np.array([[5, 2.9, 1, 0.2]])
print("X_new.shape: {}".format(X_new.shape))
Out[27]:
X_new.shape: (1, 4)
我们将这朵花的测量数据转换为二维 NumPy 数组的一行,这是因为 scikit-learn
的输入数据必须是二维数组。
预测
现在调用 knn 对象的 predict 方法来进行预测:
prediction = knn.predict(X_new)
print("Prediction: {}".format(prediction))
print("Predicted target name: {}".format(
iris_dataset['target_names'][prediction]))
输出如下:
Prediction: [0]
Predicted target name: ['setosa']
1.7.6 评估模型
这里需要用到之前创建的测试集。这些数据没有用于构建模型,但我们知道测试集中每朵
鸢尾花的实际品种。
因此,我们可以对测试数据中的每朵鸢尾花进行预测,并将预测结果与标签(已知的品 种)进行对比。我们可以通过计算精度(accuracy)来衡量模型的优劣,精度就是品种预 测正确的花所占的比例:
notebook上操作如下
In[29]:
y_pred = knn.predict(X_test)
print("Test set predictions:\n {}".format(y_pred))
Out[29]:
Test set predictions:
[2 1 0 2 0 2 0 1 1 1 2 1 1 1 1 0 1 1 0 0 2 1 0 0 2 0 0 1 1 0 2 1 0 2 2 1 0 2]
In[30]:
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))
Out[30]:
Test set score: 0.97
我们还可以使用 knn 对象的 score 方法来计算测试集的精度:
In[31]:
print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))
Out[31]:
Test set score: 0.97
结果
对于这个模型来说,测试集的精度约为 0.97,也就是说,对于测试集中的鸢尾花,我们的 预测有 97% 是正确的。根据一些数学假设,对于新的鸢尾花,可以认为我们的模型预测 结果有 97% 都是正确的。对于我们的植物学爱好者应用程序来说,高精度意味着模型足 够可信,可以使用。
未完待续