Skip to content

机器学习软件包

常用工具

IPython

IPython 是公认的现代科学计算中最重要的 Python 工具之一。它是一个加强版的 Python 交互式命令行工具,与系统自带的 Python 交互环境相比,IPython 具有以下明显的几个特点:

  • 与 Shell 紧密关联,可以在 IPython 环境下直接执行 Shell 指令;

  • 可以直接绘图操作的 Web GUI 环境,在机器学习领域、探索数据模式、可视化数据、绘制学习曲线时,这一功能特别有用;

  • 更强大的交互功能,包括内省、Tab 键自动完成、魔术命令等。

Numpy

Numpy 是 Python 科学计算的基础库,主要提供了高性能的 N 维数组实现以及计算能力,还提供了和其他语言如 C/C++ 集成的能力,此外还实现了一些基础的数学算法,如线性代数相关、傅里叶变换及随机数生成等。

需要熟练掌握以下两个知识点

  • Numpy 数组
  • Numpy 运算

Pandas

Pandas 是一个强大的[时间序列数据]处理工具包,最初开发的目的是为了分析财经数据,现在已经广泛应用在 Python 数据分析领域中。

  • 基本数据结构(Series,DataFrame)
  • 数据排序(索引、数据排序)
  • 数据访问(取值、切片)
  • 时间序列
  • 文件读写

Matplotlib

Matplotlib 是 Python 数据可视化工具包。IPython 为 Matplotlib 专门提供了特殊的交互模式。如果要在 IPython 控制台使用 Matplotlib,可以使用 ipython--matplotlib 命令来启动 IPython 控制台程序;如果要在 IPython notebook 里使用 Matplotlib,则在 notebook 的开始位置插入%matplotlib inline 魔术命令即可。IPython 的 Matplotlib 模式有两个优点,一是提供了非阻塞的画图操作,二是不需要显式地调用 show()方法来显示画出来的图片。

  • 图形样式
  • 图形对象
  • 画图操作

scikit-learn

scikit-learn 是一个开源的 Python 语言机器学习工具包,它涵盖了几乎所有主流机器学习算法的实现,并且提供了一致的调用接口。它基于 Numpy 和 scipy 等 Python 数值计算库,提供了高效的算法实现。总结起来,scikit-learn 工具包有以下几个优点。

  • 文档齐全:官方文档齐全,更新及时。

  • 接口易用:针对所有的算法提供了一致的接口调用规则,不管是 KNN、K-Mean 还是 PCA。

  • 算法全面:涵盖主流机器学习任务的算法,包括回归算法、分类算法、聚类分析、数据降维处理等。

当然,scikit-learn 不支持分布式计算,不适合用来处理超大型数据。但这并不影响 scikit-learn 作为一个优秀的机器学习工具库这个事实。许多知名的公司,包括 Evernote 和 Spotify 都使用 scikit-learn 来开发他们的机器学习应用。

Scikit-learn 工具介绍

scikit-learn 是一个开源的 Python 语言机器学习工具包,它涵盖了几乎所有主流机器学习算法的实现,并且提供了一致的调用接口。它基于 Numpy 和 scipy 等 Python 数值计算库,提供了高效的算法实现。总结起来,scikit-learn 工具包有以下几个优点。

  • 文档齐全:官方文档齐全,更新及时。

  • 接口易用:针对所有的算法提供了一致的接口调用规则,不管是 KNN、K-Mean 还是 PCA。

  • 算法全面:涵盖主流机器学习任务的算法,包括回归算法、分类算法、聚类分析、数据降维处理等。

当然,scikit-learn 不支持分布式计算,不适合用来处理超大型数据。但这并不影响 scikit-learn 作为一个优秀的机器学习工具库这个事实。许多知名的公司,包括 Evernote 和 Spotify 都使用 scikit-learn 来开发他们的机器学习应用。

安装

shell
pip3 install scikit-learn==0.19.1

安装好之后可以通过以下命令查看是否安装成功

python
import sklearn
  • 注:安装 scikit-learn 需要 Numpy, Scipy 等库

包含的内容

  • 分类、聚类、回归
  • 特征工程
  • 模型选择、调优

scikit-learn 示例

回顾前面介绍的机器学习应用开发的典型步骤,我们使用 scikit-learn 来完成一个手写数字识别的例子。这是一个有监督的学习,数据是标记过的手写数字的图片。即通过采集足够多的手写数字样本数据,选择合适的模型,并使用采集到的数据进行模型训练,最后验证手写识别程序的正确性。

1. 数据采集和标记

如果我们从头实现一个数字手写识别的程序,需要先采集数据,即让尽量多不同书写习惯的用户,写出从 0~9 的所有数字,然后把用户写出来的数据进行标记,即用户每写出一个数字,就标记他写出的是哪个数字。

为什么要采集尽量多不同书写习惯的用户写的数字呢?因为只有这样,采集到的数据才有代表性,才能保证最终训练出来的模型的准确性。极端的例子,我们采集的都是习惯写出瘦高形数字的人,那么针对习惯写出矮胖形数字的人写出来的数字,模型的识别成功率就会很低。

所幸我们不需要从头开始这项工作,scikit-learn 自带了一些数据集,其中一个是手写数字识别图片的数据,使用以下代码来加载数据。

python
from sklearn import datasets

digits = datasets.load_digits()

可以在把数据所表示的图片用 mathplotlib 显示出来:

python
# 把数据所代表的图片显示出来
print('digits.images', digits.images)
print('digits.target', digits.target)
images_and_labels = list(zip(digits.images, digits.target))
plt.figure(figsize=(8, 6))
for index, (image, label) in enumerate(images_and_labels[:8]):
    plt.subplot(2, 4, index + 1)
    plt.axis('off')
    plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')
    plt.title('Digit: %i' % label, fontsize=20)
plt.show()

2. 特征选择

针对一个手写的图片数据,应该怎么样来选择特征呢?一个直观的方法是,直接使用图片的每个像素点作为一个特征。比如一个图片是 200200 的分辨率,那么我们就有 40000 个特征,即特征向量的长度是 40000。

实际上,scikit-learn 使用 Numpy 的 array 对象来表示数据,所有的图片数据保存在 digits.images 里,每个元素都是一个 88 尺寸的灰阶图片。我们在进行机器学习时,需要把数据保存为 [样本个数 x][特征个数] 格式的 array 对象,针对手写数字识别这个案例,scikit-learn 已经为我们转换好了,它就保存在 digits.data 数据里,可以通过 digits.data.shape 来查看它的数据格式为:

python
print("shape of raw image data: {0}".format(digits.images.shape))
print("shape of data: {0}".format(digits.data.shape))

"""out
shape of raw image data: (1797, 8, 8)
shape of data: (1797, 64)
"""

可以看到,总共有 1797 个训练样本,其中原始的数据是 88 的图片,而用来训练的数据是把图片的 64 个象素点都转换为特征。下面将直接使用 digits.data 作为训练数据。

3. 数据清洗

人们不可能在 88 这么小的分辨率的图片上写出数字,在采集数据的时候,是让用户在一个大图片上写出这些数字,如果图片是 200200 分辨率,那么一个训练样例就有 40000 个特征,计算量将是巨大的。为了减少计算量,也为了模型的稳定性,我们需要把 200200 的图片缩小为 88 的图片。这个过程就是数据清洗,即把采集到的、不适合用来做机器学习训练的数据进行预处理,从而转换为适合机器学习的数据。

4. 模型选择

不同的机器学习算法模型针对特定的机器学习应用有不同的效率,模型的选择和验证留到后面章节详细介绍。此处,我们使用支持向量机来作为手写识别算法的模型。关于 [支持向量机],后面章节也会详细介绍。

5. 模型训练

在开始训练我们的模型之前,需要先把数据集分成 [训练数据集][测试数据集]。可以使用下面代码把数据集分出 20% 作为测试数据集。

python
# 把数据分成训练数据集和测试数据集
from sklearn.cross_validation import train_test_split

Xtrain, Xtest, Ytrain, Ytest = train_test_split(digits.data,
                                                digits.target, test_size=0.20, random_state=2)

接着,使用训练数据集 XtrainYtrain 来训练模型。

python
# 使用支持向量机来训练模型
from sklearn import svm

clf = svm.SVC(gamma=0.001, C=100., probability=True)
clf.fit(Xtrain, Ytrain)

训练完成后,clf 对象就会包含我们训练出来的模型参数,可以使用这个模型对象来进行预测。

6. 模型测试

