Может ловить не модифицировать переменные в более высокой масштабе
Вопрос
Я часто хочу делать по сути следующим образом:
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's применяет семью больше, чем синтаксический сахар«. Вы заметите, что если вы посмотрите на подпись функции для for
и apply
, у них одна критическая разница: for
петля оценивает выражение, в то время как apply
петля оценивает А. функция.
Если вы хотите изменить вещи за пределами объема функции Применить, вам нужно использовать <<-
или assign
. Отказ Или больше до точки, используйте что-то вроде for
Петля вместо этого. Но вам действительно нужно быть осторожным при работе с вещами вне функции, потому что она может привести к неожиданному поведению.
На мой взгляд, одна из основных причин использовать apply
Функция явно потому, что она не изменяет за пределами этого. Это основная концепция в функциональном программировании, в котором функции избегают побочные эффекты. Отказ Это также причина, по которой apply
Семья функций можно использовать в параллельной обработке (и аналогичные функции существуют в различных параллельных пакетах, таких как снег).
Наконец, правильный путь для запуска вашего примера кода должен также пройти параметры для вашей функции, так и присвоить обратно вывод:
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()
Это то, что вам не нужно инициализировать свой «контейнер» (в этом случае матрицы).
Как предполагает Fojtasek:
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
Видеть эта почта о <<-
. Отказ Но в этом конкретном примере для петли просто сделает больше смысла:
mat <- matrix(0,nrow=10,ncol=1)
for( i in 1:10 ) mat[i,] <- rnorm(1,mean=i)
с незначительной стоимостью создания переменных индексации, i
, в глобальном рабочем пространстве.
Вместо того, чтобы фактически изменять коврик, Lapply просто возвращает измененную версию мата (в виде списка). Вам просто нужно назначить его коврике и включить его обратно в матрицу, используя as.matrix()
.