Pyts入门之时间序列的分类---TimeSeriesForest算法介绍(五)

简介

时间序列的分类算法逐渐接近尾声,本节将介绍TimeSeriesForest算法,即应用在时间序列上的随机森林算法,同时下一节也就是最后一节将介绍建立在它基础上的TSBF算法。在学习本节之前呢,需要各位将Pyts升级至最新版本(到本文发表时为0.12.0),因为0.11.0(去年10月我安装的版本)是没有这两种算法的:

pip install --upgrade pyts

TimeSeriesForest的算法步骤分为以下两步:
1.从一系列随机窗口序列中提取三个特征:平均值,标准差,和简单线性回归的斜率。
2.将这三个特征输入随机森林进行训练。

所以重点在于第一步,第二步其实还是普通的随机森林,与其说这种一种时间序列的新算法,不如说这是一种新的特征提取方式。在介绍具体怎么选取窗口序列之前,还是按惯例把API先说明一遍。

API

class pyts.classification.TimeSeriesForest(n_estimators=500, 
n_windows=1.0, min_window_size=1, criterion='entropy', 
max_depth=None, min_samples_split=2, min_samples_leaf=1, 
min_weight_fraction_leaf=0.0, max_features='auto', 
max_leaf_nodes=None, min_impurity_decrease=0.0, bootstrap=True, 
oob_score=False, n_jobs=None, random_state=None, verbose=0, 
class_weight=None, ccp_alpha=0.0, max_samples=None)

和sklearn(1.0.2)的RandomForestClassifier相比多了n_windows和min_window_size两个参数,少了warm_start这个参数。

参数说明
n_estimatorsint,森林里树的数目,太多容易过拟合,太少容易信息不足
n_windowsint or float,特征提取的窗口数,窗口越多特征越多
min_window_sizeint or float,最小窗口长度,若为小数则为序列长度乘该值
criterion“gini”或“entropy”,节点划分的准则
max_depthint or None,树的深度限制,可以不设,但容易过拟合
min_samples_splitint or float,划分内部节点(能继续分出节点的节点)需包含的最小样本数,若为float,则为向上取整(min_samples_split * 样本数)
min_samples_leafint or float,叶节点包含的最小样本数,若为float,则为向上取整(min_samples_leaf * 样本数),可能可以平滑模型
min_weight_fraction_leaffloat,成为叶节点的最小权重分数,当fit时没有提供sample_weight参数时所有样本都有相同的权重
max_featuresint, float, str or None,一般为“auto”即可,划分时考虑的最多特征数目。若为float,则max_features=round(max_features * n_features),若为“auto”或“sqrt”,max_features=sqrt(n_features),若为“log2”, max_features=log2(n_features),若为None,max_features=n_features。
max_leaf_nodesint,叶节点的最多数目
min_impurity_decreasefloat,最小不纯度的减少,一个节点划分减少的不纯度大于等于这个值时才会被划分
bootstrapbool,是否使用boostrap方法来构建每棵树,若为False,则会使用整个样本集。
oob_scorebool,是否使用袋外分数来进行评分,只有bootstrap为True时,才会有一部分从来没有被抽中的样本来评分
n_jobsint or None,线程数,-1时用尽所有
random_stateint, RandomState instance or None,随机种子,影响两个过程:1.bootstrap,2.寻找划分点。
verboseint,控制信息显示
class_weightdict, “balanced”, “balanced_subsample” or None,给类别添加权重,为"balanced"时使用n_samples / (n_classes * np.bincount(y)),为“balanced_subsample”时,一样的计算,只是使用在每颗树构建时bootstrap的样本
ccp_alpha非负小数,Minimal cost-complexity pruning算法的复杂度参数,总之就是来防止过拟合的,详见Minimal cost-complexity pruning
max_samplesint or float,当boostrap=True时用来拟合每颗树的最大样本数,若为None,就是X.shape[0],若为float,为max_samples * X.shape[0]

重点问题讲解

1.前面说了它无非是在RandomForest的基础上加了一个特征提取方式,提取了平均数,标准差,线性回归斜率三个参数,那么它真的比RandomForest优秀吗?

