Я часто хочу сделать по существу следующее:
mat <- matrix(0,nrow=10,ncol=1)
lapply(1:10, function(i) { mat[i,] <- rnorm(1,mean=i)})
Но, я ожидал бы, что циновка будет иметь 10 случайных чисел в ней, а скорее она имеет 0. (Я не волнуюсь по поводу rnorm части. Очевидно существует правильный способ сделать это. Я - беспокойство о влиянии на циновку из анонимной функции lapply), разве, я не могу влиять на матричную циновку из lapply? Почему нет? Существует ли правило обзора данных R, который блокирует это?
Я обсуждал этот вопрос в следующем вопросе: « Является ли семейство приложений R чем-то большим, чем синтаксический сахар ». Вы заметите, что если вы посмотрите на сигнатуру функции для для
и apply
, у них есть одно важное отличие: цикл for
вычисляет выражение, а Цикл apply
вычисляет функцию .
Если вы хотите изменить что-либо за пределами функции применения, вам нужно использовать << -
или assign
. Или, что более важно, используйте вместо этого что-то вроде цикла for
. Но вам действительно нужно быть осторожным при работе с вещами вне функции, потому что это может привести к неожиданному поведению.
На мой взгляд, одна из основных причин использования функции apply
явно заключается в том, что она не меняет ничего за ее пределами. Это основная концепция функционального программирования, в которой функции избегают побочных эффектов . Это также причина того, почему семейство функций apply
может использоваться в параллельной обработке (и аналогичные функции существуют в различных параллельных пакетах, таких как snow).
Наконец, правильный способ запустить пример кода - это также передать параметры вашей функции и вернуть результат:
mat <- matrix(0,nrow=10,ncol=1)
mat <- matrix(lapply(1:10, function(i, mat) { mat[i,] <- rnorm(1,mean=i)}, mat=mat))
Всегда лучше явно указывать параметр, когда это возможно (следовательно, mat = mat
), а не вывести его.
Одним из основных преимуществ функций высшего порядка, таких как lapply ()
или sapply ()
, является то, что вам не нужно инициализировать свой «контейнер» (матрица в этом кейс).
Как предлагает Фойташек:
as.matrix(lapply(1:10,function(i) rnorm(1,mean=i)))
Альтернативно:
do.call(rbind,lapply(1:10,function(i) rnorm(1,mean=i)))
Или просто как числовой вектор:
sapply(1:10,function(i) rnorm(1,mean=i))
Если вы действительно хотите изменить переменную выше области действия вашей анонимной функции (в данном случае генератор случайных чисел) , используйте << -
> mat <- matrix(0,nrow=10,ncol=1)
> invisible(lapply(1:10, function(i) { mat[i,] <<- rnorm(1,mean=i)}))
> mat
[,1]
[1,] 1.6780866
[2,] 0.8591515
[3,] 2.2693493
[4,] 2.6093988
[5,] 6.6216346
[6,] 5.3469690
[7,] 7.3558518
[8,] 8.3354715
[9,] 9.5993111
[10,] 7.7545249
См. этот пост о << -
. Но в этом конкретном примере цикл for будет иметь больше смысла:
mat <- matrix(0,nrow=10,ncol=1)
for( i in 1:10 ) mat[i,] <- rnorm(1,mean=i)
с небольшими затратами на создание индексирующей переменной i
в глобальной рабочей области.
Вместо фактического изменения mat, lapply просто возвращает измененную версию mat (в виде списка). Вам просто нужно назначить его mat и снова превратить в матрицу, используя as.matrix ()
.