数据挖掘入门与实战 公众号: datadw
Scikit-learn
是一个紧密结合Python科学计算库(Numpy、Scipy、matplotlib),集成经典机器学习算法的Python模块。
一、统计学习:scikit-learn中的设置与评估函数对象
(1)数据集
scikit-learn 从二维数组描述的数据中学习信息。他们可以被理解成多维观测数据的列表。如(n,m),n表示样例轴,y表示特征轴。
使用scikit-learn装载一个简单的样例:iris数据集
>>from sklearn import datasets
>>iris = datasets.load_iris()
>>data = iris.data
>>data.shape
(150, 4)
它有150个iris观测数据构成,每一个样例被四个特征所描述:他们的萼片、花瓣长度、花瓣宽度,具体的信息可以通过iris》DESCR查看。
当数据初始时不是(
n样例,n特征
)样式时,需要将其预处理以被scikit-learn使用。
通过数字数据集讲述数据变形
数字数据集由1797个8x8手写数字图片组成
>>>digits = datasets.load_digits()
>>>digits.images.shape
(1797, 8, 8)
>>> import pylab as pl
>>>pl.imshow(digits.images[-1], cmap=pl.cm.gray_r)
matplotlib.image.AxesImage object at ...>
在scikit-learn中使用这个数据集,我们需要将其每一个8x8图片转换成长64的特征向量
python
>>>data = digits.images.reshape((digits.images.shape[0],-1))
(2)估计函数对象
拟合数据
:scikit-learn实现的主要API是估计函数。估计函数是用以从数据中学习的对象。它可能是分类、回归、聚类算法,或者提取过滤数据特征的转换器。
一个估计函数带有一个
fit
方法,以dataset作为参数(一般是个二维数组)
>>>estimator.fit(data)
估计函数对象的参数
:每一个估测器对象在实例化或者修改其相应的属性,其参数都会被设置。
>>>estimator = Estimator(param1=1, param2=2)
>>>estimator.param11
估测后的参数
:
>>>estimator.estimated_param_
二、有监督学习:从高维观察数据预测输出变量
有监督学习解决的问题
有监督学习主要是学习将两个数据集联系起来:观察数据x和我们要尝试预测的外置变量y,y通常也被称作目标、标签。多数情况下,y是一个和n个观测样例对应的一维数组。
scikit-learn中实现的所有有监督学习评估对象,都有fit(X,Y)方法来拟合模型,predict(X)方法根据未加标签的观测数据X
返回预测的标签y。
词汇:分类和回归
如果预测任务是将观测数据分类到一个有限的类别集中,换句话说,给观测对象命名,那么这个任务被称作分类任务。另一方面,如果任务的目标是预测测目标是一个连续性变量,那么这个任务成为回归任务。
用scikit-learn解决分类问题时,y是一个整数或字符串组成的向量
注意:查看[]快速了解用scikit-learn解决机器学习问题过程中的基础词汇。
(1)近邻和高维灾难
iris分类
:
iris分类是根据花瓣、萼片长度、萼片宽度来识别三种不同类型的iris的分类任务:
>> import numpy as np
>> from sklearn import datasets
>> iris = datasets.load_iris()
>> iris_X = iris.data>> iris_y = iris.target
>> np.unique(iris_y)
array([0, 1, 2])
最近邻分类器
:
近邻也许是最简的分类器:得到一个新的观测数据X-test,从训练集的观测数据中寻找特征最相近的向量。(【】)
训练集和测试集
:
当尝试任何学习算法的时候,评估一个学习算法 的预测精度是很重要的。所以在做机器学习相关的问题的时候,通常将数据集分成训练集和测试集。
KNN(最近邻)分类示例
:
np.random.seed(0)
indices = np.random.permutation(len(iris_X))
iris_X_train = iris_X[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_X_test = iris_X[indices[-10:]]
iris_y_test = iris_y[indices[-10:]]
from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train)
knn.predict(iris_X_test)
iris_y_test
高维灾难
:
对于一个有效的学习算法,你需要最近n个点之间的距离d(依赖于具体的问题)。在一维空间中,需要平局n1/d各点,在上文中提到的K-NN例子中,如果数据只是有一个0-1之间的特征和n个训练观测数据所表述的画,那么新数据将不会超过1/n。因此,最近邻决策规则非常高效,因为与类间特征变化的范围相比,1/n小的多。
如果特征数是P,你就需要n 1/d^p个点。也就是说,如果我们在一维度情况下需要10个点,在P维度情况下需要10^p个点。当P变大的时候,为获得一个好的预测函数需要的点数将急剧增长。
这被称为高维灾难(指数级增长),也是机器学习领域的一个核心问题。
(2)线性模型:从回归到稀疏性
Diabets数据集(糖尿病数据集)
糖尿病数据集包含442个患者的10个生理特征(年龄,性别、体重、血压)和一年以后疾病级数指标。
diabetes = datasets.load_diabetes()
diabetes_X_train = diabetes.data[:-20]
diabetes_X_test = diabetes.data[-20:]
diabetes_y_train = diabetes.target[:-20]
diabetes_y_test = diabetes.target[-20:]
手上的任务是从生理特征预测疾病级数
线性回归:
【线性回归】的最简单形式给数据集拟合一个线性模型,主要是通过调整一系列的参以使得模型的残差平方和尽量小。
线性模型:y = βX+b X:数据
y:目标变量
β:回归系数 b:观测噪声(bias,偏差)
from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(diabetes_X_train, diabetes_y_train)print(regr.coef_)np.mean((regr.predict(diabetes_X_test)-diabetes_y_test)**2)regr.score(diabetes_X_test, diabetes_y_test)
收缩(Shrinkage)
:
如果每一维的数据点很少,噪声将会造成很大的偏差影响:
X = np.c_[ .5, 1].T
y = [.5, 1]
test = np.c_[ 0, 2].T
regr = linear_model.LinearRegression()import pylab as pl
pl.figure()
np.random.seed(0)for _ in range(6):
this_X = .1*np.random.normal(size=(2, 1)) + X
regr.fit(this_X, y)
pl.plot(test, regr.predict(test))
pl.scatter(this_X, y, s=3)
高维统计学习的一个解决方案是将回归系数缩小到0:观测数据中随机选择的两个数据集近似不相关。这被称为岭回归(Ridge Regression):
regr = linear_model.Ridge(alpha=.1)
pl.figure()
np.random.seed(0)for _ in range(6):
this_X = .1*np.random.normal(size=(2, 1)) + X
regr.fit(this_X, y)
pl.plot(test, regr.predict(test))
pl.scatter(this_X, y, s=3)
这是一个偏差/方差(bias/variance)的权衡:岭α参数越大,偏差(bias)越大,方差(variance)越小
我们可以选择α以最小化排除错误,这里使用糖尿病数据集而不是人为制造的数据:
alphas = np.logspace(-4, -1, 6)from __future__ import print_functionprint([regr.set_params(alpha=alpha
).fit(diabetes_X_train, diabetes_y_train,
).score(diabetes_X_test, diabetes_y_test) for alpha in alphas])
【注意】
扑捉拟合参数的噪声使得模型不能推广到新的数据被称为过拟合。岭回归造成的偏差被称为正则化(归整化,regularization)
稀疏性
:
只拟合特征1和特征2:
【注意】
整个糖尿病数据包含11维数据(
10个特征维,一个目标变量
),很难对这样的数据直观地表现出来,但是记住那是一个很空的空间也许是有用的。
我们可以看到,尽管特征2在整个模型中占据很大的系数,但是和特征1相比,对结果y造成的影响很小。
为了提升问题的状况(考虑到高维灾难),只选择信息含量较大的(对结果y造成的影响较大的)的特征,不选择信息含量较小的特征会很有趣,如把特征2的系数调到0.岭回归将会减少信息含量较小的系数的值,而不是把它们设置为0.另一种抑制措施——Lasso(最小绝对收缩和选择算子)可以使得一些参数为0.这些方法被称作稀疏方法。系数操作可以看作是奥卡姆的剃刀:模型越简单越好。
regr = linear_model.Lasso()
scores = [regr.set_params(alpha=alpha
).fit(diabetes_X_train, diabetes_y_train
).score(diabetes_X_test, diabetes_y_test)
for alpha in alphas]
best_alpha = alphas[scores.index(max(scores))]
regr.alpha = best_alpha
regr.fit(diabetes_X_train, diabetes_y_train)print(regr.coef_)
针对相同问题的不同算法:
不同的算法可以被用来解决相同的数学问题。例如scikit-learn中的Lasso对象使用coordinate
decent方法解决lasso回归问题,在大数据集上是很有效的。然而,scikit-learn也使用LARS算法提供了LassoLars对象,对于处理权重向量非常稀疏的数据非常有效(数据的观测实例非常少)。
logistic = linear_model.LogisticRegression(C=1e5)
logistic.fit(iris_X_train, iris_y_train)
这就是有名的
logistic回归
。
通过Logistic回归进行收缩和稀疏
:
在LogisticRegression对象中C参数控制着正则化的数量:C越大,正则化数目越少。penalty= "12" 提供收缩(非稀疏化系数),penalty="11"提供稀疏化。
练习
:
尝试使用近邻算法和线性模型对数字数据集进行分类。留出最后的10%作为测试集用来测试预测的精确度。
from sklearn import datasets, neighbors, linear_model
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target
【完整代码】
from sklearn import datasets, neighbors, linear_model
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target
n_samples = len(X_digits)
X_train = X_digits[:.9 * n_samples]
y_train = y_digits[:.9 * n_samples]
X_test = X_digits[.9 * n_samples:]
y_test = y_digits[.9 * n_samples:]
knn = neighbors.KNeighborsClassifier()
logistic = linear_model.LogisticRegression()print('KNN score: %f' % knn.fit(X_train, y_train).score(X_test, y_test))print('LogisticRegression score: %f'
% logistic.fit(X_train, y_train).score(X_test, y_test))
(3)支持向量机(SVMs)
线性SVNs
:
支持向量机属于判别模型家族:它们尝试寻找样例的一个组合,构建一个两类之间的最大边缘平面。通过C参数进行正则化:一个较小的C意味着边缘是通过分割线周围的所有观测样例进行计算得到的(更规整化,正则化);一个较大的C意味着边缘是通过邻近分割线的观测样例计算得到的(更少的规整化,正则化):
样例:Plot different SVM分类器 iris数据集
SVMs能够被用于回归——SVR(支持向量回归)—用于分类——SVC(支持向量分类)
from sklearn import svm
svc = svm.SVC(kernel='linear')
svc.fit(iris_X_train, iris_y_train)
【警告】:规格化数据
对于大多数的估测模型,包括SVMs,处理好单位标准偏差对于获得一个好的预测是很重要的。
使用核函数:
在特征空间中类别不经常是线性可分的。解决方案是构建一个非线性但能用多项式代替的决策函数。这要通过核技巧实现:使用核可以被看作通过设置核在观测样例上创建决策力量。
svc = svm.SVC(kernel='rbf')
交互式样例:
参照SVM GUI,下载svm_gui.py;通过鼠标左右键设置两类数据点,拟合模型并改变参数和数据。
练习:
尝试使用SVMs根据iris数据集前两个特征将其分成两类。留出每一类的10%作为测试样例。
【警告】
数据集中的数据是按照分类顺序排列的,不要留出最后的10%作为测试样例,要不然你只能测试一种类别。(获取训练集和测试集是注意要进行混淆)
提示:
你可以在一个网格上使用decision_function方法获得直观的呈现。
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0, :2]
y = y[y != 0]
完整代码:
"""================================SVM Exercise================================A tutorial exercise for using different SVM kernels.This exercise is used in the :ref:`using_kernels_tut` part of the:ref:`supervised_learning_tut` section of the :ref:`stat_learn_tut_index`."""print(__doc__)import numpy as npimport matplotlib.pyplot as pltfrom sklearn import datasets, svm
iris = datasets.load_iris()
X = iris.data
y = iris.target
X = X[y != 0, :2]
y = y[y != 0]
n_sample = len(X)
np.random.seed(0)
order = np.random.permutation(n_sample)
X = X[order]
y = y[order].astype(np.float)
X_train = X[:.9 * n_sample]
y_train = y[:.9 * n_sample]
X_test = X[.9 * n_sample:]
y_test = y[.9 * n_sample:]for fig_num, kernel in enumerate(('linear', 'rbf', 'poly')):
clf = svm.SVC(kernel=kernel, gamma=10)
clf.fit(X_train, y_train)
plt.figure(fig_num)
plt.clf()
plt.scatter(X[:, 0], X[:, 1], c=y, zorder=10, cmap=plt.cm.Paired)
plt.scatter(X_test[:, 0], X_test[:, 1], s=80, facecolors='none', zorder=10)
plt.axis('tight')
x_min = X[:, 0].min()
x_max = X[:, 0].max()
y_min = X[:, 1].min()
y_max = X[:, 1].max()
XX, YY = np.mgrid[x_min:x_max:200j, y_min:y_max:200j]
Z = clf.decision_function(np.c_[XX.ravel(), YY.ravel()])
Z = Z.reshape(XX.shape)
plt.pcolormesh(XX, YY, Z > 0, cmap=plt.cm.Paired)
plt.contour(XX, YY, Z, colors=['k', 'k', 'k'], linestyles=['--', '-', '--'],
levels=[-.5, 0, .5])
plt.title(kernel)
plt.show()
三、模型选择:选择模型和他们的参数
(1)分数,和交叉验证分数
众所周知,每一个模型会得出一个score方法用于裁决模型在新的数据上拟合的质量。其值越大越好。
from sklearn import datasets, svm
digits = datasets.load_digits()
X_digits = digits.data
y_digits = digits.target
svc = svm.SVC(C=1, kernel='linear')
svc.fit(X_digits[:-100], y_digits[:-100]).score(X_digits[-100:], y_digits[-100:])
为了获得一个更好的预测精确度度量,我们可以把我们使用的数据折叠交错地分成训练集和测试集:
import numpy as np
X_folds = np.array_split(X_digits, 3)
y_folds = np.array_split(y_digits, 3)
scores = list()for k in range(3):
X_train = list(X_folds)
X_test = X_train.pop(k)
X_train = np.concatenate(X_train)
y_train = list(y_folds)
y_test = y_train.pop(k)
y_train = np.concatenate(y_train)
scores.append(svc.fit(X_train, y_train).score(X_test, y_test))print