В моем последнем сообщении в блоге я показал перевод функции правдоподобия из Think Bayes в R, и в своей первой попытке использовать эту функцию я использовал несколько вложенных циклов for.
01
02
03
04
05
06
07
08
09
10
11
|
likelihoods = function(names, mixes, observations) { scores = rep( 1 , length(names)) names(scores) = names for (name in names) { for (observation in observations) { scores[name] = scores[name] * mixes[[name]][observation] } } return (scores) } |
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
Names = c( "Bowl 1" , "Bowl 2" ) bowl1Mix = c( 0.75 , 0.25 ) names(bowl1Mix) = c( "vanilla" , "chocolate" ) bowl2Mix = c( 0.5 , 0.5 ) names(bowl2Mix) = c( "vanilla" , "chocolate" ) Mixes = list( "Bowl 1" = bowl1Mix, "Bowl 2" = bowl2Mix) Mixes Observations = c( "vanilla" , "vanilla" , "vanilla" , "chocolate" ) l = likelihoods(Names, Mixes, Observations) > l / sum(l) Bowl 1 Bowl 2 0.627907 0.372093 |
Мы передаем вектор чаш, вложенный словарь, описывающий смеси печенья в каждой чаше и сделанные нами наблюдения. Эта функция сообщает нам, что вероятность того, что файлы cookie поступят из чаши 1, составляет почти 2/3, а из чаши 2 — чуть более 1/3.
В этом случае, вероятно, не будет большого улучшения производительности за счет избавления от циклов, но мы должны быть в состоянии написать что-то более краткое и, надеюсь, идиоматическое.
Давайте начнем с избавления от внутреннего цикла for. Это можно заменить вызовом функции Reduce следующим образом:
1
2
3
4
5
6
7
8
9
|
likelihoods2 = function(names, mixes, observations) { scores = rep( 0 , length(names)) names(scores) = names for (name in names) { scores[name] = Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1 ) } return (scores) } |
1
2
3
4
5
|
l2 = likelihoods2(Names, Mixes, Observations) > l2 / sum(l2) Bowl 1 Bowl 2 0.627907 0.372093 |
Так что это хорошо, у нас все еще есть те же вероятности, что и раньше. Теперь избавимся от внешнего цикла for. Функция Map помогает нам здесь:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
likelihoods3 = function(names, mixes, observations) { scores = rep( 0 , length(names)) names(scores) = names scores = Map(function(name) Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1 ), names) return (scores) } l3 = likelihoods3(Names, Mixes, Observations) > l3 $`Bowl 1 ` vanilla 0.1054688 $`Bowl 2 ` vanilla 0.0625 |
В итоге мы получаем список вместо вектора, который нам нужно исправить с помощью функции unlist :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
likelihoods3 = function(names, mixes, observations) { scores = rep( 0 , length(names)) names(scores) = names scores = Map(function(name) Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1 ), names) return (unlist(scores)) } l3 = likelihoods3(Names, Mixes, Observations) > l3 / sum(l3) Bowl 1 .vanilla Bowl 2 .vanilla 0.627907 0.372093 |
Теперь у нас просто есть эта раздражающая «ваниль» в названии. Это достаточно легко исправить:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
likelihoods3 = function(names, mixes, observations) { scores = rep( 0 , length(names)) names(scores) = names scores = Map(function(name) Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1 ), names) result = unlist(scores) names(result) = names return (result) } l3 = likelihoods3(Names, Mixes, Observations) > l3 / sum(l3) Bowl 1 Bowl 2 0.627907 0.372093 |
Немного более чистая альтернатива использует функцию sapply :
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
|
likelihoods3 = function(names, mixes, observations) { scores = rep( 0 , length(names)) names(scores) = names scores = sapply(names, function(name) Reduce(function(acc, observation) acc * mixes[[name]][observation], Observations, 1 )) names(scores) = names return (scores) } l3 = likelihoods3(Names, Mixes, Observations) > l3 / sum(l3) Bowl 1 Bowl 2 0.627907 0.372093 |
Это лучшее, что у меня есть на данный момент, но мне интересно, могли бы мы как-нибудь написать версию с использованием матричных операций — но это в следующий раз!
Ссылка: | Р: Удаление петель от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |