八楣铁、隨機(jī)性
原文:Randomness
譯者:飛龍
協(xié)議:CC BY-NC-SA 4.0
自豪地采用谷歌翻譯
在前面的章節(jié)中道偷,我們開發(fā)了深入描述數(shù)據(jù)所需的技能缀旁。 數(shù)據(jù)科學(xué)家也必須能夠理解隨機(jī)性。 例如勺鸦,他們必須能夠隨機(jī)將個(gè)體分配到實(shí)驗(yàn)組和對照組并巍,然后試圖說明,觀察到的兩組結(jié)果之間的差異是否僅僅是由于隨機(jī)分配换途,或真正由于實(shí)驗(yàn)所致懊渡。
在這一章中刽射,我們開始分析隨機(jī)性。 首先剃执,我們將使用 Python 進(jìn)行隨機(jī)選擇誓禁。 在numpy
中有一個(gè)叫做random
的子模塊,它包含許多涉及隨機(jī)選擇的函數(shù)肾档。 其中一個(gè)函數(shù)稱為choice
摹恰。 它從一個(gè)數(shù)組中隨機(jī)選取一個(gè)項(xiàng)目,選擇任何項(xiàng)目都是等可能的怒见。 函數(shù)調(diào)用是np.random.choice(array_name)
俗慈,其中array_name
是要從中進(jìn)行選擇的數(shù)組的名稱。
因此遣耍,下面的代碼以 50% 的幾率求值為treatment
闺阱,50% 的機(jī)率為control
。
two_groups = make_array('treatment', 'control')
np.random.choice(two_groups)
'treatment'
上面的代碼和我們迄今運(yùn)行的所有其他代碼之間的巨大差異在于舵变,上面的代碼并不總是返回相同的值酣溃。 它可以返回treatment
或control
,我們不會提前知道會選擇哪一個(gè)纪隙。 我們可以通過提供第二個(gè)參數(shù)來重復(fù)這個(gè)過程赊豌,它是重復(fù)這個(gè)過程的次數(shù)。
np.random.choice(two_groups, 10)
array(['treatment', 'control', 'treatment', 'control', 'control',
'treatment', 'treatment', 'control', 'control', 'control'],
dtype='<U9')
隨機(jī)事件的根本問題是它們是否發(fā)生瘫拣。 例如:
- 個(gè)體是否被分配到實(shí)驗(yàn)組亿絮?
- 賭徒是否會贏錢告喊?
- 一個(gè)民意調(diào)查是否做出了準(zhǔn)確的預(yù)測麸拄?
一旦事件發(fā)生,你可以對所有這些問題回答“是”或“否”黔姜。 在編程中拢切,通常通過將語句標(biāo)記為True
或False
來執(zhí)行此操作。 例如秆吵,如果個(gè)體被分配到實(shí)驗(yàn)組淮椰,那么“個(gè)體被分配到實(shí)驗(yàn)組”的陳述將是真的。 如果不是纳寂,那將是假的主穗。
布爾值和比較
在 Python 中,布爾值(以邏輯學(xué)家 George Boole 命名)表示真值毙芜,并只有兩個(gè)可能的值:True
和False
忽媒。 無論問題是否涉及隨機(jī)性,布爾值通常都由比較運(yùn)算符產(chǎn)生腋粥。 Python 包含了各種比較值的運(yùn)算符晦雨。 例如架曹,3
大于1 + 1
。
3 > 1 + 1
True
True
表示比較是有效的闹瞧;Python 已經(jīng)證實(shí)了3
和1 + 1
的關(guān)系的這個(gè)簡單事實(shí)绑雄。 下面列出了一整套通用的比較運(yùn)算符。
比較 | 運(yùn)算符 | True 示例 | False 示例 |
---|---|---|---|
小于 | < |
2 < 3 |
2 < 2 |
大于 | > |
3 > 2 |
3 > 3 |
小于等于 | <= |
2 <= 2 |
3 <= 2 |
大于等于 | >= |
3 >= 3 |
2 >= 3 |
等于 | == |
3 == 3 |
3 == 2 |
不等于 | != |
3 != 2 |
2 != 2 |
注意比較中的兩個(gè)等號==
用于確定相等性奥邮。 這是必要的万牺,因?yàn)?Python 已經(jīng)使用=
來表示名稱的賦值,我們之前看到過洽腺。 它不能將相同的符號用于不同的目的杏愤。 因此,如果你想檢查5
是否等于10/2
已脓,那么你必須小心:5 = 10/
2返回一個(gè)錯(cuò)誤信息珊楼,因?yàn)?Python 假設(shè)你正試圖將表達(dá)式10/2
的值賦給一個(gè)名稱,它是數(shù)字5
度液。相反厕宗,你必須使用5 == 10/2
,其計(jì)算結(jié)果為True
堕担。
5 = 10/2
File "<ipython-input-4-5c7d3e808777>", line 1
5 = 10/2
^
SyntaxError: can't assign to literal
5 == 10/2
True
一個(gè)表達(dá)式可以包含多個(gè)比較已慢,并且它們都必須滿足,為了整個(gè)表達(dá)式為真霹购。 例如佑惠,我們可以用下面的表達(dá)式表示1 + 1
在1
和3
之間。
1 < 1 + 1 < 3
True
兩個(gè)數(shù)字的平均值總是在較小的數(shù)字和較大的數(shù)字之間齐疙。 我們用下面的數(shù)字x
和y
來表示這種關(guān)系膜楷。 你可以嘗試不同的x
和y
值來確認(rèn)這種關(guān)系。
x = 12
y = 5
min(x, y) <= (x+y)/2 <= max(x, y)
True
字符串比較
字符串也可以比較贞奋,他們的順序是字典序赌厅。 較短的字符串小于以較短的字符串開頭的較長的字符串。
'Dog' > 'Catastrophe' > 'Cat'
我們回到隨機(jī)選擇轿塔。 回想一下由兩個(gè)元素組成的數(shù)組two_groups
特愿,treatment
和control
。 為了看一個(gè)隨機(jī)分配的個(gè)體是否去了實(shí)驗(yàn)組勾缭,你可以使用比較:
np.random.choice(two_groups) == 'treatment'
False
和以前一樣揍障,隨機(jī)選擇并不總是一樣的,所以比較的結(jié)果也不總是一樣的俩由。 這取決于是選擇treatment
還是control
毒嫡。 對于任何涉及隨機(jī)選擇的單元格,多次運(yùn)行單元格來獲得結(jié)果的變化是一個(gè)好主意采驻。
比較數(shù)組和值
回想一下审胚,我們可以對數(shù)組中的很多數(shù)字執(zhí)行算術(shù)運(yùn)算匈勋。 例如,make_array(0, 5, 2)*2
等同于make_array(0, 10, 4)
膳叨。 以類似的方式洽洁,如果我們比較一個(gè)數(shù)組和一個(gè)值,則數(shù)組的每個(gè)元素都與該值進(jìn)行比較菲嘴,并將比較結(jié)果求值為布爾值數(shù)組饿自。
tosses = make_array('Tails', 'Heads', 'Tails', 'Heads', 'Heads')
tosses == 'Heads'
array([False, True, False, True, True], dtype=bool)
numpy
方法count_nonzero
計(jì)算數(shù)組的非零(即True
)元素的數(shù)量。
np.count_nonzero(tosses == 'Heads')
3
條件語句
在許多情況下龄坪,行動和結(jié)果取決于所滿足的一組特定條件昭雌。例如,隨機(jī)對照試驗(yàn)的個(gè)體如果被分配給實(shí)驗(yàn)組健田,則接受實(shí)驗(yàn)烛卧。賭徒如果贏了賭注就賺錢。
在本節(jié)中妓局,我們將學(xué)習(xí)如何使用代碼來描述這種情況总放。條件語句是一個(gè)多行語句,它允許 Python 根據(jù)表達(dá)式的真值選擇不同的選項(xiàng)好爬。雖然條件語句可以出現(xiàn)在任何地方局雄,但它們通常出現(xiàn)在函數(shù)體內(nèi),以便根據(jù)參數(shù)值執(zhí)行可變的行為存炮。
條件語句總是以if
開頭炬搭,這是一行,后面跟著一個(gè)縮進(jìn)的主體穆桂。只有當(dāng)if
后面的表達(dá)式(稱為if
表達(dá)式)求值為真時(shí)宫盔,才會執(zhí)行主體。如果if
表達(dá)式的計(jì)算結(jié)果為False
充尉,則跳過if
的主體飘言。
讓我們開始定義一個(gè)返回?cái)?shù)字符號的函數(shù)。
def sign(x):
if x > 0:
return 'Positive'
sign(3)
'Positive'
如果輸入是正數(shù)驼侠,則此函數(shù)返回正確的符號。 但是谆吴,如果輸入不是正數(shù)倒源,那么if
表達(dá)式的計(jì)算結(jié)果為false
,所以return
語句被跳過句狼,函數(shù)調(diào)用沒有值(為None
)。
sign(-3)
所以,讓我們改進(jìn)我們的函數(shù)來返回負(fù)數(shù)淋样,如果輸入是負(fù)數(shù)。 我們可以通過添加一個(gè)elif
子句來實(shí)現(xiàn)昔馋,其中elif
是 Python 的else, if
的縮寫。
def sign(x):
if x > 0:
return 'Positive'
elif x < 0:
return 'Negative'
現(xiàn)在當(dāng)輸入為-3
時(shí)糖耸,sign
返回正確答案秘遏。
sign(-3)
'Negative'
那么如果輸入是0
呢?為了處理這個(gè)情況嘉竟,我們可以添加elif
子句:
def sign(x):
if x > 0:
return 'Positive'
elif x < 0:
return 'Negative'
elif x == 0:
return 'Neither positive nor negative'
sign(0)
'Neither positive nor negative'
與之等價(jià)邦危,我們可以用else
子句替換最后的elif
子句,只有前面的所有比較都是false
舍扰,才會執(zhí)行它的正文倦蚪。 也就是說,輸入值等于0
的時(shí)候边苹。
def sign(x):
if x > 0:
return 'Positive'
elif x < 0:
return 'Negative'
else:
return 'Neither positive nor negative'
sign(0)
'Neither positive nor negative'
一般形式
條件語句也可以有多個(gè)具有多個(gè)主體的子句陵且,只有其中一個(gè)主體可以被執(zhí)行。 多子句的條件語句的一般格式如下所示个束。
if <if expression>:
<if body>
elif <elif expression 0>:
<elif body 0>
elif <elif expression 1>:
<elif body 1>
...
else:
<else body>
總是只有一個(gè)if
子句滩报,但是可以有任意數(shù)量的elif
子句。 Python 將依次求解頭部的if
和elif
表達(dá)式播急,直到找到一個(gè)真值脓钾,然后執(zhí)行相應(yīng)的主體。 else
子句是可選的桩警。 當(dāng)提供else
頭部時(shí)可训,只有在前面的子句的頭部表達(dá)式都不為真時(shí)才執(zhí)行else
頭部。 else
子句必須總是在最后(或根本沒有)捶枢。
示例:"另一個(gè)"
現(xiàn)在我們將使用條件語句來定義一個(gè)看似相當(dāng)虛假和對立的函數(shù)握截,但是在本章后面的章節(jié)中會變得方便。 它需要一個(gè)數(shù)組烂叔,包含兩個(gè)元素(例如,red
和blue
)蒜鸡,以及另一個(gè)用于比較的元素胯努。 如果該元素為red
,則該函數(shù)返回blue
逢防。 如果元素是(例如)blue
叶沛,則函數(shù)返回red
。 這就是為什么我們要將函數(shù)稱為other_one
忘朝。
def other_one(x, a_b):
"""Compare x with the two elements of a_b;
if it is equal to one of them, return the other one;
if it is not equal to either of them, return an error message.
"""
if x == a_b.item(0):
return a_b.item(1)
elif x == a_b.item(1):
return a_b.item(0)
else:
return 'The input is not valid.'
colors = make_array('red', 'blue')
other_one('red', colors)
'blue'
other_one('blue', colors)
'red'
other_one('potato', colors)
'The input is not valid.'
迭代
編程中經(jīng)常出現(xiàn)這樣的情況灰署,特別是在處理隨機(jī)性時(shí),我們希望多次重復(fù)一個(gè)過程。 例如溉箕,要檢查np.random.choice
是否實(shí)際上是隨機(jī)選取的晦墙,我們可能需要多次運(yùn)行下面的單元格,以查看Heads
是否以大約 50% 的幾率出現(xiàn)肴茄。
np.random.choice(make_array('Heads', 'Tails'))
'Heads'
我們可能希望重新運(yùn)行代碼晌畅,帶有稍微不同的輸入或其他稍微不同的行為。 我們可以多次復(fù)制粘貼代碼独郎,但是這很枯燥踩麦,容易出現(xiàn)拼寫錯(cuò)誤,如果我們想要這樣做一千次或一百萬次氓癌,忘記它吧谓谦。
更自動化的解決方案是使用for
語句遍歷序列的內(nèi)容。 這被稱為迭代贪婉。 for
語句以單詞for
開頭反粥,后面跟著一個(gè)名字,我們要把這個(gè)序列中的每個(gè)項(xiàng)目賦給它疲迂,后面跟著單詞in
才顿,最后以一個(gè)表達(dá)式結(jié)束,它求值為一個(gè)序列尤蒿。 對于序列中的每個(gè)項(xiàng)目郑气,for
語句的縮進(jìn)主體執(zhí)行一次。
for i in np.arange(3):
print(i)
0
1
2
想象一下腰池,沒有for
語句的情況下尾组,完全實(shí)現(xiàn)for
語句功能的代碼,這樣很有幫助示弓。 (這被稱為循環(huán)展開讳侨。)for
語句簡單地復(fù)制了內(nèi)部的代碼,但是在每次迭代之前奏属,它從給定的序列中將我們選擇的名稱賦為一個(gè)新的值跨跨。 例如,以下是上面循環(huán)的展開版本:
i = np.arange(3).item(0)
print(i)
i = np.arange(3).item(1)
print(i)
i = np.arange(3).item(2)
print(i)
0
1
2
譯者注:實(shí)際的實(shí)現(xiàn)方式不是這樣囱皿,但是效果一樣勇婴。這里不做深究。
請注意铆帽,我的名字是任意的咆耿,就像我們用=
賦值的名字一樣。
在這里我們用一個(gè)更為現(xiàn)實(shí)的方式使用for
語句:我們從數(shù)組中打印5
個(gè)隨機(jī)選項(xiàng)爹橱。
coin = make_array('Heads', 'Tails')
for i in np.arange(5):
print(np.random.choice(make_array('Heads', 'Tails')))
Heads
Heads
Tails
Heads
Heads
在這種情況下,我們只執(zhí)行了幾次完全相同的(隨機(jī))操作,所以我們for
語句中的代碼實(shí)際上并不涉及到i
愧驱。
擴(kuò)展數(shù)組
雖然上面的for
語句確實(shí)模擬了五次硬幣投擲的結(jié)果慰技,但結(jié)果只是簡單地打印出來,并不是我們可以用來計(jì)算的形式组砚。 因此吻商,for
語句的典型用法是創(chuàng)建一個(gè)結(jié)果數(shù)組,每次都擴(kuò)展它糟红。
numpy
中的append
方法可以幫助我們實(shí)現(xiàn)它艾帐。 調(diào)用np.append(array_name,value)
將求出一個(gè)新的數(shù)組盆偿,它是由value
擴(kuò)展的array_name
柒爸。在使用append
時(shí)請記住,數(shù)組的所有條目必須具有相同的類型事扭。
pets = make_array('Cat', 'Dog')
np.append(pets, 'Another Pet')
array(['Cat', 'Dog', 'Another Pet'],
dtype='<U11')
這會使pets
數(shù)組保持不變捎稚。
pets
array(['Cat', 'Dog'],
dtype='<U3')
但是在擴(kuò)展數(shù)組的時(shí)候,通常使用for
循環(huán)來修改它很方便求橄。 這通過將擴(kuò)展后的數(shù)組賦給原始數(shù)組的相同名稱來實(shí)現(xiàn)今野。
pets = np.append(pets, 'Another Pet')
pets
array(['Cat', 'Dog', 'Another Pet'],
dtype='<U11')
示例:計(jì)算正面的數(shù)量
現(xiàn)在我們可以模擬一個(gè)硬幣的五次投擲,并把結(jié)果放入一個(gè)數(shù)組中罐农。 我們將從創(chuàng)建一個(gè)空數(shù)組開始条霜,然后附加每次投擲的結(jié)果。
coin = make_array('Heads', 'Tails')
tosses = make_array()
for i in np.arange(5):
tosses = np.append(tosses, np.random.choice(coin))
tosses
array(['Tails', 'Heads', 'Tails', 'Heads', 'Tails'],
dtype='<U32')
讓我們將for
語句展開涵亏,重寫單元格宰睡。
coin = make_array('Heads', 'Tails')
tosses = make_array()
i = np.arange(5).item(0)
tosses = np.append(tosses, np.random.choice(coin))
i = np.arange(5).item(1)
tosses = np.append(tosses, np.random.choice(coin))
i = np.arange(5).item(2)
tosses = np.append(tosses, np.random.choice(coin))
i = np.arange(5).item(3)
tosses = np.append(tosses, np.random.choice(coin))
i = np.arange(5).item(4)
tosses = np.append(tosses, np.random.choice(coin))
tosses
array(['Heads', 'Heads', 'Tails', 'Tails', 'Heads'],
dtype='<U32')
通過將結(jié)果捕獲到數(shù)組中,我們自己有能力使用數(shù)組方法進(jìn)行計(jì)算溯乒。 例如夹厌,我們可以使用np.count_nonzero
來計(jì)算五次投擲中的正面數(shù)量。
np.count_nonzero(tosses == 'Heads')
2
迭代是一個(gè)強(qiáng)大的技術(shù)裆悄。 例如矛纹,通過為 1000 次投擲運(yùn)行完全相同的代碼,而不是5
次光稼,我們可以計(jì)算1000
次投擲的正面數(shù)量或南。
tosses = make_array()
for i in np.arange(1000):
tosses = np.append(tosses, np.random.choice(coin))
np.count_nonzero(tosses == 'Heads')
481
示例:100 次投擲中的正面數(shù)量
預(yù)測 100 次硬幣投擲中有 50 個(gè)正面是很自然的,或多或少艾君。
但多少是“或多或少”呢采够? 獲得正好 50 個(gè)正面的幾率是多少? 像數(shù)據(jù)科學(xué)這樣的問題冰垄,不僅因?yàn)樗鼈兩婕半S機(jī)性的有趣方面蹬癌,而且因?yàn)樗鼈兛梢杂糜诜治鲈囼?yàn),其中實(shí)驗(yàn)和控制組的分配由硬幣的投擲決定。
在這個(gè)例子中逝薪,我們將模擬以下實(shí)驗(yàn)的 10,000 次重復(fù):
- 擲硬幣 100 次隅要,記錄正面數(shù)量。
我們的結(jié)果的直方圖會讓我們了解有多少個(gè)正面董济。
作為一個(gè)預(yù)熱步清,請注意,np.random.choice
接受可選的第二個(gè)參數(shù)來指定選擇的數(shù)量虏肾。 默認(rèn)情況下廓啊,選擇使用替換來進(jìn)行。 這里是一個(gè)硬幣 10 次投擲的模擬:
np.random.choice(coin, 10)
array(['Tails', 'Heads', 'Heads', 'Tails', 'Tails', 'Heads', 'Tails',
'Tails', 'Heads', 'Tails'],
dtype='<U5')
現(xiàn)在我們來研究 100 次投擲封豪。 我們將首先創(chuàng)建一個(gè)名為heads
的空數(shù)組谴轮。 然后,在每個(gè)一萬次重復(fù)中撑毛,我們會拋硬幣 100 次书聚,計(jì)算正面的數(shù)量,并將其附加到heads
上藻雌。
N = 10000
heads = make_array()
for i in np.arange(N):
tosses = np.random.choice(coin, 100)
heads = np.append(heads, np.count_nonzero(tosses == 'Heads'))
heads
array([ 46., 64., 59., ..., 56., 54., 56.])
讓我們將結(jié)果收集到表格中雌续,并繪制直方圖:
results = Table().with_columns(
'Repetition', np.arange(1, N+1),
'Number of Heads', heads
)
results
Repetition | Number of Heads |
---|---|
1 | 46 |
2 | 64 |
3 | 59 |
4 | 57 |
5 | 54 |
6 | 47 |
7 | 45 |
8 | 50 |
9 | 44 |
10 | 57 |
(省略了 9990 行)
這里是數(shù)據(jù)的直方圖,桶的寬度為 1胯杭,中心為每個(gè)正面數(shù)量的值驯杜。
results.select('Number of Heads').hist(bins=np.arange(30.5, 69.6, 1))
https://gitee.com/wizardforcel/data8-textbook-zh/raw/master/img/8-1.png
毫不奇怪,直方圖看起來大約關(guān)于 50 個(gè)正面左右對稱做个。 50 處的條形的高度大約是每單位 8%鸽心。 由于每個(gè)條形的寬度都是 1 個(gè)單位,這就是說居暖,8% 的重復(fù)正好產(chǎn)生了 50 個(gè)正面顽频。 這不是一個(gè)很大的百分比,但是與其他數(shù)量的正面相比太闺,這是最大的糯景。
直方圖還顯示,在幾乎所有的重復(fù)中省骂,100 次投擲的正面數(shù)量在 35 到 65 之間蟀淮。事實(shí)上,大部分的重復(fù)產(chǎn)生 45 到 55 個(gè)正面數(shù)量钞澳。
理論上怠惶,正面數(shù)量可能在 0 到 100 之間,但模擬顯示可能值的范圍要小得多轧粟。
這是一個(gè)更普遍現(xiàn)象的例子策治,關(guān)于擲硬幣中的變化脓魏,我們將在后面看到。
Monty Hall 問題
多年來這個(gè)問題已經(jīng)使許多人感到困惑览妖,包括數(shù)學(xué)家在內(nèi)轧拄。 讓我們看看我們是否可以解決揽祥。
這個(gè)設(shè)定來源于一個(gè)名為“讓我們做個(gè)交易”(Let's Make a Deal)的電視游戲節(jié)目讽膏。Monty Hall 在二十世紀(jì)六十年代主持了這個(gè)節(jié)目,從此產(chǎn)生了一些副產(chǎn)品拄丰。 這個(gè)節(jié)目令人興奮的一部分是府树,雖然參賽者有機(jī)會贏得大獎,但他們可能最終會選擇不那么理想的“zonks”料按。 這就是現(xiàn)在所謂的 Monty Hall 問題的基礎(chǔ)奄侠。
這個(gè)設(shè)定是一個(gè)游戲節(jié)目,參賽者面對三個(gè)閉著的門载矿。 在其中一扇門的后面是一輛奇特的汽車垄潮,另外兩扇門后面有一只山羊。 參賽者不知道汽車的位置闷盔,必須按照以下規(guī)則進(jìn)行嘗試弯洗。
- 參賽者進(jìn)行初步選擇,但不打開那個(gè)門逢勾。
- 其他兩個(gè)門中至少有一個(gè)門的后面必須有一只山羊牡整。Monty 打開這些門之一來展示山羊,維基百科中顯示了他所有的榮耀溺拱。
https://gitee.com/wizardforcel/data8-textbook-zh/raw/master/img/8-2.png
- 還剩下兩個(gè)門逃贝,其中一個(gè)是參賽者的原始選擇。 其中一扇門后面有車迫摔,另一扇有一只山羊沐扳。 參賽者現(xiàn)在可以選擇打開兩扇門中的哪一扇。
參賽者需要作出決定句占。 如果她想要這輛車沪摄,她應(yīng)該選擇打開哪扇門? 她應(yīng)該堅(jiān)持最初的選擇辖众,還是轉(zhuǎn)向另一個(gè)門卓起? 這是 Monty Hall 問題。
解法
在涉及幾率的任何問題中凹炸,重要的隨機(jī)性的假設(shè)戏阅。 假設(shè)有三分之一的幾率,參賽者的最初選擇是后面有車的門啤它,這是合理的奕筐。
在這個(gè)假設(shè)下舱痘,解決這個(gè)問題的方法非常簡單,盡管簡單的解決方案并不能說服每個(gè)人离赫。 無論如何就是這樣芭逝。
- 汽車在原來選擇的門后面的幾率是 1/3。
- 汽車在原來選擇的門后面或者剩余的門后面渊胸。 它不能在其他地方旬盯。
- 因此,汽車在剩余的門后的幾率是 2/3翎猛。
- 因此胖翰,選手應(yīng)該更改選擇。
- 就是這樣切厘,故事結(jié)束了萨咳。
不相信? 那么讓我們模擬游戲疫稿,看看結(jié)果如何培他。
模擬
我們開始建立兩個(gè)實(shí)用的數(shù)組,doors
和goats
遗座,這會讓我們區(qū)分三個(gè)門和兩只山羊舀凛。
doors = make_array('Car', 'Goat 1', 'Goat 2')
goats = make_array('Goat 1', 'Goat 2')
現(xiàn)在我們定義一個(gè)函數(shù)monty_hall
來模擬游戲,并按照這個(gè)順序返回含有三個(gè)字符串的數(shù)組:
- 參賽選手的原始選擇的什么
- Monty 排除了什么
- 剩下的門是什么
如果選手的原始選擇是帶山羊的門员萍,蒙蒂必須扔掉另一只山羊腾降,剩下的就是這輛車。 如果最初的選擇是帶車的門碎绎,蒙蒂必須扔掉兩只山羊中的一只螃壤,剩下的就是另一只羊。
因此很顯然筋帖,在前一節(jié)中定義的函數(shù)將是有用的奸晴。 它需要一個(gè)字符串和一個(gè)兩個(gè)元素的數(shù)組; 如果字符串等于其中一個(gè)元素,則返回另一個(gè)元素日麸。
def other_one(x, a_b):
if x == a_b.item(0):
return a_b.item(1)
elif x == a_b.item(1):
return a_b.item(0)
else:
return 'Input Not Valid'
如果選手的原始選擇是山羊寄啼,游戲的結(jié)果是這二者之一:
original = 'Goat 1'
make_array(original, other_one(original, goats), 'Car')
array(['Goat 1', 'Goat 2', 'Car'],
dtype='<U6')
original = 'Goat 2'
make_array(original, other_one(original, goats), 'Car')
array(['Goat 2', 'Goat 1', 'Car'],
dtype='<U6')
現(xiàn)在我們可以把所有這些代碼放到monty_hall
函數(shù)中,來模擬一次游戲的結(jié)果代箭。 該函數(shù)不帶任何參數(shù)墩划。
參賽者的原始選擇將是三門之中隨機(jī)選擇的門。
為了檢查原始選擇是否是山羊嗡综,我們首先寫一個(gè)名為is_goat
的小函數(shù):
def is_goat(door_name):
""" Check whether the name of a door (a string) is a Goat.
Examples:
=========
>>> is_goat('Goat 1')
True
>>> is_goat('Goat 2')
True
>>> is_goat('Car')
False
"""
if door_name == "Goat 1":
return True
elif door_name == "Goat 2":
return True
else:
return False
def monty_hall():
""" Play the Monty Hall game once
and return an array of three strings:
original choice, what Monty throws out, what remains
"""
original = np.random.choice(doors)
if is_goat(original):
return make_array(original, other_one(original, goats), 'Car')
else:
throw_out = np.random.choice(goats)
return make_array(original, throw_out, other_one(throw_out, goats))
讓我們玩幾次這個(gè)游戲乙帮。這里是一個(gè)結(jié)果。你應(yīng)該運(yùn)行幾次單元格來觀察結(jié)果如何變化极景。
monty_hall()
array(['Car', 'Goat 2', 'Goat 1'],
dtype='<U6')
為了衡量不同結(jié)果發(fā)生的頻率察净,我們必須玩多次游戲并收集結(jié)果驾茴。 為此,我們將使用for
循環(huán)氢卡。
我們將首先定義三個(gè)空數(shù)組锈至,每個(gè)數(shù)組對應(yīng)原始選擇,Monty 排除了什么译秦,剩下的是什么峡捡。然后我們將玩這個(gè)游戲 N 次并收集結(jié)果。我們已經(jīng)將 N 設(shè)為 10,000诀浪,但是你可以改變它棋返。
# Number of times we'll play the game
N = 10000
original = make_array() # original choice
throw_out = make_array() # what Monty throws out
remains = make_array() # what remains
for i in np.arange(N):
result = monty_hall() # the result of one game
# Collect the results in the appropriate arrays
original = np.append(original, result.item(0))
throw_out = np.append(throw_out, result.item(1))
remains = np.append(remains, result.item(2))
# The for-loop is done! Now put all the arrays together in a table.
results = Table().with_columns(
'Original Door Choice', original,
'Monty Throws Out', throw_out,
'Remaining Door', remains
)
results
Original Door Choice | Monty Throws Out | Remaining Door |
---|---|---|
Car | Goat 1 | Goat 2 |
Goat 1 | Goat 2 | Car |
Goat 2 | Goat 1 | Car |
Car | Goat 2 | Goat 1 |
Car | Goat 2 | Goat 1 |
Goat 1 | Goat 2 | Car |
Goat 1 | Goat 2 | Car |
Goat 1 | Goat 2 | Car |
Goat 2 | Goat 1 | Car |
Goat 1 | Goat 2 | Car |
(省略了 9990 行)
為了看看選手是否應(yīng)該堅(jiān)持原來的選擇或更改,讓我們看看她的兩個(gè)選項(xiàng)后面的車的頻率雷猪。
results.group('Original Door Choice')
Original Door Choice | count |
---|---|
Car | 3312 |
Goat 1 | 3382 |
Goat 2 | 3306 |
results.group('Remaining Door')
Remaining Door | count |
---|---|
Car | 6688 |
Goat 1 | 1640 |
Goat 2 | 1672 |
我們的解決方案說明了,這輛車有三分之二的幾率在剩下的門后面晰房,這是相當(dāng)不錯(cuò)的近似值求摇。 如果參賽者更改了她的選擇,她有兩倍的可能性會得到車殊者。
為了使結(jié)果可視化与境,我們可以將上面的兩個(gè)表格連接在一起并繪制疊加的條形圖。
results_o = results.group('Original Door Choice')
results_r = results.group('Remaining Door')
joined = results_o.join('Original Door Choice', results_r, 'Remaining Door')
combined = joined.relabeled(0, 'Item').relabeled(1, 'Original Door').relabeled(2, 'Remaining Door')
combined
Item | Original Door | Remaining Door |
---|---|---|
Car | 3312 | 6688 |
Goat 1 | 3382 | 1640 |
Goat 2 | 3306 | 1672 |
combined.barh(0)
https://gitee.com/wizardforcel/data8-textbook-zh/raw/master/img/8-3.png
注意三條藍(lán)色條形幾乎相等 - 原始選擇有同等可能是三個(gè)可用條目中的任何一條猖吴。 但是摔刁,汽車對應(yīng)的金色條形是藍(lán)色條形的兩倍。
模擬證實(shí)了海蔽,如果參賽者改變選擇共屈,她有兩倍的可能性獲勝。
發(fā)現(xiàn)概率
幾個(gè)世紀(jì)以來党窜,對于什么是概率存在哲學(xué)爭論拗引。有些人認(rèn)為概率是相對頻率;其他人認(rèn)為他們是長期的相對頻率較長幌衣;還有一些人認(rèn)為概率是個(gè)人不確定性程度的主觀測量矾削。
在這個(gè)課程中,大多數(shù)概率將是相對頻率豁护,盡管許多人會有主觀的解釋哼凯。無論如何,在不同的解釋中楚里,概率計(jì)算和組合的方式是一致的断部。
按照慣例,概率是介于 0 和 1 之間的數(shù)字腻豌,或者 0% 和 100% 之間家坎。不可能的事件概率為 0嘱能。確定的事件概率為 1。
數(shù)學(xué)是準(zhǔn)確發(fā)現(xiàn)概率的主要工具虱疏,盡管計(jì)算機(jī)也可用于此目的惹骂。模擬可以提供出色的近似,具有很高的概率做瞪。在本節(jié)中对粪,我們將以非正式方式制定一些簡單的規(guī)則來管理概率的計(jì)算。在隨后的章節(jié)中装蓬,我們將回到模擬來近似復(fù)雜事件的概率著拭。
我們將使用標(biāo)準(zhǔn)符號 https://www.zhihu.com/equation?tex=P%28%5Cmbox%7Bevent%7D%29 來表示“事件”發(fā)生的概率,我們將交替使用“幾率”和“概率”兩個(gè)字牍帚。
事件不會發(fā)生的時(shí)候
如果事件發(fā)生的概率是 40%儡遮,不發(fā)生的幾率就是 60%。這個(gè)自然的計(jì)算可以這樣秒速:
所有結(jié)果等可能的時(shí)候
如果你投擲一個(gè)普通的骰子暗赶,一個(gè)自然的假設(shè)是鄙币,所有六個(gè)面都是等可能的。 那么一個(gè)面出現(xiàn)的概率可以很容易地計(jì)算出來蹂随。 例如十嘿,骰子顯示偶數(shù)的幾率是:
與之相似:
通常:
前提是所有的結(jié)果都是等可能的。
并非所有的隨機(jī)現(xiàn)象都像骰子一樣簡單岳锁。 下面的兩個(gè)主要的概率規(guī)則甚至允許數(shù)學(xué)家在復(fù)雜的情況下找到概率绩衷。
兩個(gè)事件必須同時(shí)發(fā)生時(shí)
假設(shè)你有一個(gè)盒子,包含三張紙條:一張紅色激率,一張藍(lán)色和一張綠色咳燕。 假設(shè)你隨機(jī)抽兩張紙條而不放回;也就是你把三張紙條打亂柱搜,抽一張迟郎,打亂其余兩張,再從這兩張中抽出一張聪蘸。 你先得到綠色紙條宪肖,然后是紅色紙條的幾率是多少?
有六種可能的顏色對:RB健爬,BR控乾,RG,GR娜遵,BG蜕衡,GB(我們已經(jīng)縮寫了每種顏色的名字,就是它的第一個(gè)字母)设拟。 所有這些都是抽樣方案是等可能的慨仿,只有其中一個(gè)(GR)使事件發(fā)生帘撰。所以:
但是還有另外一種方法來得到答案减余,可以用兩個(gè)階段來思考這個(gè)事件。 必須首先抽取綠色紙條抓于。幾率是 1/3闯估,也就是說在所有實(shí)驗(yàn)的大約 1/3 的重復(fù)中创橄,先抽取了綠色紙條卒茬,但事件還沒完成。在這 1/3 的重復(fù)中咖熟,必須再次抽取紅色紙條圃酵。這個(gè)發(fā)生在大約 1/2 的重復(fù)中,所以:
這個(gè)計(jì)算通常按照事件順序馍管,像這樣:
因數(shù) 1/2 叫做“假設(shè)第一次出現(xiàn)了綠色紙條郭赐,第二次出現(xiàn)紅色紙條的條件幾率”。
通常确沸,我們擁有乘法規(guī)則:
兩個(gè)事件同時(shí)發(fā)生的概率捌锭,等于第一個(gè)事件發(fā)生的概率,乘上第一個(gè)事件發(fā)生的情況下第二個(gè)事件發(fā)生的概率罗捎。
因此观谦,這里有兩個(gè)條件 - 一個(gè)事件必須發(fā)生,另一個(gè)也是 - 幾率是分?jǐn)?shù)的分?jǐn)?shù)桨菜,這比兩個(gè)因數(shù)的任何一個(gè)都要小豁状。 滿足的條件越多,滿足的可能性就越小倒得。
事件以兩種不同的方式發(fā)生
相反泻红,假設(shè)我們希望兩張紙條中的一張是綠色的,另一張是紅色的。 此事件不指定顏色必須出現(xiàn)的順序。所以他們可以以任何順序出現(xiàn)虐唠。
解決這樣的問題的一個(gè)好方法就是對事件進(jìn)行劃分晤锥,以便它正好能夠以幾種不同的方式之一發(fā)生。 “一綠一紅”的自然劃分是:GR,RG。
根據(jù)上面的計(jì)算,GR 和 RG 每個(gè)的幾率都是 1/6剩彬。所以你可以通過把它們相加來計(jì)算一綠一紅的概率。
通常矿卑,我們擁有加法規(guī)則:
事件發(fā)生的概率喉恋,等于以第一種方式發(fā)生的概率,加上以第二種方式發(fā)生的概率。
只要事件正好以兩種方式之一發(fā)生轻黑。
因此糊肤,當(dāng)事件以兩種不同的方式之一發(fā)生時(shí),發(fā)生的幾率是一些幾率的總和氓鄙,因此比任何一種方式的幾率都大馆揉。
乘法規(guī)則可以自然擴(kuò)展到兩個(gè)以上的事件,我們將在下面看到抖拦。 所以這個(gè)加法規(guī)則也有自然的擴(kuò)展升酣,事件可以以幾種不同的方式之一發(fā)生。
我們將所有這些規(guī)則組合成示例态罪,并用示例來結(jié)束該部分噩茄。
至少有一個(gè)成功
數(shù)據(jù)科學(xué)家經(jīng)常使用來自總體的隨機(jī)樣本。 有時(shí)候問題就來了复颈,就是總體中的一個(gè)特定個(gè)體選進(jìn)樣本的可能性绩聘。為了找出幾率,這個(gè)個(gè)體被稱為“成功”耗啦,問題是要找到樣本包含成功的幾率凿菩。
要看看如何計(jì)算這樣的幾率,我們從一個(gè)更簡單的設(shè)定開始:投擲硬幣兩次帜讲。
如果你投擲硬幣兩次衅谷,有四個(gè)等可能的結(jié)果:HH,HT似将,TH 和 TT会喝。 我們把正面縮寫為 H ,反面縮寫為 T玩郊。至少有一個(gè)正面的幾率是 3/4。
得出這個(gè)答案的另一種方法是枉阵,弄清楚如果你不能得到至少一個(gè)正面译红,會發(fā)生什么事情:這兩次投擲都必須是反面。所以:
要注意根據(jù)乘法規(guī)則:
這兩個(gè)觀察使我們能夠在任何給定數(shù)量的投擲中找到至少一個(gè)正面的幾率兴溜。 例如:
而現(xiàn)在我們有能力找到在骰子的投擲中侦厚,六點(diǎn)至少出現(xiàn)一次的幾率:
下表展示了,這些概率隨著投擲數(shù)量從 1 增加到 50 而增加拙徽。
rolls = np.arange(1, 51, 1)
results = Table().with_columns(
'Rolls', rolls,
'Chance of at least one 6', 1 - (5/6)**rolls
)
results
Rolls | Chance of at least one 6 |
---|---|
1 | 0.166667 |
2 | 0.305556 |
3 | 0.421296 |
4 | 0.517747 |
5 | 0.598122 |
6 | 0.665102 |
7 | 0.720918 |
8 | 0.767432 |
9 | 0.806193 |
10 | 0.838494 |
(省略了 40 行)
隨著投擲數(shù)量的增加刨沦,六點(diǎn)至少出現(xiàn)一次的幾率迅速增加。
results.scatter('Rolls')
https://gitee.com/wizardforcel/data8-textbook-zh/raw/master/img/8-4.png
在 50 次投擲中膘怕,你幾乎肯定能得到至少一個(gè)六想诅。
results.where('Rolls', are.equal_to(50))
Rolls | Chance of at least one 6 |
---|---|
50 | 0.99989 |
像這樣的計(jì)算可以用來找到,隨機(jī)樣本中選擇特定個(gè)體的幾率。 準(zhǔn)確的計(jì)算將取決于抽樣方案来破。 但是我們上面的觀察的通忱鹤疲可以被推廣:增加隨機(jī)樣本的大小增加了選擇個(gè)體的幾率。
抽樣
現(xiàn)在我們來仔細(xì)看看抽樣徘禁,例子基于top_movies.csv
數(shù)據(jù)集诅诱。
top1 = Table.read_table('top_movies.csv')
top2 = top1.with_column('Row Index', np.arange(top1.num_rows))
top = top2.move_to_start('Row Index')
top.set_format(make_array(3, 4), NumberFormatter)
Row Index | Title | Studio | Gross | Gross (Adjusted) | Year |
---|---|---|---|---|---|
0 | Star Wars: The Force Awakens | Buena Vista (Disney) | 906,723,418 | 906,723,400 | 2015 |
1 | Avatar | Fox | 760,507,625 | 846,120,800 | 2009 |
2 | Titanic | Paramount | 658,672,302 | 1,178,627,900 | 1997 |
3 | Jurassic World | Universal | 652,270,625 | 687,728,000 | 2015 |
4 | Marvel's The Avengers | Buena Vista (Disney) | 623,357,910 | 668,866,600 | 2012 |
5 | The Dark Knight | Warner Bros. | 534,858,444 | 647,761,600 | 2008 |
6 | Star Wars: Episode I - The Phantom Menace | Fox | 474,544,677 | 785,715,000 | 1999 |
7 | Star Wars | Fox | 460,998,007 | 1,549,640,500 | 1977 |
8 | Avengers: Age of Ultron | Buena Vista (Disney) | 459,005,868 | 465,684,200 | 2015 |
9 | The Dark Knight Rises | Warner Bros. | 448,139,099 | 500,961,700 | 2012 |
(省略了 190 行)
對表格的行進(jìn)行抽樣
數(shù)據(jù)表的每一行代表一個(gè)個(gè)體;最重要的是送朱,每個(gè)個(gè)體都是一部電影娘荡。 因此可以通過表格的行的抽樣來實(shí)現(xiàn)對個(gè)體的抽樣。
一行的內(nèi)容是在同一個(gè)個(gè)體上測量的不同變量的值驶沼。 因此炮沐,行的內(nèi)容的抽樣形成了每個(gè)變量值的樣本。
確定性樣本
當(dāng)你只是簡單地指定商乎,你要選擇的集合中的哪些元素時(shí)央拖,就不會涉及任何幾率,可以創(chuàng)建確定性樣本鹉戚。
你已經(jīng)做了很多次了鲜戒,例如使用take
:
top.take(make_array(3, 18, 100))
Row Index | Title | Studio | Gross | Gross (Adjusted) | Year |
---|---|---|---|---|---|
3 | Jurassic World | Universal | 652,270,625 | 687,728,000 | 2015 |
18 | Spider-Man | Sony | 403,706,375 | 604,517,300 | 2002 |
100 | Gone with the Wind | MGM | 198,676,459 | 1,757,788,200 | 1939 |
你也使用了where
:
top.where('Title', are.containing('Harry Potter'))
Row Index | Title | Studio | Gross | Gross (Adjusted) | Year |
---|---|---|---|---|---|
22 | Harry Potter and the Deathly Hallows Part 2 | Warner Bros. | 381,011,219 | 417,512,200 | 2011 |
43 | Harry Potter and the Sorcerer's Stone | Warner Bros. | 317,575,550 | 486,442,900 | 2001 |
54 | Harry Potter and the Half-Blood Prince | Warner Bros. | 301,959,197 | 352,098,800 | 2009 |
59 | Harry Potter and the Order of the Phoenix | Warner Bros. | 292,004,738 | 369,250,200 | 2007 |
62 | Harry Potter and the Goblet of Fire | Warner Bros. | 290,013,036 | 393,024,800 | 2005 |
69 | Harry Potter and the Chamber of Secrets | Warner Bros. | 261,988,482 | 390,768,100 | 2002 |
76 | Harry Potter and the Prisoner of Azkaban | Warner Bros. | 249,541,069 | 349,598,600 | 2004 |
雖然這些是電影的樣本,它們并不涉及幾率抹凳。
概率抽樣
很多數(shù)據(jù)科學(xué)都根據(jù)隨機(jī)樣本中的數(shù)據(jù)得到結(jié)論遏餐。 根據(jù)隨機(jī)樣本的正確解釋分析,需要數(shù)據(jù)科學(xué)家準(zhǔn)確地檢查隨機(jī)樣本赢底。
總體是從中抽取樣本的所有元素的集合失都。
概率樣本是一種樣本,在抽取樣本之前幸冻,可以計(jì)算出的元素的任何子集將進(jìn)入樣本的幾率粹庞。
在概率樣本中,所有的元素不需要有相同的選中幾率洽损。
隨機(jī)抽樣方案
例如庞溜,假設(shè)根據(jù)以下方案,從三個(gè)個(gè)體 A碑定,B 和 C 組成的總體中選擇兩個(gè)個(gè)體:
- 個(gè)體 A 選中概率為 1流码。
- 個(gè)體 B 或 C 根據(jù)擲硬幣來選擇:如果硬幣為正面,選擇 B延刘,否則漫试,選擇 C。
這是一個(gè)大小為 2 的概率樣本碘赖。下面是所有非空子集的選中幾率:
A: 1
B: 1/2
C: 1/2
AB: 1/2
AC: 1/2
BC: 0
ABC: 0
個(gè)體 A 比 B 或 C 有更高的選中幾率驾荣;的確外构,個(gè)體 A 肯定會被選中。由于這些差異是已知的和量化的秘车,所以在處理樣本時(shí)可以考慮這些差異典勇。
系統(tǒng)樣本
想象一下,總體的所有元素都列出在序列中叮趴。 抽樣的一種方法是割笙,先從列表中選擇一個(gè)隨機(jī)的位置,然后是它后面的等間隔的位置眯亦。樣本由這些位置上的元素組成伤溉。這樣的樣本被稱為系統(tǒng)樣本。
在這里妻率,我們將選擇頂部一些行的系統(tǒng)樣本乱顾。我們最開始隨機(jī)選取前 10 行中的一行,然后我們將選取它后面的每個(gè)第 10 行宫静。
"""Choose a random start among rows 0 through 9;
then take every 10th row."""
start = np.random.choice(np.arange(10))
top.take(np.arange(start, top.num_rows, 10))
Row Index | Title | Studio | Gross | Gross (Adjusted) | Year |
---|---|---|---|---|---|
6 | Star Wars: Episode I - The Phantom Menace | Fox | 474,544,677 | 785,715,000 | 1999 |
16 | Iron Man 3 | Buena Vista (Disney) | 409,013,994 | 424,632,700 | 2013 |
26 | Spider-Man 2 | Sony | 373,585,825 | 523,381,100 | 2004 |
36 | Minions | Universal | 336,045,770 | 354,213,900 | 2015 |
46 | Iron Man 2 | Paramount | 312,433,331 | 341,908,200 | 2010 |
56 | The Twilight Saga: New Moon | Sum. | 296,623,634 | 338,517,700 | 2009 |
66 | Meet the Fockers | Universal | 279,261,160 | 384,305,300 | 2004 |
76 | Harry Potter and the Prisoner of Azkaban | Warner Bros. | 249,541,069 | 349,598,600 | 2004 |
86 | The Exorcist | Warner Bros. | 232,906,145 | 962,212,800 | 1973 |
96 | Back to the Future | Universal | 210,609,762 | 513,740,700 | 1985 |
(省略了 10 行)
運(yùn)行單元個(gè)幾次走净,看看輸出如何變化。
這個(gè)系統(tǒng)樣本是一個(gè)概率樣本孤里。 在這個(gè)方案中伏伯,所有的行都有機(jī)會被選中。 例如捌袜,當(dāng)且僅當(dāng)?shù)?3 行被選中時(shí)说搅,第 23 行才被選中,并且其幾率是 1/10虏等。
但并不是所有的子集都有相同的選中幾率弄唧。 由于選中的行是等間隔的,大多數(shù)行的子集都沒有機(jī)會被選中霍衫。 唯一可能的子集是由所有間隔為 10 的行構(gòu)成的子集候引。任何這些子集都以 1/10 的幾率被選中。 其他子集敦跌,如包含表格前 11 行的子集背伴,選中幾率都是 0。
放回或不放回的隨機(jī)抽樣
在這個(gè)課程中峰髓,我們將主要處理兩個(gè)最直接的抽樣方法。
首先是帶放回的隨機(jī)抽樣息尺,它(如我們前面所見)是np.random.choice
從數(shù)組中抽樣時(shí)的默認(rèn)行為携兵。
另一個(gè)稱為“簡單隨機(jī)樣本”,是隨機(jī)抽取的樣本搂誉,不帶放回徐紧。在下一個(gè)個(gè)體被抽中之前,抽中的個(gè)體不會放回總體。例如并级,當(dāng)你發(fā)牌時(shí)拂檩,就會發(fā)生這種抽樣。
在下一章中嘲碧,我們將使用模擬來研究帶放回和不放回的大樣本隨機(jī)抽取稻励。
繪制隨機(jī)樣本需要謹(jǐn)慎和精確。這不是隨便的愈涩,即使這是“隨機(jī)”一詞的口語意義望抽。如果你站在街頭,選取前十名經(jīng)過的人作為樣本履婉,你可能會認(rèn)為你在隨機(jī)抽樣煤篙,因?yàn)槟銢]有選擇誰走過。但它不是一個(gè)隨機(jī)樣本 - 這是一個(gè)方便的例子毁腿。你沒有提前知道每個(gè)人進(jìn)入樣本的概率辑奈,也許甚至你沒有具體指定誰在總體中。