You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Scikit-learn框架中对面板数据进行时间序列交叉验证式超参数调优?

面板数据的时间序列交叉验证超参数调优方案

问题背景

我们有多组多实体的时间序列观测数据(面板数据),需要为单个模型做超参数调优,并且采用时间序列交叉验证的方式划分数据。但Scikit-learn内置的TimeSeriesSplit仅适用于单时间序列场景,无法直接处理多实体的面板数据。

举个简单的面板数据示例(代码生成的DataFrame):

from itertools import product
import pandas as pd
import numpy as np

# 创建面板数据
countries = ['ESP','FRA']
periods = list(range(10))
df = pd.DataFrame(list(product(countries,periods)), columns = ['country','period'])
df['target'] = np.concatenate((np.repeat(1, 10), np.repeat(0, 10)))
df['a_feature'] = np.random.randn(20, 1)

生成的数据结构如下:

countryperiodtargeta_feature
ESP010.08
ESP11-2.0
ESP210.1
ESP31-0.59
ESP41-0.83
ESP510.05
ESP610.05
ESP710.42
ESP810.04
ESP912.17
FRA00-0.44
FRA10-0.48
FRA200.82
FRA30-1.64
FRA400.19
FRA500.6
FRA60-0.73
FRA70-0.5
FRA801.11
FRA90-0.75

核心需求是:用所有实体某一时期之前的全部数据训练统一模型,再预测这两个实体的下一时期数据,通过这种交叉验证逻辑选出最优超参数。

解决方案

核心思路是自定义符合面板数据逻辑的交叉验证拆分器,再结合Scikit-learn的超参数搜索工具使用。

步骤1:自定义面板时间序列交叉验证拆分器

这个拆分器会按时间周期划分训练集和测试集:训练集包含所有实体period <= t的数据,测试集包含所有实体period = t+1的数据,循环迭代覆盖可用周期。

import numpy as np
from sklearn.model_selection import BaseCrossValidator

class PanelTimeSeriesSplit(BaseCrossValidator):
    def __init__(self, n_splits=5):
        self.n_splits = n_splits
        
    def get_n_splits(self, X=None, y=None, groups=None):
        return self.n_splits
    
    def split(self, X, y=None, groups=None):
        # 提取并排序所有唯一时间周期
        periods = np.sort(X['period'].unique())
        # 计算拆分点,确保训练集和测试集有足够数据
        split_points = np.linspace(1, len(periods)-1, self.n_splits, dtype=int)
        
        for split in split_points:
            # 训练集:所有period <= periods[split-1]的数据
            train_mask = X['period'] <= periods[split-1]
            # 测试集:所有period == periods[split]的数据
            test_mask = X['period'] == periods[split]
            
            train_idx = X[train_mask].index
            test_idx = X[test_mask].index
            
            yield train_idx, test_idx

步骤2:结合超参数搜索工具使用

以随机森林分类器为例,用RandomizedSearchCV配合自定义拆分器完成调优:

from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import RandomizedSearchCV
import scipy.stats as stats

# 定义模型与超参数空间
model = RandomForestClassifier(random_state=42)
param_dist = {
    'n_estimators': stats.randint(50, 200),
    'max_depth': [3, 5, 7, None],
    'min_samples_split': stats.randint(2, 10)
}

# 初始化自定义交叉验证拆分器
tscv = PanelTimeSeriesSplit(n_splits=6)  # 拆分数量需小于总周期数-1,示例有10个周期,最多可做8次拆分

# 初始化超参数搜索器
search = RandomizedSearchCV(
    model,
    param_distributions=param_dist,
    n_iter=20,
    cv=tscv,
    scoring='accuracy',
    n_jobs=-1,
    random_state=42
)

# 预处理特征:对类别特征(country)做独热编码
X = df[['country', 'period', 'a_feature']]
X_encoded = pd.get_dummies(X, columns=['country'])
y = df['target']

# 执行超参数搜索
search.fit(X_encoded, y)

# 输出结果
print("最优超参数:", search.best_params_)
print("交叉验证最优得分:", search.best_score_)

关键注意事项

  • 数据排序:确保数据按实体和时间周期排序,避免训练集混入未来数据。
  • 类别特征处理:实体标签(如示例中的country)需做编码(独热编码、目标编码等),否则模型无法处理。
  • 拆分数量限制:n_splits不能超过总周期数-1,每个拆分需要至少1个训练周期和1个测试周期。
  • 模型兼容性:该方案适用于所有Scikit-learn兼容的模型,包括回归、分类模型。

内容的提问来源于stack exchange,提问作者Slash

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 10:53:09