在测试和训练数据集中使用基于时间的拆分来拆分数据

Posted

技术标签:

【中文标题】在测试和训练数据集中使用基于时间的拆分来拆分数据【英文标题】:Splitting data using time-based splitting in test and train datasets 【发布时间】:2018-11-25 13:19:34 【问题描述】:

我知道train_test_split会随机拆分,但我需要知道如何根据时间拆分。

  X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=42) 
  # this splits the data randomly as 67% test and 33% train

如何根据时间分割相同的数据集作为 67% 的训练和 33% 的测试?数据集有一列 TimeStamp。

我尝试搜索类似的问题,但不确定方法。

谁能简单解释一下?

【问题讨论】:

你想要一个单调分割 - 例如最早的第三个是测试数据,剩下的是测试?还是您想要一个仅考虑时间而不是时间的确定性函数的随机拆分? 我想要一个基于时间的拆分,即根据时间将数据分别拆分为训练和测试。 您的采样时间是否一致?连续样本之间是否存在恒定延迟,还是延迟变量? 延迟是可变的。我认为的一种方法是根据时间按样本排序,然后将其拆分训练和测试数据,然后在 sklearn 中使用 TimeSeriesSplit 但是 train_test_split 正在随机拆分它,正如我在其文档中看到的那样。 【参考方案1】:

如果您的数据已经按时间排序,那么只需使用shuffle=False

例如:

train, test = train_test_split(newdf, test_size=0.3, shuffle=False)

【讨论】:

【参考方案2】:

在时间序列数据集上,数据拆分以不同的方式进行。 See this link 了解更多信息。或者,您可以尝试 scikit-learn 包中的 TimeSeriesSplit。所以主要思想是这样的,假设你根据时间戳有10个数据点。现在拆分将是这样的:

Split 1 : 
Train_indices : 1 
Test_indices  : 2


Split 2 : 
Train_indices : 1, 2 
Test_indices  : 3


Split 3 : 
Train_indices : 1, 2, 3 
Test_indices  : 4

Split 4 : 
Train_indices : 1, 2, 3, 4 
Test_indices  : 5

如此等等。您可以查看上面链接中显示的示例,以更好地了解 TimeSeriesSplit 在 sklearn 中的工作原理

更新 如果您有一个单独的时间列,您可以简单地根据该列对数据进行排序,然后如上所述应用 timeSeriesSplit 来获取拆分。

为确保最终拆分中 67% 的训练数据和 33% 的测试数据,请指定拆分数量如下:

no_of_split = int((len(data)-3)/3)

例子

X = np.array([[1, 2], [3, 4], [1, 2], [3, 4],[1, 2], [3, 4],[3, 4],[1, 2],     [3, 4],[3, 4],[1, 2], [3, 4] ])
y = np.array([1, 2, 3, 4, 5, 6,7,8,9,10,11,12])
tscv = TimeSeriesSplit(n_splits=int((len(y)-3)/3))
for train_index, test_index in tscv.split(X):
     print("TRAIN:", train_index, "TEST:", test_index)

     #To get the indices 
     X_train, X_test = X[train_index], X[test_index]
     y_train, y_test = y[train_index], y[test_index]

输出:

('TRAIN:', array([0, 1, 2]), 'TEST:', array([3, 4, 5]))
('TRAIN:', array([0, 1, 2, 3, 4, 5]), 'TEST:', array([6, 7, 8]))
('TRAIN:', array([0, 1, 2, 3, 4, 5, 6, 7, 8]), 'TEST:', array([ 9, 10, 11]))

【讨论】:

看,我知道 sklearn 中的 TimeSeriesSplit 但只有在数据根据时间而不是“随机”拆分为训练和测试时才会使用,因为 train_test_split 这会将其随机拆分为训练和测试要求。 sklearn 中是否有一个库,可以根据时间而不是随机地将数据分成训练和测试,还是有其他方法? 您的数据是否有专门的“日期时间”列? 它有一个时间列 我假设这里的时间列没有排序,对吧?【参考方案3】:

一种简单的方法..

首先:按时间对数据进行排序

第二个:

import numpy as np 
train_set, test_set= np.split(data, [int(.67 *len(data))])

这使得 train_set 包含前 67% 的数据,而 test_set 包含其余 33% 的数据。

【讨论】:

【参考方案4】:

如果您有一个简单的数据集,其中每一行都是一个观察值(例如分类问题的非时间序列数据集),并且您想将其拆分为训练和测试,则此函数将拆分为基于训练和测试的数据集在一列日期上:

import pandas as pd
import numpy as np
from math import ceil

def train_test_split_sorted(X, y, test_size, dates):
"""Splits X and y into train and test sets, with test set separated by most recent dates.

    Example:
    --------
    >>> from sklearn import datasets

    # Fake dataset:
    >>> gen_data = datasets.make_classification(n_samples=10000, n_features=5)
    >>> dates = np.array(pd.date_range('2016-01-01', periods=10000, freq='5min'))
    >>> np.random.shuffle(dates)
    >>> df = pd.DataFrame(gen_data[0])
    >>> df['date'] = dates
    >>> df['target'] = gen_data[1]

    # Separate:
    >>> X_train, X_test, y_train, y_test = train_test_split_sorted(df.drop('target', axis=1), df['target'], 0.33, df['date'])

    >>> print('Length train set: '.format(len(y_train)))
    Length train set: 8000
    >>> print('Length test set: '.format(len(y_test)))
    Length test set: 2000
    >>> print('Last date in train set: '.format(X_train['date'].max()))
    Last date in train set: 2016-01-28 18:35:00
    >>> print('First date in test set: '.format(X_test['date'].min()))
    First date in test set: 2016-01-28 18:40:00
    """

    n_test = ceil(test_size * len(X))

    sorted_index = [x for _, x in sorted(zip(np.array(dates), np.arange(0, len(dates))), key=lambda pair: pair[0])]
    train_idx = sorted_index[:-n_test]
    test_idx = sorted_index[-n_test:]

    if isinstance(X, (pd.Series, pd.DataFrame)):
        X_train = X.iloc[train_idx]
        X_test = X.iloc[test_idx]
    else:
        X_train = X[train_idx]
        X_test = X[test_idx]
    if isinstance(y, (pd.Series, pd.DataFrame)):
        y_train = y.iloc[train_idx]
        y_test = y.iloc[test_idx]
    else:
        y_train = y[train_idx]
        y_test = y[test_idx]

    return X_train, X_test, y_train, y_test

dates 参数实际上可以是您希望用来对数据进行排序的任何类型的数组或系列。

在您的情况下,您应该调用:X_train, X_test, y_train, y_test = train_test_split_sorted(X, y, 0.333, TimeStamp) TimeStamp 是您拥有每个观察的时间戳信息的数组或列。

【讨论】:

以上是关于在测试和训练数据集中使用基于时间的拆分来拆分数据的主要内容,如果未能解决你的问题,请参考以下文章

使用 tensorflow 将数据集拆分为训练和测试

根据分类列拆分训练和测试集

在训练测试拆分操作(scikit)后使数据平衡?

拆分训练测试数据集将相似的值保持在一起

正确拆分数据集

特征选择应该在训练测试拆分之前还是之后完成?