前言:彩票是一個坑,千萬不要往裏面跳。任何預測彩票的方法都不可能100%,都只能說比你盲目去買要多那麼一些機會而已。算法
已經3個月沒寫博客了,由於業餘時間一直在研究彩票,發現仍是有不少樂趣,偶爾買買,娛樂一下。本文的目的是向你們分享一個經典的數學預測算法的思路以及代碼。對於這個馬爾可夫鏈模型,我本人之前也只是據說過,研究不深,若有錯誤,還請賜教,互相學習。數組
馬爾可夫鏈是一個可以用數學方法就能解釋天然變化的通常規律模型,它是由著名的俄國數學家馬爾科夫在1910年左右提出的。馬爾科夫過程已是如今機率論中隨機過程理論的一個重要方面。通過了一百年左右的發展,馬爾可夫過程已經滲透到各個領域併發揮了重要的做用,如在咱們熟知的經濟、通訊領域,除此以外在地質災害、醫療衛生事業、生物學等天然科學領域也發揮了很是重要的做用。併發
人們在對實際問題的研究中會發現隨着時間的持續發展變化會產生不少現象。還有一些現象或過程能夠表述以下:在「如今」是已知的狀況下,這種變化過程的「將來」與「過去」是毫無聯繫的。也就是說這種過程的將來所出現的狀況不依賴於過去的發展變化,咱們就把具備上述性質的過程稱之爲馬爾可夫過程。馬爾可夫過程能夠描述現實生活中的不少現象。例如,咱們熟知的液體中的顆粒所作的布朗運動、在商業活動中所要研究的天天銷售狀況、在數字通訊中的語音信號、視頻信號等。馬爾可夫鏈在其餘領域的應用還有不少,如在銀行的不良資產的管理、機車管理、企業管理、生態環境演變、城市用水量仿真、信息處理等科學研究和生產生活中都有普遍應用。函數
定義1:學習
定義2:測試
上面是2個最簡單的馬爾可夫鏈的數學定義,看不懂不要緊,簡單解釋一下:this
1.從狀態k到k+1與時間k無關,也就是說這個隨機過程與時間k無關,而從k到k+1狀態,有一個轉移機率,馬爾可夫鏈的核心其實也就是這個轉移機率;spa
2.根據馬爾可夫鏈的思想,一步轉移機率Pij很容易獲得,可是預測的時候,每每要根據最近K期的數據來進行,因此要計算K步轉移機率;code
3.任意步的轉移機率能夠根據C-K方程來計算,CK方程是一種計算轉移機率的基本方法,簡單的算法就是:經過一步轉移機率矩陣P獨自相乘m次,就能夠獲得m步轉移機率。視頻
4.馬爾可夫鏈的思想,就是根據歷史的數據,統計獲得轉移機率,而後根據滯時權重對每一個狀態進行預測,機率最高的是最可能出現的。
5.對於離散型馬爾可夫鏈序列變量,通常計算以前須要對變量進行「馬氏性」檢驗,統計量就是卡方分佈。
6.馬爾可夫鏈的研究還有不少其餘的方面,好比狀態分類,極限機率,平穩分佈等等,這些過高級,沒時間去搞很懂,這些對預測過程的精度是有必定影響的。
對於離散型變量來講,首先要把目標的數據進行歸類,對模型來講,通常狀態都是有限的,好比說雙色球,能夠把16個籃球號碼分爲8個狀態,2個一組。固然一些經濟和實際生活數據的狀態分類,就要根據實際狀況了。
轉移機率矩陣是能夠根據歷史數據的頻率f(i,j)統計獲得。f(i,j)是狀態i到狀態j轉移的次數;而後機率轉移矩陣
p(i,j) = f(i,j)/f(i.) ;頻數除以當前行的和值即爲機率
對於離散型的變量,須要利用歷史數據進行「馬氏性」檢驗。檢驗公式爲:
而後根據顯著性水平(程序中固定取0.05) ,查表求m自由度時的閥值,若 ,則知足 馬氏性,能夠進行下一步的預測,不然沒有多大的意義。
若知足馬氏性,就能夠對下一個狀態進行預測了,預測根據滯時k,有權重調整,權重W(k)是根據自相關係數R(k)計算獲得的,公式以下:
k爲滯時期,我程序測試裏面選的5,L是總的歷史數據次數,X是歷史數據序列。
根據C-K方程提供的算法,計算k步的轉移機率矩陣 Pi(k) ,又一次轉移機率矩陣自乘 k次獲得。
下一個狀態的預測機率經過相同狀態的各個預測機率加權和獲得,計算用到公式:
最後一步的時候要注意,要根據最後k期的歷史數據所在狀態值和步長的權值相乘。滯時期爲1的數據,是最後1期數據(最新的數據),這個循環的時候要注意,很容易掉進坑裏。
本文使用C#實現了簡單的離散型馬爾可夫鏈模型,在驗證馬氏性的時候,因爲須要查表求值,因此暫時固定了自由度25,顯著性水平0.05,模型核心代碼:
1 /// <summary>離散型馬爾可夫鏈預測模型</summary> 2 public class DiscreteMarkov 3 { 4 #region 屬性 5 /// <summary>樣本點狀態時間序列,按照時間升序</summary> 6 public List<int> StateList { get; set; } 7 /// <summary>狀態總數,對應模型的m</summary> 8 public int Count { get; set; } 9 /// <summary>機率轉移矩陣Pij</summary> 10 public List<DenseMatrix> ProbMatrix { get; set; } 11 /// <summary>各階的自相關係數</summary> 12 public double[] Rk { get; set; } 13 /// <summary>各階的權重/summary> 14 public double[] Wk { get; set; } 15 /// <summary>頻數矩陣/summary> 16 public int[][] CountStatic { get; set; } 17 /// <summary>目標序列是否知足"馬氏性"/summary> 18 public Boolean IsMarkov { get; set; } 19 /// <summary>滯時期,K/summary> 20 public int LagPeriod { get; set; } 21 22 /// <summary>預測機率</summary> 23 public double[] PredictValue { get; set; } 24 #endregion 25 26 #region 構造函數 27 public DiscreteMarkov(List<int> data, int count,int K = 5) 28 { 29 this.StateList = data; 30 this.LagPeriod = K; 31 this.Count = count; 32 this.CountStatic = StaticCount(data, count); 33 this.ProbMatrix = new List<DenseMatrix>(); 34 var t0 = DenseMatrix.OfArray(StaticProbability(this.CountStatic).ConvertToArray<double>()); 35 ProbMatrix.Add(t0); 36 37 for (int i = 1; i < K; i++) //根據CK方程,計算各步的狀態轉移矩陣 38 { 39 var temp = ProbMatrix[i - 1] * t0; 40 ProbMatrix.Add(temp); 41 } 42 if (ValidateMarkov()) 43 { 44 CorrCoefficient(); 45 TimeWeight(); 46 PredictProb(); 47 } 48 else 49 { 50 Console.WriteLine("馬氏性 檢驗失敗,沒法進行下一步預測"); 51 } 52 } 53 #endregion 54 55 #region 驗證 56 /// <summary>驗證是否知足馬氏性,默認的顯著性水平是0.05,自由度25</summary> 57 /// <returns></returns> 58 public Boolean ValidateMarkov() 59 { 60 //計算列和 61 int[] cp1 = new int[Count]; 62 int allcount = CountStatic.Select(n => n.Sum()).Sum();//總數 63 64 for (int i = 0; i < Count; i++) 65 { 66 for (int j = 0; j < Count; j++) cp1[i] += CountStatic[j][i]; 67 } 68 double[] cp = cp1.Select(n => (double)n / (double)allcount).ToArray(); 69 70 //計算伽馬平方統計量 71 double gm = 0; 72 for (int i = 0; i < Count; i++) 73 { 74 for (int j = 0; j < Count; j++) 75 { 76 if (CountStatic[i][j] != 0) 77 gm += 2 * CountStatic[i][j] * Math.Abs(Math.Log(ProbMatrix[0][i,j] / cp[j], Math.E)); 78 } 79 } 80 //查表求a = 0.05時,伽馬分佈的臨界值F(m-1)^2,若是實際的gm值大於差異求得的值,則知足 81 //查表要本身作表,這裏只演示0.05的狀況 卡方分佈 82 return gm >= 37.65; 83 } 84 85 /// <summary>計算相關係數</summary> 86 public void CorrCoefficient() 87 { 88 double mean = (double)StateList.Sum() /(double) StateList.Count;//均值 89 90 double p = StateList.Select(n => (n - mean)*(n-mean)).Sum(); 91 92 Rk = new double[LagPeriod]; 93 94 for (int i = 0; i < LagPeriod; i++) 95 { 96 double s1 = 0; 97 for (int L = 0; L < StateList.Count - LagPeriod ; L++) 98 { 99 s1 += (StateList[L] - mean) * (StateList[L + i] - mean); 100 } 101 Rk[i] = s1 / p; 102 } 103 } 104 105 /// <summary>計算滯時的步長</summary> 106 public void TimeWeight() 107 { 108 double sum = Rk.Select(n=>Math.Abs(n)).Sum(); 109 Wk = Rk.Select(n => Math.Abs(n) / sum).ToArray(); 110 } 111 112 /// <summary>預測狀態機率</summary> 113 public void PredictProb() 114 { 115 PredictValue = new double[Count]; 116 //這裏很關鍵,權重和滯時的關係要顛倒,循環計算的時候要注意 117 //另外,要根據最近幾期的出現數,肯定機率的狀態,必須取出最後幾期的數據 118 119 //1.先取最後K期數據 120 var last = StateList.GetRange(StateList.Count - LagPeriod, LagPeriod); 121 //2.注意last數據是升序,最後一位對於的滯時期 是k =1 122 for (int i = 0; i < Count; i++) 123 { 124 for (int j = 0; j < LagPeriod; j++) 125 { 126 //滯時期j的數據狀態 127 var state = last[last.Count - 1 - j] - 1; 128 PredictValue[i] += Wk[j] * ProbMatrix[j][state ,i]; 129 } 130 } 131 } 132 #endregion 133 134 #region 靜態 輔助方法 135 /// <summary>統計頻數矩陣</summary> 136 /// <param name="data">升序數據</param> 137 public static int[][] StaticCount(List<int> data, int statusCount) 138 { 139 int[][] res = new int[statusCount][]; 140 141 for (int i = 0; i < statusCount; i++) res[i] = new int[statusCount]; 142 143 for (int i = 0; i < data.Count - 1; i++) res[data[i]-1][data[i + 1]-1]++; 144 145 return res; 146 } 147 /// <summary>根據頻數,計算轉移機率矩陣</summary> 148 /// <param name="data">頻率矩陣</param> 149 public static double[][] StaticProbability(int[][] data) 150 { 151 double[][] res = new double[data.Length][]; 152 for (int i = 0; i < data.Length; i++) 153 { 154 int sum = data[i].Sum(); 155 res[i] = data[i].Select(n => (double)n / (double)sum).ToArray(); 156 } 157 return res; 158 } 159 #endregion 160 }
調用方法很簡單,以下代碼:這裏使用的是論文文獻中的數據,單個號碼的隨機機率爲16.6%,程序預測的機率能夠到25-30%的樣子,應該還有調整的空間。
1 //歷史狀態數據 2 List<int> data = new List<int>(){ 3 6,4,4,5,2,4,6,1,2,6, 5,6,4,4,6 , 5,3,6,5,2 , 5,3,3,4,4, 4 4,1,1,1,1,3,5,6,5,5, 5,5,4,6,5 , 4,1,3,1,3 , 1,3,1,2,5, 5 2,2,5,5,1,4,4,2,6,1, 5,4,6,3,2, 2,6,4,4,4, 4,3,1,5,3, 6 1,2,6,5,3,6,3,6,4,6, 2,4,4,6,3, 3,6,2,6,1, 3,2,2,6,6, 7 4,4,3,1,4,1,2,6,4,4, 1,2};//,6,4,3,6,2,5,5,5 8 9 var result = new DiscreteMarkov(data, 6,5);
哈哈,請關注博客,年後將根據此算法,對高頻彩快3和11選5進行實證分析。由於這個過程有點複雜,不是一會兒能夠搞定的。
本文的相關文字資料,公式和數據來源根據這篇文獻:「馬爾可夫鏈預測模型及一些應用」,2012.3 溫海彬
最後,彩票風險很大,購彩需謹慎。你的熱情和推薦,是個人動力哦。
補充一下,其中有一個擴展方法,進行數組轉換的,忘記貼上去了:
1 public static T[,] ConvertToArray<T>(this T[][] data) 2 { 3 T[,] res = new T[data.Length, data[0].Length]; 4 for (int i = 0; i < data.Length; i++) 5 { 6 for (int j = 0; j < data[i].Length; j++) res[i, j] = data[i][j]; 7 } 8 return res; 9 }