scikit-learn 中 longitudinal/panel 数据的交叉验证
Cross Validation for longitudinal/panel data in scikit-learn
我有一些 longitudinal/panel 数据采用以下形式(数据输入代码在问题下方)。 X 和 y 的观测值按时间和国家索引(例如美国在时间 1,美国在时间 2,加拿大在时间 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
。对于可重现的示例,我们可以使用线性回归。
为了执行 CV,我不能使用 test_train_split
,因为这样拆分可能会,例如,将来自 time = 3
的数据放入 X_train
,以及来自 time = 2
变成 y_test
。这将无济于事,因为在 time = 2
,当我们尝试预测 y
时,我们还没有 time = 3
的数据可供训练。
我正在尝试使用 TimeSeriesSplit
来获得如图所示的 CV:
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
索引,而且由 country
索引,因此 longitudinal/panel 性质的数据。
我想要的输出是:
- 允许我执行“向前走”CV的一系列测试和训练索引
例如
TRAIN: [1] TEST: [2]
TRAIN: [1 2] TEST: [3]
An X_train
, x_test
, y_test
, y_train
使用上面的索引拆分,基于 [=28 的值=],或明确我是否需要这样做。
使用“向前走”CV 方法交叉验证的任何模型(例如线性回归)的准确度得分。
编辑:感谢@sabacherli 回答我问题的第一部分,并修复了抛出的错误。
数据输入代码
import numpy as np
import pandas as pd
data = np.array([['country','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]],
)
df = pd.DataFrame(data=data[1:,1:],
index=data[1:,0],
columns=data[0,1:])
df
TimeSeriesSplit
假设您的数据集是按时间索引的,这意味着每一行都属于不同的时间步长。那么为什么不unstack
这样的数据,你只有时间作为索引,然后拆分。拆分后,您可以再次 stack
数据形状以获得您的基础 table 进行训练。
data = np.array([['country','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]],
)
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']]
所以现在您可以按时间拆分数据帧,并将其扩展回训练所需的形状。
我有一些 longitudinal/panel 数据采用以下形式(数据输入代码在问题下方)。 X 和 y 的观测值按时间和国家索引(例如美国在时间 1,美国在时间 2,加拿大在时间 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
。对于可重现的示例,我们可以使用线性回归。
为了执行 CV,我不能使用 test_train_split
,因为这样拆分可能会,例如,将来自 time = 3
的数据放入 X_train
,以及来自 time = 2
变成 y_test
。这将无济于事,因为在 time = 2
,当我们尝试预测 y
时,我们还没有 time = 3
的数据可供训练。
我正在尝试使用 TimeSeriesSplit
来获得如图所示的 CV:
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
索引,而且由 country
索引,因此 longitudinal/panel 性质的数据。
我想要的输出是:
- 允许我执行“向前走”CV的一系列测试和训练索引
例如
TRAIN: [1] TEST: [2]
TRAIN: [1 2] TEST: [3]
An
X_train
,x_test
,y_test
,y_train
使用上面的索引拆分,基于 [=28 的值=],或明确我是否需要这样做。使用“向前走”CV 方法交叉验证的任何模型(例如线性回归)的准确度得分。
编辑:感谢@sabacherli 回答我问题的第一部分,并修复了抛出的错误。
数据输入代码
import numpy as np
import pandas as pd
data = np.array([['country','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]],
)
df = pd.DataFrame(data=data[1:,1:],
index=data[1:,0],
columns=data[0,1:])
df
TimeSeriesSplit
假设您的数据集是按时间索引的,这意味着每一行都属于不同的时间步长。那么为什么不unstack
这样的数据,你只有时间作为索引,然后拆分。拆分后,您可以再次 stack
数据形状以获得您的基础 table 进行训练。
data = np.array([['country','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]],
)
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']]
所以现在您可以按时间拆分数据帧,并将其扩展回训练所需的形状。