Может ловить не модифицировать переменные в более высокой масштабе

StackOverflow https://stackoverflow.com/questions/2656792

  •  27-09-2019
  •  | 
  •  

Вопрос

Я часто хочу делать по сути следующим образом:

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().

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top