时间序列中的模式识别

通过处理一个时间序列图,我想要发现类似于下面这样的模式:

enter image description here

以一个样本时间序列为例,我希望能够检测到这里标记的模式:

enter image description here

我需要使用什么样的人工智能算法(我假设是机器学习技术)来实现这一点?有没有我可以用的(C/C + + 中的)库?

57543 次浏览

Weka 是一个强大的机器学习软件集合,支持一些时间序列分析工具,但是我对这个领域的了解还不足以推荐一个最好的方法。但是,它是基于 Java 的; 您可以毫不费力地使用 从 C/C + + 调用 Java 代码

时间序列操纵的一揽子方案主要是针对股票市场的。我在评论中建议使用 克罗诺斯; 我不知道如何使用它进行模式识别,除了一个显而易见的问题: 任何一个你的系列长度的好模型都应该能够预测,在一定距离的小颠簸后,最后一个小颠簸,大颠簸接踵而至。也就是说,您的系列展示了自相似性,而在 Cronos 中使用的模型被设计用于对其进行建模。

如果你不介意 C # ,你应该向 HCIL 的人请求一个版本的 TimeSearcher2时间搜索2——对于这个系统来说,模式识别就是画出一个模式的样子,然后检查你的模型是否足够通用,能够以低误报率捕获大多数实例。可能是您将发现的最方便用户的方法; 所有其他方法都需要有相当的统计学或模式识别策略背景。

我不知道什么方案最适合这个。我在大学的时候也做过类似的事情,我试图自动检测出一系列不同图形在 x-y 轴上的相似形状。您可以执行以下操作。

类别标签如:

  • 没档次
  • 区域起点
  • 中部地区
  • 区域末端

特点如下:

  1. 相对 y 轴的相对和绝对差 在一个窗口的周围点11点宽
  2. 特征如与平均值不同
  3. 前点和后点之间的相对差值

下面是我对 ecg 数据进行分区的一个小项目的示例结果。

enter image description here

我的方法是“切换自回归 HMM”(如果你没有听说过,谷歌一下这个) ,其中每个数据点都是使用贝叶斯回归模型从前面的数据点预测的。我创建了81个隐藏状态: 一个垃圾状态来捕获每个拍之间的数据,以及80个对应于心跳模式中不同位置的独立隐藏状态。该模式80个状态直接从一个次采样单拍模式构建,并有两个转换-一个自转换和一个转换到模式中的下一个状态。模式中的最终状态转换为它自己或垃圾状态。

我用 维特比训练训练模型,只更新回归参数。

结果在大多数情况下是足够的。一个类似的结构条件随机域可能会表现得更好,但是如果你还没有标记数据的话,训练一个通用报告格式需要在数据集中手动标记模式。

编辑:

下面是一些 Python 代码示例-它并不完美,但它提供了一般的方法。它实现 EM 而不是维特比训练,这可能稍微更稳定。 心电图数据集来自 < a href = “ http://www.cs.ucr.edu/% 7Eeamonn/discords/ECG _ data.zip”rel = “ nofollow noReferrer”> 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()

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

如果你愿意的话,我可以用深度学习。这是用 Java 编写的,深呼吸。我在试验 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 非常善于挑选模式的时间序列。
  • 试验采用一个时间序列和一组不同的时间序列,模式易于识别。
  • 它还试图找出模式,而不仅仅是一个节奏。如果每周和每月都有模式,那么这两种模式都可以通过网络学习。