[机器学习基础][笔记] 一、鸢尾花分类

鸢尾花分类

作者:解琛
时间:2020 年 8 月 28 日

  • 鸢尾花分类
  • 一、环境搭建
    • 1.1 Jupyter Notebook
    • 1.2 numpy
    • 1.3 Scipy
    • 1.4 matplotlib
    • 1.5 pandas
    • 1.6 mglearn
  • 二、案例
    • 2.1 加载数据集
    • 2.2 构建训练数据和测试数据集
    • 2.3 观察数据
    • 2.4 K 近邻
    • 2.5 做预测
    • 2.6 评估模型

一、环境搭建

python 修改 pip 的源

1.1 Jupyter Notebook

sudo apt install jupyter-notebook

Jupyter Notebook 是可以在浏览器中运行代码的交互环境。这个工具在探索性数据分析方面非常有用,在数据科学家中广为使用。

pip3 install numpy scipy matplotlib ipython scikit-learn pandas mglearn

1.2 numpy

NumPy 是 Python 科学计算的基础包之一。它的功能包括多维数组、高级数学函数(比如线性代数运算和傅里叶变换),以及伪随机数生成器。

import numpy as np
x = np.array([[1, 2, 3], [4, 5, 6]])
print("x:\n{}".format(x))

x:
[[1 2 3]
 [4 5 6]]

NumPy 的核心功能是 ndarray 类,即多维( n 维)数组。数组的所有元素必须是同一类型。

经常用到 NumP,对于 NumPy ndarray 类的对象,我们将其简称为“NumPy 数组”或“数组”。

1.3 Scipy

SciPy 是 Python 中用于科学计算的函数集合。它具有线性代数高级程序、数学函数优化、信号处理、特殊数学函数和统计分布等多项功能。

from scipy import sparse
# 创建一个二维NumPy数组,对角线为1,其余都为0
eye = np.eye(4)
print("NumPy array:\n{}".format(eye))
# 将NumPy数组转换为CSR格式的SciPy稀疏矩阵
# 只保存非零元素
sparse_matrix = sparse.csr_matrix(eye)
print("\nSciPy sparse CSR matrix:\n{}".format(sparse_matrix))

NumPy array:
[[1. 0. 0. 0.]
 [0. 1. 0. 0.]
 [0. 0. 1. 0.]
 [0. 0. 0. 1.]]

SciPy sparse CSR matrix:
  (0, 0)	1.0
  (1, 1)	1.0
  (2, 2)	1.0
  (3, 3)	1.0

SciPy 中最重要的是 scipy.sparse:它可以给出稀疏矩阵(sparse matrice),稀疏矩阵是 scikit-learn 中数据的另一种表示方法。

如果想保存一个大部分元素都是 0 的二维数组,就可以使用稀疏矩阵。

通常来说,创建稀疏数据的稠密表示(dense representation)是不可能的(因为太浪费内存),所以我们需要直接创建其稀疏表示(sparse representation)。

data = np.ones(4)
row_indices = np.arange(4)
col_indices = np.arange(4)
eye_coo = sparse.coo_matrix((data, (row_indices, col_indices)))
print("COO representation:\n{}".format(eye_coo))

COO representation:
  (0, 0)	1.0
  (1, 1)	1.0
  (2, 2)	1.0
  (3, 3)	1.0

1.4 matplotlib

matplotlib 是 Python 主要的科学绘图库,其功能为生成可发布的可视图,如折线图、直方图、散点图等。将数据及各种分析可视化,可以让你产生深刻的理解,而我们将用 matplotlib 完成所有的可视化内容。

在 Jupyter Notebook 中,可以使用 %matplotlib notebook%matplotlib inline 命令,将图像直接显示在浏览器中。

%matplotlib inline
import matplotlib.pyplot as plt
# 在-10和10之间生成一个数列,共100个数
x = np.linspace(-10, 10, 100)
# 用正弦函数创建第二个数组
y = np.sin(x)
# plot函数绘制一个数组关于另一个数组的折线图
plt.plot(x, y, marker="x")

[<matplotlib.lines.Line2D at 0x7fd63d5e3e10>]

[机器学习基础][笔记] 一、鸢尾花分类_第1张图片

1.5 pandas

pandas 是用于处理和分析数据的 Python 库。它基于一种叫作 DataFrame 的数据结构,这种数据结构模仿了 R 语言中的 DataFrame 。

一个 pandas DataFrame 是一张表格,类似于 Excel 表格。

pandas 中包含大量用于修改表格和操作表格的方法,尤其是可以像 SQL 一样对表格进行查询和连接。

NumPy 要求数组中的所有元素类型必须完全相同,而 pandas 不是这样,每一列数据的类型可以互不相同(比如整型、日期、浮点数和字符串)。

