scikit-learn中纵向/面板数据的交叉验证

问题描述

我有一些纵向/面板数据,格式如下(数据输入的代码在问题下方)。 X和y的观测值按时间和国家/地区索引(例如,美国在时间1,美国在时间2,CAN在时间1)。

    time x  y
USA 1    5  10
USA 2    5  12
USA 3    6  13
CAN 1    2  2
CAN 2    2  3
CAN 3    4  5

我正在尝试使用sklearn预测y。对于一个可重现的示例,我们可以使用线性回归。

为了执行简历,我不能使用test_train_split,因为这样拆分可能会,例如,将time = 3中的数据放入X_train中,并将{{1}中的数据放入}插入time = 2。这将无济于事,因为在y_test上,当我们试图预测time = 2时,我们还没有真正在y上进行训练的数据。

我正尝试使用time = 3来实现CV,如下图所示:

enter image description here

(来源:https://stats.stackexchange.com/questions/14099/using-k-fold-cross-validation-for-time-series-model-selection

TimeSeriessplit
y = df.y
X = df.drop(['y'],1)
print(y)
print(X)

接近我的需求,但不完全是

from sklearn.model_selection import TimeSeriessplit

X = X.to_numpy()

from sklearn.model_selection import TimeSeriessplit
tscv = TimeSeriessplit(n_splits = 2,max_train_size=3)
print(tscv)
for train_index,test_index in tscv.split(X):
    print("TRAIN:",train_index,"TEST:",test_index)
    X_train,X_test = X[train_index],X[test_index]
    y_train,y_test = y[train_index],y[test_index]
  • 我现在如何使用TRAIN: [0 1] TEST: [2 3] TRAIN: [1 2 3] TEST: [4 5] 索引对模型进行交叉验证?

我相信一个复杂的问题可能是我的数据不是严格按时间顺序排列的:它不仅由TimeSeriessplit索引,而且还由time索引,因此数据的纵向/面板性质。

我想要的输出是:

  1. 一系列测试和培训指标,使我能够进行“前行”简历

例如

country
  1. 根据TRAIN: [1] TEST: [2] TRAIN: [1 2] TEST: [3] 的值使用上面的索引拆分的X_trainx_testy_testy_train,或者明确我是否需要这样做。

  2. 使用“前行” CV方法交叉验证的任何模型(例如线性回归)的准确性得分。

编辑:感谢@sabacherli回答了我的问题的第一部分,并修复了所抛出的错误

数据输入代码

time

解决方法

TimeSeriesSplit假定您的数据集已按时间索引,这意味着每一行都属于一个不同的时间步长。因此,为什么不unstack这样的数据仅将时间作为索引,然后进行拆分。分割之后,您可以再次stack调整数据形状以获取基础表进行训练。

data = np.array([['country','time','x','y'],['USA',1,5,10],2,12],3,6,13],['CAN',2],3],4,5]],)

df = pd.DataFrame(data=data[1:,1:],index=data[1:,0],columns=data[0,1:])

df1 = df.reset_index().set_index(['time','index']).unstack(-1)
print(df1)
        x       y    
index CAN USA CAN USA
time                 
1       2   5   2  10
2       2   5   3  12
3       4   6   5  13

现在,由于每一行都是按时间索引的,因此您可以轻松地将此数据分为几组,然后在拆分之后再次堆叠以获取X_train X_test等。

from sklearn.model_selection import TimeSeriesSplit
tscv = TimeSeriesSplit(n_splits = 2,max_train_size=3)

X_cols = ['time','index','x']
y_cols = ['y']

for train_index,test_index in tscv.split(df1):
    print("TRAIN:",train_index,"TEST:",test_index)
    X_train,X_test = df1.iloc[train_index].stack(-1).reset_index()[X_cols].to_numpy(),df1.iloc[test_index].stack(-1).reset_index()[X_cols].to_numpy()
    y_train,y_test = df1.iloc[train_index].stack(-1).reset_index()[y_cols].to_numpy(),df1.iloc[test_index].stack(-1).reset_index()[y_cols].to_numpy()
TRAIN: [0] TEST: [1]
TRAIN: [0 1] TEST: [2]

您可以打印最新折页的X_train和y_train以查看发生的情况-

print('For - TRAIN: [0 1] TEST: [2]')
print(" ")
print("X_train:")
print(X_train)
print(" ")
print("X_test:")
print(X_test)
print(" ")
print("y_train:")
print(y_train)
print(" ")
print("y_test:")
print(y_test)
print("X_train:")
print(X_train)
print(" ")
print("X_test:")
print(X_test)
print(" ")
print("y_train:")
print(y_train)
print(" ")
print("y_test:")
print(y_test)
For - TRAIN: [0 1] TEST: [2]

X_train:
[['1' 'CAN' '2']
 ['1' 'USA' '5']
 ['2' 'CAN' '2']
 ['2' 'USA' '5']]
 
X_test:
[['3' 'CAN' '4']
 ['3' 'USA' '6']]
 
y_train:
[['2']
 ['10']
 ['3']
 ['12']]
 
y_test:
[['5']
 ['13']]

因此,现在您可以按时间分割数据帧,并将其扩展回训练所需的形状。