
sktime Splitters 完整指南从时间序列分割到交叉验证的滑动/扩展窗口体系【免费下载链接】sktimeA unified framework for machine learning with time series项目地址: https://gitcode.com/GitHub_Trending/sk/sktimesktime.split是 sktime 中负责时间序列分割与重采样splitting and resampling的官方模块为单条序列Series、面板Panel与分层Hierarchical时间序列提供统一的 train/test 切分抽象。所有分割器共享同一套BaseSplitter接口——split、split_loc、split_series、get_n_splits与get_cutoffs并通过 tag 体系split_type取temporal或instance区分按时间切与按实例切两类策略。读完本文你将掌握如何用temporal_train_test_split快速切分数据、如何用滑动/扩展窗口分割器搭建完整的回测与调参流程、如何用SameLocSplitter/Repeat/SyncToLongest组合出更复杂的切分策略以及如何在分层数据上按实例整条序列划分训练/测试集。一、模块定位sktime 的分割器全景官方 API 参考split.rst将该模块描述为 contains algorithms for splitting and resampling data。与sklearn.model_selection.TimeSeriesSplit仅支持整数索引 扩展窗口不同sktime的分割器天然支持多种索引类型整数索引、pd.DatetimeIndex、pd.PeriodIndex以及pd.Timedelta/pd.DateOffset形式的window_length多种数据形态Series、Panel、Hierarchical分割逻辑对每条序列独立生效与预测语义对齐分割结果直接由预测步长forecasting horizon驱动测试折由fh相对训练窗口终点确定。1.1 如何列出所有分割器文档明确给出了两条官方路径from sktime.registry import all_estimators # 列出全部 splitter可按 tag 过滤 splitters all_estimators(estimator_typessplitter) # 查看全部合法 tag from sktime.registry import all_tags all_tags(estimator_typesplitter)此外官方还维护了一张带 tag 搜索能力的Estimator Search Page即 estimator_overview.md 生成的页面在该页的 Estimator type 下拉框中选择 splitter 即可按 tag 交互式筛选。1.2 分割器的统一基类接口所有分割器继承自 BaseSplitter其核心语义是把序列y(y_1,…,y_T)切为不重叠的训练段(y_{t(1)},…,y_{t(k)})与测试段(y_{t(k1)},…,y_{t(kl)})。基类公开四组关键方法方法作用split(y)生成iloc整数位置索引的训练/测试对生成器split_loc(y)生成loc标签索引的训练/测试对split_series(y)直接返回切分后的数据容器保持原 mtype是split的便捷封装get_n_splits(y)返回切分轮数基类默认实现为len(list(self.split(y)))get_cutoffs(y)返回各训练窗口终点cutoff对应的iloc整数位置基类还定义了三个重要 tag见 BaseSplitter._tagssplit_typetemporal按时间切或instance按实例切split_hierarchical是否原生支持分层索引否则会走_split_vectorized对每个实例广播切分split_series_usesiloc或loc决定split_series底层调用split还是split_loc。值得注意的是_split_vectorizedsktime/split/base/_base_splitter.py#L164-L197当输入是pd.MultiIndex且分割器不支持分层时基类按除最后一层时间层外的所有层划分实例对每个实例分别调用_split再把结果按锚点偏移拼回原索引——这就是对每条序列独立切分的实现来源。二、快速上手temporal_train_test_split单次切分工具对于只想把一条序列切成训练集和测试集的简单场景官方提供了temporal_train_test_split工具函数源码见 sktime/split/temporal_train_test_split.py#L19-L140from sktime.datasets import load_airline from sktime.split import temporal_train_test_split y load_airline() y_train, y_test temporal_train_test_split(y, test_size36) y_test.shape # (36,)2.1 参数语义参数类型默认说明ysktime 兼容容器必填内生时间序列Series/Panel/HierarchicalXsktime 兼容容器None外生序列若提供则与y在同一loc索引处同步切分返回(y_train, y_test, X_train, X_test)test_sizefloat / int /NoneNonefloat 表示测试集占比向上取整ceilint 表示测试样本绝对数None时取 train_size 的补集两者都为None时固定为0.25train_sizefloat / int /NoneNonefloat 表示训练集占比向下取整floorint 表示训练样本绝对数None时取 test_size 的补集fhForecastingHorizonNone若给定则不能再指定test_size/train_size相对fh取序列内最后可匹配的索引绝对fh取对应绝对位置anchorstart/endstart仅当fhNone且两个 size 均非None时生效start从序列开头截取end从序列结尾截取关键行为均可在源码中直接验证比例取整不对称test_size用math.ceiltrain_size用math.floortemporal_train_test_split.py#L236-L239只给test_size时anchor被强制为end训练集是测试集之前的补集只给train_size时anchor被强制为start测试集是训练集之后的补集若数据是 Panel 或 Hierarchical比例与切分会按每条序列独立计算内部实现上fh分支委托给ForecastingHorizonSplittersize 分支委托给TemporalTrainTestSplitterX的切分则复用SameLocSplitter见 5.2 节保证X与y使用完全一致的索引temporal_train_test_split.py#L113-L138。面板与分层示例来自函数 docstringfrom sktime.utils._testing.panel import _make_panel from sktime.utils._testing.hierarchical import _make_hierarchical # 面板每个实例取最后 5 个时间点 y _make_panel(n_instances2, n_timepoints20) y_train, y_test temporal_train_test_split(y, test_size5) y_test.shape # (10, 1) # 分层按比例 0.2 逐序列切分 y _make_hierarchical() y_train, y_test temporal_train_test_split(y, test_size0.2)三、时间索引分割器Time Index Splitters时间索引分割器按时间先后顺序切分一条或多条序列是预测模型评估backtesting与超参调优tuning的主力工具统一带有 tagsplit_typetemporal。完整清单见 split.rst下面按功能分组逐一讲解并附源码级参数细节。3.1 指定 cutoff 型CutoffSplitter与CutoffFhSplitterCutoffSplittersktime/split/cutoff.py#L103-L269在用户给定的 cutoff 点处切出定长训练窗口cutoffslist / np.ndarray / pd.Index训练窗口终点可为整数或日期时间索引fh预测步长决定测试折的索引默认1window_length训练窗口长度默认10可为 int / timedelta /pd.DateOffset。对 cutoffk_i与窗口长度w训练窗口为(k_i-w1, …, k_i)测试窗口为(k_ih_1, …, k_ih_H)get_n_splits恒等于 cutoff 个数import numpy as np from sktime.split import CutoffSplitter ts np.arange(10) splitter CutoffSplitter(fh[2, 4], cutoffsnp.array([3, 5]), window_length3) list(splitter.split(ts)) # [(array([1, 2, 3]), array([5, 7])), (array([3, 4, 5]), array([7, 9]))]CutoffFhSplittersktime/split/cutoff.py#L272-L404则不用窗口长度而是由fh直接定义测试折每个 cutoffk处训练折为所有 ≤ k 的 loc 索引fh为None时测试折为所有严格 k 的索引fh为相对值时测试折为fh.to_absolute_index(cutoffk)为绝对值时测试折就是fh本身。由于测试折由fh的索引直接给出即便数据索引规则测试折也可能不连续这一点与CutoffSplitter有本质区别import pandas as pd from sktime.split import CutoffFhSplitter y pd.period_range(2020-01-01, periods10, freqD) cutoff pd.PeriodIndex([2020-01-04, 2020-01-07], freqD) splitter CutoffFhSplitter(cutoffcutoff, fh[1, 2]) [(t[0].tolist(), t[1].tolist()) for t in splitter.split(y)] # [([0, 1, 2, 3], [4, 5]), ([0, 1, 2, 3, 4, 5, 6], [7, 8])]3.2 单窗口型SingleWindowSplitterSingleWindowSplittersktime/split/singlewindow.py#L26-L191产生唯一一个训练/测试窗口训练集终点 len(y) - fh[-1] - 1起点 终点 - window_length 1负数则截为 0fh决定测试折测试索引 训练终点 fhwindow_length默认10支持 int / timedelta /pd.DateOffset。重要文档特别强调该分割器始终使用位置索引iloc即使window_length是 timedelta 或pd.DateOffset也按位置数量解释而非标签索引。官方示例from sktime.split import SingleWindowSplitter ts np.arange(10) splitter SingleWindowSplitter(fh[2, 4], window_length3) list(splitter.split(ts)) # [(array([3, 4, 5]), array([7, 9]))]即train_end 10 - 4 - 1 5训练窗口[5-31, …, 5] [3,4,5]测试[52, 54] [7, 9]。3.3 滑动窗口型SlidingWindowSplitter与SlidingGreedySplitterSlidingWindowSplittersktime/split/slidingwindow.py#L15-L133以固定window_length的窗口从序列起点开始逐步滑动每次滑动step_length测试折由fh相对训练窗口终点确定参数类型默认说明fhint / list / np.array1相对预测步长决定测试窗口window_lengthint / timedelta /pd.DateOffset10训练窗口长度step_lengthint / timedelta /pd.DateOffset1窗口步进长度initial_window同上None首个窗口的长度若设置第一个训练窗口用initial_window而非window_length适合需要最少训练数据的算法其余折仍为window_lengthstart_with_windowboolTrueTrue从完整训练窗口开始False从空窗口开始等价于initial_window0官方用 ASCII 图直观展示了window_length5, step_length1, fh[1,2,3]的折形态*训练、x测试| * * * * * x x x - - - | | - * * * * * x x x - - | | - - * * * * * x x x - | | - - - * * * * * x x x |折数由数据总长决定直到最后一个测试窗口落入观测索引内即满足k_n h_H t_N的最大整数nfrom sktime.split import SlidingWindowSplitter ts np.arange(10) splitter SlidingWindowSplitter(fh[2, 4], window_length3, step_length2) list(splitter.split(ts)) # [(array([0, 1, 2]), array([4, 6])), (array([2, 3, 4]), array([6, 8]))]SlidingGreedySplittersktime/split/slidinggreedy.py与滑动窗口类似但采用贪心推进首个训练窗口从序列起点开始其测试窗口后续又成为下一个训练窗口的一部分训练/测试窗口在时间上首尾相接、连续铺满序列适合需要覆盖全部观测、不重叠浪费的滚动评估场景。3.4 扩展窗口型ExpandingWindowSplitter、ExpandingCutoffSplitter、ExpandingGreedySplitter、ExpandingSlidingWindowSplitterExpandingWindowSplittersktime/split/expandingwindow.py#L14-L104是经典的起点固定、终点后移策略训练集逐步扩大测试集由fh决定、大小固定。参数为fh默认 1、initial_window初始训练折长度默认 10、step_length步进默认 1。官方 ASCII 图initial_window5, step_length1, fh[1,2,3]| * * * * * x x x - - - | | * * * * * * x x x - - | | * * * * * * * x x x - | | * * * * * * * * x x x |from sktime.split import ExpandingWindowSplitter ts np.arange(10) splitter ExpandingWindowSplitter(fh[2, 4], initial_window5, step_length2) list(splitter.split(ts)) # [(array([0, 1, 2, 3, 4]), array([6, 8]))]同一家族的另外三个分割器ExpandingCutoffSplittersktime/split/expandingcutoff.py等价于在给定 cutoffs 上执行扩展窗口训练窗口从序列起点延伸到每个 cutoffExpandingGreedySplittersktime/split/expandinggreedy.py扩展窗口的贪心版本训练窗口逐折向后吸收前一折的测试窗口全程无观测被遗漏ExpandingSlidingWindowSplittersktime/split/expandingslidingwindow.py允许设置initial_window先从短窗口起步再转为标准扩展窗口逐步扩大。这一家族的共同点训练集单调增长最早的历史观测始终被保留。3.5 预测步长驱动型ForecastingHorizonSplitterForecastingHorizonSplittersktime/split/fh.py#L12-L105只产生一个切分但完全由ForecastingHorizon驱动同时支持相对与绝对步长相对fh训练集为严格早于t_N - h_H的所有时间点测试集为(t_jh_1, …, t_jh_H)绝对fh训练集为严格早于h_1的所有时间点测试集为(h_1, …, h_H)。import pandas as pd from sktime.split import ForecastingHorizonSplitter y pd.Series(range(8)) splitter ForecastingHorizonSplitter(fh[1, 2]) train, test next(splitter.split(y)) train.tolist() # [0, 1, 2, 3, 4, 5] test.tolist() # [6, 7]docstring 中提醒了两个使用注意事项其一对不连续的fh训练与测试集的并集不会覆盖整条序列其二对≤ 0 的相对步长训练集里会出现晚于部分测试点的时间点造成数据泄漏leakage仅在明确有需要时才应如此使用。该分割器也是temporal_train_test_split(fh...)的内部执行引擎。3.6 样本量驱动型TemporalTrainTestSplitterTemporalTrainTestSplittersktime/split/temporal_train_test_split.py#L143-L306是temporal_train_test_split在 size 分支背后的分割器类参数为train_size、test_size、anchor语义与 2.1 节表格完全一致。它的切分按连续iloc位置进行对不规则时间索引同样成立只产生一个折import numpy as np from sktime.split import TemporalTrainTestSplitter ts np.arange(10) splitter TemporalTrainTestSplitter(test_size0.3) list(splitter.split(ts)) # [(array([0, 1, 2, 3, 4, 5, 6]), array([7, 8, 9]))]test_size0.3对len10向上取整为 3测试集取最后 3 个位置。分数化参数行为ceil/floor与anchor的自动推导逻辑可直接在 temporal_train_test_split.py#L228-L261 中核对。3.7 底层实现BaseWindowSplitter与参数校验滑动/扩展窗口家族共同继承BaseWindowSplittersktime/split/base/_base_windowsplitter.py#L88-L150它负责统一的参数兼容性校验_check_inputs_for_compatibility确保fh、initial_window、window_length、step_length的类型互相匹配不能混用 int 与 timedelta_check_window_lengths要求window_length max(fh) len(y)且initial_window max(fh) len(y)否则抛出带完整诊断信息的ValueErrorsktime/split/base/_base_windowsplitter.py#L27-L85。initial_window设置后首个折由_split_for_initial_window单独产出之后再连续产出window_length折。这套首窗口 常规窗口的结构正是initial_window与start_with_window参数协同工作的底层实现。四、实例分割器Instance Splitters实例分割器针对面板或分层时间序列**按实例索引整条序列的标识**切分——训练集与测试集各自包含原始面板中的整条序列对应 tagsplit_typeinstance见 split.rst。InstanceSplittersktime/split/instance.py#L18-L80是这一类别目前唯一的官方实现其思路是把 sklearn 的分割器套用在实例索引上参数cv接受任意 sklearn splitter如KFold、StratifiedKFold实例索引 面板/分层索引中除最后一层时间层外的所有层级返回的iloc/loc索引仍指向原始y的位置而非实例索引本身若输入不是MultiIndex内部会自动构造一层全零实例索引以保证可分割sktime/split/instance.py#L58-L61。from sktime.split import InstanceSplitter from sktime.utils._testing.hierarchical import _make_hierarchical from sklearn.model_selection import KFold y _make_hierarchical() splitter InstanceSplitter(KFold(n_splits3)) list(splitter.split(y))在分层数据上做按序列划分的分类/聚类评估每个实例整体进入训练或测试时InstanceSplitter是标准入口。五、分割器组合Compositionssplit.rst专列了一节 Time index splitter composition收录 4 个用于构造更复杂切分策略的组合器SyncToLongest、Repeat位于 sktime/split/compose/经sktime.split.compose导出、SameLocSplitter、TestPlusTrainSplitter。5.1SyncToLongest让时间分割器适配不等长面板SyncToLongestsktime/split/compose/_sync_to_longest.py#L18-L90把任意时间分割器包装起来使其在不等长面板上正常工作折cutoff取自面板中最长的那条序列每个折中其他实例在其自身可用历史范围内尽量覆盖到该 cutoff只要它能盖满完整预测步长并具备足够训练历史不符合条件的实例从该折中剔除而不是像默认base_cv那样截断到最短实例每个折本身仍是一个面板但不同折包含的实例数可以不同前提是所有实例共享可比的时间索引例如都在同一最新时间戳截止。若y是单条序列或所有实例等长且索引一致SyncToLongest行为与base_cv完全一致。参数base_cv底层时间分割器如SlidingWindowSplitter、min_length可选实例至少需要的历史观测数None时仅包含能提供完整训练窗口的实例。5.2SameLocSplitter跨序列复刻同一组 loc 切分SameLocSplittersktime/split/sameloc.py#L17-L70接受一个分割器cv和一条模板序列y_template然后在目标序列y上产生与cv作用于y_template完全相同的 loc 索引切分。这在需要多序列共享同一套时间切分时非常关键——比如外生变量X与内生变量y必须严格对齐temporal_train_test_split对X的切分正是复用它实现。官方示例from sktime.datasets import load_airline from sktime.split import ExpandingWindowSplitter, SameLocSplitter y load_airline() y_template y[:60] cv_tpl ExpandingWindowSplitter(fh[2, 4], initial_window24, step_length12) splitter SameLocSplitter(cv_tpl, y_template) # 以下两者等价 list(cv_tpl.split(y_template)) list(splitter.split(y))SyncToLongest的文档还特别建议若把它用作evaluate中显式的cv_X应先用SameLocSplitter(TestPlusTrainSplitter(cv), y)包装以保证X与y的逐折实例选择完全一致否则会因X的覆盖范围不同而出现两套实例集合不一致的静默错误。5.3Repeat重复分割器Repeatsktime/split/compose/_repeat.py#L11-L62为已有分割器增加重复次数支持两种模式参数类型默认说明splitterBaseSplitter实例必填被重复的分割器timesint1重复次数modeentry/sequenceentryentry逐个重复每个折s1,s1,s2,s2,s3,s3sequence整段重复整个折序列s1,s2,s3,s1,s2,s3random_repeatboolFalse为True时每次重复独立克隆一个带伪随机的分割器注意若splitter内已设置随机种子效果等同False5.4TestPlusTrainSplitterTestPlusTrainSplittersktime/split/testplustrain.py把训练折 测试折合并为新的训练集再叠加后续测试折用于扩展评估窗口类的组合策略例如上面evaluate默认的cv_X包装即使用TestPlusTrainSplitter(cv)使被评估的模型能看到更多历史数据。六、工程实践与evaluate回测及调参流程衔接官方文档明确建议做性能评估时应使用完整回测而非单次切分——Forecasting users interested in performance evaluation are advised to use full backtesting instead of a single split, e.g., viaevaluate并指向 forecasting API reference。一条典型的评估流水线可以这样组织from sktime.forecasting.model_evaluation import evaluate from sktime.forecasting.naive import NaiveForecaster from sktime.split import ExpandingWindowSplitter y load_airline() fh [1, 2, 3] cv ExpandingWindowSplitter(fhfh, initial_window24, step_length12) results evaluate( forecasterNaiveForecaster(strategylast), yy, cvcv, )实践中可以遵循几条经验原则需要平滑逐折推进、覆盖全部观测→SlidingGreedySplitter/ExpandingGreedySplitter需要控制首折规模、保证最小训练量→ 滑动/扩展家族配合initial_window需要多序列严格对齐切分→SameLocSplitterevaluate内部正是用它同步X需要在分层/面板数据上按整条序列划分→InstanceSplitter sklearn 分割器需要让时间分割器兼容不等长面板→SyncToLongest包装。get_cutoffs在自定义回测中也很有用例如CutoffSplitter.get_cutoffs会返回按升序排序后的 cutoff 整数位置对日期时间型输入还会先映射回整数位置可用于绘制每个 cutoff 处模型表现的诊断图。七、补充验证与测试体系仓库为分割器配备了完整的自动化测试可作为行为契约参考基类契约测试sktime/split/base/tests/test_base.py 验证split/split_loc/split_series三套 API 的一致性全量分割器测试sktime/split/tests/ 下每个分割器均有对应测试文件覆盖默认参数与自定义参数各分割器的get_test_params提供了有趣的测试实例例如CutoffSplitter.get_test_params返回{cutoffs: np.array([3, 7, 10])}与{cutoffs: [6, 9]}两组配置sktime/split/cutoff.py#L250-L269框架级回归sktime/tests/test_all_estimators.py会对所有注册的 splitter 统一跑估计器通用检查因此新增分割器时必须满足基类约定的接口与 tag 规范。若需要把自定义分割器注册进all_estimators(estimator_typessplitter)的检索体系需遵循 registry 模块 的注册规范并确保实现_split/get_n_splits/get_cutoffs与_tags。八、总结sktime.split用统一的BaseSplitter接口把时间分割与实例分割两类需求收敛为一套可组合的构件temporal_train_test_split满足快速切分滑动/扩展窗口家族覆盖绝大多数回测与调参场景CutoffFhSplitter与ForecastingHorizonSplitter让切分与预测步长语义精确对齐而SameLocSplitter、Repeat、SyncToLongest、TestPlusTrainSplitter则提供了跨序列对齐、重复抽样与不等长面板适配等进阶能力。理解每个分割器的fh/window_length/step_length/initial_window/anchor等核心参数及其默认值分别对应 1 / 10 / 1 /None/start是正确搭建回测实验的第一步更复杂的策略组合则可以从 split.rst 的清单出发逐个对照源码与测试验证其行为。【免费下载链接】sktimeA unified framework for machine learning with time series项目地址: https://gitcode.com/GitHub_Trending/sk/sktime创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考