用 Python 轻松实现时间序列预测:共形预测模型 Conformal Prediction Models

文中内容仅限技术学习与代码实践参考,市场存在不确定性,技术分析需谨慎验证,不构成任何投资建议。

Darts

Darts 是一个 Python 库,用于对时间序列进行用户友好型预测和异常检测。它包含多种模型,从 ARIMA 等经典模型到深度神经网络。所有预测模型都能以类似 scikit-learn 的方式使用 fit()predict() 函数。该库还可以轻松地对模型进行回溯测试,将多个模型的预测结果结合起来,并将外部数据考虑在内。Darts 支持单变量和多变量时间序列和模型。基于 ML 的模型可以在包含多个时间序列的潜在大型数据集上进行训练,其中一些模型还为概率预测提供了丰富的支持。

共形预测模型

以下是 Darts 中共形预测模型的演示。

简而言之:

  • Darts 中的共形预测无需任何分布假设即可构建有效的预测区间。
  • 我们使用分割共形预测 (SCP),因为它简单高效。
  • 您可以将共形预测应用于任何预训练的全局预测模型。
  • 为了提升您的体验,我们的共形模型会自动从您的输入序列中提取生成区间所需的相关校准数据。
  • 我们提供一些实用功能(校准长度 cal_length 和校准步长 cal_stride),用于配置提取过程,并提高您的共形模型的自适应性和效率。
  • 共形预测支持所有用例(单变量和多变量、单个和多个序列以及单期和多期预测,提供直接分位数预测或抽样预测)。
  • 我们将使用四个真实数据示例演示如何使用和评估共形预测。

以下内容是将原文逐字逐句、完整无删减地翻译成中文。所有链接、图片地址、表格属性、代码均保持原样,仅翻译说明文字与注释。

# fix python path if working locally
from utils import fix_pythonpath_if_working_locally

fix_pythonpath_if_working_locally()
%load_ext autoreload
%autoreload 2
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd

from darts import concatenate, metrics
from darts.datasets import ElectricityConsumptionZurichDataset
from darts.models import ConformalNaiveModel, ConformalQRModel, LinearRegressionModel

时间序列预测的共形预测

共形预测是一种构造预测区间的技术,旨在在不假设数据分布的情况下,在有限样本中实现有效覆盖。来源

换句话说:如果我们想要一个预测区间,该区间能在某段时间内包含80%的所有实际值,那么共形模型会尝试生成这样的区间,使得实际值有80%的概率落在其中。

有多种技术可以执行共形预测。在Darts中,我们目前使用Split共形预测SCP, Lei et al., 2018)(经过一些不错的适配),因为它简单且高效。

Split共形预测

SCP通过在基础模型的预测结果上添加指定置信水平的校准预测区间来实现。它涉及将数据分为训练(+可选验证)集和校准(+测试)集。模型在训练集上训练,校准集用于计算预测区间,以确保它们以期望的概率包含真实值。

优点
  • 有效覆盖:提供在有限样本上保证包含真实值的指定置信水平的有效预测区间。

  • 模型无关:可应用于任何预测模型:

    • 可为点预测模型添加校准预测区间

    • 或在概率预测模型的情况下校准预测区间

  • 无分布假设:除要求校准集上的误差是可交换的(例如,我们无需假设数据是正态分布的,然后使用GaussianLikelihood拟合模型)外,无需对数据做任何分布假设。

  • 高效:Split共形预测高效,因为它不需要重新训练模型。

  • 可解释:方法简单,因此可解释。

  • 有用应用:它用于在多个行业中提供更可靠和信息丰富的预测,以帮助决策。参见这篇关于共形预测的文章

缺点
  • 需要校准集:共形预测需要另一个数据/保留集,仅用于计算校准预测区间。对于小型数据集,这可能效率不高。

  • 校准数据的可交换性(a):预测区间的准确性取决于校准数据(或更准确地说,是在校准集上产生的预测误差)的代表性。如果预测误差存在分布偏移(例如,序列有趋势,但预测模型无法预测趋势),则无法保证覆盖。

  • 保守性(a):可能产生比必要更宽的区间,导致预测保守。

  1. Darts共形模型有一些参数,用于控制校准集的提取,以提高适应性(参见此处更多信息)。

Darts共形模型

