入门指南¶
以下信息旨在帮助用户快速上手aeon。
如果需要安装,请参阅我们的安装指南以安装aeon。
我们假设您对scikit-learn包有基本的了解。如果您需要关于scikit-learn的帮助,您可能想查看他们的入门指南。
aeon 是一个用于从时间序列中学习的开源工具包。它提供了最新的时间序列机器学习算法,以及一系列用于以下学习任务的经典技术:
异常检测,其目标是找到单个时间序列中不代表整个序列的值或区域。
aeon 还提供了上述模块使用的核心模块:
有专门的笔记本更详细地介绍了这些模块中的每一个。本指南旨在为您提供每个任务的主要概念和代码的最简要介绍,以便开始使用。有关每个任务可用的各种估计器的更多信息,请参见上面的链接、API和示例页面。
单一时间序列¶
时间序列是一系列假设为有序的实值数据。单变量时间序列在每个时间点都有一个单一的值。例如,来自单个传感器的心电图读数或每月使用航空公司的乘客数量将形成一个单变量序列。单个时间序列默认存储在np.ndarray中(我们尽可能在内部使用)。我们也可以处理pd.Series和pd.DataFrame对象作为输入,但这些可能会在内部转换为np.ndarray。航空公司序列是预测领域中单变量序列的经典示例。该序列是1949年至1960年国际航空公司乘客的月度总数,单位为千。
>>> from aeon.datasets import load_airline
>>> y = load_airline() # load an example univariate series as an array
>>> y[:5] # first five time points
606.0
508.0
461.0
390.0
432.0
多元时间序列由多个序列或通道组成,其中每个观测值是在相同时间索引下的相关记录的向量。一个例子是来自智能手表的运动轨迹,至少有三个维度(X、Y、Z坐标),或者是随时间记录的多个财务统计数据。单个多元序列输入通常默认遵循形状(n_channels, n_timepoints)。算法可能有一个axis参数来改变这一点,其中axis=1假设默认形状并且是默认设置,而axis=0假设形状(n_timepoints, n_channels)。
>>> from aeon.datasets import load_uschange
>>> data = load_uschange() # load an example multivariate series
>>> data[:,:5] # all channels, first five time points
[[ 0.61598622 0.46037569 0.87679142 -0.27424514 1.89737076]
[ 0.97226104 1.16908472 1.55327055 -0.25527238 1.98715363]
[-2.45270031 -0.55152509 -0.35870786 -2.18545486 1.90973412]
[ 4.8103115 7.28799234 7.28901306 0.98522964 3.65777061]
[ 0.9 0.5 0.5 0.7 -0.1 ]]
我们通常将时间序列的观测次数称为n_timepoints。
如果序列是多变量的,我们将维度称为通道
(以避免与数组的维度混淆),并在代码中使用n_channels。因此
上面加载的US Change数据有五个通道和187个时间点。有关
我们提供的数据集的更多详细信息以及如何将数据加载到aeon兼容的数据
结构中,请参阅我们的datasets笔记本。
单系列模块¶
不同的 aeon 模块处理单个序列或序列集合。
anomaly detection、forecasting 和 segmentation 模块中的估计器使用
单个序列输入(它们继承自 BaseSeriesEstimator)。distances 中的函数
接受两个序列作为参数。
异常检测¶
异常检测(AD)是识别与其余数据显著不同的观测值的过程。更多详细信息将在我们编写完笔记本后很快提供。
>>> from aeon.datasets import load_airline
>>> from aeon.anomaly_detection import STOMP
>>> stomp = STOMP(window_size=200)
>>> scores = est.fit_predict(X) # Get the anomaly scores
分割¶
时间序列分割(TSS)是将时间序列划分为彼此不同的段或区域的过程。例如,这可能是将智能手表的运动轨迹分割为不同的活动,如步行、跑步和坐着。它与变化点检测领域密切相关,这是一个在统计学文献中更常用的术语。
>>> from aeon.datasets import load_airline
>>> from aeon.segmentation import ClaSPSegmenter
>>> series = load_airline()
>>> clasp = ClaSPSegmenter() # An example segmenter
>>> clasp.fit(data) # fit the segmenter on the data
>>> clasp.fit_predict(ts)
[51]
距离¶
时间序列之间的距离是许多时间序列任务中的基本操作。我们在aeon.distances模块中提供了广泛的距离函数,所有这些函数都使用numba进行了优化。它们都适用于多变量和不等长的时间序列。
>>> from aeon.datasets import load_japanese_vowels
>>> from aeon.distances import dtw_distance
>>> data = load_japanese_vowels() # load an example multivariate series collection
>>> dtw_distance(data[0], data[1]) # calculate the dtw distance
14.416269807978
时间序列集合¶
时间序列集合的默认存储是一个3D的np.ndarray。
如果n_timepoints在不同情况下变化,我们将集合存储在list中的
np.ndarray数组中,每个数组具有相同数量的通道。我们没有能力使用具有不同通道数的时间序列集合。
我们还假设单个序列的所有通道的序列长度始终相同。
>>> from aeon.datasets import load_italy_power_demand
>>> X, y = load_italy_power_demand() # load an example univariate collection
>>> X.shape
(1096, 1, 24)
>>> X[:5, :, :5]
[[[-0.71051757 -1.1833204 -1.3724416 -1.5930829 -1.4670021 ]]
[[-0.99300935 -1.4267865 -1.5798843 -1.6054006 -1.6309169 ]]
[[ 1.3190669 0.56977448 0.19512825 -0.08585642 -0.17951799]]
[[-0.81244429 -1.1575534 -1.4163852 -1.5314215 -1.5026624 ]]
[[-0.97284033 -1.3905178 -1.5367049 -1.6202404 -1.6202404 ]]]
>>> y[:5]
['1' '1' '2' '2' '1']
我们在提到集合中包含的单个时间序列时,会交替使用术语“案例”和“实例”。时间序列集合的大小在代码中被称为n_cases。集合的形状为(n_cases, n_channels, n_timepoints)。
我们建议将集合存储在3D np.ndarray 中,即使每个时间序列是单变量的(即 n_channels == 1)。集合估计器将处理形状为 (n_cases, n_timepoints) 的2D输入,正如您从 scikit-learn 中所期望的那样,但可能会将形状为 (n_cases, n_timepoints) 的单变量系列集合与形状为 (n_channels, n_timepoints) 的单个多变量系列混淆。这种潜在的混淆是我们区分系列和集合估计器的原因之一。
>>>from aeon.datasets import load_basic_motions, load_plaid, load_japanese_vowels
>>> X2, y2 = load_basic_motions() # example equal length multivariate collection
>>> X2.shape
(80, 6, 100)
>>> X3, y3 = load_plaid() # example unequal length univariate collection
>>> type(X3)
<class 'list'>
>>> len(X3)
1074
>>> X3[0].shape
(1, 500)
>>> X4, y4 = load_japanese_vowels() # example unequal length mutlivariate collection
>>> len(X4)
640
>>> X4[0].shape
(12, 20)
基于集合的模块¶
classification、regression 和 clustering 模块中的估计器从时间序列集合中学习(它们继承自 BaseCollectionEstimator 类)。时间序列集合通常会伴随一个目标变量数组用于监督学习。similarity_search 模块也适用于时间序列集合。
集合估计器紧密遵循scikit-learn估计器接口,适当使用fit、predict、transform、predict_proba、fit_predict和fit_transform。它们还设计为直接与scikit-learn功能配合使用,例如模型评估、参数搜索和管道(在适当的情况下)。
分类¶
时间序列分类(TSC)涉及在标记的时间序列集合上训练模型。这些标签,在代码中称为y,应该是类型为int或str的numpy数组。
如果您曾经使用过scikit-learn,那么分类估计器接口应该很熟悉。在这个例子中,我们在示例数据上使用动态时间规整(DTW)拟合了一个KNeighborsTimeSeriesClassifier。
>>> import numpy as np
>>> from aeon.classification.distance_based import KNeighborsTimeSeriesClassifier
>>> X = [[[1, 2, 3, 4, 5, 6, 7]], # 3D array example (univariate)
... [[4, 4, 4, 5, 6, 7, 3]]] # Two samples, one channel, seven series length
>>> y = [0, 1] # class labels for each sample
>>> X = np.array(X)
>>> y = np.array(y)
>>> clf = KNeighborsTimeSeriesClassifier(distance="dtw")
>>> clf.fit(X, y) # fit the classifier on train data
KNeighborsTimeSeriesClassifier()
>>> X_test = np.array([[2, 2, 2, 2, 2, 2, 2], [4, 4, 4, 4, 4, 4, 4]])
>>> clf.predict(X_test) # make class predictions on new data
[0 1]
一旦分类器使用训练数据和类别标签进行拟合后,我们可以预测新案例的标签。像scikit-learn一样,predict_proba方法可用于预测类别概率,并且存在score方法来计算新数据的准确性。
回归¶
时间序列回归假设目标变量不是分类中的离散标签,而是一个连续变量或目标变量。与分类部分相同的输入数据考虑因素适用,模块功能类似。目标变量应该是一个类型为float的numpy数组。
时间序列回归是预测中常用的术语,通常与滑动窗口结合使用。然而,该术语还包括“时间序列外部回归”,其中目标变量不是未来值,而是某些外部变量。 在以下示例中,我们在一个名为Covid3Month的时间序列回归问题上使用了KNeighborsTimeSeriesRegressor。
>>> from aeon.regression.distance_based import KNeighborsTimeSeriesRegressor
>>> from aeon.datasets import load_covid_3month
>>> from sklearn.metrics import mean_squared_error
>>> X_train, y_train = load_covid_3month(split="train")
>>> X_test, y_test = load_covid_3month(split="test")
>>> reg = KNeighborsTimeSeriesRegressor(distance="dtw")
>>> reg.fit(X_train, y_train) # fit the regressor on train data
KNeighborsTimeSeriesRegressor()
>>> y_pred = reg.predict(X_test) # make label predictions on new data
>>> y_pred[:6]
[0.04218472 0.01459854 0. 0.0164468 0.06254257 0.11111111]
>>> mean_squared_error(y_test, y_pred)
0.002921957478363366
聚类¶
与分类和回归类似,时间序列聚类(TSCL)旨在尽可能遵循scikit-learn接口。使用与TSC和TSER模块相同的输入数据格式。此示例在ArrowHead数据集上拟合了一个TimeSeriesKMeans聚类器。
>>> from aeon.clustering import TimeSeriesKMeans
>>> from aeon.datasets import load_arrow_head
>>> from sklearn.metrics import rand_score
>>> X, y = load_arrow_head()
>>> kmeans = TimeSeriesKMeans(n_clusters=3, metric="dtw")
>>> kmeans.fit(X) # fit the clusterer
TimeSeriesKMeans(n_clusters=3)
>>> kmeans.labels_[0:10] # cluster labels
[2 1 1 0 1 1 0 1 1 0]
>>> rand_score(y, kmeans.labels_)
0.6377792823290453
调用fit后,labels_属性包含每个时间序列的聚类标签。predict方法可用于预测新数据的聚类标签。
相似性搜索¶
aeon中的相似性搜索模块提供了一组函数和估计器来解决与时间序列相似性搜索相关的任务。这些估计器可以单独使用,也可以作为管道的一部分使用,而函数则为您提供了构建自己的估计器的工具,这些估计器在某个时候会依赖于相似性搜索。
估计器继承自BaseSimiliaritySearch类,接受3D时间序列(n_cases, n_channels, n_timepoints)作为fit方法的输入。单变量和单序列仍然可以使用,但需要重新调整为这种格式。
这个集合,用于fit方法,被存储为一个数据库。它将在predict方法中使用,该方法期望一个单一的2D时间序列作为输入(n_channels, query_length)。这个2D时间序列将用作查询,以在3D数据库中进行搜索。
预测方法的结果将取决于您是否使用QuerySearch和SeriesSearch估计器。在QuerySearch中,2D序列是一个子序列,我们希望在其中识别3D数据库中的最佳(或最差!)匹配。对于SeriesSearch,我们需要一个length参数,并且我们将在3D数据库中搜索2D序列中所有大小为length的子序列的最佳匹配。默认情况下,这些估计器将使用欧几里得(或平方欧几里得)距离,但未来将添加更多距离。
>>> import numpy as np
>>> from aeon.similarity_search import QuerySearch
>>> X = [[[1, 2, 3, 4, 5, 6, 7]], # 3D array example (univariate)
... [[4, 4, 4, 5, 6, 7, 3]]] # Two samples, one channel, seven series length
>>> X = np.array(X) # X is of shape (2, 1, 7) : (n_cases, n_channels, n_timepoints)
>>> top_k = QuerySearch(k=2)
>>> top_k.fit(X) # fit the estimator on train data
...
>>> q = np.array([[4, 5, 6]]) # q is of shape (1,3) :
>>> top_k.predict(q) # Identify the two (k=2) most similar subsequences of length 3 in X
[(0, 3), (1, 2)]
predict 的输出给出一个大小为 k 的列表,其中每个元素是一个集合,表示 X 中最佳匹配的位置为 (id_sample, id_timestamp)。这相当于子序列 X[id_sample, :, id_timestamps:id_timestamp + q.shape[0]]。
变压器¶
我们将变压器分为两类:一类是转换单一时间序列的变压器,另一类是转换集合的变压器。
单时间序列的Transformers¶
继承自BaseSeriesTransformer的Transformers在aeon.transformations.series包中将单个(可能是多变量的)时间序列转换为不同的时间序列或特征向量。更多信息即将发布。
以下示例展示了如何使用 AutoCorrelationSeriesTransformer 类来提取时间序列的自相关项。
>>> from aeon.transformations.series import AutoCorrelationSeriesTransformer
>>> from aeon.datasets import load_airline
>>> acf = AutoCorrelationSeriesTransformer()
>>> y = load_airline() # load single series airline dataset
>>> res = acf.fit_transform(y)
>>> res[0][:5]
[0.96019465 0.89567531 0.83739477 0.7977347 0.78594315]
时间序列集合的Transformers¶
aeon.transformations.collections 模块包含一系列用于时间序列集合的转换器。这些转换器不允许单一系列输入,将二维输入类型视为单变量系列的集合,并且对输出的数据类型没有限制。
大多数时间序列分类和回归算法都基于某种形式的转换到替代特征空间。例如,我们可能会从每个序列中提取一些摘要时间序列特征,并在这些特征上拟合传统的分类器或回归器。例如,我们可以使用Catch22,它为每个序列计算22个摘要统计量。
>>> from aeon.transformations.collection.feature_based import Catch22
>>> import numpy as np
>>> X = np.random.RandomState().random(size=(4, 1, 10)) # four cases of 10 timepoints
>>> c22 = Catch22(replace_nans=True) # transform to four cases of 22 features
>>> c22.fit_transform(X)[0]
[ 4.99485761e-01 4.12452579e-01 3.00000000e+00 1.00000000e-01
0.00000000e+00 1.00000000e+00 2.00000000e+00 3.08148791e-34
1.96349541e+00 2.56152262e-01 -1.09028518e-02 9.08908735e-01
2.00000000e+00 1.00000000e+00 4.00000000e+00 1.88915916e+00
1.00000000e+00 5.95334611e-01 0.00000000e+00 0.00000000e+00
8.23045267e-03 0.00000000e+00]
还有序列到序列的转换,例如Padder用于延长序列并处理不等长的集合。
>>> from aeon.transformations.collection import Padder
>>> from aeon.testing.data_generation import make_example_3d_numpy_list
>>> X, _ = make_example_3d_numpy_list( # unequal length data with 8-12 timepoints
... n_cases=2,
... min_n_timepoints=8,
... max_n_timepoints=12,
... random_state=0,
... )
>>> print(X[0])
[[0. 1.6885315 1.71589124 1.69450348 1.24712739 0.76876341
0.59506921 0.11342595 0.54531259 0.95533023 1.62433746 0.95995434]]
>>> print(X[1])
[[2. 0.28414423 0.3485172 0.08087359 3.33047938 3.112627
3.48004859 3.91447337 3.19663426]]
>>> pad = Padder(pad_length=12, fill_value=0) # pad to length 12
>>> pad.fit_transform(X)
[[[0. 1.6885315 1.71589124 1.69450348 1.24712739 0.76876341
0.59506921 0.11342595 0.54531259 0.95533023 1.62433746 0.95995434]]
[[2. 0.28414423 0.3485172 0.08087359 3.33047938 3.112627
3.48004859 3.91447337 3.19663426 0. 0. 0. ]]]
aeon估计器的管道¶
与 scikit-learn 类似,aeon 提供了管道类,可用于将转换和估计器链接在一起。
对于分类、回归和聚类等机器学习任务,如果转换器输出有效的输入类型,可以使用scikit-learn的make_pipeline功能。
以下示例使用Catch22特征提取转换器和随机森林分类器进行分类。
>>> from aeon.datasets import load_italy_power_demand
>>> from aeon.transformations.collection.feature_based import Catch22
>>> from sklearn.ensemble import RandomForestClassifier
>>> from sklearn.pipeline import make_pipeline
>>> from sklearn.metrics import accuracy_score
...
>>> # Load the italy power demand dataset
>>> X_train, y_train = load_italy_power_demand(split="train")
>>> X_test, y_test = load_italy_power_demand(split="test")
...
>>> # Create and fit the pipeline
>>> pipe = make_pipeline(
... Catch22(replace_nans=True),
... RandomForestClassifier(random_state=42),
... )
>>> pipe.fit(X_train, y_train)
Pipeline(steps=[('catch22', Catch22(replace_nans=True)),
('randomforestclassifier',
RandomForestClassifier(random_state=42))])
>>> # Make predictions like any other sklearn estimator
>>> accuracy_score(pipe.predict(X_test), y_test)
0.8989310009718173
与管道类似,分类、回归和聚类等任务可以使用可用的scikit-learn功能。
>>> from sklearn.metrics import accuracy_score
>>> from sklearn.model_selection import GridSearchCV, KFold
>>> from aeon.classification.distance_based import KNeighborsTimeSeriesClassifier
>>> from aeon.datasets import load_italy_power_demand
...
>>> # Load the italy power demand dataset
>>> X_train, y_train = load_italy_power_demand(split="train")
>>> X_test, y_test = load_italy_power_demand(split="test")
...
>>> knn = KNeighborsTimeSeriesClassifier()
>>> param_grid = {"n_neighbors": [1, 5], "distance": ["euclidean", "dtw"]}
...
>>> gscv = GridSearchCV(knn, param_grid, cv=KFold(n_splits=4))
>>> gscv.fit(X_train, y_train)
...
>>> y_pred = gscv.predict(X_test)
>>> y_pred[:6]
['2' '2' '2' '2' '2' '1']
>>> accuracy_score(y_test, y_pred)
0.9523809523809523
>>> gscv.best_params_
{'distance': 'euclidean', 'n_neighbors': 5}