pandas 的另一个强大之处在于,它可以从许多文件格式和数据库中提取数据,如SQL、Excel 文件和逗号分隔值(CSV)文件。

import pandas as pd
from IPython.display import display
# 创建关于人的简单数据集
data = {
     'Name': ["John", "Anna", "Peter", "Linda"],
'Location' : ["New York", "Paris", "Berlin", "London"],
'Age' : [24, 13, 53, 33]
}
data_pandas = pd.DataFrame(data)
# IPython.display可以在Jupyter Notebook中打印出“美观的”DataFrame
display(data_pandas)
# 选择年龄大于30的所有行
display(data_pandas[data_pandas.Age > 30])

   Age  Location   Name
0   24  New York   John
1   13     Paris   Anna
2   53    Berlin  Peter
3   33    London  Linda


    Name    Location Age
2	Peter	Berlin   53
3	Linda	London   33

1.6 mglearn

对 mglearn 的调用,通常是用来快速美化绘图,或者用于获取一些有趣的数据。

二、案例

我们将完成一个简单的机器学习应用,鸢尾花分类,并构建第一个模型。

假设有一名植物学爱好者对她发现的鸢尾花的品种很感兴趣。

她收集了每朵鸢尾花的一些测量数据:花瓣的长度和宽度以及花萼的长度和宽,所有测量结果的单位都是厘米。

[机器学习基础][笔记] 一、鸢尾花分类_第2张图片

她还有一些鸢尾花的测量数据,这些花之前已经被植物学专家鉴定为属于 setosa、versicolor 或 virginica 三个品种之一。

对于这些测量数据,她可以确定每朵鸢尾花所属的品种。

我们假设这位植物学爱好者在野外只会遇到这三种鸢尾花。

我们的目标是构建一个机器学习模型,可以从这些已知品种的鸢尾花测量数据中进行学习,从而能够预测新鸢尾花的品种。

所以这是一个监督学习问题。在这个问题中,我们要在多个选项中预测其中一个(鸢尾花的品种)。

这是一个 分类(classification) 问题的示例。

可能的输出(鸢尾花的不同品种)叫作 类别(class)

数据集中的每朵鸢尾花都属于三个类别之一,所以这是一个三分类问题。

单个数据点(一朵鸢尾花)的预期输出是这朵花的品种。

对于一个数据点来说,它的品种叫作 标签(label)

2.1 加载数据集

from sklearn.datasets import load_iris
iris_dataset = load_iris()
print("Keys of iris_dataset: \n{}".format(iris_dataset.keys()))

load_iris 返回的 iris 对象是一个 Bunch 对象,与字典非常相似,里面包含键和值。

Keys of iris_dataset:
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
  • DESCR 键对应的值是数据集的简要说明;
  • target_names 键对应的值是一个字符串数组,里面包含我们要预测的花的品种;
  • feature_names 键对应的值是一个字符串列表,对每一个特征进行了说明;
  • 数据包含在 target 和 data 字段中。 data 里面是花萼长度、花萼宽度、花瓣长度、花瓣宽度的测量数据,格式为 NumPy 数组;
  • data 数组的每一行对应一朵花,列代表每朵花的四个测量数据;
  • target 数组包含的是测量过的每朵花的品种,也是一个 NumPy 数组;
  • iris[‘target_names’] 数组给出:0 代表 setosa,1 代表 versicolor,2 代表 virginica

2.2 构建训练数据和测试数据集

我们不能将用于构建模型的数据用于评估模型。因为我们的模型会一直记住整个训练集,所以对于训练集中的任何数据点总会预测正确的标签。

这种“记忆”无法告诉我们模型的 泛化(generalize) 能力如何(换句话说,在新数据上能否正确预测)。

将收集好的带标签数据(此例中是 150 朵花的测量数据)分成两部分。

一部分数据用于构建机器学习模型,叫作 训练数据(training data)训练集(training set)

其余的数据用来评估模型性能,叫作 测试数据(test data)测试集(test set)留出集(hold-out set)

scikit-learn 中的 train_test_split 函数可以打乱数据集并进行拆分。

这个函数将 75% 的行数据及对应标签作为训练集,剩下 25% 的数据及其标签作为测试集。

训练集与测试集的分配比例可以是随意的,但使用 25% 的数据作为测试集是很好的经验法则。

scikit-learn 中的数据通常用大写的 X X X 表示,而标签用小写的 y y y 表示。

这是受到了数学标准公式 f ( x ) = y f(x) = y f(x)=y 的启发,其中 x x x 是函数的输入, y y y 是输出。

