时间序列中的模式识别。

74
通过处理时间序列图,我想要检测类似下面这样的模式:

enter image description here

举个例子,使用一组时间序列数据,我希望能够检测出以下标记的模式:

enter image description here

为了实现这个目标,我需要使用何种人工智能算法(我假设是机器学习技术)?是否有 C/C++ 库可供使用?

你能澄清一下吗:你正在寻找的模式,它们的大小是否固定(始终跨越相同数量的时间步)?此外,你是否已经考虑过滑动窗口方法? - schaul
5个回答

60

这是我做的一个小项目中对心电图数据进行分区的样例结果。

enter image description here

我的方法是使用“切换自回归隐马尔可夫模型”(如果您还没有听说过,请谷歌一下),其中每个数据点都是通过贝叶斯回归模型从前一个数据点进行预测的。我创建了81个隐藏状态:一个垃圾状态来捕获每个心跳之间的数据,以及80个不同位置对应的隐藏状态,构成心跳模式。这80个状态直接从子采样的单个心跳模式构建而成,并具有两个转换——自我转换和向模式中的下一个状态转换。模式中的最后一个状态会转换到自身或垃圾状态。
我使用Viterbi training训练了该模型,仅更新回归参数。
在大多数情况下,结果是足够好的。类似结构的条件随机场可能表现更好,但如果您没有标记数据集,则需要手动标记模式才能训练CRF。 编辑: 这里有一些 Python 代码示例 - 它并不完美,但是它给出了一般的方法。它实现了 EM 而不是 Viterbi 训练,可能会更加稳定。ECG 数据集来自http://www.cs.ucr.edu/~eamonn/discords/ECG_data.zip
import numpy as np
import numpy.random as rnd
import matplotlib.pyplot as plt 
import scipy.linalg as lin
import re
    
data=np.array(map(lambda l: map(float, filter(lambda x:len(x)>0,            
    re.split('\\s+',l))), open('chfdb_chf01_275.txt'))).T
dK=230
pattern=data[1,:dK]
data=data[1,dK:]
    
def create_mats(dat):
    '''
    create 
        A - an initial transition matrix 
        pA - pseudocounts for A
        w - emission distribution regression weights
        K - number of hidden states
    '''
    step=5  #adjust this to change the granularity of the pattern
    eps=.1
    dat=dat[::step]
    K=len(dat)+1
    A=np.zeros( (K,K) )
    A[0,1]=1.
    pA=np.zeros( (K,K) )
    pA[0,1]=1.
    for i in xrange(1,K-1):
        A[i,i]=(step-1.+eps)/(step+2*eps)
        A[i,i+1]=(1.+eps)/(step+2*eps)
        pA[i,i]=1.
        pA[i,i+1]=1.
    A[-1,-1]=(step-1.+eps)/(step+2*eps)
    A[-1,1]=(1.+eps)/(step+2*eps)
    pA[-1,-1]=1.
    pA[-1,1]=1.
        
    w=np.ones( (K,2) , dtype=np.float)
    w[0,1]=dat[0]
    w[1:-1,1]=(dat[:-1]-dat[1:])/step
    w[-1,1]=(dat[0]-dat[-1])/step
        
    return A,pA,w,K
    
# Initialize stuff
A,pA,w,K=create_mats(pattern)
        
eta=10. # precision parameter for the autoregressive portion of the model 
lam=.1  # precision parameter for the weights prior 
    
N=1 #number of sequences
M=2 #number of dimensions - the second variable is for the bias term
T=len(data) #length of sequences
    
x=np.ones( (T+1,M) ) # sequence data (just one sequence)
x[0,1]=1
x[1:,0]=data
    
# Emissions
e=np.zeros( (T,K) )

# Residuals
v=np.zeros( (T,K) )
    
# Store the forward and backward recurrences
f=np.zeros( (T+1,K) )
fls=np.zeros( (T+1) )
f[0,0]=1
b=np.zeros( (T+1,K) )
bls=np.zeros( (T+1) )
b[-1,1:]=1./(K-1)
    
# Hidden states
z=np.zeros( (T+1),dtype=np.int )
    
# Expected hidden states
ex_k=np.zeros( (T,K) )
    
# Expected pairs of hidden states
ex_kk=np.zeros( (K,K) )
nkk=np.zeros( (K,K) )
    
def fwd(xn):
    global f,e
    for t in xrange(T):
        f[t+1,:]=np.dot(f[t,:],A)*e[t,:]
        sm=np.sum(f[t+1,:])
        fls[t+1]=fls[t]+np.log(sm)
        f[t+1,:]/=sm
        assert f[t+1,0]==0
    