Darts的共形模型为任何预训练的全局预测模型的预测结果添加校准预测区间。无需训练共形模型本身(例如,无需fit()),可直接调用predict()historical_forecasts()。在后台,Darts将自动从输入序列的过去中提取校准集,并用其生成校准预测区间(参见此处更多详情)。

重要:传递给预测方法的 series 不应与用于训练预测模型的序列有任何重叠,否则会导致过于乐观的预测区间。

模型支持

Darts中的所有共形模型均支持:

  • 任何预训练的全局预测模型作为基础预测器(可在此处找到列表

  • 单变量多变量预测(单列/多列)

  • 单个多个序列预测

  • 单步多步预测

  • 生成单个多个校准预测区间

  • 直接分位数值预测(区间边界)或从这些分位数值采样预测

  • 基于底层预测模型的任何协变量

直接区间预测或采样预测

共形模型是概率性的,因此您可以通过两种方式预测(调用predict()historical_forecasts()等):

  • 直接预测校准分位数区间边界(示例在此处)。

    • predict(..., predict_likelihood_parameters=True)
  • 通过从这些校准分位数区间中采样来生成随机预测(示例在此处):

    • predict(..., num_samples=1000)

后台工作流程

注意:cal_lengthcal_stride将在下面进一步解释。

通常,模型生成一个校准预测/预测结果的工作流程如下(使用predict()):

  • 提取校准集:每个共形预测的校准集会自动从输入序列相对于预测起点的最近过去中提取。要使用的校准示例(预测误差/非一致性分数)数量可在模型创建时通过参数cal_length定义。注意,当使用cal_stride>1时,需要更长的历史记录,因为校准示例是通过跨步历史预测生成的。

  • 在校准集上生成历史预测(使用预测模型),步长为cal_stride

  • 计算这些历史预测的误差/非一致性分数(特定于每个共形模型)

  • 从误差/非一致性分数计算分位数值(使用我们在模型创建时通过参数quantiles设置的期望分位数)。

  • 计算共形预测:使用这些分位数值,将校准区间添加到预测模型的预测结果中(或调整现有区间)。

对于多步预测,上述内容分别应用于范围内的每一步。

当计算historical_forecasts()backtest()residuals()等时,上述内容应用于每个预测(预测模型的历史预测仅生成一次以提高效率)。

可用的共形模型

在撰写本文时(Darts版本0.32.0),我们有两个共形模型:

ConformalNaiveModel

任何预训练的全局预测模型的中位数预测添加校准区间。它支持两种对称模式:

  • symmetric=True

    • 下区间和上区间边界以相同幅度校准。

    • 非一致性分数:使用绝对误差ae()在校准集上计算非一致性分数。

  • symmetric=False

    • 下区间和上区间边界分别校准。

    • 非一致性分数:使用误差err()在校准集上计算上边界的非一致性分数,使用-err()计算下边界的非一致性分数。

ConformalQRModel(共形化分位数回归模型)

校准预训练概率全局预测模型的分位数预测。它支持两种对称模式:

Darts特性使您的共形模型更具适应性

Split共形预测-缺点中所述,校准集对我们共形预测技术的有效性有很大影响。

我们实现了一些很酷的特性,使校准集的自动提取对您来说更加强大。

我们所有的共形模型在模型创建时都有以下两个参数:

  • cal_length:用于每次共形预测(以及范围内的每一步)校准的最近过去非一致性分数(NCS)的数量。

    • 如果为None,则表现为扩展窗口模式

    • 如果>=1,则使用移动固定长度窗口模式

    • 好处:

      • 使用cal_length使您的模型对NCS的分布偏移反应更快。

      • 使用cal_length降低了执行校准的计算成本。

    • 注意:使用足够大的值以确保有足够示例进行校准。

  • cal_stride:(默认为1)在计算校准集上的历史预测和非一致性分数时应用的步长(两个连续预测之间的时间步数)。

    • 如果我们希望按计划运行模型(例如每24小时一次),并且只关心在此计划上产生的NCS,则这很有用。

    • 注意:cal_stride>1需要更长的series历史记录(大约cal_length * stride个点)。

示例

我们将展示四个示例:

  1. 如何执行共形预测并基于量化不确定性比较不同模型。为简单起见,我们将使用单步范围n=1

  2. 如何执行多步共形预测

  3. 如何按计划执行多步共形预测

  4. 共形化分位数回归的示例

输入数据集

对于这两个示例,我们使用来自瑞士苏黎世家庭的电力消费数据集。

数据集具有15分钟频率(15分钟时间间隔),但我们将其重采样为每小时频率以保持简单。

为简单起见,我们不会使用任何协变量,仅专注于我们想要预测的电力消费作为目标。共形模型的协变量支持和API与基础预测器相同。

目标序列(我们想要预测的序列):- Value_NE5:电网5级家庭的电力消费(单位:kWh)。

series = ElectricityConsumptionZurichDataset().load().astype(np.float32)

# 提取目标并按小时频率重新采样
series = series["Value_NE5"].resample(freq="h")

# 绘制两周的每小时消耗量
ax = series[: 2 * 7 * 24].plot()
ax.set_ylabel("El. Consuption [kWh]")
ax.set_title("Target series (Electricity Consumption) extract");

img

提取训练、校准和测试集。注意cal不与训练集train重叠。

train_start = pd.Timestamp("2015-01-01")
cal_start = pd.Timestamp("2016-01-01")
test_start = pd.Timestamp("2017-01-01")
test_end = pd.Timestamp("2018-01-01")

train = series[train_start : cal_start - series.freq]
cal = series[cal_start : test_start - series.freq]
test = series[test_start:test_end]

ax = train.plot(label="train")
cal.plot(label="val")
test.plot(label="test")

ax.set_ylabel("El. Consuption [kWh]")
ax.set_title("Dataset splits");

img

示例1:在单步预测中比较不同模型

让我们看看如何在Darts中使用共形预测。我们将展示如何:

  • 使用共形预测(预测和历史预测)

  • 评估预测区间(简单预测和回溯测试)。

  • 使用共形预测比较两个不同的基础预测模型。

为演示该过程,我们首先仅关注一个基础预测模型。

训练基础预测器

让我们使用LinearRegressionModel作为基础预测模型。我们配置它使用最后两小时作为回望以预测下一小时(单步范围;多步范围将在示例2中介绍)。

  • train集上训练

  • cal集结束后预测下一小时

horizon = 1

# 训练模型
model = LinearRegressionModel(lags=2, output_chunk_length=horizon)
model.fit(train)

# 预测
pred = model.predict(n=horizon, series=cal)

# 绘图
ax = series[pred.start_time() - 7 * 24 * series.freq : pred.end_time()].plot(
    label="actual"
)
pred.plot(label="pred")
ax.set_title("First 1-step point prediction");

img

很好,我们有了单步预测。但如果不了解该时间的实际目标值,我们无法估计不确定性。

应用共形预测

现在让我们应用共形预测来量化不确定性。我们使用对称(默认)朴素模型,包括我们想要预测的分位数水平。同时:

  • 我们无需训练/拟合共形模型

  • 我们应向predict()提供一个series,该序列与用于训练模型的序列无重叠。在我们的例子中caltrain无重叠。

  • API与Darts的预测模型相同。

让我们配置共形模型: - 添加90%分位数区间(分位数0.05 - 0.95)( quantiles)。 - 仅考虑最后4周的非一致性分数以校准预测区间( cal_length)。

注意:您可以添加任意数量的区间,例如[0.10, 0.20, 0.50, 0.80, 0.90]将添加80%(0.10 - 0.90)和60%(0.20 - 0.80)区间

quantiles = [0.05, 0.50, 0.95]
four_weeks = 4 * 7 * 24
pred_kwargs = {"predict_likelihood_parameters": True, "verbose": True}

# 创建共形模型
cp_model = ConformalNaiveModel(model=model, quantiles=quantiles, cal_length=four_weeks)

# 共形预测
pred = cp_model.predict(n=horizon, series=cal, **pred_kwargs)

# 绘图
ax = series[pred.start_time() - 7 * 24 * series.freq : pred.end_time()].plot(
    label="actual"
)
pred.plot(label="cp")
ax.set_title("First 1-step conformal prediction");

img

很好,我们可以看到基础模型预测(紫色)周围添加了预测区间(绿松石色、深蓝色)。很明显,预测区间包含实际值。让我们看看如何评估此预测。

评估共形预测

Darts有专门针对预测区间的指标。您可以在我们的指标页面中的_分位数区间指标_下找到它们。您可以将它们用作独立指标或用于回溯测试。

  • (m)ic:(平均)区间覆盖率

  • (m)iw:(平均)区间宽度

  • (m)iws:(平均)区间温克勒分数

  • (m)incs_qr:(平均)分位数回归区间非一致性分数

注意:对于backtest()使用(m)ean指标如mic(),对于residuals()使用每时间步指标如ic()

让我们检查区间覆盖率(实际值落在每个区间内的比率)和区间宽度:

q_interval = cp_model.q_interval  # [(0.05, 0.95)]
q_range = cp_model.interval_range  # [0.9]

def compute_metrics(pred_):
    mic = metrics.mic(series, pred_, q_interval=q_interval)
    miw = metrics.miw(series, pred_, q_interval=q_interval)
    return pd.DataFrame({"Interval": q_range, "Coverage": mic, "Width": miw}).round(2)

compute_metrics(pred)
IntervalCoverageWidth
00.91.03321.12

好的,我们看到区间宽度为3.3 MWh,覆盖率为100%。我们期望覆盖率为90%(在有限样本上)。但到目前为止我们只看了1个示例。它在整个测试集上的表现如何?

# 连接校准集和测试集,以便能够在“测试”开始时间点开始预测
cal_test = concatenate([cal, test], axis=0)

hfcs = cp_model.historical_forecasts(
    series=cal_test,
    forecast_horizon=horizon,
    start=test.start_time(),
    last_points_only=True,  # 返回单个时间序列
    **pred_kwargs,
)
def plot_historical_forecasts(hfcs_):
    fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(16, 4.3))
    test[: 2 * 7 * 24].plot(ax=ax1)
    hfcs_[: 2 * 7 * 24].plot(ax=ax1)
    ax1.set_title("Predictions on the first two weeks")
    ax1.legend(loc="lower center", bbox_to_anchor=(0.5, -0.25), ncol=4, fontsize=9)

    test.plot(ax=ax2)
    hfcs_.plot(ax=ax2, lw=0.2)
    ax2.set_title("Predictions on the entire test set")
    ax2.legend(loc="lower center", bbox_to_anchor=(0.5, -0.25), ncol=4, fontsize=9)

