本節書摘來異步社群《機率程式設計實戰》一書中的第2章,第2.6節,作者:【美】avi pfeffer(艾維·費弗),更多章節内容可以通路雲栖社群“異步社群”公衆号檢視。
現在,我已經相當詳細地介紹了構模組化型的方法。使用figaro時,您的很大一部分精力将花在建立模型上。但是不要忽略證據的指定。figaro提供了3種說明證據的機制:觀測值,條件和限制。
您已經看到使用觀測值指定證據的方法。在hello world程式中已經提供了一個例子,使用如下的語句:
greetingtoday.unobserve()<code>`</code>
上述語句删除greetingtoday上的觀測值(如果有的話),這樣就不會排除任何随機執行。結果是,關于greetingtoday的證據不影響其他元素的機率。
observe指定元素的特定值。如果您知道元素值的某些相關情況,但是不确定該值,該怎麼辦?figaro允許将任何預測作為證據。這稱作條件。條件指定一個布爾函數,該函數為真某個值才可能出現。例如:
val sunnydaysinmonth = binomial(30, 0.2)
val monthquality = apply(sunnydaysinmonth,
(i: int) => if (i > 10) "good"; else if (i > 5) "average"; else "poor")
val goodmood = chain(monthquality, (s: string) =>
println(variableelimination.probability(goodmood, true))
// prints 0.3939286578054374 with no evidence<code>`</code>
設定條件,規定sunnydaysinmonth的值必須大于8。然後,可以看到它對goodmood的影響:
sunnydaysinmonth.addcondition((i: int) => i % 3 == 2)<code>`</code>
上述語句說明,除了大于8之外,sunnydaysinmonth的值還必須比3的倍數大2。這就排除了9和10等可能值,是以,最小的可能值為11。當然,當您查詢好心情的機率時,可以看到它再次上升:
sunnydaysinmonth.removeconditions()
// prints 0.3939286578054374 again<code>`</code>
順便說一句,觀測值隻是條件的一個特例,要求某個元素取單一特定值。下面總結與條件相關的方法。
setcondition是元素上的一個方法,以一個預測作為參數。預測必須是從元素值類型到布爾類型的函數。setcondition方法使這個預測成為元素上的唯一條件,删除現有條件和觀測值。
addcondition也是元素上的方法,以預測作為參數,預測必須是從元素值類型到布爾類型的函數。addcondition在現有條件和觀測值之上添加這個預測。
removeconditions是元素上的方法,删除元素的所有條件和觀測值。
限制提供了規定元素相關情況的更通用手段,它通常有兩個目的:(1)作為指定“軟”證據的手段;(2)作為提供模型中元素間附加關系的手段。
用作軟證據的限制
假定您有關于元素的某種證據,但是不是很确定。例如,您認為我看上去脾氣暴躁,但是從外表無法得知我的情緒。是以您不指定goodmood為false這樣的硬證據,而是指定軟證據:goodmood為false的可能性大于true的可能性。
這可以使用限制實作。限制是一個從元素值到double類型值的函數。雖然figaro沒有強制規定,但是限制在這個函數值始終在0和1(含)之間時工作得最好。例如,為了表示我的情緒似乎暴躁但是不确定的證據,您可以為goodmood添加一個限制,當goodmood為true時生成值0.5,在goodmood為false時生成1.0:
// prints 0.24527469450215497<code>`</code>
限制提供了和條件類似的一組方法。
setconstraint是元素上的一個方法,以預測作為參數。預測必須是從元素值類型到double類型值的函數。setconstraint方法使該預測成為元素上的唯一限制。
addconstraint也是元素上的一個方法,以預測作為參數,該參數必須是從元素值類型到double類型值的函數。addconstraint方法在任何現有限制上添加這個預測。
removeconstraints是元素上的一個方法,從元素中删除所有限制。
條件和限制是互相獨立的,是以設定條件或者删除所有條件不會删除任何現有限制,反之亦然。
作為連接配接元素的限制
限制有一種強大的用途。假定您認為兩個元素的值相關,但是無法在元素定義中捕捉。例如,假設您的壘球隊勝率為40%,每場比賽可以通過flip(0.4)定義。再假設您認為自己的球隊有連續性,是以相鄰的比賽可能有相同的結果。您可以添加對相鄰比賽的限制以捕捉這一信念,這個限制說明相鄰比賽得到相同值的可能性大于得到不同值的可能性。用如下的代碼可以實作上述模型。我介紹的是3場比賽的代碼。但是可以用數組和for循環将其推廣到任何數量的比賽。
首先,定義3場比賽的結果:
val allwins = apply(result1, result2, result3,
(w1: boolean, w2: boolean, w3: boolean) => w1 && w2 && w3)<code>`</code>
我們來看看添加任何限制之前所有比賽全勝的機率:
def makestreaky(r1: element[boolean], r2: element[boolean]) {
val pair = apply(r1, r2, (b1: boolean, b2: boolean) => (b1, b2))
)}<code>`</code>
這個函數以兩個boolean元素為參數,這兩個參數表示兩場比賽的結果。因為限制隻能應用到一個元素,您希望使用限制建立兩個元素之間的關系,是以首先将兩個元素打包成單一進制素,該元素的值是一個二進制組。這通過apply(r1, r2, (b1: boolean, b2: boolean) => (b1, b2))實作。現在,您有了一個值為兩場比賽結果配對的元素。然後,設定該配對的限制為一個函數,該函數取一對boolean變量bb,如果bb._1 ==bb._2(配對的第一部分和第二部分相等)則傳回1,否則傳回0.5。這個限制說明,在其他條件不變時,兩場比賽結果相同的機率兩倍于不同的機率。
現在,您可以使相鄰兩場比賽的結果保持延續性,并查詢所有比賽全勝的機率: