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

Posted

技术标签:

【中文标题】sklearn:用户定义的时间序列数据交叉验证【英文标题】:sklearn: User defined cross validation for time series data 【发布时间】:2016-02-28 22:17:56 【问题描述】:

我正在尝试解决机器学习问题。我有一个带有 time-series 元素的特定数据集。对于这个问题,我使用了著名的 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]

但还是不如之前的数据拆分好

【问题讨论】:

你的数据集中有哪些变量?为什么使用时间序列进行拆分很重要,为什么不随机拆分? 您可以在不使用 scikit-learn 的情况下生成拆分,如下所示:cv_split = [(data[:i], data[i:]) for i in range(1, len(data))]。你怎么看? @maxymoo,不使用时间序列数据随机拆分的原因是时间可能很重要(不仅仅是您确定的其他功能),但“在野外”您永远无法训练您的模型来自未来的数据。因此,在测试您的模型时,您应该采取类似的行为,而不是使用测试日期之后的数据进行训练。 @DanOneață 很抱歉,我没有在问题中提及这一点,但在创建 PredifinedSplit 之后,我将其放入需要交叉验证生成器或可迭代生成火车的 RFECV /test 分裂。所以我可能可以用 sklearn 工具解决问题 @Demyanov 但是,如果我们将data 视为数据的索引,那么我上面定义的cv_split 是一个产生训练/测试拆分的可迭代对象。 【参考方案1】:

您可以在不使用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 没错。只需使用大于一的step 参数,例如cv_splits = [(idxs[:i], idxs[i:]) for i in range(1, N, 2)] 只是为了确定:StratifiedKFold 被抛在了后面,对吧? @paulochf 你指的是StratifiedKFold的导入吗?你是对的,那是未使用的——我将从代码 sn-p 中删除它。【参考方案2】:

同时这已添加到库中: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]

【讨论】:

以上是关于sklearn:用户定义的时间序列数据交叉验证的主要内容,如果未能解决你的问题,请参考以下文章

如何在 sklearn 中编写自定义估算器并对其使用交叉验证?

sklearn 交叉验证中的自定义评分功能

Sklearn:分组数据的交叉验证

使用 sklearn 进行交叉验证的高级特征提取

sklearn:文本分类交叉验证中的向量化

sklearn中的交叉验证+决策树