plot_historical_forecasts(hfcs)

img

很好,我们刚刚在不到1秒的时间内完成了一年的共形预测模拟!区间似乎也校准得很好。让我们通过计算所有历史预测(回溯测试)的指标来找出答案。

bt = cp_model.backtest(
    cal_test,
    historical_forecasts=hfcs,
    last_points_only=True,
    metric=[metrics.mic, metrics.miw],
    metric_kwargs={"q_interval": q_interval},
)
bt = pd.DataFrame({"Interval": q_range, "Coverage": bt[0], "Width": bt[1]})
bt
IntervalCoverageWidth
00.90.9016092908.944092

很好!我们的区间确实覆盖了90%的所有实际值。平均宽度/不确定度范围略低于3MWh。

看看覆盖率和宽度随时间的变化也很有趣。

覆盖率指标ic()为每个时间步给出一个二进制值(区间是否包含实际值)。为了获得一段时间内的覆盖率比率,我们计算4周窗口的移动平均。

def compute_moving_average_metrics(hfcs_, metric=metrics.ic):
    """Computes the moving 4-week average of a specific time-dependent metric."""
    # 计算每个时间步的指标
    residuals = cp_model.residuals(
        cal_test,
        historical_forecasts=hfcs_,
        last_points_only=True,
        metric=metric,
        metric_kwargs={"q_interval": q_interval},
    )

    # 对残差应用移动平均法,窗口期为 4 周
    windowed_residuals = residuals.window_transform(
        transforms={"function": "mean", "mode": "rolling", "window": four_weeks}
    )
    return windowed_residuals
