binder

使用 Sktime 的签名方法#

“签名方法”是指一系列用于多模态序列数据的特征提取技术,源自受控微分方程理论。近年来,人们对签名方法提出了大量的改进,以期在某些方面进行优化。

在论文“时间序列的广义签名方法”[1]中,作者将这些改进中的绝大多数整合到了一篇文档中,并对多元 UEA 数据集进行了大规模超参数研究,以构建一个通用的签名算法,该算法有望在各种数据集上表现良好。我们在SignatureClassifier模块中实现了该研究的最佳实践结果,将其作为超参数的默认起始值。

路径签名#

签名方法的核心是所谓的“签名变换”。

一个在\(\textit{d}\)维空间中有限长度的路径\(X\)可以通过映射\(X:[a, b]\rightarrow\mathbb{R}\) \(\!\!^d\)来描述,或者用坐标表示为\(X=(X^1_t, X^2_t, ...,X^d_t)\),其中每个坐标\(X^i_t\)是实数值,由\(t\in[a,b]\)参数化。

路径\(X\)签名变换\(S\)被定义为一个无限序列的值: :nbsphinx-math:`begin{equation}

S(X)_{a, b} = (1, S(X)_{a, b}^1, S(X)_{a, b}^2, …, S(X)_{a, b}^d, S(X)_{a,b}^{1, 1}, S(X)_{a,b}^{1, 2}, …), label{eq:path_signature}

end{equation}`其中每一项都是\(X\)\(k\)重迭代积分,带有多重索引\(i_1,...,i_k\): :nbsphinx-math:`begin{equation}

S(X)_{a, b}^{i_1,…,i_k} = int_{a<t_k<b}…int_{a<t_1<t_2} mathrm{d}X_{t_1}^{i_1}…mathrm{d}X_{t_k}^{i_k}. label{eq:sig_moments}

end{equation}` 这定义了一个与路径相关联的有序数字序列,已知该序列可以表征路径,直至广义形式的重新参数化 [2]。可以将签名看作是一组几乎唯一确定路径的汇总统计量。此外,路径\(X\)上的任何连续函数都可以通过其签名的线性函数任意好地逼近 [3];签名揭示了无参数化路径空间上函数的非线性性质。

可视化#

为了了解签名项在物理上代表什么,我们考虑一名在 ICU 中被追踪其收缩压 (SBP) 和心率 (HR) 随时间变化的患者。这可以表示为\(\mathbb{R}^3\)中的一条路径(假设时间被包含为一个通道)。

signature_visualisation

上图草绘了这样一条路径可能出现的两种情景。这里我们假设每幅图都包含一个隐式的时间维度,使得路径沿着蓝色线从左到右遍历。

深度 1:#

深度为 1 的签名项就是每个变量在时间间隔内的变化量,图中即为\(\Delta \text{HR}\)\(\Delta \text{SBP}\)项。注意,这些值在每种情况下都是相同的。

深度 2:#

第二层给了我们带符号的面积(阴影的橙色区域),其中最左边图的方向产生了负号的面积,而第二个则给出了正值,因此,在签名的二阶时,我们现在有了足够的信息来区分这两种情况:第一种是心率先于(或者至少最初快于)血压上升,反之亦然。

深度 > 2:#

深度大于 2 的项在图形上更难可视化,但其思想与深度 2 的情况类似,我们在深度 2 中看到签名提供了关于 HR 或 SBP 增加哪个先发生的信息,并对其发生程度进行了数值量化。在更高阶时,签名也在做类似的事情,但现在是涉及三个事件,而不是两个。签名提取出关于事件发生顺序的结构信息。

时序分析中的签名#

签名是应用于时序分析相关问题的自然工具。如上所述,它可以将多维时序数据转换为静态特征,这些特征代表了时序序列性质的信息,可以输入到标准的机器学习模型中。

一个关于其工作原理的简化视图如下: :nbsphinx-math:`begin{equation}

text{模型}(text{签名}(text{序列数据}))) = text{预测}

end{equation}`

