Sklearn中的CV与KFold详解

关于交叉验证,我在之前的文章中已经进行了简单的介绍,而现在我们则通过几个更加详尽的例子.详细的介绍

CV

%matplotlib inline
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn import datasets
from sklearn import svm

iris = datasets.load_iris()
iris.data.shape,iris.target.shape
((150, 4), (150,))

一般的分割方式,训练集-测试集.然而这种方式并不是很好

X_train, X_test, y_train, y_test = train_test_split(iris.data, iris.target, test_size=0.4, random_state=0) 

clf_svc = svm.SVC(kernel='linear').fit(X_train,y_train)
clf_svc.score(X_test,y_test)
0.9666666666666667
  • 缺点一:浪费数据
  • 缺点二:容易过拟合,且矫正方式不方便

这时,我们需要使用另外一种分割方式-交叉验证

from sklearn.model_selection import cross_val_score
clf_svc_cv = svm.SVC(kernel='linear',C=1)
scores_clf_svc_cv = cross_val_score(clf_svc_cv,iris.data,iris.target,cv=5)
print(scores_clf_svc_cv)
print("Accuracy: %0.2f (+/- %0.2f)" % (scores_clf_svc_cv.mean(), scores_clf_svc_cv.std() * 2))
[ 0.96666667  1.          0.96666667  0.96666667  1.        ]
Accuracy: 0.98 (+/- 0.03)

同时我们也可以为cross_val_score选择不同的性能度量函数

from sklearn import metrics
scores_clf_svc_cv_f1 = cross_val_score(clf_svc_cv,iris.data,iris.target,cv=5,scoring='f1_macro')
print("F1: %0.2f (+/- %0.2f)" % (scores_clf_svc_cv_f1.mean(), scores_clf_svc_cv_f1.std() * 2))
F1: 0.98 (+/- 0.03)

同时也正是这些特性使得,cv与数据转化以及pipline(sklearn中的管道机制)变得更加契合

from sklearn import preprocessing
from sklearn.pipeline import make_pipeline
clf_pipline = make_pipeline(preprocessing.StandardScaler(),svm.SVC(C=1))
scores_pipline_cv = cross_val_score(clf_pipline,iris.data,iris.target,cv=5)
print("Accuracy: %0.2f (+/- %0.2f)" % (scores_clf_svc_cv_f1.mean(), scores_clf_svc_cv_f1.std() * 2))
Accuracy: 0.98 (+/- 0.03)

同时我们还可以在交叉验证使用多个度量函数

from sklearn.model_selection import cross_validate
from sklearn import metrics

scoring = ['precision_macro', 'recall_macro']
clf_cvs = svm.SVC(kernel='linear', C=1, random_state=0)
scores_cvs = cross_validate(clf_cvs,iris.data,iris.target,cv=5,scoring=scoring,return_train_score = False)
sorted(scores_cvs.keys())
['fit_time', 'score_time', 'test_precision_macro', 'test_recall_macro']
print(scores_cvs['test_recall_macro'])
print("test_recall_macro: %0.2f (+/- %0.2f)" % (scores_cvs['test_recall_macro'].mean(), scores_cvs['test_recall_macro'].std() * 2))
[ 0.96666667  1.          0.96666667  0.96666667  1.        ]
test_recall_macro: 0.98 (+/- 0.03)

同时cross_validate也可以使用make_scorer自定义度量功能
或者使用单一独量

from sklearn.metrics.scorer import make_scorer
scoring_new = {'prec_macro': 'precision_macro','recall_micro': make_scorer(metrics.recall_score, average='macro')}
# 注意此处的make_scorer
scores_cvs_new = cross_validate(clf_cvs,iris.data,iris.target,cv=5,scoring=scoring_new,return_train_score = False)
sorted(scores_cvs_new.keys())
['fit_time', 'score_time', 'test_prec_macro', 'test_recall_micro']
print(scores_cvs_new['test_recall_micro'])
print("test_recall_micro: %0.2f (+/- %0.2f)" % (scores_cvs_new['test_recall_micro'].mean(), scores_cvs_new['test_recall_micro'].std() * 2))
[ 0.96666667  1.          0.96666667  0.96666667  1.        ]
test_recall_micro: 0.98 (+/- 0.03)