covs = compute_moving_average_metrics(hfcs, metrics.ic)
widths = compute_moving_average_metrics(hfcs, metrics.iw)

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 4.3))
covs.plot(ax=ax1, label="coverages")
ax1.set_ylabel("Ratio covered [-]")
ax1.set_title("Moving 4-week average of Interval Coverages")

widths.plot(ax=ax2, label="widths")
ax2.set_ylabel("Width [kWh]")
ax2.set_title("Moving 4-week average of Interval Widths");

img

同样,覆盖率全年稳定在90%左右 -> 共形模型有效。

区间宽度范围从2.5 - 3.5 MWh。宽度对模型性能变化的适应性/响应性主要由cal_length的值控制。

与另一个模型比较

好的,现在让我们将第一个模型的不确定性与一个更强大的回归模型进行比较。

  • 使用最后一周(7*24)的消费作为回望窗口

  • 还使用一天中的小时和一周中的天的循环编码作为未来协变量

过程与第一个模型完全相同,因此我们不再赘述。

add_encoders = {"cyclic": {"future": ["hour", "dayofweek"]}}
input_length = 7 * 24
model2 = LinearRegressionModel(
    lags=input_length,
    lags_future_covariates=(input_length, 1),
    output_chunk_length=1,
    add_encoders=add_encoders,
)
model2.fit(train)