from pyts.datasets import load_gunpoint
from pyts.classification import TimeSeriesForest
from sklearn.ensemble import RandomForestClassifier
X_train, X_test, y_train, y_test = load_gunpoint(return_X_y=True)
TSF = TimeSeriesForest(random_state=2)
RFC = RandomForestClassifier(n_estimators=500,criterion='entropy',random_state=2)
RFC.fit(X_train, y_train)
print(RFC.score(X_test, y_test) #0.9333333333333333
TSF.fit(X_train, y_train)
print(TSF.score(X_test, y_test) #0.9733333333333334

公平起见使用了一样的参数一样的随机数,在本例中准确率高出了0.04个百分点。当然不排除是本例特征太多(150个时间点)导致的,至于其他情况,请读者自行测试。
2.那么它是怎么提取的,这种特征提取方式是否值得学习?
先贴一段略加修改的源代码:

def extract_features(X, n_samples, n_windows, indices):
    X_new = np.empty((n_samples, 3 * n_windows)) #创建空序列
    for j in range(n_windows):
        start, end = indices[j] #取一个窗口的起点和终点
        arange = np.arange((start - end + 1) / 2, (end + 1 - start) / 2) #取x序列
        if end - start == 1:
            var_arange = 1.
        else:
            var_arange = np.sum(arange ** 2) #取x序列的平方和

        for i in range(n_samples):
            mean = np.mean(X[i, start:end]) #取y序列的平均值
            X_new[i, 3 * j] = mean #第一个特征为平均值
            X_new[i, 3 * j + 1] = np.std(X[i, start:end]) #第二个特征值为标准差
            X_new[i, 3 * j + 2] = (
                np.sum((X[i, start:end] - mean) * arange) / var_arange
            ) #第三个特征值为斜率

    return X_new
start = rng.randint(0, n_timestamps - min_window_size, size=n_windows) #随机窗口起点序列
end = rng.randint(start + min_window_size, n_timestamps + 1,
                          size=n_windows) #随机窗口终点序列
indices = np.c_[start, end] #将起点序列和终点序列对应拼接

可能有人看了注释还是不懂什么意思,这里举一个简单的例子,比如我们有以下序列:

X = np.array([[1, 2, 2, 1, 2, 3, 2],
     [0, 2, 0, 2, 0, 2, 3],
     [0, 1, 2, 2, 1, 2, 2]])

之前章节也讲过,此时n_samples=3,也就是包含三个序列,n_timestamps=7,有7个时间点,如果默认参数n_windows=1,也就是我们只需要随机出一个窗口,那么最后返回的特征值也就只有一个窗口的三个特征,如果n_windows=2,有两个窗口,也就是2x3=6个特征。当n_windows=1时,randint由于size=1,只返回一个点:

start = rng.randint(0, 7 - 1, size=1)
end = rng.randint(start + 1, 7 + 1, size=1)
indices = np.c_[start, end]

在这里插入图片描述
也就是说我们此时选取了X里面的一个值(X[i, start:end])来进行平均数,标准差,斜率的计算。
这个时候可能有小伙伴想问,平均数,标准差,这些用numpy的一个函数就能计算完成,看得懂,但这个斜率为什么是这样计算的呢?

np.sum((X[i, start:end] - mean) * arange) / var_arange
var_arange = np.sum(arange ** 2)

这里要说明的很重要的一点是arange是np.arange生成的和X窗口长度相同的序列,窗口有几个数,arange里面就有几个数。也就是在这里我们其实把X的窗口作为了y序列,arange作为了x序列。
比如我有[4,5,6,7,8]这个窗口,start=3,end=8,那么生成的arange就为[-2,-1,0,1,2]。于是我们就是对x:[-2,-1,0,1,2]和对应的y值[4,5,6,7,8]求最佳的拟合直线的斜率:
在这里插入图片描述
这里贴一段知乎抄来的数学公式图,它的最后一部分用代码实现其实就是上面这个样子,(X[i, start:end] - mean)=yi-y平均,arange=xi-x平均,var_arange=(xi-x平均)的平方和。

参考

https://zhuanlan.zhihu.com/p/73494604
https://pyts.readthedocs.io/en/stable/generated/pyts.classification.TimeSeriesForest.html#pyts.classification.TimeSeriesForest

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值