1. sklearn中的数据集和估计量
- 数据集
上节提到最后拿去训练的数据集应该是个二维数组,横向样本纵向为特征,因此有时候需要对数据做一些变换。
from sklearn import datasets
digits = datasets.load_digits()
# digits的image维数为8*8,因此reshape为一个16*1的数组
data = digits.images.reshape((digits.images.shape[0], -1))
- 估计量(estimator)
用于拟合数据的东东,可以是个分类器,一个聚类算法,一个变换。如上节的clf,就是一个estimator。其实就是个抽象出来的模型。
2. 监督学习
- 近邻算法和维度的诅咒
给一堆观察到的数据集,打上预测的标签,继续拿iris举例:
iris 数据集为给定了一堆花瓣和花萼的特征,据此来推测这是Setosa还是Versicolour还是Virginica,因此是个分类问题。花的种类就是label y。X即为花瓣和花萼的长度和宽度
import numpy as np
from sklearn import datasets
iris = datasets.load_iris()
iris_X = iris.data
iris_y = iris.target
#查看y到底有哪些值,因此去了个重
print np.unique(iris_y)
- K近邻算法(我也没想到这么快就上算法了)
这就是一个(最简单的)分类器,其原理基本上和看你朋友圈的收入就大概能猜出你的收入是差不多的,之后细谈。
同样的,数据集要抽出一部分来,假装你不知道这部分数据属于哪种花,从而可以用来考验我们的模型能否把这些数据预测对。这部分数据就是常说的测试集。
import numpy as np
from sklearn.neighbors import KNeighborsClassifier
#随机排列数组,类似于linux的shuffle,seed用于保证该序列可重现,方便调试
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:]]
#创建我们的分类器,estimator
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train)
# 将预测值与原值放一起对比
print knn.predict(iris_X_test)
print iris_y_test
维度的诅咒
暂时还没看懂,再续Shrinkage 和 Sparsity
Shrinkage: 当某一维度的数据很少时,一丢丢的噪声点也可以让方差很大,故,对多维的数据集,偶尔要对这一维度的数据做一些限制,常说的L2正则就是这个作用了。(亦为统计学中的岭回归)
Sparsity:还有时,某一特征虽然和模型的关系较大,但主要是因为另一特征的影响。当另一feature确定时,该特征和y的关系就一去不复返了。因此,可以考虑直接将该类特征系数设为0,所谓简单的才是最好的。常说的L1正则便是如此作用(亦为统计学中的Lasso)
(这边的代码上的都是Ridge方法,Lasso方法,不感兴趣,以后直接玩L1, L2吧)
稍稍提示:Lasso常用的求解算法为坐标下降法,有时矩阵实在稀疏至极,也可考虑LassoLars算法。
3. 模型参数选择
机器学习的世界基本没有拿满分的时候,因为总是会有一些不按牌理出牌的人。但还是要分出个好和更好来啊,所以就有了对模型的评价函数。
sklearn里每个estimator都使用了一个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')
print svc.fit(X_digits[:-100], y_digits[:-100]).score(X_digits[-100:], y_digits[-100:])
结果出来可以发现,分数很高。可是不放心啊,万一只是运气好呢。于是就有了K折验证
- K折验证(交叉验证)
把数据集分成K份,轮流从里面拿出一份来做测试集,其它的作为训练集,以便观察模型的参数设置的是否合理。
人工实现版:
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):
#split的数组转成list,方便下面pop
X_train = list(X_folds)
#将list的第k个元素pop出来赋给X_test
X_test = X_train.pop(k)
#将list中剩下的元素连接起来
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 scores
高大上调库版:
from sklearn import cross_validation
# n样本个数,n_folds为份数, 返回两个索引列表
k_fold = cross_validation.KFold(n=len(X_digits), n_folds=3)
print [svc.fit(X_digits[train], y_digits[train]).score(X_digits[test], y_digits[test]) for train, test in kfold]
#or如下,n_jobs=-1表示CPU火力全开
print cross_validation.cross_val_score(svc, X_digits, y_digits, cv=kfold, n_jobs=-1)
除了cross_validation.KFold, 还有其它的交叉验证函数:
- KFold(n, k) : 平均分K份,交叉
- StratifiedKFold(y, k):在保证每一类所占的比例不变的情况下分K份
- LeaveOneOut(n):只留一个样本为测试集,相当于k==n
- LeaveOneLabelOut(labels): 根据一个第三方的label列表来决定哪些做测试集。相当于可以人为去定义条件
- Grid-search
大概的意思,模型的参数A可以取3个值,模型的参数B可以取2个值,那就把那个3*2的参数组合都拿来一试咯。
from sklearn.grid_search import GridSearchCV
# -6为始,-1为终,步速ln(n_sample)/ln(10)
Cs = np.logspace(-6, -1, 10)
# param_grid接收一个字典or字典组成的列表,其中字典的key为参数,value为取值列表
clf = GridSearchCV(estimator=svc, param_grid=dict(C=Cs), n_jobs=-1)
clf.fit(X_digits[:1000], y_digits[:1000])
print clf.best_score_, clf.best_estimator_C