我们用大写的 X X X 是因为数据是一个二维数组(矩阵),用小写的 y y y 是因为目标是一个一维数组(向量),这也是数学中的约定。

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 参数指定了随机数生成器的种子。这样函数输出就是固定不变的,所以这行代码的输出始终相同。

X_train 包含 75% 的行数据, X_test 包含剩下的 25%:

2.3 观察数据

在构建机器学习模型之前,通常最好检查一下数据,看看如果不用机器学习能不能轻松完成任务,或者需要的信息有没有包含在数据中。

检查数据也是发现异常值和特殊值的好方法,在现实世界中,经常会遇到不一致的数据和意料之外的测量数据。

检查数据的最佳方法之一就是将其可视化。

一种可视化方法是绘制 散点图(scatter plot),用这种方法难以对多于 3 个特征的数据集作图。

另一种方法是绘制 散点图矩阵(pair plot),从而可以两两查看所有的特征。

散点图矩阵无法同时显示所有特征之间的关系,所以这种可视化方法可能无法展示数据的某些有趣内容。

import pandas as pd
# 利用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)

[机器学习基础][笔记] 一、鸢尾花分类_第3张图片

从图中可以看出,利用花瓣和花萼的测量数据基本可以将三个类别区分开。这说明机器学习模型很可能可以学会区分它们。

2.4 K 近邻

可以开始构建真实的机器学习模型了。scikit-learn 中有许多可用的分类算法。

这里我们用的是 k 近邻分类器,这是一个很容易理解的算法。构建此模型只需要保存训练集即可。

要对一个新的数据点做出预测,算法会在训练集中寻找与这个新数据点距离最近的数据点,然后将找到的数据点的标签赋值给这个新数据点。

k 近邻算法中 k 的含义是,我们可以考虑训练集中与新数据点最近的任意 k 个邻居(比如说,距离最近的 3 个或 5 个邻居),而不是只考虑最近的那一个。

然后,我们可以用这些邻居中数量最多的类别做出预测。

scikit-learn 中所有的机器学习模型都在各自的类中实现,这些类被称为 Estimator 类。

k 近邻分类算法是在 neighbors 模块的 KNeighborsClassifier 类中实现的。

我们需要将这个类实例化为一个对象,然后才能使用这个模型。

这时我们需要设置模型的参数,KNeighborsClassifier 最重要的参数就是邻居的数目,这里我们设为 1。

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier(n_neighbors=1)

knn 对象对算法进行了封装,既包括用训练数据构建模型的算法,也包括对新数据点进行预测的算法。它还包括算法从训练数据中提取的信息。

对于 KNeighborsClassifier 来说,里面只保存了训练集。

想要基于训练集来构建模型,需要调用 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')

fit 方法返回的是 knn 对象本身并做原处修改,因此我们得到了分类器的字符串表示。从中可以看出构建模型时用到的参数。

2.5 做预测

我们可能并不知道这些新数据的正确标签。想象一下,我们在野外发现了一朵鸢尾花,花萼长 5cm 宽 2.9cm,花瓣长 1cm 宽 0.2cm。这朵鸢尾花属于哪个品种?

import numpy as np
X_new = np.array([[5, 2.9, 1, 0.2]])
print("X_new.shape: {}".format(X_new.shape))

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']

根据我们模型的预测,这朵新的鸢尾花属于类别 0,也就是说它属于 setosa 品种。

但我们怎么知道能否相信这个模型呢?

2.6 评估模型

这里需要用到之前创建的测试集,测试集用于评估模型对前所未见的新数据的 泛化能力。。这些数据没有用于构建模型,但我们知道测试集中每朵鸢尾花的实际品种。

我们可以对测试数据中的每朵鸢尾花进行预测,并将预测结果与标签(已知的品种)进行对比。

我们可以通过计算 精度(accuracy) 来衡量模型的优劣,精度就是品种预测正确的花所占的比例。

y_pred = knn.predict(X_test)
print("Test set predictions:\n {}".format(y_pred))
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))

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]
Test set score: 0.97

我们还可以使用 knn 对象的 score 方法来计算测试集的精度。

print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))

Test set score: 0.97

对于这个模型来说,测试集的精度约为 0.97,也就是说,对于测试集中的鸢尾花,我们的预测有 97% 是正确的。

根据一些数学假设,对于新的鸢尾花,可以认为我们的模型预测结果有 97% 都是正确的。

对于我们的植物学爱好者应用程序来说,高精度意味着模型足够可信,可以使用。

这个案例包含了应用 scikit-learn 中任何机器学习算法的核心代码。fit 、 predict 和 score 方法是 scikit-learn 监督学习 模型中最常用的接口。

你可能感兴趣的:(机器学习,算法,可视化,python,机器学习,supervised,learning)