1個擲硬幣問題,4個Python解法:讀書筆記
我在學習機器學習算法和玩Kaggle 比賽時候,不斷地發現需要重新回顧概率、統計、矩陣、微積分等知識。如果按照機器學習的標準衡量自我水平,這些知識都需要重新梳理一遍。
網上或許有各種各樣知識片斷,卻較難找到一本書將概率,統計、矩陣、微積分公式和Python結合起來。 要麽是講的比較淺顯,要麽跨度比較大。 最近看到一本書,恰好把上面的問題解決了。著重講解Python for 概率,統計,機器學習. 相比較吳恩達教授的網上課程,各有千秋。
- l 感覺吳教授的課程偏學術。 假設學生數學基礎比較紮實(畢竟課堂受眾是斯坦福大學學生,起點比較高),用矩陣推導公式,簡潔明了。整個課程把絕大多數機器學習算法都教了一遍。
- 這本書偏工程實踐。 書中從多個層面來介紹經典算法。尤其是後期的泛化,正則化等章節。介紹的算法,但是每個算法都用2-5種python方法實現。例如:
Python 循環或自帶Itertools ((笛卡爾乘積,經典概率)
Python sympy(數學符號) (微積分公式推導和實現)
Python Pandas(分組計算) (程序員看得懂)
Python numpy (矩陣計算) (註:用矩陣計算,有速度飛起來的感覺)
Python scipy (科學計算庫) (算法增強器)
個人感覺這本書比較適合我的學習目標。 也許也有人喜歡這樣的書。書名和下載地址在文章最後面。
我先來翻譯一段書中的一道期望計算題目,分享一下這種庖丁解牛和層次漸近的感覺。
題目:
三個硬幣: 1角,2角,5角。 同時擲硬幣,正面朝上的將面值加在一起求和。 只有兩個硬幣正面朝上的期望和是多少?
- Xi ∈ {0, 1} 註:硬幣為Xi, (面值10,10,50,分別為X10,X20,X50,只有正面和反面,是服從二項分布(0,1)
- ξ := 10X10 + 20X20+ 50X50註: ξ 為正面朝上的硬幣面值之和
- η := X10X20(1 ?X50) + (1 ? X10)X20X50 + X10(1 ? X20)X50 註: η 為只有兩個硬幣正面朝上的情況
這樣此題就變成了計算 E(ξ |η) 在 η 條件為真時,ξ 的期望。我們首先需要找到一個函數 h(η)。 這個函數可以讓殘差最小化。
現在,計算兩個硬幣朝上的面值之和公式變成了如何定義h(η)函數。
註:η的結果是{0,1},所以h函數的只有兩種輸入值{0,1}。因此,正交內積條件為
因為我們只需要知道滿足兩個硬幣朝上的情況,(即η =1 ),所以公式簡化為:
兩邊積分計算求和
數學公式到此就結束了。本書中定義h(η) = αη,並求α。這樣公式就變成了如下形式。
註:
公式推導完了,下面就看看Python的四種解法吧。
解法1 :Sympy數學符號方法
上述推導公式,直接可以用數學符號語言,在Sympy中計算。
計算結果精準 alpha = 160/3
E(ξ |η) = (160/3)*η
# Do it by sympy import sympy as S X10,X20,X50 = S.symbols("X10,X20,X50",real=True) xi = 10*X10+20*X20+50*X50 print("ξ = ",xi) eta = X10*X20*(1-X50)+X10*(1-X20)*(X50)+(1-X10)*X20*(X50) print("η = ",eta) num=S.summation(xi*eta,(X10,0,1),(X20,0,1),(X50,0,1)) den=S.summation(eta*eta,(X10,0,1),(X20,0,1),(X50,0,1)) alpha=num/den print(alpha)
ξ = 10*X10 + 20*X20 + 50*X50
η = X10*X20*(-X50 + 1) + X10*X50*(-X20 + 1) + X20*X50*(-X10 + 1)
160/3
解法2 :用Pandas,分組和計算(程序員的方式)
註:做1000次試驗(蒙特卡羅仿真),然後計算試驗的均值。計算結果近似於推導結果。
# Do it by pandas import pandas as pd d = pd.DataFrame(columns=[‘X10‘,‘X20‘,‘X50‘]) ntest = 10**6 d.X10 = np.random.randint(0,2,ntest) d.X10 = np.random.randint(0,2,ntest) d.X20 = np.random.randint(0,2,ntest) d.X50 = np.random.randint(0,2,ntest) grp=d.groupby(d.eval(‘X10+X20+X50‘)) grp.get_group(2).eval(‘10*X10+20*X20+50*X50‘).mean()
53.340141339548644
解法3:用Numpy,矩陣計算(速度快,有飛起來的感覺)
# Do it by numpy import numpy as np from numpy import array ntest = 10**6 x=np.random.randint(0,2,(3,ntest)) expectation =np.dot(x[:,x.sum(axis=0)==2].T,array([10,20,50])).mean() print(expectation)
53.3542987559
解法4: 用笛卡爾笛卡爾乘積,過濾只有兩個硬幣朝上事件,計算期望
#do it by pure python import itertools as it Xi = list(it.product((0,1),(0,1),(0,1))) #笛卡爾乘積函數 初始化 - 所有擲硬幣的事件 8種情況,三個硬幣,每個硬幣只有正面和反面 Xi_conditioned = list(it.filterfalse(lambda i:sum(i)!=2,Xi)) #過濾 只有兩個硬幣正面朝上的事件,只有三個事件 results = list((map(lambda k:10*k[0]+20*k[1]+50*k[2],Xi_conditioned))) dem = len(results) num = sum(results) print(Xi) print(Xi_conditioned) print(results) print(num/dem)
[(0, 0, 0), (0, 0, 1), (0, 1, 0), (0, 1, 1), (1, 0, 0), (1, 0, 1), (1, 1, 0), (1, 1, 1)]
[(0, 1, 1), (1, 0, 1), (1, 1, 0)]
[70, 60, 30]
53.333333333333336
這道概率期望題,書中演示了4種方法: Sympy,Numpy, Pandas 和Itertools. 在科學計算和機器學習中,采用不同的實現方法可以有助於問題解決和交叉檢查。
python學習交流群:125240963
原文鏈接:https://zhuanlan.zhihu.com/p/31673263
1個擲硬幣問題,4個Python解法:讀書筆記