cp_model2 = ConformalNaiveModel(
    model=model2, quantiles=quantiles, cal_length=four_weeks
)
hfcs2 = cp_model2.historical_forecasts(
    series=cal_test,
    forecast_horizon=horizon,
    start=test.start_time(),
    last_points_only=True,
    stride=horizon,
    **pred_kwargs,
)
plot_historical_forecasts(hfcs2)

bt2 = cp_model.backtest(
    cal_test,
    historical_forecasts=hfcs2,
    last_points_only=True,
    metric=[metrics.mic, metrics.miw],
    metric_kwargs={"q_interval": q_interval},
)
bt2 = pd.DataFrame({"Interval": q_range, "Coverage": bt2[0], "Width": bt2[1]})
bt2
IntervalCoverageWidth
00.90.8984131662.243896

img

很好!我们再次实现90%的覆盖率,但平均**区间宽度从2.9 MWh降低到1.7 MWh!**最后,让我们也看看随时间变化的指标并比较我们的两个模型。

covs2 = compute_moving_average_metrics(hfcs2, metrics.ic)
widths2 = compute_moving_average_metrics(hfcs2, metrics.iw)

fig, (ax1, ax2) = plt.subplots(ncols=2, figsize=(12, 4.3))
covs.plot(ax=ax1, label="coverages model 1")
covs2.plot(ax=ax1, label="coverages model 2")
ax1.set_ylabel("Ratio covered [-]")
ax1.set_title("Moving 4-week average of Interval Coverages")

widths.plot(ax=ax2, label="widths model 1")
widths2.plot(ax=ax2, label="widths model 2")
ax2.set_ylabel("Width [kWh]")
ax2.set_title("Moving 4-week average of Interval Widths")

bts = pd.concat([bt, bt2], axis=0).round(3)
bts.index = ["Model 1", "Model 2"]
bts
IntervalCoverageWidth
Model 10.90.9022908.944
Model 20.90.8981662.244

img

两个模型的覆盖率随时间稳定,但模型2的区间宽度始终较低 -> 我们可以明确地说模型2是赢家(通过较低的不确定性)。

示例2:多步预测

多步预测开箱即用。只需设置n>1(或forecast_horizon),模型就会为每一步生成校准预测区间。

multi_horizon = 24
pred = cp_model.predict(n=multi_horizon, series=cal, **pred_kwargs)

# plot
ax = series[pred.start_time() - 7 * 24 * series.freq : pred.end_time()].plot(
    label="actual"
)
pred.plot()
<Axes: xlabel='Timestamp'>

img

哦,为什么我们现在有这么大的区间?这是因为我们使用了模型1(较差的那个),它被训练为仅预测下一小时。然后在后台我们执行自回归以在校准集上生成24小时预测。因此,这导致我们预测得越远,误差/非一致性分数越大,最终导致更高的模型不确定性。

如果我们使用一个被训练为直接预测接下来24小时的基础预测器,我们可以表现得更好:

multi_horizon = 24

model = LinearRegressionModel(lags=input_length, output_chunk_length=multi_horizon).fit(
    train
)
cp_model = ConformalNaiveModel(model=model, quantiles=quantiles, cal_length=four_weeks)

pred = cp_model.predict(n=multi_horizon, series=cal, **pred_kwargs)

# plot
ax = series[pred.start_time() - 7 * 24 * series.freq : pred.end_time()].plot(
    label="actual"
)
pred.plot()
<Axes: xlabel='Timestamp'>

img

示例3:按计划执行多步预测并实现有效覆盖

但如果我们希望按计划执行多步预测怎么办?

例如,我们希望每24小时进行一次一天(24小时)的预测。

默认情况下,校准集考虑校准集上所有可能的历史预测( cal_stride=1)。这将使用在我们24小时计划之外生成的示例,并可能导致无效覆盖。

设置cal_stride=24将提取正确的示例。

