副标题#e#
数据挖掘入门与实战 ?公众号: 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(最近邻)分类示例:
# Split iris data in train and test data
# A random permutation,to split the data randomlynp.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:]]
# Create and fit a nearest-neighbor classifierfrom sklearn.neighbors import KNeighborsClassifier knn = KNeighborsClassifier() knn.fit(iris_X_train,iris_y_train) knn.predict(iris_X_test) iris_y_test
#p#分页标题#e#
高维灾难:
对于一个有效的学习算法,你需要最近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_)
# The mean square errornp.mean((regr.predict(diabetes_X_test)-diabetes_y_test)**2)# Explained variance score: 1 is perfect prediction# and 0 means that there is no linear relationship# between X and Y.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,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造成的影响很小。
#p#副标题#e#
练习:
使用digits数据集,绘制使用线性核的SVC进行交叉验证的分数(使用对数坐标轴,1——10)
import numpy as npfrom sklearn import cross_validation,datasets,svm digits = datasets.load_digits() X = digits.data y = digits.target svc = svm.SVC(kernel='linear') C_s = np.logspace(-10,10)
完整代码:
(3)网格搜索和交叉验证模型
网格搜索:
scikit-learn提供一个对象,他得到数据可以在采用一个参数的模型拟合过程中选择使得交叉验证分数最高的参数。该对象的构造函数需要一个模型作为参数:
from sklearn.grid_search import GridSearchCV Cs = np.logspace(-6,10) clf = GridSearchCV(estimator=svc,param_grid=dict(C=Cs),? ? ? ? ? ? ? ? ? n_jobs=-1) clf.fit(X_digits[:1000],y_digits[:1000]) ? ? ? ? clf.best_score_ ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? clf.best_estimator_.C ? ? ? ? ? ? ? ? ? ? ? ? ? ?# Prediction performance on test set is not as good as on train setclf.score(X_digits[1000:],y_digits[1000:]) ? ? ?
默认情况下,GridSearchCV
使用3-fold
交叉验证。然而,当他探测到是一个分类器而不是回归量,将会采用分层的3-fold
。
嵌套 交叉验证
cross_validation.cross_val_score(clf,y_digits)
两个交叉验证循环是并行执行的:一个GridSearchCV
模型设置gamma
,另一个使用cross_val_score
度量模型的预测表现。结果分数是在新数据预测分数的无偏差估测。
【警告】你不能在并行计算时嵌套对象(n_jobs
不同于1)
交叉验证估测:
在算法by算法的基础上使用交叉验证去设置参数更高效。这也是为什么对于一个特定的模型/估测器引入Cross-validation
:评估估测器表现模型去自动的通过交叉验证设置参数。
from sklearn import linear_model,datasets lasso = linear_model.LassoCV() diabetes = datasets.load_diabetes() X_diabetes = diabetes.data y_diabetes = diabetes.target lasso.fit(X_diabetes,y_diabetes)# The estimator chose automatically its lambda:lasso.alpha_
这些模型的称呼和他们的对应模型很相似,只是在他们模型名字的后面加上了'CV
'.
练习:
使用糖尿病数据集,寻找最佳的正则化参数α
-
#p#分页标题#e#
附加:你对选择的α值信任度有多高?
from sklearn import cross_validation,linear_model diabetes = datasets.load_diabetes() X = diabetes.data[:150] y = diabetes.target[:150] lasso = linear_model.Lasso() alphas = np.logspace(-4,-.5,30)
完整代码:
```python
```
四、无监督学习:寻找数据的代表
(1)聚类:将观测样例聚集到一起
聚类解决的问题:
比如对于iris数据集,如果我们知道我们知道有三种iris,但是我们没有标签标定他们:我们可以尝试聚类任务:将观测样例分成分离的族群中,这些族群可以被称为簇。
-
K-mean聚类(K均值聚类)
注意存在很多不同的聚类标准和关联算法。最简的聚类算法是——K均值(K-means)
from sklearn import cluster,datasets iris = datasets.load_iris() X_iris = iris.data y_iris = iris.target k_means = cluster.KMeans(n_clusters=3) k_means.fit(X_iris) print(k_means.labels_[::10])print(y_iris[::10])
注意:没有绝对的保证能够恢复真实的分类。首先,尽管scikit-learn使用很多技巧来缓和问题的难度,但选择簇的个数还是是很困难的,初始状态下算法是很敏感的,可能会陷入局部最小。
不好的初始状态:
8个簇:
真实情况:
不要“过解释”聚类结果
应用实例:矢量化
K-means和一般的聚类,可以看作是选择少量的示例压缩信息的方式。这个问题被称之为矢量化。例如,这可以被用于分离一个图像:
import scipy as sptry: ? lena = sp.lena()except AttributeError: ? from scipy import misc ? lena = misc.lena() X = lena.reshape((-1,1)) # We need an (n_sample,n_feature) arrayk_means = cluster.KMeans(n_clusters=5,n_init=1) k_means.fit(X) values = k_means.cluster_centers_.squeeze() labels = k_means.labels_ lena_compressed = np.choose(labels,values) lena_compressed.shape = lena.shape
原始图像:
K-means矢量化:
等段:(Equal bins)
图像直方图:
-
分层凝聚聚类:Ward
分层聚类方法是一种针对构建一个簇的分层的簇分析。通常它的实现方式有以下两种: -
凝聚:自下而上的方法:每一个观测样例开始于他自己的簇,以一种最小连接标准迭代合并。这种方法在观测样例较少的情况下非常有效(有趣)。当簇的数量变大时,计算效率比K-means高的多。
-
分裂:自上而下的方法:所有的观测样例开始于同一个簇。迭代的进行分层。对于预计簇很多的情况,这种方法既慢(由于所有的观测样例作为一个簇开始的,是递归进行分离的)又有统计学行的病态。
-
连同-驱使聚类(Conectivity-constrained clustering)
使用凝聚聚类,通过一个连通图可以指定某些样例能被聚集在一起。scikit-learn中的图通过邻接矩阵来表示,且通常是一个稀疏矩阵。例如,在聚类一张图片时检索连通区域(有时也被称作连同单元、部件):from sklearn.feature_extraction.image import grid_to_graphfrom sklearn.cluster import AgglomerativeClustering################################################################################ Generate datalena = sp.misc.lena()# Downsample the image by a factor of 4lena = lena[::2,::2] + lena[1::2,::2] + lena[::2,1::2] + lena[1::2,1::2] X = np.reshape(lena,(-1,1))################################################################################ Define the structure A of the data. Pixels connected to their neighbors.connectivity = grid_to_graph(*lena.shape)################################################################################ Compute clusteringprint("Compute structured hierarchical clustering...") st = time.time() n_clusters = 15 ?# number of regionsward = AgglomerativeClustering(n_clusters=n_clusters,? ?linkage='ward',connectivity=connectivity).fit(X) label = np.reshape(ward.labels_,lena.shape)print("Elapsed time: ",time.time() - st)print("Number of pixels: ",label.size)print("Number of clusters: ",np.unique(label).size)
特征凝聚:
我们已经知道稀疏性可以缓和高维灾难。i.e相对于特征数量观测样例数量不足的情况。另一种方法是合并相似的特征:特征凝聚。这种方法通过在特征方向上进行聚类实现。在特征方向上聚类也可以理解为聚合转置的数据。
digits = datasets.load_digits() images = digits.images X = np.reshape(images,(len(images),-1)) connectivity = grid_to_graph(*images[0].shape) agglo = cluster.FeatureAgglomeration(connectivity=connectivity,? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? n_clusters=32) agglo.fit(X) X_reduced = agglo.transform(X) X_approx = agglo.inverse_transform(X_reduced) images_approx = np.reshape(X_approx,images.shape)
transeform
和invers_transeform
方法
有些模型带有转置方法。例如用来降低数据集的维度
(2)分解:从一个信号到成分和加载
#p#分页标题#e#
成分及其加载:
如果X是我们的多变量数据,那么我们要要尝试解决的问题就是在不同的观测样例上复写写它:我们想要学习加载L和其它一系列的成分C,如X = LC。存在不同的标准和条件去选择成分。
-
主成分分析:PCA
主成分分析(PCA)选择在信号上解释极大方差的连续成分。
上面观测样例的点分布在一个方向上是非常平坦的:三个特征单变量的一个甚至可以有其他两个准确的计算出来。PCA用来发现数据在哪个方向上是不平坦的。
当被用来转换数据的时候,PCA可以通过投射到一个主子空间来降低数据的维度。:
# Create a signal with only 2 useful dimensionsx1 = np.random.normal(size=100) x2 = np.random.normal(size=100) x3 = x1 + x2 X = np.c_[x1,x2,x3]from sklearn import decomposition pca = decomposition.PCA() pca.fit(X)print(pca.explained_variance_) ?# As we can see,only the 2 first components are usefulpca.n_components = 2X_reduced = pca.fit_transform(X) X_reduced.shape