Python机器学习学习笔记之——引言

引言

mglearn 库的下载地址:
链接:https://pan.baidu.com/s/1FkRGBFgtjqsZTikLEJbtzg
提取码:4db0

机器学习是从数据中提取知识。它是统计学、人工智能和计算机科学交叉的研究领域,也被称为预测分析或统计学习。

1、为何选择机器学习

在 “智能” 应用早期,许多系统使用人为制定的 “if” 和 “else” 决策规则来处理数据,或根据用户输入的内容进行调整。但人为制定决策规则主要有两个缺点:

  • 做决策所需要的逻辑只适用于单一领域和单项任务;
  • 想要制定规则,需要对人类专家的决策过程有很深刻的理解。

这种人为制定规则的方法并不适用的一个例子就是图像中的人脸检测。其主要问题在于,计算机 “感知” 像素(像素组成了计算机中的图像)的方式与人类感知面部的方式有非常大的不同。正是由于这种表征差异,人类想要制定出一套好的规则来描述数字图像中的人脸构成,基本上不可能。

但是有了机器学习算法,仅向程序输入海量人脸图像,就足以让算法确定识别人脸需要哪些特征。

1.1、机器学习能够解决的问题

最成功的机器学习算法是能够将决策过程自动化的那些算法,这些决策过程是从已知示例中泛化得出的。在这种叫做监督学习(supervised learning)的方法中,用户将成对的输入和预期输出提供给算法,算法会找到一种方法,根据给定输入给出预期输出尤其是在没有人类帮助的情况下,给定前所未见的输入,算法也能够给出相应的输出

输入 / 输出对中进行学习的机器学习算法叫做监督学习算法(supervised learning algorithm),因为每个用于算法学习的样例都对应一个预期输出,好像有一个 “老师” 在监督着算法。虽然创建一个包含输入和输出的数据集往往费时费力,但监督学习算法很好理解,其性能也易于测量

另一种算法是无监督机器学习(unsupervised learning algorithm)。在无监督学习中,只有输入数据是已知的,没有为算法提供输出数据。虽然这种算法有许多成功的应用,但理解和评估这些算法往往更加困难

无论是监督学习任务还是无监督学习任务,将输入数据表征为计算机可以理解的形式都是十分重要的。通常来说,将数据表征成表格是很有用的。你想要处理的每一个数据点(每一封电子邮件、每一名客户、每一次交易)对应表格中的一行,描述该数据点的每一项属性(比如客户年龄、交易金额或交易地点)对应表格中的一列

在机器学习中,这里的每个实体或每一行被称为有一个样本(sample)或数据点,而每一列(用来描述这些实体的属性)则被称为特征(feature)。

后面还会更详细地介绍如何构建良好的数据表征,这被称为特征提取(feature extraction)或特征工程(feature engineering)。

1.2、熟悉任务和数据

在机器学习过程中,最重要的部分很可能是理解你正在处理的数据,以及这些数据与你想要解决的任务之间的关系。随机选择一个算法并将你的数据输入进去,这种做法是不会有什么用的,在构建机器学习解决方案的过程中,你应该给出以下问题:

  • 我想要回答的问题是什么?已经收集到的数据能够回答这个问题吗?
  • 要将我的问题表示成机器学习问题,用哪种方法最好?
  • 我收集的数据是否足够表达我想要解决的问题?
  • 我提取了数据的哪些特征?这些特征能否实现正确的预测?
  • 如何衡量应用是否成功?
  • 机器学习解决方案与我的研究或商业产品中的其他部分是如何相互影响的?

2、Scikit-Learn

scikit-learn 是一个开源项目,可以免费使用和开发。它包含许多目前最先进的机器学习算法,每个算法都有详细的文档:

scikit-learn中文文档
scikit-learn官方文档


3、必要的库和工具

  • NumPy

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

  • SciPy

    SciPy 是 Python 中用于科学计算的函数集合。它具有线性代数高级程序、数学函数优化、信号处理、特殊数学函数和统计分布等多项功能。SciPy 中最重要的是 scipy.sparse:它可以给出稀疏矩阵(sparse matrice),稀疏矩阵是 scikit-learn 中数据的另一种表示方法。如果想要保存一个大部分元素都是 0 的二维数组,就可以用稀疏矩阵。

  • matplotlib

    科学绘图库。

  • pandas

    用于处理和分析数据的 Python 库。

一个特有的库:

  • mglearn

    编写的特有库,通常用来快速美化绘图。


4、所用到的版本

import sys
print("Python version : {}".format(sys.version))
# Python version : 3.7.0 (default, Jun 28 2018, 08:04:48) [MSC v.1912 64 bit (AMD64)]

import pandas as pd
print("Pandas version : {}".format(pd.__version__))
# Pandas version : 0.23.4

