一、 排列熵算法简介:
排列熵算法(Permutation Entroy)为度量时间序列复杂性的一种方法,算法描述如下:
设一维时间序列:
采用相空间重构延迟坐标法对X中任一元素x(i)进行相空间重构,对每个采样点取其连续的m个样点,得到点x(i)的m维空间的重构向量:
则序列X的相空间矩阵为:
其中m和l分别为重构维数和延迟时间;
对x(i)的重构向量Xi各元素进行升序排列,得到:
这样得到的排列方式为
相对来说,排列熵的计算过程较为简洁,计算量主要为k次序列长度为m的全排序,在满足功能的前提下,窗口可以尽量的小,同时,窗口大小和延迟l值的大小选取非常重要。排列熵H的大小表征时间序列的随机程度,值越小说明该时间序列越规则,反之,该时间序列越具有随机性。在排列熵算法的基础上也可以发展出诸多使用熵值的对时间序列进行异常检测的算法
二.排列熵算法的实现
已排列窗口长度为4为例(由于涉及对数组的重复排序,该窗口长度宜设置较小,已加快计算速度),计算一段序列值得排列熵
</pre><span style="white-space:pre"> </span>private double PermutationEntropyCalCulator(double[] dArrData)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>/*<span style="white-space:pre"> </span> * 计算一段序列值的排列熵<span style="white-space:pre"> </span> */<span style="white-space:pre"> </span>int M = 4; //窗口长度值<span style="white-space:pre"> </span>int nMPer = 24;// 大小为窗口长度的集合全排列数<span style="white-space:pre"> </span>int L = 8; //延迟<span style="white-space:pre"> </span>double[] dArrSample = new double[M];<span style="white-space:pre"> </span>int[] nArrSampleSortIndex = new int[M];<span style="white-space:pre"> </span>int[] nPermCount = new int[nMPer];<span style="white-space:pre"> </span><span style="white-space:pre"> </span>Dictionary<string, int> permlist = new Dictionary<string, int>();<span style="white-space:pre"> </span>//构建字典索性<span style="white-space:pre"> </span>permlist.Add("4321", 0);<span style="white-space:pre"> </span>permlist.Add("4312", 1);<span style="white-space:pre"> </span>permlist.Add("4231", 2);<span style="white-space:pre"> </span>permlist.Add("4213", 3);<span style="white-space:pre"> </span>permlist.Add("4123", 4);<span style="white-space:pre"> </span>permlist.Add("4132", 5);<span style="white-space:pre"> </span><span style="white-space:pre"> </span>permlist.Add("3421", 6);<span style="white-space:pre"> </span>permlist.Add("3412", 7);<span style="white-space:pre"> </span>permlist.Add("3241", 8);<span style="white-space:pre"> </span>permlist.Add("3214", 9);<span style="white-space:pre"> </span>permlist.Add("3124", 10);<span style="white-space:pre"> </span>permlist.Add("3142", 11);<span style="white-space:pre"> </span><span style="white-space:pre"> </span>permlist.Add("2341", 12);<span style="white-space:pre"> </span>permlist.Add("2314", 13);<span style="white-space:pre"> </span>permlist.Add("2431", 14);<span style="white-space:pre"> </span>permlist.Add("2413", 15);<span style="white-space:pre"> </span>permlist.Add("2143", 16);<span style="white-space:pre"> </span>permlist.Add("2134", 17);<span style="white-space:pre"> </span><span style="white-space:pre"> </span>permlist.Add("1324", 18);<span style="white-space:pre"> </span>permlist.Add("1342", 19);<span style="white-space:pre"> </span>permlist.Add("1234", 20);<span style="white-space:pre"> </span>permlist.Add("1243", 21);<span style="white-space:pre"> </span>permlist.Add("1423", 22);<span style="white-space:pre"> </span>permlist.Add("1432", 23);<span style="white-space:pre"> </span><span style="white-space:pre"> </span><span style="white-space:pre"> </span>Array.Clear(nPermCount, 0, nPermCount.Length);<span style="white-space:pre"> </span><span style="white-space:pre"> </span>int j, k;<span style="white-space:pre"> </span><span style="white-space:pre"> </span>for (j=0; j < (dArrData.Length- M*L); j++)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>for (k=0; k<M; k++)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>dArrSample[k] = dArrData[j+k*L];<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span><span style="white-space:pre"> </span>SortIdex(dArrSample, ref nArrSampleSortIndex);//排序<span style="white-space:pre"> </span><span style="white-space:pre"> </span>string strSampleSortIndex = "";<span style="white-space:pre"> </span>for (k=0; k<M; k++)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>strSampleSortIndex += nArrSampleSortIndex[k];<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span><span style="white-space:pre"> </span>if (permlist.TryGetValue(strSampleSortIndex, out k) == false)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>k = 0;<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span><span style="white-space:pre"> </span>nPermCount[k]++;<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span><span style="white-space:pre"> </span>double dPermSum = 0;<span style="white-space:pre"> </span>nMPer = 24;<span style="white-space:pre"> </span>for (j=0; j<nMPer; j++)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>dPermSum += nPermCount[j];<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span><span style="white-space:pre"> </span>double dPermutationEntropy = 0;<span style="white-space:pre"> </span>for (j=0; j<nMPer; j++)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span>if(nPermCount[j]>0)<span style="white-space:pre"> </span>{<span style="white-space:pre"> </span> double dProb = nPermCount[j]/dPermSum;<span style="white-space:pre"> </span> dPermutationEntropy += -dProb*Math.Log(dProb);//计算熵值<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span>}<span style="white-space:pre"> </span><span style="white-space:pre"> </span>dPermutationEntropy = dPermutationEntropy/Math.Log(nMPer);<span style="white-space:pre"> </span><span style="white-space:pre"> </span>double dWeight = (dPermSum-nPermCount[0])/dPermSum;<span style="white-space:pre"> </span>dPermutationEntropy = dPermutationEntropy*dWeight;<span style="white-space:pre"> </span><span style="white-space:pre"> </span>return dPermutationEntropy;<span style="white-space:pre"> </span>}</p><p style="color: rgb(54, 46, 43); font-family: Arial; font-size: 14px; line-height: 26px;"><pre name="code" class="html">private void SortIdex(double[] dArrSample, ref int[] nArrSampleSortIndex)
{
/*
* 由小至大,依次排序
*
*/
if (dArrSample.Length != nArrSampleSortIndex.Length)
{
return;
}
int i,j;
int nTempIndex = 0;
double dTempValue = 0;
for(i=0; i<nArrSampleSortIndex.Length; i++)
{
nArrSampleSortIndex[i] = i+1;
}
for(i=0; i<dArrSample.Length; i++)
{
for(j=(dArrSample.Length-1); j>i; j--)
{
if(dArrSample[j-1]>dArrSample[j])
{
dTempValue = dArrSample[j-1];
nTempIndex = nArrSampleSortIndex[j-1];
dArrSample[j-1] = dArrSample[j];
nArrSampleSortIndex[j-1] = nArrSampleSortIndex[j];
dArrSample[j] = dTempValue;
nArrSampleSortIndex[j] = nTempIndex;
}
}
}
}
窗口长度较大的时,在小型设备上实时运行需要耗费较多的资源,不知道能否做进一步的优化呢