В моем последнем сообщении в блоге я показал перевод функции правдоподобия из 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 20.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 20.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 20.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 20.627907 0.372093 |
Это лучшее, что у меня есть на данный момент, но мне интересно, могли бы мы как-нибудь написать версию с использованием матричных операций — но это в следующий раз!
| Ссылка: | Р: Удаление петель от нашего партнера по JCG Марка Нидхэма в блоге Марка Нидхэма . |