import matplotlib
print("matplotlib version : {}".format(matplotlib.__version__))
# matplotlib version : 2.2.3

import numpy as np
print("NumPy version : {}".format(np.__version__))
# NumPy version : 1.15.1

import scipy as sp
print("SciPy version : {}".format(sp.__version__))
# SciPy version : 1.1.0

import sklearn
print("scikit-learn version : {}".format(sklearn.__version__))
# scikit-learn version : 0.19.2

5、第一个应用:鸢尾花分类

假如一名植物学爱好者对她发现的鸢尾花的品种很感兴趣。她收集了每朵鸢尾花的一些测量数据花瓣的长度和宽度以及花萼的长度与宽度,所有测量结果的单位都是厘米。

她还有一些鸢尾花的测量数据,这些花之前已经被植物学家鉴定为属于 setosa、versicolor 或 virginica 三个品种之一。对于这些测量数据,她可以确定每朵鸢尾花所属的品种。我们假定这位植物学爱好者在野外只会碰到这三种鸢尾花。

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

因为我们有已知品种的鸢尾花的测量数据,所以这是一个监督学习问题。在这个问题中,我们要在多个选项中预测其中一个(鸢尾花的品种)。这是一个分类classification)问题的示例。可能的输出(鸢尾花的不同品种)叫做类别class)。数据集中的每朵鸢尾花都属于三个类别之一,所以这是一个三分类问题。单个数据点(一朵鸢尾花)的预期输出是这朵花的品种。对于一个数据点来说,它的品种叫做标签label)。

5.1、初识数据

本例中我们用到了鸢尾花(iris)数据集,这是机器学习和统计学中一个经典的数据集。它包含在 scikit-learn 的 datasets 模块中。我们可以调用 load_iris 函数来加载数据:

from sklearn.datasets import load_iris
iris_datasets = load_iris()

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

print("Keys of iris_datasets: \n {}".format(iris_datasets.keys))
'''
Keys of iris_datasets: 
 
'''

DESCR 键对应的值是数据集的简要说明。我们这里给出说明的开头部分:

print(iris_datasets['DESCR'][:193] + "\n...")
'''
Iris Plants Database
====================

Notes
-----
Data Set Characteristics:
    :Number of Instances: 150 (50 in each of three classes)
    :Number of Attributes: 4 numeric, predictive att
...
'''

target_names 键对应的是一个字符串数组,里边包含了我们要预测的花的品种。

print("Target names: {}".format(iris_datasets['target_names']))
# Target names: ['setosa' 'versicolor' 'virginica']

feature_name 键对应的值是一个字符串列表,对每一个特征进行了说明:

print("Feature names: \n {}".format(iris_datasets['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_datasets['data'])))
# Type of data: 

data 数组的每一行对应一朵花,列代表每朵花的四个测量数据:

print("Shape of data: {}".format(iris_datasets['data'].shape))
# Shape of data: (150, 4)

可以看出,数组中包含 150 朵不同的花的测量数据。下面给出前 5 个样本的特征数值:

print("First five rows of data: \n {}".format(iris_datasets['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 数组包含的是测量过的每朵花的品种,也是一个 NumPy 数组:

print("Type of target: {}".format(type(iris_datasets['target'])))
# Type of target: 

target 是一维数组,每朵花对应其中一个数据:

print("Shape of target: {}".format(iris_datasets['target'].shape))
# Shape of target: (150,)

品种被转换成从 0 到 2 的整数:

print("Target: \n {}".format(iris_datasets['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 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]
'''

0 代表 setosa、1 代表 versicolor、2 代表 virginica。

5.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 表示,而标签用小写的 y 表示。这是受到了数学标准公式 f(x)=y 的启发,其中 x 是函数的输入,y 是输出。我们用大写的 X 是因为数据是一个二维数据(矩阵),用小写的 y 是因为目标是一个一维数组(向量),这也是数学中的约定。

对数据调用 train_test_split,并对输出结果采用下面的命令方法:

from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(
    iris_datasets['data'], iris_datasets['target'], random_state=0)

在对数据进行拆分之前,train_test_split 函数利用伪随机数生成器将数据集打乱,因为数据点是按照标签排序的,如果不打乱,那么测试集中包含的类别可能就只有一种。为了确保多次运行同一个函数能够得到相同的输出,我们利用 random_state 参数指定了随机数生成器的种子

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

print("X_train shape: {}".format(X_train.shape))
# X_train shape: (112, 4)
print("X_test shape: {}".format(X_test.shape))
# X_test shape: (38, 4)

5.3、要事第一:观察数据

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

检查数据的最佳方法之一就是将其可视化。一种可视化方法是绘制散点图(scatter plot)数据散点图将一个特征作为 x 轴,另一个特征作为 y 轴,将每一个数据点绘制为图上的一个点。不幸的是,计算机屏幕只有两个维度,所以我们一次只能绘制两个特征(也可能是 3 个)。用这种方法难以对多于 3 个特征的数据集作图。解决这个问题的一种方法是绘制散点图矩阵(pair plot),从而可以两两查看所有的特征。如果特征数不多的话,比如我们这里有 4 个,这种方法是很合理的。但是,散点图矩阵无法同时显示所有特征之间的关系,所以这种可视化可能无法展示数据的某些有趣内容

下图就是训练集中特征的散点矩阵图。数据点的颜色与鸢尾花的品种相对应。矩阵的对角线是每个特征的直方图

import seaborn as sns
import matplotlib.pyplot as plt
sns.set()

iris = sns.load_dataset('iris')
sns.pairplot(iris,hue='species',size=1.5)

plt.show()

Python机器学习学习笔记之——引言_第1张图片

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


6、构建第一个模型: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 数组,前者包含训练数据,后者包含相应的训练标签:

print(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 对象本身并做原处修改,因此我们得到了分类器的字符串表示。从中可以看出构建模型时用到的参数。几乎所有参数都是默认值,但你也会注意到 n_neighbor=1,这是我们传入的参数。scikit-learn 中大多数模型都有很多参数。


7、做出预测

现在我们可以用这个模型对新数据进行预测了,我们可能并不知道这些新数据的正确标签。想象一下,我们在野外发现了一朵鸢尾花,花萼长 5cm 宽 2.9cm,花瓣长 1cm 宽 0.2cm。这朵鸢尾花属于哪个品种?我们可以将这些数据放在一个 NumPy 数组中,再次计算形状,数组形状为样本数(1)乘以特征数(4):

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))	# Prediction: [0]
print("Predicted target name: {}".format(iris_datasets['target_names'][prediction]))
# Predicted target name: ['setosa']

根据我们模型的预测,这朵新的鸢尾花属于类别 0,也就是说它属于 setosa 品种。但我们怎么知道能否相信这个模型呢?我们并不知道这个样本的实际品种,这也是我们构建模型的重点啊!


8、评估模型

这里需要用到之前创建的测试集。这些数据没有用于构建模型,但我们知道测试集中每朵鸢尾花的实际品种。

因此,我们可以对测试数据中的每朵鸢尾花进行预测,并将预测结果与标签(已知的品种)进行对比。我们可以通过计算**精度(accuracy)**来衡量模型的优劣,精度就是品种预测正确的花所占的比例

y_pred = knn.predict(X_test)
print("Test set predictions: \n {}".format(y_pred))
'''
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]
'''
print("Test set score: {:.2f}".format(np.mean(y_pred == y_test)))
# 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% 都是正确的。


9、小结与展望

总结一下前面的内容:

  • 我们首先介绍了机器学习及其应用,然后讨论了监督学习和无监督学习之间的区别,并介绍了将会用到的一些工具;

  • 随后,我们构思了一项任务,要利用鸢尾花的物理测量数据来预测其品种。我们在构建模型时用到了由专家标注过的测量数据集,专家已经给出了花的正确品种,因此这是一个监督学习问题。这是一个三分类问题,可能的品种被称为类别(class)每朵花的品种被称为它的标签(label)

    鸢尾花(iris)数据集包含两个 NumPy 数组:一个包含数据,在 scikit-learn 中被称为 X;一个包含正确的输出或预期输出,被称为 y。数组 X 是特征的二维数组,每个数据点对应一行,每个特征对应一列。数组 y 是一维数组,里面包含一个类别标签,对每个样本都是一个 0 到 2 之间的整数。

    我们将数据集分成训练集和测试集,前者用于构建模型,后者用于评估模型对前所未见的新数据的泛化能力

  • 我们选择了 k 近邻分类算法,根据新数据点在训练集中距离最近的邻居来进行预测。该算法在 KNeighborsClassifier 类中实现,里边既包含构建模型的算法,也包含利用模型进行预测的算法。我们将类实例化,并设定参数。然后调用 fit 方法来构建模型,传入训练数据(X_train)和训练输出(y_train)作为参数。我们调用 score 方法来评估模型,该方法计算的是模型精度。

下面汇总了整个训练和评估过程所必需的代码:

# 划分数据集,分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(
    iris_datasets['data'], iris_datasets['target'], random_state=0)

# 实例化 k 近邻算法类
knn = KNeighborsClassifier(n_neighbors=1)

# 利用训练集来构建模型
knn.fit(X_train, y_train)

# 利用测试集来预测
y_pred = knn.predict(X_test)

# 计算精度
print("Test set score: {:.2f}".format(knn.score(X_test, y_test)))

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

你可能感兴趣的:(tensorflow深度学习,机器学习)