关于Sklearn中的CV还有cross_val_predict可用于预测,下面则是Sklearn中一个关于使用该方法进行可视化预测错误的案例

from sklearn import datasets
from sklearn.model_selection import cross_val_predict
from sklearn import linear_model
import matplotlib.pyplot as plt

lr = linear_model.LinearRegression()
boston = datasets.load_boston()
y = boston.target

# cross_val_predict returns an array of the same size as `y` where each entry
# is a prediction obtained by cross validation:
predicted = cross_val_predict(lr, boston.data, y, cv=10)

fig, ax = plt.subplots()
fig.set_size_inches(18.5,10.5)
ax.scatter(y, predicted, edgecolors=(0, 0, 0))
ax.plot([y.min(), y.max()], [y.min(), y.max()], 'k--', lw=4)
ax.set_xlabel('Measured')
ax.set_ylabel('Predicted')
plt.show()

通过交叉验证进行数据错误的可视化

KFlod的例子

Stratified k-fold:实现了分层交叉切分

from sklearn.model_selection import StratifiedKFold
X = np.array([[1, 2, 3, 4],
              [11, 12, 13, 14],
              [21, 22, 23, 24],
              [31, 32, 33, 34],
              [41, 42, 43, 44],
              [51, 52, 53, 54],
              [61, 62, 63, 64],
              [71, 72, 73, 74]])

y = np.array([1, 1, 0, 0, 1, 1, 0, 0])

stratified_folder = StratifiedKFold(n_splits=4, random_state=0, shuffle=False)
for train_index, test_index in stratified_folder.split(X, y):
    print("Stratified Train Index:", train_index)
    print("Stratified Test Index:", test_index)
    print("Stratified y_train:", y[train_index])
    print("Stratified y_test:", y[test_index],'\n')
Stratified Train Index: [1 3 4 5 6 7]
Stratified Test Index: [0 2]
Stratified y_train: [1 0 1 1 0 0]
Stratified y_test: [1 0] 

Stratified Train Index: [0 2 4 5 6 7]
Stratified Test Index: [1 3]
Stratified y_train: [1 0 1 1 0 0]
Stratified y_test: [1 0] 

Stratified Train Index: [0 1 2 3 5 7]
Stratified Test Index: [4 6]
Stratified y_train: [1 1 0 0 1 0]
Stratified y_test: [1 0] 

Stratified Train Index: [0 1 2 3 4 6]
Stratified Test Index: [5 7]
Stratified y_train: [1 1 0 0 1 0]
Stratified y_test: [1 0] 
from sklearn.model_selection import StratifiedKFold
X = np.array([[1, 2, 3, 4],
              [11, 12, 13, 14],
              [21, 22, 23, 24],
              [31, 32, 33, 34],
              [41, 42, 43, 44],
              [51, 52, 53, 54],
              [61, 62, 63, 64],
              [71, 72, 73, 74]])

y = np.array([1, 1, 0, 0, 1, 1, 0, 0])

stratified_folder = StratifiedKFold(n_splits=4, random_state=0, shuffle=False)
for train_index, test_index in stratified_folder.split(X, y):
    print("Stratified Train Index:", train_index)
    print("Stratified Test Index:", test_index)
    print("Stratified y_train:", y[train_index])
    print("Stratified y_test:", y[test_index],'\n')
Stratified Train Index: [1 3 4 5 6 7]
Stratified Test Index: [0 2]
Stratified y_train: [1 0 1 1 0 0]
Stratified y_test: [1 0] 

Stratified Train Index: [0 2 4 5 6 7]
Stratified Test Index: [1 3]
Stratified y_train: [1 0 1 1 0 0]
Stratified y_test: [1 0] 

Stratified Train Index: [0 1 2 3 5 7]
Stratified Test Index: [4 6]
Stratified y_train: [1 1 0 0 1 0]
Stratified y_test: [1 0] 

Stratified Train Index: [0 1 2 3 4 6]
Stratified Test Index: [5 7]
Stratified y_train: [1 1 0 0 1 0]
Stratified y_test: [1 0] 

除了这几种交叉切分KFlod外,还有很多其他的分割方式,比如StratifiedShuffleSplit重复分层KFold,实现了每个K中各类别的比例与原数据集大致一致,而RepeatedStratifiedKFold 可用于在每次重复中用不同的随机化重复分层 K-Fold n 次。至此基本的KFlod在Sklearn中都实现了

注意

i.i.d 数据是机器学习理论中的一个常见假设,在实践中很少成立。如果知道样本是使用时间相关的过程生成的,则使用 time-series aware cross-validation scheme 更安全。 同样,如果我们知道生成过程具有 group structure (群体结构)(从不同 subjects(主体) , experiments(实验), measurement devices (测量设备)收集的样本),则使用 group-wise cross-validation 更安全。

下面就是一个分组KFold的例子,

from sklearn.model_selection import GroupKFold

X = [0.1, 0.2, 2.2, 2.4, 2.3, 4.55, 5.8, 8.8, 9, 10]
y = ["a", "b", "b", "b", "c", "c", "c", "d", "d", "d"]
groups = [1, 1, 1, 2, 2, 2, 3, 3, 3, 3]

gkf = GroupKFold(n_splits=3)
for train, test in gkf.split(X, y, groups=groups):
    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]

更多内容请参考:sklearn相应手册

