累加和检测

累加和检测

0 简述

这个测试的重点是序列中调整后的(-1,+1)数字的累积和所定义的随机游走的最大偏移(与0的偏移)。 测试的目的是确定测试序列中出现的部分序列的累积和是否相对于随机序列的累积和的预期行为太大或太小。 这个累积和可以被认为是随机游走。 对于随机序列,随机游走应该接近于零。 对于某些类型的非随机序列,从零开始随机游走的偏移将会很大。

1、算法描述

首先定义几个变量:

  • bits表示输入的01序列,
  • n表示bits的长度,
  • mod表示序列的遍历方向,mod=0为向前遍历,mod为1表示向后遍历。(秒速一下向前向后遍历的具体情况)

下面将以输入源1011010111为例,进行该算法的具体说明

(1)修改数据

该步骤将数据的由原有的01组成形式转换为由-1和1所组成,即1 -> 1,0 -> -1。

\[X_{i} = 2bits_{i}-1 \]

代码如下所示

X = map(lambda x:2int(x)-1,bits)

(2)累加和计算

累加和,顾名思义计算累加之后的和值。累加的对象为(1)中所计算得到的X,从X的第一位累加至X的第n位(或以相反的防线进行累加),一共产生n个累加值。

向前累加(mod=0):

\[S_{1} = X_{1}\\ S_{2} = X_{1}+X_{2}\\ S_{3} = X_{1}+X_{2}+X_{3}\\ ...\\ S_{n-1} = X_{1}+X_{2}+X_{3}+...+X_{n-1}\\ S_{n} = X_{1}+X_{2}+X_{3}+...+X_{n-1}+X_{n} \]

向后累加(mod=1):

\[S'_{1} = X_{n}\\ S'_{2} = X_{n}+X_{n-1}\\ S'_{3} = X_{n}+X_{2}+X_{3}\\ ....\\ S'_{n-1} = X_{n}+X_{n-1}+X_{n-2}+X_{n-3}+...+X_{2}\\ S'_{n} = X_{n} + X_{n-1}+X_{n-2}+X_{n-3}+...+X_{2}+X_{1}\\ \]

上面的代码可以描述为如下的代码

#向前
    S = 0
    S = [0]*n
    for k in xrange(0, n):
        S += X[i]
        S[i] = S
# 向后
    S_ = 0
    S_ = [0]*n
    for k in xrange(0, n):
        S_ += X[n-i]
        S_[i] = S

上面的代码明眼人就知道包含了太多的重复操作,根据后面的算法操作,这部分会进行进一步的优化。

(3)求S的最大值

针对S和S'求出其中绝对值最大的值,令z为S中绝对值最大的值,zrev为S'中绝对值最大的值。

\[z = MAX_{1 \leq k \leq n}(|S_{k}|)\\ zrev = MAX_{1 \leq k \leq n}(|S'_{k}|) \]

(4)计算p_value

计算公式如下所示:

\[Pvalue = 1 - \sum_{k=(\frac{-n}{z} + 1)/4}^{(\frac{n}{z} - 1)/4} [Φ(\frac{(4k+1)z}{\sqrt(n)})-Φ(\frac{(4k-1)z}{\sqrt(n)})] + \sum_{k=(\frac{-n}{z} + 1)/4}^{(\frac{n}{z} - 3)/4} [Φ(\frac{(4k+3)z}{\sqrt(n)})-Φ(\frac{(4k+1)z}{\sqrt(n)})] \]

2、Python Code

从3、4两个步骤看出,第一部分和第二部分存在的意义就是求和与求最大值,所关注的内容仅仅为最大值。那么我们就可以对第二步进行适当的优化:

向前累加(mod=0):

\[S_{1} = X_{1}\\ S_{2} = X_{1}+X_{2}\\ S_{3} = X_{1}+X_{2}+X_{3}\\ ...\\ S_{n-1} = X_{1}+X_{2}+X_{3}+...+X_{n-1}\\ S_{n} = X_{1}+X_{2}+X_{3}+...+X_{n-1}+X_{n}\\ \]

向后累加(mod=1):

\[S'_{1} = X_{n}\\ S'_{2} = X_{n}+X_{n-1}\\ S'_{3} = X_{n}+X_{2}+X_{3}\\ ...\\ S'_{n-1} = X_{n}+X_{n-1}+X_{n-2}+X_{n-3}+...+X_{2}\\ S'_{n} = X_{n} + X_{n-1}+X_{n-2}+X_{n-3}+...+X_{2}+X_{1}\\ \]

从上式可以得出以下的结论

\[S'_{1} = S_{n} - S_{n-1}\\ S'_{2} = S_{n} - S_{n-2}\\ S'_{2} = S_{n} - S_{n-3}\\ ....\\ S'_{k} = S_{n} - S_{n-k}\\ ....\\ S'_{k} = S_{n}\\ \]

需要求出S'的最大值,很显然上面的等式有错可以理解为一个常数C减去正向累加和。那么当S'[k]的绝对值最大时,存在着两种情况。INF表示累加和到达过的0以下的最大距离,SUP表示累加和到达过0以上的最大距离

\[S_{k} > 0 \to z = S_{k} - INF\\ S_{k} < 0 \to z = SUP - S_{k} \]

那么现在求负向的zrev的操作就可以包含在求正向z值的过程中了。

针对正向的累加和有

    for k in xrange(0, n):
        S += X[k]
        if S > sup:
        #0以上的最大距离
            sup += 1
        if S < inf:
        #0以下的最大距离
            inf -= 1
        #得到Z
        z = max((sup,-inf))
        zrev = max((sup-S,S-inf))
        
def CumulativeSums(input_str):
    """
    参数: 
    输出: 
    描述: 
    """
    S = 0
    sup = 0
    inf = 0
    sum1,sum2 = 0,0
    zrev = 0
    n = len(input_str)
    for k in xrange(0, n):
        if input_str[k] == "1":
            S += 1
        else:
            S -= 1 
        if S > sup:
            sup += 1
        if S < inf:
            inf -= 1
        z = max((sup,-inf))
        zrev = max((sup-S,S-inf))
    
    # // 向前
    sum1 = 0.0
    for k in xrange(int((-n/z+1)/4),int((n/z-1)/4)+1):
        sum1 += normal(((4*k+1)*z)/math.sqrt(n));
        sum1 -= normal(((4*k-1)*z)/math.sqrt(n));

    sum2 = 0.0;
    for k in xrange(int((-n/z-3)/4),int((n/z-1)/4)+1):
        sum2 += normal(((4*k+3)*z)/math.sqrt(n));
        sum2 -= normal(((4*k+1)*z)/math.sqrt(n));


    p_value = 1.0 - sum1 + sum2;
    
    
    # // 向后
    sum1 = 0.0
    for k in xrange(int((-n/zrev+1)/4),int((n/zrev-1)/4)+1):
        sum1 += normal(((4*k+1)*zrev)/math.sqrt(n));
        sum1 -= normal(((4*k-1)*zrev)/math.sqrt(n));

    sum2 = 0.0
    for k in xrange(int((-n/zrev-3)/4),int((n/zrev-1)/4)+1):
        sum2 += normal(((4*k+3)*zrev)/math.sqrt(n));
        sum2 -= normal(((4*k+1)*zrev)/math.sqrt(n));

    p_value2 = 1.0 - sum1 + sum2;

    return p_value,p_value2
posted @ 2017-11-21 16:26  Dead_Micky  阅读(1646)  评论(0)    收藏  举报