我们来测试一下训练出来的模型的准确度。一个直观的方法是,我们用训练出来的模型 clf 预测测试数据集,然后把预测结果 Ypred 和真正的结果 Ytest 比较,看有多少个是正确的,这样就能评估出模型的准确度了。所幸,scikit-learn 提供了现成的方法来完成这项工作:

python
# 评估模型的准确度
from sklearn.metrics import accuracy_score

Ypred = clf.predict(Xtest)
accuracy_score(Ytest, Ypred)

clf.score(Xtest, Ytest)

"""out
0.97777777777777775
"""

显示出模型有 97.8% 的准确率。读者如果运行这段代码的话,在准确率上可能会稍有差异。

除此之外,还可以直接把测试数据集里的部分图片显示出来,并且在图片的左下角显示预测值,右下角显示真实值。

python
# 查看预测的情况
fig, axes = plt.subplots(4, 4, figsize=(8, 8))
fig.subplots_adjust(hspace=0.1, wspace=0.1)

for i, ax in enumerate(axes.flat):
    ax.imshow(Xtest[i].reshape(8, 8), cmap=plt.cm.gray_r, interpolation='nearest')
    ax.text(0.05, 0.05, str(Ypred[i]), fontsize=32,
            transform=ax.transAxes,
            color='green' if Ypred[i] == Ytest[i] else 'red')
    ax.text(0.8, 0.05, str(Ytest[i]), fontsize=32,
            transform=ax.transAxes,
            color='black')
    ax.set_xticks([])
    ax.set_yticks([])
plt.show()

7. 模型保存与加载

当我们对模型的准确度感到满意后,就可以把模型保存下来。这样下次需要预测时,可以直接加载模型来进行预测,而不是重新训练一遍模型。可以使用下面的代码来保存模型:

python
# 保存模型参数
import joblib

joblib.dump(clf, 'digits_svm.pkl')

当我们需要这个模型来进行预测时,直接加载模型即可进行预测。

python
# 导入模型参数,直接进行预测
clf = joblib.load('digits_svm.pkl')
Ypred = clf.predict(Xtest)
clf.score(Xtest, Ytest)

附录:scikit-learn 数据集介绍

数据集加载 API

scikit-learn 工具内置了一部分的数据,相关接口存放在 sklearn.datasets 下面。

  • 加载获取流行数据集

  • datasets.load_*()

    • 获取小规模数据集,数据包含在 datasets 里
  • datasets.fetch_*(data_home=None)

    • 获取大规模数据集,需要从网络上下载,函数的第一个参数是 data_home,表示数据集下载的目录,默认是 ~/scikit_learn_data/

加载并返回鸢尾花数据集

python
from sklearn.datasets import load_iris

# 加载数据(本地内置数据)
iris_data = load_iris()
from pprint import pprint

print(iris_data.keys())
"""
data            : 数据集
target          : 数据类型
frame           :
target_names:数据类型的名字
DESCR:数据的描述
feature_names:特征名字
filename:数据存放的位置
"""
pprint(iris_data)

加载大数据集

  • sklearn.datasets.fetch_20newsgroups(data_home=None,subset='train')
    • subset:'train' 或者 'test','all',可选,选择要加载的数据集。
    • 训练集的“训练”,测试集的“测试”,两者的“全部”
python
from sklearn.datasets import fetch_20newsgroups

# 注意:需要稳定的国际网络环境,否则无法正常使用
fetch_data = fetch_20newsgroups()
print(fetch_data)

sklearn 数据集返回值介绍

load 和 fetch 返回的数据类型 datasets.base.Bunch(字典格式)

  • data:特征数据数组,是 [n_samples * n_features] 的二维 numpy.ndarray 数组
  • target:标签数组,是 n_samples 的一维 numpy.ndarray 数组
  • DESCR:数据描述
  • feature_names:特征名,新闻数据,手写数字、回归数据集没有
  • target_names:标签名
python
from sklearn.datasets import load_iris

# 获取鸢尾花数据集
iris = load_iris()
print("鸢尾花数据集的返回值:\n", iris)
# 返回值是一个继承自字典的 Bench
print("鸢尾花的特征值:\n", iris["data"])
print("鸢尾花的目标值:\n", iris.target)
print("鸢尾花特征的名字:\n", iris.feature_names)
print("鸢尾花目标值的名字:\n", iris.target_names)
print("鸢尾花的描述:\n", iris.DESCR)