<think>好的,我现在需要处理用户关于sklearn中TimeSeriesSplit的问题。用户希望了解使用方法、示例和参数详解。首先,我应该回忆一下TimeSeriesSplit的相关知识,并确保信息准确。 首先,TimeSeriesSplit是用于时间序列交叉验证的类。标准的k-fold不同,时间序列数据需要保持时序性,不能打乱数据顺序。TimeSeriesSplit通过逐步扩展训练集,同时保持测试集始终在训练集之后,来避免未来数据泄漏。这一点非常重要,因为时间序列的预测任务中,模型不能提前看到未来的数据。 接下来,我需要确定参数。根据文档,主要的参数包括n_splits(折数)、max_train_size(最大训练集大小)、test_size(测试集大小)和gap(间隔)。需要解释每个参数的作用和默认值。例如,n_splits默认是5,max_train_size默认不限制,test_size默认None,即每个测试集的大小等于n_samples // (n_splits + 1)。gap参数是在0.24版本中添加的,用于设置训练集和测试集之间的间隔,防止过拟合。 然后,使用方法部分需要说明如何初始化TimeSeriesSplit对象,如何GridSearchCV结合使用进行超参数调优。例如,创建一个TimeSeriesSplit实例,设置参数后,传入到GridSearchCVcv参数中。需要提醒用户在使用时保持数据的时间顺序,避免随机打乱。 示例部分需要提供一个具体的代码示例。比如,生成一个简单的时间序列数据集,使用TimeSeriesSplit进行交叉验证,并展示每次拆分后的训练集和测试集的索引。这可以帮助用户直观理解拆分过程。此外,可以结合GridSearchCV展示如何在模型调优中使用TimeSeriesSplit,比如对SVM模型进行参数搜索,并输出最佳参数。 还需要注意版本问题,特别是gap参数在0.24版本引入。如果用户使用较旧版本,可能需要升级sklearn。此外,时间序列数据通常需要预处理,如确保数据按时间排序,处理缺失值等,这些也可以作为注意事项提到。 在回答中,需要引用用户提供的参考引用,特别是引用[1]中的内容,其中提到了TimeSeriesSplit和GridSearchCV的使用,所以要在相关部分添加引用标记。同时,用户提到的引用[2]关于策略优化和参数调优,可能和交叉验证的应用场景相关,可以在应用场景部分提及。 最后,生成相关问题需要考虑用户可能进一步想知道的内容,比如KFold的区别、如何处理数据中的季节性、如何结合Pipeline使用等。这些问题有助于用户深入学习和解决问题。 总结步骤: 1. 介绍TimeSeriesSplit的作用和KFold的区别。 2. 详细解释每个参数的意义和用法。 3. 分步骤说明使用方法,包括对象初始化和结合GridSearchCV。 4. 提供代码示例,展示拆分过程和实际应用。 5. 注意事项和常见问题,如数据顺序、版本兼容性。 6. 相关问题部分,列出可能的扩展问题。 需要确保所有数学公式和代码块格式正确,行内公式用$...$,独立公式用$$...$$,代码用三个反引号包裹。同时,引用标记要自然添加在相关段落末尾。</think>### sklearn TimeSeriesSplit 使用方法及参数详解 #### 1. TimeSeriesSplit 的作用 `TimeSeriesSplit` 是 scikit-learn 中用于时间序列数据的交叉验证方法,其核心是**保持数据的时间顺序**。传统的随机划分(如 `KFold`)不同,时间序列要求训练集始终在测试集之前,避免未来信息泄漏[^1]。例如,若数据按时间排序为 $[t_1, t_2, t_3, t_4, t_5]$,拆分结果可能为: - 训练集:$[t_1]$, 测试集:$[t_2]$ - 训练集:$[t_1, t_2]$, 测试集:$[t_3]$ - 依此类推。 #### 2. 关键参数详解 - **`n_splits`**(默认=5) 折数,即交叉验证的轮次。 $$n_{\text{test\_samples}} = \frac{n_{\text{samples}}}{n_{\text{splits}} + 1}$$ 例如,100 个样本,5 折时每轮测试集大小为 16。 - **`max_train_size`**(默认=None) 限制训练集的最大样本数。例如设置为 50,则训练集最多取前 50 个样本。 - **`test_size`**(默认=None) 直接指定测试集大小。例如设置为 10,则每轮测试集固定为 10 个样本。 - **`gap`**(默认=0) 训练集测试集之间的间隔。例如 `gap=2`,则训练集结束于 $t_i$,测试集开始于 $t_{i+3}$。 #### 3. 使用方法示例 ##### 基本拆分示例 ```python from sklearn.model_selection import TimeSeriesSplit import numpy as np # 生成示例数据(需按时间排序) X = np.array([[i] for i in range(10)]) y = np.arange(10) # 初始化 TimeSeriesSplit tscv = TimeSeriesSplit(n_splits=3, test_size=2, gap=1) # 查看拆分结果 for train_index, test_index in tscv.split(X): print(f"训练集索引: {train_index}, 测试集索引: {test_index}") ``` **输出**: ``` 训练集索引: [0 1 2 3], 测试集索引: [5 6] # gap=1 跳过索引4 训练集索引: [0 1 2 3 4 5], 测试集索引: [7 8] 训练集索引: [0 1 2 3 4 5 6 7], 测试集索引: [9] ``` ##### 结合 GridSearchCV 调参 ```python from sklearn.svm import SVR from sklearn.model_selection import GridSearchCV # 定义参数网格 param_grid = {'C': [0.1, 1, 10]} # 创建模型交叉验证对象 model = SVR() tscv = TimeSeriesSplit(n_splits=3) grid_search = GridSearchCV(model, param_grid, cv=tscv) # 拟合数据 grid_search.fit(X, y) print(f"最佳参数: {grid_search.best_params_}") ``` #### 4. 注意事项 1. **数据必须按时间排序**,否则会导致验证失效。 2. `gap` 参数在 scikit-learn ≥ 0.24 版本中可用,旧版本需升级。 3. 时间序列预测任务中,通常需要滞后特征(如前 3 天的数据作为输入)。 ####
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tian Fengshou

写的很好,请给我钱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值