跳转到主要内容

基于时间的交叉验证

项目描述

license-shield interrogate-badge Ruff coverage-badge versions-shield

基于时间的交叉验证

timebasedcv 是一个Python代码库,提供了一个基于时间的交叉验证策略。


文档 | 仓库 | 问题追踪器


免责声明 ⚠️

此代码库是实验性的,并且在我的用例中工作。很可能存在一些没有完全覆盖的情况,并且它可能会崩溃(严重)。如果您发现它们,请随时在问题页面{:target="_blank"}上打开一个问题。

描述 ✨

当前实现中的scikit-learn TimeSeriesSplit{:target="_blank"} 缺乏在相同时间段(或时间单位)内具有多个样本的灵活性。

timebasedcv 通过提供一个基于 时间段 的交叉验证策略来解决此类问题,而不是基于样本数量。当数据具有时间依赖性时,此策略很有用,并且分割应将同一时间窗口内的样本保留在一起。

时间数据泄露是一个问题,我们希望通过提供分割,确保过去和未来得到很好的分离,从而防止数据泄露在模型交叉验证中造成破坏。

再次强调,这些分割点仅取决于时间段,而不是观测数。

特征 📜

我们引入了两个主要类别

  • TimeBasedSplit 允许根据时间单位(频率)、训练大小、测试大小、间隔、步长、窗口类型和模式定义分割。请注意,TimeBasedSplitscikit-learn CV Splitters 不兼容。实际上,我们做出了(有意见的)选择

    • .split(...) 返回切片数组,而 scikit-learn CV Splitters 返回分割的培训集和测试集索引。
    • 需要将时间序列作为输入传递给 .split(...) 方法,而 scikit-learn CV Splitters 只需要提供 X, y, groups.split(...)
    • 此类时间序列用于生成布尔掩码,我们将原始数组切片成每个分割的培训集和测试集。
  • 考虑到上述选择,我们还提供了一种 scikit-learn 兼容的分割器: TimeBasedCVSplitter。考虑到 .split(...) 所需的签名以及 CV Splitters 需要事先知道分割数,TimeBasedCVSplitter 使用包含用于生成每个分割训练集和测试集索引的时间信息的时间序列进行初始化。

安装 💻

TL;DR

python -m pip install timebasedcv

有关更多信息,请参阅专门的 安装 部分。

快速入门 🏃

以下代码片段是您开始所需的所有内容,但请考虑查看文档的 入门 部分,以获取有关如何使用库的详细指南。

主要结论应该是 TimeBasedSplit 允许有很多灵活性,但需要指定一个很长的参数列表。这使得库非常强大且灵活,可以涵盖大多数用例。

首先让我们生成一些具有不同每天点数的数据

import numpy as np
import pandas as pd

RNG = np.random.default_rng(seed=42)

dates = pd.Series(pd.date_range("2023-01-01", "2023-01-31", freq="D"))
size = len(dates)

df = (pd.concat([
        pd.DataFrame({
            "time": pd.date_range(start, end, periods=_size, inclusive="left"),
            "a": RNG.normal(size=_size-1),
            "b": RNG.normal(size=_size-1),
        })
        for start, end, _size in zip(dates[:-1], dates[1:], RNG.integers(2, 24, size-1))
    ])
    .reset_index(drop=True)
    .assign(y=lambda t: t[["a", "b"]].sum(axis=1) + RNG.normal(size=t.shape[0])/25)
)

df.set_index("time").resample("D").agg(count=("y", np.size)).head(5)
            count
time
2023-01-01      2
2023-01-02     18
2023-01-03     15
2023-01-04     10
2023-01-05     10

然后让我们实例化 TimeBasedSplit

from timebasedcv import TimeBasedSplit

tbs = TimeBasedSplit(
    frequency="days",
    train_size=10,
    forecast_horizon=5,
    gap=1,
    stride=3,
    window="rolling",
    mode="forward",
)

现在让我们使用提供的 TimeBasedSplit 实例分割数据

X, y, time_series = df.loc[:, ["a", "b"]], df["y"], df["time"]

for X_train, X_forecast, y_train, y_forecast in tbs.split(X, y, time_series=time_series):
    print(f"Train: {X_train.shape}, Forecast: {X_forecast.shape}")
Train: (100, 2), Forecast: (51, 2)
Train: (114, 2), Forecast: (50, 2)
...
Train: (124, 2), Forecast: (40, 2)
Train: (137, 2), Forecast: (22, 2)

如我们所见,每个分割不一定有相同数量的点,这是因为时间序列每天的点数不同。

一图胜千言,让我们可视化分割(蓝色点表示训练点,而红色点表示预测点)

cross-validation

贡献 ✌️

请参阅文档网站上的 贡献指南

许可 👀

项目具有 MIT 许可证

项目详情


下载文件

下载适用于您平台的文件。如果您不确定选择哪个,请了解有关 安装包 的更多信息。

源分布

timebasedcv-0.2.1.tar.gz (16.2 kB 查看哈希值)

上传时间 源码

构建版本

timebasedcv-0.2.1-py3-none-any.whl (19.1 kB 查看哈希值)

上传时间 Python 3