考虑的签名变体#

再次,遵循 [1] 中的工作,我们将签名方法的变体概念上分为

  • 增广 (Augmentations) - 将输入序列或时序变换为一个或多个新序列,以便签名可以返回关于路径的不同信息。

  • 窗口 (Windows) - 窗口操作,以便签名可以在局部范围内作用。

  • 变换 (Transforms) - 选择签名变换或对数签名变换。

  • 重标度 (Rescalings) - 签名重标度的方法。

这可以很好地用下面的图表示,其中\(\phi\)表示增广,\(W^{i, j}\)表示窗口操作,\(S^N\)表示签名,\(\rho_{\text{pre}/\text{post}}\)表示重标度方法。

b082cd53f458445790932d00742ecc16

请参阅完整论文,以更全面地了解这些分组的含义。

Sktime 模块#

现在我们将介绍 sktime 接口中包含的分类和转换模块,并提供一个示例,展示如何执行高效的超参数优化,这在 [1] 中被证明能给出良好结果。

[1]:
# Some additional imports we will use
from sklearn.ensemble import RandomForestClassifier
from sklearn.metrics import accuracy_score

from sktime.datasets import load_gunpoint
[2]:
# Load an example dataset
train_x, train_y = load_gunpoint(split="train", return_X_y=True)
test_x, test_y = load_gunpoint(split="test", return_X_y=True)
D:\CMP Machine Learning\sktime-workshop-boss\sktime\utils\data_io.py:63: FutureWarning: This function has moved to datasets/_data_io, this version will be removed in V0.10
  warn(

概述#

我们提供以下模块:

  • sktime.transformers.panel.signature_based.SignatureTransformer - 一个 sklearn 转换器,提供应用签名方法的功能,并可选择上述一些变体。

  • sktime.classification.feature_based.SignatureClassifier - 提供一个简单的接口,用于将分类器附加到 SignatureTransformer 类。

[3]:
from sktime.classification.feature_based import SignatureClassifier
from sktime.transformations.panel.signature_based import SignatureTransformer

示例 1:序列数据 -> 签名特征。#

这里我们将给出一个非常简单的示例,将形状为 [num_batch, series_length, num_features] 的序列 3D GunPoint 数据转换为形状为 [num_batch, signature_features] 的数据。

[4]:
# First build a very simple signature transform module
signature_transform = SignatureTransformer(
    augmentation_list=("addtime",),
    window_name="global",
    window_depth=None,
    window_length=None,
    window_step=None,
    rescaling=None,
    sig_tfm="signature",
    depth=3,
)

# The simply transform the stream data
print(f"Raw data shape is: {train_x.shape}")
train_signature_x = signature_transform.fit_transform(train_x)
print(f"Signature shape is: {train_signature_x.shape}")
Raw data shape is: (50, 1)
Signature shape is: (50, 14)

然后构建一个时序分类模型变得极其容易。例如:

[5]:
# Train
model = RandomForestClassifier()
model.fit(train_signature_x, train_y)

# Evaluate
test_signature_x = signature_transform.transform(test_x)
test_pred = model.predict(test_signature_x)
print(f"Accuracy: {accuracy_score(test_y, test_pred):.3f}%")
Accuracy: 0.740%

示例 2:通用模型的微调#

如前所述,在 [1] 中,作者对完整的 UEA 存档上的签名变体进行了大规模超参数搜索,以开发一种构建模型的“最佳实践”方法。这需要对以下参数进行微调,因为它们被发现与数据集高度相关:

  • depth 在 [1, 2, 3, 4, 5, 6] 范围内

  • window_depth 在 [2, 3, 4] 范围内

  • RandomForestClassifier 超参数。

这里我们展示如何使用 sktime 框架轻松完成这项工作。

[6]:
from sklearn.model_selection import RandomizedSearchCV, StratifiedKFold

# Some params
n_cv_splits = 5
n_gs_iter = 20

# Random forests found to perform very well in general
estimator = RandomForestClassifier()

# The grid to be passed to an sklearn gridsearch
signature_grid = {
    # Signature params
    "depth": [1, 2, 3, 4, 5],
    "window_name": ["dyadic"],
    "augmentation_list": [["basepoint", "addtime"]],
    "window_depth": [1, 2, 3, 4],
    "rescaling": ["post"],
    # Classifier and classifier params
    "estimator": [estimator],
    "estimator__n_estimators": [50, 100, 500],
    "estimator__max_depth": [2, 4, 6, 8, 12, 16, 24, 32, 45, 60],
}

# Initialise the estimator
estimator = SignatureClassifier()

# Run a random grid search and return the gs object
cv = StratifiedKFold(n_splits=n_cv_splits)
gs = RandomizedSearchCV(estimator, signature_grid, cv=n_cv_splits, n_iter=n_gs_iter)
gs.fit(train_x, train_y)

# Get the best classifier
best_classifier = gs.best_estimator_

# Evaluate
train_preds = best_classifier.predict(train_x)
test_preds = best_classifier.predict(test_x)
train_score = accuracy_score(train_y, train_preds)
test_score = accuracy_score(test_y, test_preds)
print(f"Train acc: {train_score * 100:.3f}%  |  Test acc: {test_score * 100:.3f}%")
Train acc: 100.000%  |  Test acc: 96.000%

参数的完整描述#

最后,我们将对SignatureClassifier模块中的每个参数及其可能取值进行进一步解释。

参数#

下面我们列出每个参数及其可能取值。关于选项含义的更多细节,请参阅 [1]。

classifier 必须是任何 sklearn 估计器。默认为RandomForestClassifier()

augmentation_list: 字符串元组列表,在应用签名变换之前应用的增广列表。可以是以下任意组合:

  • 'addtime' - 添加一个等间隔的时间通道。

  • 'leadlag' - 应用 leadlag 变换。

  • 'ir' - 执行 invisibility reset 变换。

  • 'cumsum' - 执行累积求和变换。

  • 'basepoint' - 在路径开头附加零以消除平移不变性。

window_name str,要应用的窗口变换名称。可以是以下任意一种:

  • 'global' - 对所有数据应用单一窗口。

  • 'expanding' - 从第一个数据点开始,扩展覆盖数据的多个窗口(宽度增加)。

  • 'sliding' - 沿数据滑动(固定宽度)的多个窗口。

  • 'dyadic' - 将数据划分成二进位窗口。

window_depth: int,二进位窗口的深度。(仅当window_name == 'dyadic']时有效)。

