Oto inne podejście, które znalazłem. Jest szybki, ale nie tak szybki, jak proste wywołanie próbki z pętlą for. Początkowo myślałem, że to bardzo dobrze, ale użyłem benchmark() niepoprawnie.
luke2 = function(probs) { # takes a matrix of probability vectors, each in its own row
probs <- probs/rowSums(probs)
probs <- t(apply(probs,1,cumsum))
answer <- rowSums(probs - runif(nrow(probs)) < 0) + 1
return(answer) }
Oto jak to działa: obraz prawdopodobieństwa jak linie o różnych długościach określonymi na osi liczbowej od 0 do 1. Dużym prawdopodobieństwem zajmie więcej osi liczbowej niż małych. Następnie możesz wybrać wynik, wybierając losowy punkt na linii liczbowej - duże prawdopodobieństwa będą miały większe prawdopodobieństwo wyboru. Zaletą tego podejścia jest to, że można przetasować wszystkie liczby losowe potrzebne w jednym wywołaniu zrzutu(), zamiast wywoływać próbkę w kółko, jak w funkcjach luke, roman i roman2. Wygląda jednak na to, że dodatkowe przetwarzanie danych spowalnia to, a koszty z nawiązką kompensują tę korzyść.
library(rbenchmark)
probs <- matrix(runif(2000), ncol = 10)
answers <- numeric(200)
benchmark(replications = 1000,
luke = for(i in 1:20) answers[i] <- sample(10,1,prob=probs[i,]),
luke2 = luke2(probs),
roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)),
roman2 = replicate(20, sample(10, 1, prob = runif(10))))
roman = apply(probs, MARGIN = 1, FUN = function(x) sample(10, 1, prob = x)),
roman2 = replicate(20, sample(10, 1, prob = runif(10))))
test replications elapsed relative user.self sys.self user.child sys.child
1 luke 1000 0.171 1.000 0.166 0.005 0 0
2 luke2 1000 0.529 3.094 0.518 0.012 0 0
3 roman 1000 1.564 9.146 1.513 0.052 0 0
4 roman2 1000 0.225 1.316 0.213 0.012 0 0
Z jakiegoś powodu, apply() bardzo źle, gdy dodajesz więcej wierszy. Nie rozumiem, dlaczego, ponieważ myślałem, że to opakowanie dla(), a więc powinien Roman() powinien działać podobnie jak luke().
+1 Należy dodać losową odpowiedź na rolkę jako rozwiązanie. To całkiem fajne podejście! Czy sprawdziłeś, jak jest skalowalny? –
Należy zauważyć, że argument 'prob' w funkcji R' sample' bez zastąpienia * NIE jest proporcjonalny do prawdopodobieństwa włączenia pierwszego rzędu. Jeśli chcesz to zachować, sprawdź pakiet 'sampling' @ CRAN. –
Dzięki za wejście. Ferdinand, trochę mnie tam zgubiłeś, ale domyślam się, że w tym przykładzie nie ma to znaczenia, ponieważ próbka ma długość 1 (więc pobieranie próbek z wymianą i bez niej jest takie samo). Również rozwiązanie w luke2 całkowicie eliminuje próbkę. Wymienię to jako rozwiązanie. – lukeholman