def bck(xn):
    global b,e
    for t in xrange(T-1,-1,-1):
        b[t,:]=np.dot(A,b[t+1,:]*e[t,:])
        sm=np.sum(b[t,:])
        bls[t]=bls[t+1]+np.log(sm)
        b[t,:]/=sm
    
def em_step(xn):
    global A,w,eta
    global f,b,e,v
    global ex_k,ex_kk,nkk
        
    x=xn[:-1] #current data vectors
    y=xn[1:,:1] #next data vectors predicted from current
    
    # Compute residuals
    v=np.dot(x,w.T) # (N,K) <- (N,1) (N,K)
    v-=y
    e=np.exp(-eta/2*v**2,e)
        
    fwd(xn)
    bck(xn)
        
    # Compute expected hidden states
    for t in xrange(len(e)):
        ex_k[t,:]=f[t+1,:]*b[t+1,:]
        ex_k[t,:]/=np.sum(ex_k[t,:])
        
    # Compute expected pairs of hidden states    
    for t in xrange(len(f)-1):
        ex_kk=A*f[t,:][:,np.newaxis]*e[t,:]*b[t+1,:]
        ex_kk/=np.sum(ex_kk)
        nkk+=ex_kk
        
    # max w/ respect to transition probabilities
    A=pA+nkk
    A/=np.sum(A,1)[:,np.newaxis]
        
    # Solve the weighted regression problem for emissions weights
    # x and y are from above 
    for k in xrange(K):
        ex=ex_k[:,k][:,np.newaxis]
        dx=np.dot(x.T,ex*x)
        dy=np.dot(x.T,ex*y)
        dy.shape=(2)
        w[k,:]=lin.solve(dx+lam*np.eye(x.shape[1]), dy)
            
    # Return the probability of the sequence (computed by the forward algorithm)
    return fls[-1]
    
if __name__=='__main__':
    # Run the em algorithm
    for i in xrange(20):
        print em_step(x)
    
    # Get rough boundaries by taking the maximum expected hidden state for each position
    r=np.arange(len(ex_k))[np.argmax(ex_k,1)<3]
        
    # Plot
    plt.plot(range(T),x[1:,0])
        
    yr=[np.min(x[:,0]),np.max(x[:,0])]
    for i in r:
        plt.plot([i,i],yr,'-r')
    
    plt.show()

2
抱歉,我在这个领域非常新,仍然被与模式识别相关的大量信息所压倒。我大致理解您的建议,但如果可能的话,可能需要更多的解释。我了解HMM的工作原理,但我现在的问题是如何将我的问题映射到HMM中,您能否通过类似于这里的示例格式帮助我更好地理解:http://en.wikipedia.org/wiki/Hidden_Markov_model#A_concrete_example - Ali
4
Rabiner的《隐马尔可夫模型入门》是一个不错的起点。我还提供了代码,以展示HMM在实践中的运作。 - user1149913
1
由于其记忆特性,是否有机会使用LSTM作为这种工具的合适选择? - Norman H
我希望您能看一下这个链接:https://stackoverflow.com/questions/44458859/python-finding-pattern-in-a-plot - Desta Haileselassie Hagos
@user1149913 如果我有一个时间序列数据,其中我正在绘制总玩家数量,并且我必须检测模式何时像一条平坦的线,不完全是平坦的线,而是类似于平坦的线。我想实现类似于这个网站上的内容 https://dracodoc.wordpress.com/2014/07/21/a-simple-algorithm-to-detect-flat-segments-in-noisy-signals/comment-page-1/?unapproved=34&moderation-hash=ff7caf64c800954c49e7d0413f99afa7#comment-34 - ak3191
显示剩余3条评论

7

为什么不使用一个简单的匹配滤波器?或者它的一般统计对应物称为交叉相关。给定一个已知的模式x(t)和一个包含你的模式在a,b,...,z中移动的嘈杂复合时间序列,如。x和y之间的交叉相关函数应该在a,b,...,z中显示峰值。


5

Weka是一个强大的机器学习软件集合,支持一些时间序列分析工具,但我不了解该领域足够推荐最佳方法。然而,它基于Java;您可以轻松调用C/C++中的Java代码

用于时间序列操作的软件包大多针对股票市场。我在评论中建议使用Cronos;我不知道如何进行模式识别,除了显而易见的:你的系列长度的任何良好模型都应该能够预测,在距离上一个小峰值的位置发生小波动后,会出现大波动。也就是说,您的系列表现出自相似性,并且Cronos中使用的模型旨在对其进行建模。

