首页 > 其他分享 >时间序列分类方法:SAX-VSM学习

时间序列分类方法:SAX-VSM学习

时间:2024-04-10 19:58:26浏览次数:33  
标签:10 self label tf SAX key 序列 VSM

时间序列分类方法:SAX-VSM学习


前言

SAX是一种通过将时间序列离散化后投影到字符的算法,简单来说,SAX利用分段聚合近似PAA将时间序列平均分为n个段,再将该段用平均值表示,根据正态分布的分位数将这些值映射为一个字符。
VSM(Vector Space Model),它是信息检索和自然语言处理领域中常用的一种模型。VSM 将文档表示为高维向量,每个维度代表一个特定的词语或术语,从而将文档转换为数值化的形式,便于计算机进行处理和分析。
SAX-VSM利用了SAX将时间序列转换为字符的特点,将自然语言处理的TF-IDF方法应用其中,实现了时间序列分类的效果。
本文主要为个人的学习记录以及实际测试,和大家一起学习qwq


一、理论部分

长度为n的时间序列 T T T: { t 1 , t 2 , . . . , t n } \{t_1,t_2,...,t_n\} {t1​,t2​,...,tn​}

1.SAX

  • 分段聚合近似PAA

    • 标准化:将时间序列 T T T进行z标准化: T = T − μ σ T=\frac{T-\mu}{\sigma} T=σT−μ​,这样的目的是为了将时间序列划分到统一尺度下,消除尺度差异;
    • 分段:将时间序列 T T T平均划分为 m m m个段(这里假设可以n可以被m整除,在实际应用中会对不能整除的情况进行处理);
    • 聚合:计算每个段的平均值 t ˉ i = 1 m ∑ j = n m ( i − 1 ) + 1 n m i t j \bar t_i = \frac{1}{m}\sum_{j=\frac{n}{m}(i-1)+1}^{\frac{n}{m}i}t_j tˉi​=m1​∑j=mn​(i−1)+1mn​i​tj​;
    • 最终得到的离散序列: T ˉ = { t ˉ 1 , t ˉ 2 , . . . , t ˉ w } \bar T=\{\bar t_1,\bar t_2,...,\bar t_w\} Tˉ={tˉ1​,tˉ2​,...,tˉw​}。
      在这里插入图片描述

    如上图中,蓝色曲线为原始数据,红色为每一段的平均值。

  • 字符映射
    原始的SAX在选择字符数量上限后根据正态分布的分位数进行分配,如下:
    在这里插入图片描述
    即:
    s j = a l p h a j , i f f β j − 1 ≤ t ˉ i ≤ β j s_j = alpha_j,iff \beta_{j-1}\le \bar t_i \le \beta_j sj​=alphaj​,iffβj−1​≤tˉi​≤βj​
    这里主要讲的是SAX-VSM实现分类,就不详细去讲如何对字符进行距离比较了。
    原始的时间序列经过SAX进行降维,减少了数据量,并且在分段聚合近似的过程中也实现了一定的降噪效果,但是需要注意的是,SAX是依靠均值来分配字符的,这导致人直观感觉到的和实际计算的有些出入,且会因为一些细小的变化导致分配的字符不同。
    在这里插入图片描述
    如上图所示,这是两个具有一定“相位差”的子序列,由于幅值的差别,导致离散化字符的差别很大。这是由于划分字符的规则是由分段的平均值决定,虽然第二段有显著的尖峰,但是平均下来不如总体略高的第四段(上)和第一段(下)。

2.词袋(Bag-of-Word)

对于一个长时间序列,往往需要利用滑窗的方法来将其中每一个子序列转换为SAX字符串(单词),为了避免相邻子序列因高度相似导致的相同字符串,当出现连续相同的字符串时仅保留第一个单词。
这样我们将一个长时间序列转换为了一个单词序列:
T = { t 1 , t 2 , . . . , t n } ⇒ S = { w o r d 1 , w o r d 2 , . . . , w o r d j } T=\{t_1,t_2,...,t_n\}\Rightarrow S=\{word_1,word_2,...,word_j\} T={t1​,t2​,...,tn​}⇒S={word1​,word2​,...,wordj​}
此时,我们可以利用直方图的方式将所有的单词表示出来:
在这里插入图片描述
利用这种词袋方法的一个好处是可以实现时间序列的相位不变性,即将时间序列转换为无序的词袋后进行比较。利用直方图也可以进行相似或者分类的任务,但不是本文的重点。
在这里插入图片描述

