机器学习软件包
常用工具
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 来开发他们的机器学习应用。
安装
pip3 install scikit-learn==0.19.1
安装好之后可以通过以下命令查看是否安装成功
import sklearn
- 注:安装 scikit-learn 需要 Numpy, Scipy 等库
包含的内容
- 分类、聚类、回归
- 特征工程
- 模型选择、调优
scikit-learn 示例
回顾前面介绍的机器学习应用开发的典型步骤,我们使用 scikit-learn 来完成一个手写数字识别的例子。这是一个有监督的学习,数据是标记过的手写数字的图片。即通过采集足够多的手写数字样本数据,选择合适的模型,并使用采集到的数据进行模型训练,最后验证手写识别程序的正确性。
1. 数据采集和标记
如果我们从头实现一个数字手写识别的程序,需要先采集数据,即让尽量多不同书写习惯的用户,写出从 0~9 的所有数字,然后把用户写出来的数据进行标记,即用户每写出一个数字,就标记他写出的是哪个数字。
为什么要采集尽量多不同书写习惯的用户写的数字呢?因为只有这样,采集到的数据才有代表性,才能保证最终训练出来的模型的准确性。极端的例子,我们采集的都是习惯写出瘦高形数字的人,那么针对习惯写出矮胖形数字的人写出来的数字,模型的识别成功率就会很低。
所幸我们不需要从头开始这项工作,scikit-learn 自带了一些数据集,其中一个是手写数字识别图片的数据,使用以下代码来加载数据。
from sklearn import datasets
digits = datasets.load_digits()
可以在把数据所表示的图片用 mathplotlib 显示出来:
# 把数据所代表的图片显示出来
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 来查看它的数据格式为:
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% 作为测试数据集。
# 把数据分成训练数据集和测试数据集
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)
接着,使用训练数据集 Xtrain
和 Ytrain
来训练模型。
# 使用支持向量机来训练模型
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 提供了现成的方法来完成这项工作:
# 评估模型的准确度
from sklearn.metrics import accuracy_score
Ypred = clf.predict(Xtest)
accuracy_score(Ytest, Ypred)
clf.score(Xtest, Ytest)
"""out
0.97777777777777775
"""
显示出模型有 97.8% 的准确率。读者如果运行这段代码的话,在准确率上可能会稍有差异。
除此之外,还可以直接把测试数据集里的部分图片显示出来,并且在图片的左下角显示预测值,右下角显示真实值。
# 查看预测的情况
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. 模型保存与加载
当我们对模型的准确度感到满意后,就可以把模型保存下来。这样下次需要预测时,可以直接加载模型来进行预测,而不是重新训练一遍模型。可以使用下面的代码来保存模型:
# 保存模型参数
import joblib
joblib.dump(clf, 'digits_svm.pkl')
当我们需要这个模型来进行预测时,直接加载模型即可进行预测。
# 导入模型参数,直接进行预测
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/
- 获取大规模数据集,需要从网络上下载,函数的第一个参数是 data_home,表示数据集下载的目录,默认是
加载并返回鸢尾花数据集
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',可选,选择要加载的数据集。- 训练集的“训练”,测试集的“测试”,两者的“全部”
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:标签名
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)