如果您不介意使用C#,则应向HCIL的人员请求TimeSearcher2版本-对于这个系统,模式识别是绘制模式的外观,然后检查您的模型是否足够通用,以捕获大多数实例并具有低的误报率。这可能是您能找到的最用户友好的方法;其他所有方法都需要相当背景的统计或模式识别策略。


是的,我有标记好的数据集可用于监督学习。Weka似乎是针对Java语言的,是否有C/C++等价库? - Ali
抱歉,我没有阅读问题的那部分... 那么 Cronos 呢?http://www.stat.cmu.edu/~abrock/oldcronos/ - tucuxi
抱歉,你知道如何使用Cronos进行模式识别吗?我浏览了网站,只看到了估计和预测。 - Ali
2
我认为它们之间存在着很强的关系。在使用序列的一部分进行训练后,鉴于小尖峰,GARCH等应该会生成一个信号来预测大尖峰... - tucuxi

3

我不确定哪个包最适合这个任务。在大学的某个时候,我尝试自动检测xy坐标系上的一些相似形状的点,用于处理一堆不同的图表。你可以尝试以下方式:

类别标签如下:

  • 无类别
  • 区域起点
  • 区域中点
  • 区域终点

特征如下:

  1. 每个窗口里面11个点的y轴相对值和绝对差异
  2. 与平均值之间的差异等特征
  3. 前后点之间的相对差异比较等

2

如果可以的话,我会使用深度学习来处理。这是用Java实现的,使用Deeplearning4j库。我正在尝试使用LSTM进行实验。我已经尝试过使用1个隐藏层和2个隐藏层来处理时间序列。

return new NeuralNetConfiguration.Builder()
                .seed(HyperParameter.seed)
                .iterations(HyperParameter.nItr)
                .miniBatch(false)
                .learningRate(HyperParameter.learningRate)
                .biasInit(0)
                .weightInit(WeightInit.XAVIER)
                .momentum(HyperParameter.momentum)
                .optimizationAlgo(
                        OptimizationAlgorithm.STOCHASTIC_GRADIENT_DESCENT  // RMSE: ????
                )
                .regularization(true)
                .updater(Updater.RMSPROP) // NESTEROVS
                // .l2(0.001)
                .list()
                .layer(0,
                        new GravesLSTM.Builder().nIn(HyperParameter.numInputs).nOut(HyperParameter.nHNodes_1).activation("tanh").build())
                .layer(1,
                        new GravesLSTM.Builder().nIn(HyperParameter.nHNodes_1).nOut(HyperParameter.nHNodes_2).dropOut(HyperParameter.dropOut).activation("tanh").build())
                .layer(2,
                        new GravesLSTM.Builder().nIn(HyperParameter.nHNodes_2).nOut(HyperParameter.nHNodes_2).dropOut(HyperParameter.dropOut).activation("tanh").build())
                .layer(3, // "identity" make regression output
                        new RnnOutputLayer.Builder(LossFunctions.LossFunction.MSE).nIn(HyperParameter.nHNodes_2).nOut(HyperParameter.numOutputs).activation("identity").build()) // "identity"
                .backpropType(BackpropType.TruncatedBPTT)
                .tBPTTBackwardLength(100)
                .pretrain(false)
                .backprop(true)
                .build();

发现了一些事情:

  • LSTM或RNN非常擅长挑选时间序列中的模式。
  • 尝试在一个时间序列和一组不同的时间序列上进行测试。模式很容易被挑选出来。
  • 它也试图挑选出不仅仅是一个节奏的模式。如果有按周和按月的模式,网络都将学习到。

这是一个分类问题吗?数据集是什么样子的? - Saddle Point
这是一个预测实验。 要使用LSTM进行分类,可以训练网络以期望标签的最后时间步长,使网络能够学习生成标签而不是我所做的预测。 希望这有所帮助。 - Neil Han
与其使用 LSTM,变压器架构(注意力机制的全息网络)可能是一种更现代的方法,导致相似的结果。 - MovGP0
好久不见,我正在尝试识别股票市场时间序列中的特定模式。 我可以使用LSTM / RNN来做到这一点吗?请问有没有人有相关经验和意见?感谢。 - ozgurozkanakdemirci
LSTM的训练速度较慢,我不记得它在我的情况下表现如何。如果“识别特定模式”意味着分类,您可以使用CNN,1-D CNN可用于时间序列模式识别。您只需要将数据转换为1-D,在数据上设置一个滑动窗口,并通过CNN运行它。CNN将将其分类为匹配“模式”或不匹配。我记得我曾经使用RNN来预测下一步。我现在对使用RNN的兴趣较小。 - Neil Han

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接