而方差 α2 由下式算出:
α2 = ((2*n1*n2) * (2*n1*n2 - n1 - n2)) / ((n1 + n2)2 * (n1 + n2 - 1)) |
這兩個公式均根據概率論得出。我們可以用平均值和方差來確定某個特定模式是隨機過程結果的概率。假設我們以兩個符號的模式開始,該模式表示為以下字符串:
string s = "XOOOXXXXOXXXXXXXOOOOXXXXXXXXXX"; |
盡管可以手動計算該模式中 X 和 O 的數量以及游程數,但讓我的程序代勞會更輕松。首先,我將確定該模式字符串中的兩個符號類型:
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 統計量等于模式中的實際游程數減去模式中的預期游程數,然后再除以預期游程數的標準偏差(即方差的平方根)后所得到的值。解譯模式中的標準化游程數要比解譯實際游程數容易。解譯代碼很簡單,但在概念上稍微有些隱晦。它的開頭如下所示:
原文轉自:http://www.uml.org.cn/Test/200611225.htm