sklearn:面向时间序列数据的用户定义交叉验证

11

我正在尝试解决一个机器学习问题。我有一个包含时间序列元素的特定数据集。为了解决这个问题,我正在使用广为人知的Python库 - sklearn。在这个库中有很多交叉验证迭代器。同时也有几种自定义交叉验证的迭代器。问题是我不知道如何定义时间序列的简单交叉验证。这里有个好的例子:

假设我们有几个时间段(年份),我们想将数据集分成若干块,具体如下:

data = [1, 2, 3, 4, 5, 6, 7]

train: [1]                test: [2] (or test: [2, 3, 4, 5, 6, 7])
train: [1, 2]             test: [3] (or test: [3, 4, 5, 6, 7])
train: [1, 2, 3]          test: [4] (or test: [4, 5, 6, 7])
...
train: [1, 2, 3, 4, 5, 6] test: [7]

我实际上不太明白如何使用sklearn工具创建这种交叉验证。可能我应该像这样使用sklearn.cross_validation中的PredefinedSplit

train_fraction  = 0.8
train_size      = int(train_fraction * X_train.shape[0])
validation_size = X_train.shape[0] - train_size

cv_split = cross_validation.PredefinedSplit(test_fold=[-1] * train_size + [1] * validation_size)

结果:

train: [1, 2, 3, 4, 5] test: [6, 7]

但仍然不如之前的数据分割好


你的数据集中有哪些变量?为什么使用时间序列进行拆分很重要,而不是随机拆分? - maxymoo
1
你可以不使用scikit-learn生成拆分,而是按照以下方式进行:cv_split = [(data[:i], data[i:]) for i in range(1, len(data))]。你觉得呢? - Dan Oneață
@maxymoo,在使用时间序列数据进行拆分时不建议随机拆分的原因是,时间可能很重要(不仅仅是您已经识别出来的其他特征),但是在实际应用中你从未得到过来自未来的数据来训练模型。所以,在测试模型时,您应该采取类似的方法,不要使用测试日期之后的数据进行训练。 - dslack
@DanOneață 很抱歉我在问题中没有提到这一点,但是在创建PredifinedSplit之后,我将其放入了需要交叉验证生成器或可迭代的训练/测试拆分的RFECV中。因此,我认为可以使用sklearn工具来解决这个问题。 - Demyanov
1
@Demyanov 但是,根据我上面定义的cv_split,如果我们将data视为数据的索引,则它是一个可迭代对象,生成训练/测试拆分。 - Dan Oneață
2个回答

7

您可以不使用sklearn获取所需的交叉验证拆分。下面是一个示例:

import numpy as np

from sklearn.svm import SVR
from sklearn.feature_selection import RFECV

# Generate some data.
N = 10
X_train = np.random.randn(N, 3)
y_train = np.random.randn(N)

# Define the splits.
idxs = np.arange(N)
cv_splits = [(idxs[:i], idxs[i:]) for i in range(1, N)]

# Create the RFE object and compute a cross-validated score.
svr = SVR(kernel="linear")
rfecv = RFECV(estimator=svr, step=1, cv=cv_splits)
rfecv.fit(X_train, y_train)

这样做会不会在向前窗口处理时为每个观测创建一个单独的分割?如果我想减少这种情况,我应该使用step参数来增加范围,以便更大的“块”? - dreyco676
1
@dreyco676 没错。只需使用大于1的step参数,例如cv_splits = [(idxs[:i], idxs[i:]) for i in range(1, N, 2)] - Dan Oneață
只是为了确认一下:StratifiedKFold被遗弃了,对吧? - paulochf
1
@paulochf 您是在指到 StratifiedKFold 的导入吗?您是对的,它没有被使用——我将从代码片段中将其删除。 - Dan Oneață

4
同时,这个库新增了一个内容:http://scikit-learn.org/stable/modules/cross_validation.html#time-series-split 文档中的示例:
>>> from sklearn.model_selection import TimeSeriesSplit

>>> X = np.array([[1, 2], [3, 4], [1, 2], [3, 4], [1, 2], [3, 4]])
>>> y = np.array([1, 2, 3, 4, 5, 6])
>>> tscv = TimeSeriesSplit(n_splits=3)
>>> print(tscv)  
TimeSeriesSplit(n_splits=3)
>>> for train, test in tscv.split(X):
...     print("%s %s" % (train, test))
[0 1 2] [3]
[0 1 2 3] [4]
[0 1 2 3 4] [5]

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接