Функция ifelse вместо цикла for - PullRequest
0 голосов
/ 24 ноября 2018

У меня есть оригинальный код R, как показано ниже.

 Bernoulli <- rbinom(1000, 1, 0.5)
 mix.sample <- rep(0, 1000)  #reserve storage
 for (i in 1:1000) { #for each Bernoulli realization
   if (Bernoulli[i] == 1){ #sample corresponding normal component
     mix.sample[i] <- rnorm(1, mean=10, sd=1)
   }
   else {
     mix.sample[i] <- rnorm(1, mean=0, sd=1)
   }
 }
 plot(density(mix.sample))

И я попробовал следующий код вместо цикла for, но возникает проблема с полученными результатами, кто-нибудь может мне помочь?

 Bernorm <- ifelse(Bernoulli == 1, rnorm(1, mean=10, sd=1), rnorm(1, mean=0, sd=1))

Ответы [ 4 ]

0 голосов
/ 24 ноября 2018

Другой вариант - поместить значения в фрейм данных, а затем добавить переменную, используя ifelse, как вы пытались в начале.Здесь я также просто строю данные, но вы можете назначить их обратно для хранения значений.

library(tidyverse)

set.seed(81)
df <- data_frame(Bernoulli = rbinom(1000, 1, 0.5))

df %>% 
  mutate(mix.sample = if_else(Bernoulli == 1, 
                              rnorm(1, mean=10, sd=1), 
                              rnorm(1, mean=0, sd=1))) %>%
  ggplot(aes(mix.sample))+
  geom_density()+
  scale_x_continuous(limits = c(-5, 15))

0 голосов
/ 24 ноября 2018

Подобно тому, как вы создаете весь тестовый вектор за один раз (rbinom), вы можете создать все значения обоих rnorm векторов за один раз.Поместите все в матрицу, используйте значение тестового вектора, чтобы выбрать любой из двух столбцов значений.

set.seed(1)
n <- 8
m <- cbind(test = rbinom(n, 1, 0.5),
           norm0 = rnorm(n, mean = 0, sd = 1),
           norm10 = rnorm(n, mean = 10, sd = 1))

m <- cbind(m, res = m[cbind(1:nrow(m), (m[ , "test"] == 1) + 2)])
#     test      norm0    norm10        res
# [1,]   0  0.3295078  9.378759  0.3295078
# [2,]   0 -0.8204684  7.785300 -0.8204684
# [3,]   1  0.4874291 11.124931 11.1249309
# [4,]   1  0.7383247  9.955066  9.9550664
# [5,]   0  0.5757814  9.983810  0.5757814
# [6,]   1 -0.3053884 10.943836 10.9438362
# [7,]   1  1.5117812 10.821221 10.8212212
# [8,]   1  0.3898432 10.593901 10.5939013
# [10,]  0  1.1249309 10.619826  1.1249309  
0 голосов
/ 24 ноября 2018

Лично я бы использовал тот факт, что вы можете конвертировать Binomial в logical сразу.

  Bernoulli <- as.logical(rbinom(1e3, 1, 0.5))
  samp <- numeric(1e3)
  n <- sum(Bernoulli)
  samp[Bernoulli] <- rnorm(n, 10, 1)
  samp[!Bernoulli] <- rnorm(1e3 - n)
  samp
0 голосов
/ 24 ноября 2018

Вместо цикла for вы можете выполнить

set.seed(42)
sim.fun <- function(x) {
  if (x == 1) {
    rnorm(1, 10, 1)
  } else {
    rnorm(1, 0, 1)
  }
}

P <- sapply(Bernoulli, sim.fun)
plot(density(P))

Или, если вы полагаетесь на ifelse(), использовать его с sapply():

P <- sapply(Bernoulli, function(x) ifelse(x == 1, rnorm(1, 10, 1), rnorm(1, 0, 1)))

Функцияхотя быстрее.

microbenchmark() выход:

Unit: milliseconds
    expr      min       lq     mean   median       uq      max neval cld
for-loop 8.015976 8.232972 8.712522 8.316147 8.475865 14.65216   100   c
 sim.fun 3.622982 3.672990 4.493131 3.700290 3.752339 54.14139   100 a  
  sapply 5.932761 6.016319 6.479058 6.070026 6.115951 12.38065   100  b 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...