3.词频-逆文档频率 TF-IDF

术语频率指的是一个词语在文档中出现的次数,如果一个词在一个文档中出现次数越多,对文档重要性越大。
t f t , d = { l o g ( 1 + f t , d ) , i f   f t , d > 0 0 , o t h e r w i s e tf_{t,d}=\left\{ \begin{aligned} log(1+f_{t,d}),if\ f_{t,d}>0\\ 0,otherwise \end{aligned} \right. tft,d​={log(1+ft,d​),if ft,d​>00,otherwise​
简单来说, t t t就是每一种单词, d d d就是一类数据的单词集合, f t , d f_{t,d} ft,d​是单词的词频。

逆文档频率的思想是从全局(所有类别的数据)来看,如果一个单词在很少的类别中出现,则它对于该类来说很重要:
i d f t , D = l o g ∣ D ∣ ∣ d ∈ D : t ∈ d ∣ = l o g N d f t idf_{t,D}=log\frac{|D|}{|d\in D:t\in d|}=log\frac{N}{df_t} idft,D​=log∣d∈D:t∈d∣∣D∣​=logdft​N​
其中 N N N是数据的类别数, d f t df_t dft​是单词 t t t出现过的词袋数。

则最终 t f − i d f tf-idf tf−idf:
t f ∗ i d f ( t , d , D ) = t f t , d × i d f t , D = l o g ( 1 + f t , d ) × l o g N d f t tf*idf(t,d,D)=tf_{t,d}\times idf_{t,D}=log(1+f_{t,d})\times log\frac{N}{df_t} tf∗idf(t,d,D)=tft,d​×idft,D​=log(1+ft,d​)×logdft​N​
一旦计算出所有频率值,单词频率矩阵就成为词频-逆文档频率权重矩阵,每一行表示对应的单词,每一列对应一类数据的权重向量,将其归一化处理。
将未知类别的时间序列转换为词袋后,在转换为词频向量,通过余弦相似度计算来划分类别:
s i m i l a r i t y ( a , b ) = c o s ( θ ) = a ⋅ b ∣ ∣ a ∣ ∣ ⋅ ∣ ∣ b ∣ ∣ similarity(a,b)=cos(\theta)=\frac{a\cdot b}{||a||\cdot ||b||} similarity(a,b)=cos(θ)=∣∣a∣∣⋅∣∣b∣∣a⋅b​
在这里插入图片描述
如果未知类别的词袋中出现了TF-IDF矩阵中不存在的单词则忽略。

二、实际应用

个人学习的习惯是学到一种新的算法后,按照伪代码编出来,再跟一些标准的函数库pyts进行对比,SAX算法其原创团队已经提供了代码,但是由于其正态分位数是直接设定了几位有效数字,因此可能和理论上分配的单词稍微有所偏差,但是问题不大。

1.自编代码

1.1 Matlab部分代码:

function [saxseries,indexs] = SAX(x,winSize,wordSize,num,stepSize)
    n = length(x);
    beta = [-inf,norminv((1:num-1)/num,0,1)];	% 正态分布的分位数
    temp = '';
    alpha = ['a','b','c','d','e','f','g','h','i','j','k','l','m','n'];
    tempPAA = PAA(x,winSize,wordSize,stepSize);   % 预先计算好PAA得到的均值
    saxseries = "";
    indexs = [];
    for i = 1:size(tempPAA,1)
        for j = 1:wordSize
            temp(j) = alpha(sum(beta<=tempPAA(i,j),2));	% 以当前均值大于分位数的个数作为索引,从字母表中取出对应的字母
        end
        if length(saxseries)==1||~all(temp==saxseries(end))	 % 连续相同的单词仅保存第一个
            saxseries(end+1) = temp;
            indexs(end+1) = i;
        end
        temp = '';
    end
    saxseries(1) = [];  % 第一个字符是""
end

上述代码为Matlab实现SAX的函数,其中PAA为预先计算各个子序列均值的函数,由于对每一个子序列都进行标准化非常消耗时间,因此利用了名为MASS的提前计算统计量的思想,可以提前计算许多标准化需要的均值和标准差,从而减少运行时间。

第一部分提到如果分段数不能整除,则可以按照如下的方式进行分配:

if m/N~=ceil(m/N)
	temp = zeros(N,m);
    for j = 1 : N
    	temp(j, :) = sub;
    end
    sub = reshape(temp, 1, N*m);
    sub = reshape(sub,m,N);
else
    sub = reshape(sub,m/N,N);
end

这里的思想就是将数据重复后进行叠加分配计算均值:
T = [ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ] T=[1,2,3,4,5,6,7,8,9,10] T=[1,2,3,4,5,6,7,8,9,10]共十个数据,如果要划分为3个段则将数据重复为:
T ′ = [ 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10 ] T'=\begin{bmatrix}1&2&3&4&5&6&7&8&9&10\\1&2&3&4&5&6&7&8&9&10\\1&2&3&4&5&6&7&8&9&10\\\end{bmatrix} T′= ​111​222​333​444​555​666​777​888​999​101010​
再将其重新排列:
T ′ ′ = [ 1 4 7 1 4 8 1 5 8 2 5 8 2 5 9 2 6 9 3 6 9 3 6 10 3 7 10 4 7 10 ] T''=\begin{bmatrix}1&4&7\\1&4&8\\1&5&8\\2&5&8\\2&5&9\\2&6&9\\3&6&9\\3&6&10\\3&7&10\\4&7&10\end{bmatrix} T′′= ​1112223334​4455566677​7888999101010​
然后计算这三列数据的平均值即可。

后续需要计算单词数量、每个类别的单词数量等等,我比较习惯python的字典,因此SAX-VSM在python实现。

1.2 Python部分代码:

转换代码:

    def trans(self, x, y):
        label = sorted(tuple(set(y)))	# 标签
        allclass = {key: {} for key in label}	# 每一个单词出现数量的字典
        count_class = {key: 0 for key in label}	  # 每一个单词在不同类中出现数量的字典
        tf = {key: {} for key in label}
        for i in range(np.size(x, 0)):
            data = x[i, :]
            sax = self.sax(data, self.win_size, self.word_len)
            un_sax, counts = np.unique(sax, return_counts=True)
            for key, count in zip(un_sax, counts):
                self.wordlist[key] = self.wordlist.get(key, 0) + count
                allclass[y[i]][key] = allclass[y[i]].get(key, 0) + count
                class_list[y[i]][key] = class_list[y[i]].get(key, 0) + count
        N = len(label)
        #   计算IDF
        self.dft = {}
        for key, values in self.wordlist.items():
            n = 0
            for i in range(len(self.label)):
                if key in class_list[self.label[i]]:
                    n += 1
            self.dft[key] = np.log(N / n) + 1
            for i in range(len(self.label)):
                dic = class_list[self.label[i]]
                if key in dic:
                    tf[self.label[i]][key] = tf[self.label[i]].get(key, 0) + dic[key]
        #   计算tf-idf矩阵
        self.allwords = list(self.wordlist.keys())
        label_len = len(self.label)
        allwords_len = len(self.allwords)
        # 预计算tf中每个单词的log值
        tf_log_values = {label: {word: np.log(tf_count) + 1 for word, tf_count in tf[label].items()}
                         for label in self.label}
        self.tf_idf = np.zeros((allwords_len, label_len))
        for j, label in enumerate(self.label):
            dic = class_list[label]
            for key in dic.keys():
                if key in self.allwords:
                    i = self.allwords.index(key)
                    self.tf_idf[i, j] = self.dft[key] * tf_log_values[label][key]

和pyts的SAX-VSM库对比了结果,完全相同,但是官方代码似乎是用了稀疏矩阵等方式,运行速度受数据量大小影响更小,我这种方法对于样本点数少的速度更快。

2.Pyts库函数

代码如下:

from pyts.classification import SAXVSM
from pyts.datasets import load_gunpoint,load_pig_central_venous_pressure,load_coffee
# 导入数据
X_train, X_test, y_train, y_test = load_gunpoint(return_X_y=True)
# 滑窗宽度为70,单词长度为10,单词表长度为10,分箱策略为正态分布,这里threshold_std是指当子序列标准差小于阈值则在标准化过程不除以标准差了
clf = SAXVSM(window_size=70,word_size=10, n_bins=10, strategy='normal', numerosity_reduction=True,threshold_std=0.01)
clf.fit(X_train, y_train)
score = clf.score(X_test, y_test)
print(score)

测试结果:
在这里插入图片描述


总结

本文简述了SAX-VSM的基本内容,并且展示了部分自己编的代码和pyts库函数的应用,个人体验来说SAX-VSM还是挺有趣的,因为SAX转换允许将很多相似形状的时间序列用一类单词表示,再根据它的索引可以一次性筛选出这些子序列,又由于转换为了词袋,使用了TF-IDF来进行分类任务,在一些不是特别复杂的数据里,其效果还是比较好的。但是需要注意,随着单词长度和单词表范围的增长,潜在的单词类别呈指数上升,如我自己编的代码就会大大增加计算量,但是用库函数的话还好。

这是我第一次写文章,可能内容差一些,还是希望能和大家一起学习。

参考文献

Lin J, Keogh E, Lonardi S, et al. A symbolic representation of time series, with implications for streaming algorithms[C]//Proceedings of the 8th ACM SIGMOD workshop on Research issues in data mining and knowledge discovery. 2003: 2-11.
Senin P, Malinchik S. Sax-vsm: Interpretable time series classification using sax and vector space model[C]//2013 IEEE 13th international conference on data mining. IEEE, 2013: 1175-1180.

标签:10,self,label,tf,SAX,key,序列,VSM
From: https://blog.csdn.net/weixin_48841772/article/details/137543395

相关文章

  • 从0到1的二次反序列化
    前言简单介绍下二次反序列化,顾名思义,就是反序列化两次,其主要意义是绕过黑名单的限制或不出网利用,有些CTF题把一大堆关键类全都ban了,这就让人无从下手,二次反序列化就是为此而生的SignedObject原理看构造函数,接受一个可序列化的对象,再进行一次序列化,简直不要太perfect关注一下......
  • 小论文随便发,最新算法!变分模态分解+霜冰算法优化+LSTM时间序列预测(附matlab代码实现)
     专题推荐:论文推荐,代码分享,视角(点击即可跳转)所有链接建议使用电脑端打开,手机端打开较慢【代码推荐购买指南】电力系统运行优化与规划、时间序列预测、回归分类预测matlab代码公众号历史推文合集23.3.21(电力系统前沿视角/预测和优化方向matlab代码/电力系统优秀论文推荐......
  • 【leetcode面试经典150题】26.判断子序列(C++)
    【leetcode面试经典150题】专栏系列将为准备暑期实习生以及秋招的同学们提高在面试时的经典面试算法题的思路和想法。本专栏将以一题多解和精简算法思路为主,题解使用C++语言。(若有使用其他语言的同学也可了解题解思路,本质上语法内容一致)【题目描述】给定字符串 s 和 t ......
  • 516. 最长回文子序列
    题目链接:本题考察区间\(dp\)。设\(f[i][j]\)表示子串\(i\simj\)中的最长回文子序列的长度。思考状态转移方程。因为是判断回文的问题,考虑首尾元素是否相同。若首尾元素相同,则考虑去掉首尾元素之后子串的最长回文子序列的长度+2(首、尾元素各一个)反之若首尾元素不相同......
  • 被3整除的子序列
    题目描述给你一个长度为50的数字串,问你有多少个子序列构成的数字可以被3整除答案对1e9+7取模输入描述输入一个字符串,由数字构成,长度小于等于50输出描述输出一个整数代码实现#include<iostream>#include<string>usingnamespacestd;//这里利用了两个性质//1.添加下......
  • 基于GA优化的CNN-LSTM-Attention的时间序列回归预测matlab仿真
    1.算法运行效果图预览ga优化前:     ga优化后:    2.算法运行软件版本matlab2022a  3.算法理论概述      时间序列预测是许多领域中的核心问题,如金融市场分析、气候预测、交通流量预测等。近年来,深度学习在时间序列分析上取得了显著的成果,尤......
  • 记一次php反序列化漏洞中的POPchain和POC构造实战
    来自于橙子科技反序列化靶场源代码如下:<?php//flagisinflag.phphighlight_file(__FILE__);error_reporting(0);classModifier{private$var;publicfunctionappend($value){include($value);echo$flag;}publicfunction......
  • 最长公共子序列(线性dp)-java
    本文主要来描述两个字符串的最长公共子序列问题文章目录前言一、最长公共子序列二、算法思路1.dp[i][j]的四种情况2.dp[i-1][j]、dp[i][j-1]、dp[i-1][j-1]的关系3.dp数组的状态转移方程 4.dp数组具体如下三、代码如下1.代码如下(示例):2.读入数据3.代码运行结......
  • LeetCode题练习与总结:排列序列--60
    一、题目描述给出集合 [1,2,3,...,n],其所有元素共有 n!种排列。按大小顺序列出所有排列情况,并一一标记,当 n=3时,所有排列如下:"123""132""213""231""312""321"给定 n和 k,返回第 k 个排列。示例1:输入:n=3,k=3输出:"213"示例2:输入:n=4,k=......
  • Rome反序列化链分析
    环境搭建<dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><de......