#r #random-walk
Вопрос:
Я пытаюсь написать функцию, которая генерирует случайное блуждание, связанное единичной сферой, в результате чего определяется последнее местоположение случайного блуждания, заданное вектором. Пытаясь выяснить, где нарушается моя функция, я попытался разобраться в этом следующим образом:
norm_vec <- function(x) sqrt(sum(x^2))
sphere_start_checker <- function() {
repeat {
start_loc <- runif(3, min = -1, max = 1)
if (norm_vec(start_loc) < 1) return(start_loc)
}
}
n <- 10
set.seed(1)
new_loc <- as.matrix(t(sphere_start_checker()))
temp_loc <- as.matrix(t(c(0, 0, 0)))
for(i in n) {
repeat {
temp_loc <- new_loc[i, ] runif(3, min = -.01, max = .01)
if (norm_vec(temp_loc) < 1) {
return(new_loc <- rbind(new_loc, temp_loc))
}
}
}
new_loc
Я получаю ошибку: Ошибка в new_loc[i, ] : индекс выходит за рамки
Однако, когда я вручную повторяю код за пределами цикла for, все работает нормально. Я предполагаю, что это как-то связано с правилами определения области R, и я пытался возиться с назначением результата rbind глобальной среде, но это не работает.
Сначала я попытался написать функцию следующим образом:
randomwalk_sphere <- function(n, radius, stepmax) {
# initialize sphere bounds
sphere_radius <- as.double(radius)
# initialize random starting vector
# while loop that adds a random vector to our start_loc n times, repeating once boundary condition is met
loop <- 0
new_loc <- sphere_start_checker()
while(loop <= n) {
repeat {
temp_loc <- new_loc runif(3, min = -stepmax, max = stepmax)
if (norm_vec(temp_loc) < sphere_radius) {
return(assign("new_loc", temp_loc, env = .GlobalEnv))
}
}
loop <- loop 1
}
new_loc
}
но когда я делаю это таким образом, цикл while, похоже, не работает, и я просто получаю начальную координату new_loc из равномерного распределения, а не из случайного блуждания. Я понимаю, что использование rbind, вероятно, является более правильным способом сделать это, но мне интересно узнать, почему этот подход не работает.
Комментарии:
1.
for (i in n)
всегда будет повторяться ровно один раз со значением ifi = 10
. Вы намереныseq(n)
это сделать ? Кроме того, первый раз, когда вы запускаетеfor
цикл,i
равен 10 иnew_loc
содержит всего 1 строку, поэтомуnew_loc[10,]
сбой должен быть очевиден.2. Я вижу ошибку в том, что не использую seq_along, однако, если я попробую
n <- 1:10 set.seed(1) new_loc <- as.matrix(t(sphere_start_checker())) temp_loc <- as.matrix(t(c(0, 0, 0))) for(i in seq_along(n)) { repeat { temp_loc <- new_loc[i, ] runif(3, min = -.01, max = .01) if (norm_vec(temp_loc) < 1) { return(new_loc <- rbind(new_loc, temp_loc)) } } } new_loc new_loc[10,]
, он все равно вернет ту же ошибку.
Ответ №1:
Некоторые мысли:
- в то время как вы «исправили» проблему
for (i in n)
, канонический (более распространенный) метод, как правило, сохраняетсяn
как счетчик одной длины и используетсяseq_len(n)
или аналогичен вfor
вызове, напримерn <- 10; for (i in seq_len(n))
. return
ни в чем , кроме формальногоfunction(.){..}
заявления, это неправильно; если вы хотите остановить arepeat
, используйтеbreak
. Как показано здесь, область повторного назначения не является правильной, поэтомуnew_loc
она никогда не переназначается со всеми результатами итераций.
В конечном счете, как только вы перестанете пытаться return
избавиться от какой-либо функции, это сработает.
n <- 10
set.seed(1)
new_loc <- as.matrix(t(sphere_start_checker()))
temp_loc <- as.matrix(t(c(0, 0, 0)))
for (i in seq_len(n)) {
repeat {
temp_loc <- new_loc[i, ] runif(3, min = -.01, max = .01)
if (norm_vec(temp_loc) < 1) {
new_loc <- rbind(new_loc, temp_loc)
break
}
}
}
new_loc
# [,1] [,2] [,3]
# -0.4689827 -0.2557522 0.1457067
# temp_loc -0.4608185 -0.2617186 0.1536745
# temp_loc -0.4519250 -0.2585026 0.1562568
# temp_loc -0.4606893 -0.2643831 0.1497879
# temp_loc -0.4569488 -0.2667010 0.1551848
# temp_loc -0.4569948 -0.2623487 0.1650229
# temp_loc -0.4593941 -0.2567998 0.1737170
# temp_loc -0.4651513 -0.2537663 0.1662281
# temp_loc -0.4698069 -0.2560440 0.1564959
# temp_loc -0.4721591 -0.2486502 0.1533029
# temp_loc -0.4725175 -0.2466589 0.1531737