char kind1 = s[0], kind2 = s[0]; for (int i = 0; i < s.Length && kind1 == kind2; ++i) { if (s[i] != kind1) kind2 = s[i]; } |
我將模式字符串中的第一個字符指定給第一種符號,接著掃描整個模式字符串,直到找到第二種符號類型。接下來,將執行兩項簡單的錯誤檢查,以確保該模式中至少存在兩種不同字符并且存在的字符類型不超過兩種。
if (kind2 == kind1)
for (int i = 0; i < s.Length; ++i) |
如果要考慮性能,則可將這三次對模式字符串的遍歷重新轉換為僅僅一次遍歷,但清晰性可能會受到一些影響。
現在,我就可以開始計算模式中每種類型符號的數量以及游程數了:
int n1 = 0, n2 = 0, runs = 1; for (int i = 0; i < s.Length-1; ++i) { if (s[i] == kind1) ++n1; else if (s[i] == kind2) ++n2; if (s[i+1] != s[i]) ++runs; } if (s[s.Length-1] == kind1) ++n1; else if (s[s.Length-1] == kind2) ++n2; |
我從第一個字符開始掃描該模式,一直持續到倒數第二個字符。如果當前字符與我先前確定的符號類型匹配,則我將遞增相應的計數器。為計算模式中的游程數,我利用了游程取決于符號類型的變化的這樣一個事實。如果當前字符與下一個字符不同,則我就知道又出現一個游程,然后我將相應遞增游程計數器。由于我在模式字符串中的倒數第二個字符處停止,因此最后我要檢查最后一個字符。我還會從 1(而不是 0)開始累計游程計數器,因為根據定義,所有模式都至少具備一個游程。
Wald-Wolfowitz 檢驗方法僅在所分析模式中每種類型符號的數量為 8 或大于 8 時才有效,因此我將執行以下檢查:
if (n1 < 8 || n2 < 8) throw new Exception("n1 和 n2 必須均大于等于 8," + "本次測試才有意義"); |
分析過程進行到這時,我已算出模式中兩種符號類型中每一種的數量以及實際游程數?,F在,如果兩個符號類型是隨機生成,則我將計算模式中的預期游程數:
double expectedRuns = 1 + ((2.0*n1*n2) / (n1 + n2)); |
然后我將計算游程數的方差(如果隨機生成),如下所示:
double varianceNumerator = (2.0*n1*n2) * (2.0*n1*n2 - N); double varianceDenominator = (double)((N*N)*(N-1)); double variance = varianceNumerator / varianceDenominator; |
分析中的下一步是計算標準化檢驗統計量 z:
double z = (R - expectedRuns) / Math.Sqrt(variance); |
z 統計量等于模式中的實際游程數減去模式中的預期游程數,然后再除以預期游程數的標準偏差(即方差的平方根)后所得到的值。解譯模式中的標準化游程數要比解譯實際游程數容易。解譯代碼很簡單,但在概念上稍微有些隱晦。它的開頭如下所示:
if (z < -2.580 || z > 2.580) { Console.Write("充分證明 (1%) 模式不是隨機生成的:"); Console.WriteLine(z < -2.580 ? "游程太少。" : 游程太多。"); } |
我以百分之一的顯著性水平執行了一次所謂的雙側檢驗。如果標準化檢驗統計量的絕對值大于 2.580,則不嚴格地說,這意味著所分析模式由隨機過程生成的幾率不到百分之一。值 2.580 源自統計表。如果檢驗統計量為負值,則實際游程數小于預期游程數,反之亦然。在圖 2 中,我也在查找證明該模式不是隨機生成的不充分證據。請注意,您在任何時候都不能肯定地說給定模式是隨機生成的;您只能通過檢驗來了解是否存在統計證據來證明該模式不是隨機生成的。
原文轉自:http://www.uml.org.cn/Test/200611225.htm