window_length: int,滑动/扩展窗口的长度。(仅当window_name in ['sliding, 'expanding'].时有效)。

window_step: int,滑动/扩展窗口的步长。(仅当window_name in ['sliding, 'expanding'].时有效)。

rescaling: str,签名重标度的方法。可以是以下任意一种:

  • 'pre' - 在签名变换之前对路径进行重标度。

  • 'post' - 在签名变换之后对路径进行重标度。

  • None - 不进行重标度。

sig_tfm: str,指定签名变换类型的字符串。可以是以下之一:['signature', 'logsignature']。

depth: int,签名截断深度。

random_state: int,随机状态初始化。

参考文献#

[1] Morrill, James, Adeline Fermanian, Patrick Kidger, and Terry Lyons. “A Generalised Signature Method for Time Series.” arXiv preprint arXiv:2006.00873 (2020).

[2] Hambly, B., Lyons, T.: Uniqueness for the signature of a path of bounded variation and the reduced pathgroup. Annals of Mathematics171(1), 109–167 (2010). doi:10.4007/annals.2010.171.10913.

[3] Lyons, T.J.: Differential equations driven by rough signals. Revista Matem ́atica Iberoamericana14(2), 215–310(1998)


使用 nbsphinx 生成。Jupyter notebook 可在 此处 找到。