# 共形模型
cp_model = ConformalNaiveModel(
    model=model,
    quantiles=quantiles,
    cal_length=100,
    cal_stride=multi_horizon,  # 校准集的步长
)

hfcs = cp_model.historical_forecasts(
    series=cal_test,
    forecast_horizon=multi_horizon,
    start=test.start_time(),
    last_points_only=False,  # 返回每个多水平预测值
    stride=multi_horizon,  # 对历史预测值使用相同的步长
    **pred_kwargs,
)

# 将预测值连接成单个时间序列
hfcs_concat = concatenate(hfcs, axis=0)
plot_historical_forecasts(hfcs_concat)

bt = cp_model.backtest(
    cal_test,
    historical_forecasts=hfcs,
    last_points_only=False,
    metric=[metrics.mic, metrics.miw],
    metric_kwargs={"q_interval": q_interval},
)
pd.DataFrame({"Interval": q_range, "Coverage": bt[0], "Width": bt[1]})
IntervalCoverageWidth
00.90.9022834772.75975

img

很好,当我们每天仅应用一次模型时,我们也实现了有效覆盖。

由于我们有多步预测,检查范围内每一步的覆盖率和宽度也很重要:

def compute_hfc_horizon_metric(metric=metrics.ic):
    # 计算每个历史预测、预测范围和成分的指标
    # 形状为 `(n 个预测, 预测范围, n 个成分, 1)`
    residuals = cp_model.residuals(
        cal_test,
        historical_forecasts=hfcs,
        last_points_only=False,
        metric=metric,
        metric_kwargs={"q_interval": q_interval},
        values_only=True,
    )
    # 创建数组并删除成分和样本轴
    residuals = np.array(residuals)[:, :, 0, 0]

    # 计算每个预测范围的所有预测(365 个 1 天预测)的平均值
    return np.mean(residuals, axis=0)

covs_horizon = compute_hfc_horizon_metric(metrics.ic)
widths_horizon = compute_hfc_horizon_metric(metrics.iw)
fig, (ax1, ax2) = plt.subplots(nrows=2, figsize=(6, 8.6), sharex=True)

horizons = [i + 1 for i in range(24)]
ax1.plot(horizons, covs_horizon)
ax2.plot(horizons, widths_horizon)

ax1.set_ylabel("coverage ratio [-]")
ax1.set_title("Interval coverage per step in horizon")

ax2.set_xlabel("horizon")
ax2.set_ylabel("width [kWh]")
ax2.set_title("Interval width per step in horizon");

img

所有范围内的覆盖都是有效的,范围在89%到92%之间。

通常,宽度随范围增加而增加。在范围16之后它们再次下降,这是由于目标序列的性质(夜间电力消耗低 -> 不确定性较低)。

示例4:共形化分位数回归

最后,让我们看看我们的ConformalQRModel的示例。API完全相同。

唯一的区别是它需要一个概率性基础预测器。

让我们使用一个具有分位数回归的线性模型,并执行与示例1相同的单步预测。

# 概率回归模型(含分位数)
model = LinearRegressionModel(
    lags=input_length,
    output_chunk_length=horizon,
    likelihood="quantile",
    quantiles=quantiles,
).fit(train)

# 共形分位数回归模型
cp_model = ConformalQRModel(model=model, quantiles=quantiles, cal_length=four_weeks)
hfcs = cp_model.historical_forecasts(
    series=cal_test,
    forecast_horizon=horizon,
    start=test.start_time(),
    last_points_only=True,
    stride=horizon,
    **pred_kwargs,
)
plot_historical_forecasts(hfcs)

bt = cp_model.backtest(
    cal_test,
    historical_forecasts=hfcs,
    last_points_only=True,
    metric=[metrics.mic, metrics.miw],
    metric_kwargs={"q_interval": q_interval},
)
pd.DataFrame({"Interval": q_range, "Coverage": bt[0], "Width": bt[1]})
IntervalCoverageWidth
00.90.900241770.154514

img

相同的覆盖率,但区间略大于朴素共形预测情况。

风险提示与免责声明
本文内容基于公开信息研究整理,不构成任何形式的投资建议。历史表现不应作为未来收益保证,市场存在不可预见的波动风险。投资者需结合自身财务状况及风险承受能力独立决策,并自行承担交易结果。作者及发布方不对任何依据本文操作导致的损失承担法律责任。市场有风险,投资须谨慎。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

船长Q

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值