还没决定

sklearn-交叉验证&GridSearch

交叉验证,sklearn0.17版本将其独立封装在cross_validation模块中,0.18后就做了调整,但不要去管它了,用法思路是一样的。

最简单的数据集划分:train_test_split

最单纯的训练集和测试集划分使用的train_test_split 方法 ,单局限平时练手用,用法固定:

1
2
3
4
5
from sklearn import cross_validation
X_train, X_test, y_train, y_test = cross_validation.train_test_split(X,
y,
test_size=0.3,
random_state=0)


K折交叉检验

常规对数据集的使用方法如下:

  1. 训练集合上训练
  2. 之后再验证集合上评估
  3. 完成实验后, 最终在测试集合上进行评价

然而,将可用的数据分为三个部分后,可以用于模型训练的样例数量被大大降低了,而且结果会受到随机选择的(训练,验证)集合的影响。 于是交叉检验出场了:

  1. 将训练集划分为K份
  2. 使用K-1份的数据集合训练模型
  3. 使用余下的那一份作为检验集合
  4. 循环K次,计算均值
  5. 使用测试集合评价

sklearn有K折交叉验证的两个方法:

  • 计算交叉验证指标

    cross_val_score :当 cv 参数是一个整数时,默认地使用 KFold 或者 StratifiedKFold 策略;也可以通过传入一个交叉验证迭代器来使用其他的交叉验证策略

    1
    2
    3
    4
    5
    6
    7
    8
    9
    sklearn.cross_validation.cross_val_score(estimator, # 估计器/模型
    X,
    y=None,
    scoring=None, #
    cv=None, # 交叉验证迭代器
    n_jobs=1,
    verbose=0,
    fit_params=None,
    pre_dispatch='2*n_jobs')
  • 通过交叉验证获得预测

    cross_val_predict :具有和 cross_val_score相同的接口, 对于每一个输入的元素,如果其在测试集合中,将会得到预测结果。

    1
    2
    3
    4
    5
    6
    7
    8
    sklearn.cross_validation.cross_val_predict(estimator,
    X,
    y=None,
    cv=None,
    n_jobs=1,
    verbose=0,
    fit_params=None,
    pre_dispatch='2*n_jobs')


交叉验证迭代器

在使用K折交叉检验之前,先了解交叉检验迭代器,即划分K份数据集合的方法。
KFold :将所有的样例随机划分为$k$个组,称为折叠 (fold) (如果 $k=n$, 这等价于 Leave One Out 留一策略)。

1
2
3
4
5
class sklearn.cross_validation.KFold(n, # Total number of elements
n_folds=3, # 折数
shuffle=False, # 是否进行打散
random_state=None # 伪随机种子
)

StratifiedKFold :是 k-fold 的变种,会返回分层的折叠:每个小集合中, 各个类别的样例比例大致和完整数据集中相同

1
2
3
4
5
6
7
8
9
>>> from sklearn.cross_validation import StratifiedKFold
>>> labels = [0, 0, 0, 0, 1, 1, 1, 1, 1, 1]
# 下面划分好的训练集和测试集的比例 与 labels中的基本一致
>>> skf = StratifiedKFold(labels, 3)
>>> for train, test in skf:
... print("%s %s" % (train, test))
[2 3 6 7 8 9] [0 1 4 5]
[0 1 3 4 5 8 9] [2 6 7]
[0 1 2 4 5 6 7] [3 8 9]

LabelKFold 也是一个 k-fold 的变种(最重要),它会保证相同的 label 不会同时属于测试和训练集合。有label字样的,就是把不同的label在训练集和测试集分开,不分层,与StratifiedKFold 是反义词。

1
2
3
4
5
6
7
8
9
>>> from sklearn.cross_validation import LabelKFold
>>> labels = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3]
# 下面划分好的训练集和测试集,是根据labels进行切割的(一种label不会同时存在于训练集与测试集)
>>> lkf = LabelKFold(labels, n_folds=3)
>>> for train, test in lkf:
... print("%s %s" % (train, test))
[0 1 2 3 4 5] [6 7 8 9]
[0 1 2 6 7 8 9] [3 4 5]
[3 4 5 6 7 8 9] [0 1 2]

下面这几个,看看就好,感觉用不上
LeaveOneOut(LOO) 留一法
LeavePOut(LPO) 留P法
LeaveOneLabelOut (LOLO)
LeavePLabelOut(LPLO)


数据划分类

ShuffleSplit 迭代器 将会生成一个用户给定数量的独立的训练/测试数据划分。样例首先被打散然后划分为一对训练测试集合。

1
2
class sklearn.cross_validation.ShuffleSplit(n, n_iter=10, test_size=0.1,
train_size=None, random_state=None)

1
2
3
4
5
6
7
>>> ss = cross_validation.ShuffleSplit(5, n_iter=3, test_size=0.25,random_state=0)
>>> for train_index, test_index in ss:
... print("%s %s" % (train_index, test_index))
...
[1 3 4] [2 0]
[1 4 3] [0 2]
[4 0 2] [1 3]

LabelShuffleSplit 迭代器是 ShuffleSplit 和 LeavePLabelsOut 的组合。就是多一步先打散数据。
StratifiedShuffleSplit 迭代器是 ShuffleSplit 和 StratifiedKFold 的组合。就是多一步先打散数据。
PredefinedSplit 不懂


关于打散数据顺序

打不打散数据根据实际情况判断,其实大部分的交叉验证迭代器都内建一个划分数据前进行数据索引打散的选项,而train_test_split 方法内部使用的就是交叉验证迭代器,所以上面几个数据划分类在练手使用阶段几乎用不上。

  • 这种方式仅需要很少的内存就可以打散数据。
  • 默认不会进行打散,包括设置 cv=some_integer (直接)k 折叠交叉验证的 cross_val_score 会返回一个随机的划分。
  • 参数 random_state 默认设置为 None,这意为着每次进行KFold(..., shuffle=True) 时,打散都是不同的。 然而,GridSearchCV 通过调用 fit 方法验证时,将会使用相同的打散来训练每一组参数。
  • 为了保证结果的可重复性(在相同的平台上),应该给 random_state 设定一个固定的值。
  • 如果数据集具有时间性,千万不要打散数据再划分!

GridSearch贪婪搜索

在sklearn在cv参数填整数的,都是默认使用分层划分StratifiedKFold

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 全模式搜索
class sklearn.grid_search.GridSearchCV(estimator, # 估计器/模型
param_grid, # 参数网格
cv=None, # 交叉验证迭代器
scoring=None, # 检验指标
refit=True, # True:搜索后,模型以最佳参数fit好了
iid=True, # 样本为独立同分布
fit_params=None,
n_jobs=1,
verbose=0, # 1:打印信息
pre_dispatch='2*n_jobs',
# 报错,当参数网格中有某个参数有问题,建议不要用默认的
error_score='raise'
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 随机搜索:指定参数的范围和分布,抽取个数
class sklearn.grid_search.RandomizedSearchCV(estimator,
param_distributions,
cv=None,
n_iter=10,
scoring=None,
refit=True,
iid=True,
fit_params=None,
n_jobs=1,
verbose=0,
pre_dispatch='2*n_jobs',
random_state=None,
error_score='raise')