1.必要的背景知识
Python基础知识
安装scikit-learn包(scikit-learn:Python机器学习库)
了解机器学习的基础知识:比如分类、回归、聚类常用的算法的名字及其适用情况。
- 机器学习的大致流程:数据获取——数据预处理——选择学习算法——训练模型——模型优化——可视化
2.scikit-learn模块
- scikit-learn大致分为6个部分(算法/模型)
2.1.数据预处理:Preprocessing
- 特征提取与归一化
- 应用场景:把输入数据(如文本)转换为机器学习算法可用的数据
- 模块:preprocessing(预处理), feature extraction(特征提取).
- Examples
2.2.分类:clasification
- 识别某个对象属于哪个类别
- 常见应用场景:垃圾邮件检测、图像识别
- 常用算法:SVM(支持向量机), nearest neighbors(近邻), random forest(随机森林), ...
- Examples
2.3.回归:regression
- 预测一个与对象相关的值连续的属性
- 常见的应用场景:药品反应、股票价格
- 常见算法:线性回归、SVR(支持向量回归), ridge regression(岭回归), Lasso回归, ...
- Examples
2.4.聚类:clustering
- 相似对象的自动分组
- 常见的应用场景:客户细分、分组实验结果
- k-Means, spectral clustering(谱聚类), mean-shift(中值移动), ...
2.5.模型评估和优化:model selection
- 比较,验证,选择参数和模型
- 目的:通过参数调试提高模型精度
- grid search(网格搜索), cross validation(交叉验证), metrics(度量).
- Examples
2.6.降维:Dimensionality reduction
- 减少要考虑的随机变量的数量
- 常见应用场景:可视化、提高效率
- 常见算法:PCA(主成分分析), feature selection(特征选取), non-negative matrix factorization(非负矩阵分解).
- Examples
- 官网首页见下图
3.如何选择合适的算法(或模型)?
- 官网图示
- 具体选择时,可点击图上算法或模块名到官网查看文档
4.快速上手-使用scikit-learn进行机器学习
-
- 通常,机器学习问题是根据n个样本的数据集,并尝试预测出未知数据的性质。
- 如果每一个样本多个单一的数据,例如,一个多维度条目(又名“多元数据multivariate data”),它将被描述为多个属性或特征。
4.1.两大类别
- 我们可以将机器学习问题分成几个大的类别:
- 监督学习(supervised learning),数据包含我们想要预测的额外属性(这些模型包括了点击查看)。这个问题可以是:
- 分类(classification):样本属于两个或以上分类,我们想要从已标记的数据中学习预测未标记的数据是什么分类。一个分类问题的例子:手写体数字识别,这个例子目的是分配每一个向量给一个有限数量的离散类别。另一方面认为分类是监督学习的一个非连续的离散形式,分类对每1组样本都是标记有限数量的类别和正确类目/类别。
- 回归(regression):如果期望输出的结果是由1或多组连续的变量组成,那么这个任务被称为“回归”。一个回归问题的例子是预测三文鱼的长度函数,根据三文鱼的年龄和重量。
- 非监督学习(unsupervised learning),它是训练的数据是一组向量x数据集,而没有任何对应的目标值。这个问题目标在于发现数据中可能的相似的样本组,这种训练方式被称为“聚类,clustering”。或用于确定输入空间内的数据分布,这种方式被称作“密度估计,density estimation”。或从一个高维度空间将数据映射到2维或3维空间,这种方式可用于“可视化,visualization”点击查看非监督学习算法。
- 监督学习(supervised learning),数据包含我们想要预测的额外属性(这些模型包括了点击查看)。这个问题可以是:
4.1.1.总结
- 监督学习:数据包含了我们所预期的属性(标签)。
- 分类:数据输出结果可被分为离散的形式(类别)。
- 回归:数据输出结果可被分为连续区间的形式。
- 非监督学习:数据没有任何目标值(标签)。
- 聚类:输出多组类别,每组类别相似。
- 密度估计:输出数据分布。
- 可视化:将多维度空间数据映射到2、3维空间,便于可视化展示。
机器学习是关于学习一批数据集的属性,并应用到新的数据上。这就是为什么常见的操作是在机器学习中去评估一个算法时,会将数据分成两部分。
一部分叫做“训练集”,用于学习这批数据的属性。
4.2.加载一个样本数据集
scikit-learn自带一些标准的数据集,例如可用于分类模块的“iris(鸢尾花)数据集”、“digits(数字)数据集”,可用于聚类模块的“boston house prices dataset(波士顿房屋价格)数据集”。
接下来,从我们的shell开启一个Python解释器,并加载“iris数据集”和“digits数据集”。
符号“$”表示shell命令行的提示,符号“>>>”表示Python解释器的提示:
$ python
>>> from sklearn import datasets
>>> iris = datasets.load_iris()
>>> digits = datasets.load_digits()
一个数据集是一个类字典对象,它包含了所有的数据及元数据。这个数据存储在“.data”成员里,由“n个样本*n个特征”的数组组成。在监督学习的问题中,一个或更多的响应变量,存储在“.target”成员里。不同数据集的更多细节,可以在相关章节找到。
比方,这个digits数据集的例子,“digits.data”是用于数字样本分类的特征:
>>> print(digits.data)
[[ 0. 0. 5. ..., 0. 0. 0.]
[ 0. 0. 0. ..., 10. 0. 0.]
[ 0. 0. 0. ..., 16. 9. 0.]
...,
[ 0. 0. 1. ..., 6. 0. 0.]
[ 0. 0. 2. ..., 12. 0. 0.]
[ 0. 0. 10. ..., 12. 1. 0.]]
和“digits.target”是digits数据集对每个数字图片的真实数据值,这是我们正在学习的:
>>> digits.target
array([0, 1, 2, ..., 8, 9, 8])
数据通常是一个2维的数组(n个样本,n个特征),虽然原始数据可能有不同的形状。在这个digits数据集中,每一个原始样本是一个可被使用的(8,8)形状的图片。
>>> digits.images[0]
array([[ 0., 0., 5., 13., 9., 1., 0., 0.],
[ 0., 0., 13., 15., 10., 15., 5., 0.],
[ 0., 3., 15., 2., 0., 11., 8., 0.],
[ 0., 4., 12., 0., 0., 8., 8., 0.],
[ 0., 5., 8., 0., 0., 9., 8., 0.],
[ 0., 4., 11., 0., 1., 12., 7., 0.],
[ 0., 2., 14., 5., 10., 12., 0., 0.],
[ 0., 0., 6., 13., 10., 0., 0., 0.]])
这个简单的数据集例子说明了怎么一步一步将原来的问题塑造成可使用scikit-learn解决的数据问题。
4.3.学习与预测
在这个digits数据集的问题中,任务是预测一张图片展现出来的数字是哪个。
我们有10种可能的样本(数字0到9),以一个评估器去预测出未知的样本是属于哪种类型。
- 在scikit-learn中,用于分类的评估器estimator是一个Python对象,它执行
fit(X,y)
和predict(T)
方法。 - 一个评估器的例子,
sklearn.svm.SVC
这个类,实现了支持向量分类support vector classification。这个评估器的构造函数需要模型的参数。但是因为时间的问题,我们会将这个评估器当作一个黑盒:
>>> from sklearn import svm
>>> clf = svm.SVC(gamma=0.001, C=100.)
这个例子里,我们手工地设置
gamma
的值。这让我们使用像是grid search(网格搜索)
或cross validation(交叉验证)
这样的工具,去自动化地找到合适的参数值,成为一个可能。
我们把评估器的实例命名为clf
,作为一个分类器。现在它必须“拟合”于模型,也就说,它必须学习这个模型。通过我们训练集
去“拟合”方法,可以做到。
作为训练集
,我们使用数据集除了最后一个部分的所有图像。在python语法中使用[:-1]
表示我们选择了这部分的训练集,这会产生一个新的数组,包括除了最后一个实体以外的所有的digits.data
数据:
>>> clf.fit(digits.data[:-1], digits.target[:-1])
SVC(C=100.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma=0.001, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
现在你可以预测新的值,特别是我们可以知道digits
数据集的最后一张图片是什么数字,之前我们没有使用这组数据去训练分类器:
>>> clf.predict(digits.data[-1:])
array([8])
对应的图片如下:
正如你所见,这是一个有挑战性的任务:这张图片的分辨率很低。你同意分类器给出的答案吗?
这个分类问题的完整例子是识别手写数字,你可以运行和学习它。
4.4.模型持久化
这可以使用Python内建的持久化模块“pickle”,来保存scikit的模型。
>>> from sklearn import svm
>>> from sklearn import datasets
>>> clf = svm.SVC()
>>> iris = datasets.load_iris()
>>> X, y = iris.data, iris.target
>>> clf.fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> import pickle
>>> s = pickle.dumps(clf)
>>> clf2 = pickle.loads(s)
>>> clf2.predict(X[0:1])
array([0])
>>> y[0]
0
针对这个scikit问题。使用joblib
(joblib.dump
& joblib.load
)来代替pickle
会更有趣,它处理大数据更高效,但它只能把数据存储到硬盘里,而不是一个字符串:
>>> from sklearn.externals import joblib
>>> joblib.dump(clf, 'filename.pkl')
以后你就可以加载这个转存的模型(可以在另外的python进程中使用它):
>>> clf = joblib.load('filename.pkl')
注意:joblib.dump 返回的文件名列表。每一个numpy数组元素都包含在
clf
对象中,并且在文件系统中是以单个的序列化文件的形式存在。当使用joblib.load
再次加载这个模型时,全部文件需要在同一目录下。
注意pickle有一些安全性和可维护性的问题。请参考章节模型持久化了解更多关于scikit-learn模型持久化的细节信息。
4.5.约定
scikit-learn 评估器是根据一些明确的规则让行为更能被预测到。
4.5.1.类型转换
除非有特别的指定,默认的输入都将被转换成float64类型
:
>>> import numpy as np
>>> from sklearn import random_projection
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(10, 2000)
>>> X = np.array(X, dtype='float32')
>>> X.dtype
dtype('float32')
>>> transformer = random_projection.GaussianRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.dtype
dtype('float64')
在这个例子中,X
原本是float32
类型,被fit_transform(X)
转换为float64
类型。
回归的目标会被转换为“float64”格式,分类的目标会保持不变:
>>> from sklearn import datasets
>>> from sklearn.svm import SVC
>>> iris = datasets.load_iris()
>>> clf = SVC()
>>> clf.fit(iris.data, iris.target)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> list(clf.predict(iris.data[:3]))
[0, 0, 0] # 返回整数数组
>>> clf.fit(iris.data, iris.target_names[iris.target])
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa'] #返回字符串数组
这里,第一个“predict()”返回一个整数数组,因为“iris.target(一个整数数组)”被用于模型“拟合”。
第二个“predict()”返回一个字符串数组,因为“iris.target_names”被用户拟合。
4.5.2.重拟合和更新参数
一个评估器的超参数,在通过sklearn.pipeline.Pipeline.set_params方法被构造之后,可以被更新。调用“fit()”多次将重写之前“fit()”学习的内容:
>>> import numpy as np
>>> from sklearn.svm import SVC
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(100, 10)
>>> y = rng.binomial(1, 0.5, 100)
>>> X_test = rng.rand(5, 10)
>>> clf = SVC()
>>> clf.set_params(kernel='linear').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='linear',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([1, 0, 1, 1, 0])
>>> clf.set_params(kernel='rbf').fit(X, y)
SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma='auto', kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False)
>>> clf.predict(X_test)
array([0, 0, 0, 1, 0])
这里,在评估器通过“SVC()”被构造后,默认的“rbf”核第一次被更改为“linear”。后来又被改回“rbf”去做评估器的重拟合,得出第二次预测。
4.6.识别手写数字的完整例子
- 这个例子展示了怎么使用scikit-learn去识别手写数字的图片。
- 这个例子在用户手册教程的章节,进行了注释。
Classification report for classifier SVC(C=1.0, cache_size=200, class_weight=None, coef0=0.0,
decision_function_shape=None, degree=3, gamma=0.001, kernel='rbf',
max_iter=-1, probability=False, random_state=None, shrinking=True,
tol=0.001, verbose=False):
precision recall f1-score support
0 1.00 0.99 0.99 88
1 0.99 0.97 0.98 91
2 0.99 0.99 0.99 86
3 0.98 0.87 0.92 91
4 0.99 0.96 0.97 92
5 0.95 0.97 0.96 91
6 0.99 0.99 0.99 91
7 0.96 0.99 0.97 89
8 0.94 1.00 0.97 88
9 0.93 0.98 0.95 92
avg / total 0.97 0.97 0.97 899
Confusion matrix:
[[87 0 0 0 1 0 0 0 0 0]
[ 0 88 1 0 0 0 0 0 1 1]
[ 0 0 85 1 0 0 0 0 0 0]
[ 0 0 0 79 0 3 0 4 5 0]
[ 0 0 0 0 88 0 0 0 0 4]
[ 0 0 0 0 0 88 1 0 0 2]
[ 0 1 0 0 0 0 90 0 0 0]
[ 0 0 0 0 0 1 0 88 0 0]
[ 0 0 0 0 0 0 0 0 88 0]
[ 0 0 0 1 0 1 0 0 0 90]]
print(__doc__)
# Author: Gael Varoquaux <gael dot varoquaux at normalesup dot org>
# License: BSD 3 clause
# Standard scientific Python imports
import matplotlib.pyplot as plt
# Import datasets, classifiers and performance metrics
from sklearn import datasets, svm, metrics
# The digits dataset
digits = datasets.load_digits()
# The data that we are interested in is made of 8x8 images of digits, let's
# have a look at the first 3 images, stored in the `images` attribute of the
# dataset. If we were working from image files, we could load them using
# pylab.imread. Note that each image must have the same size. For these
# images, we know which digit they represent: it is given in the 'target' of
# the dataset.
images_and_labels = list(zip(digits.images, digits.target))
for index, (image, label) in enumerate(images_and_labels[:4]):
plt.subplot(2, 4, index + 1)
plt.axis('off')
plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')
plt.title('Training: %i' % label)
# To apply a classifier on this data, we need to flatten the image, to
# turn the data in a (samples, feature) matrix:
n_samples = len(digits.images)
data = digits.images.reshape((n_samples, -1))
# Create a classifier: a support vector classifier
classifier = svm.SVC(gamma=0.001)
# We learn the digits on the first half of the digits
classifier.fit(data[:n_samples / 2], digits.target[:n_samples / 2])
# Now predict the value of the digit on the second half:
expected = digits.target[n_samples / 2:]
predicted = classifier.predict(data[n_samples / 2:])
print("Classification report for classifier %s:\n%s\n"
% (classifier, metrics.classification_report(expected, predicted)))
print("Confusion matrix:\n%s" % metrics.confusion_matrix(expected, predicted))
images_and_predictions = list(zip(digits.images[n_samples / 2:], predicted))
for index, (image, prediction) in enumerate(images_and_predictions[:4]):
plt.subplot(2, 4, index + 5)
plt.axis('off')
plt.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest')
plt.title('Prediction: %i' % prediction)
plt.show()
这个例子的总共运行时间:0.70秒(0分0.70秒)
Q:
运行Matplotlib的图像显示的问题。如果在虚拟环境中,默认后端是以非交互的方式显示,所以没有办法显示。
出现这样的错误提醒:
RuntimeError: Python is not installed as a framework. The Mac OS X backend will not be able to function correctly if Python is not installed as a framework. See the Python documentation for more information on installing Python as a framework on Mac OS X. Please either reinstall Python as a framework, or try one of the other backends.
A:
代码中每次运行都指定后端:import matplotlib; matplotlib.use('TkAgg')
:what-is-a-backend
或在配置文件中标注使用的后端,echo "backend: TkAgg" >> ~/.matplotlib/matplotlibrc
The matplotlibrc file
选择哪个后端,根据已有的GUI图形库来决定,比如博主已经安装了TK库,可在python解释器中键入import Tkinter; Tkinter._test()
进行测试。
5.常用的算法/模型
5.1.朴素贝叶斯
5.1.1.朴素贝叶斯--高斯模型
5.1.2.朴素贝叶斯--多项式模型
5.1.3.朴素贝叶斯--伯努利模型
5.1.4.基于外存(Out-of-core)的朴素贝叶斯模型拟合