может lapply не изменять переменные в более высоком объеме

Я часто хочу сделать по существу следующее:

mat <- matrix(0,nrow=10,ncol=1)
lapply(1:10, function(i) { mat[i,] <- rnorm(1,mean=i)})

Но, я ожидал бы, что циновка будет иметь 10 случайных чисел в ней, а скорее она имеет 0. (Я не волнуюсь по поводу rnorm части. Очевидно существует правильный способ сделать это. Я - беспокойство о влиянии на циновку из анонимной функции lapply), разве, я не могу влиять на матричную циновку из lapply? Почему нет? Существует ли правило обзора данных R, который блокирует это?

15
задан jogo 2 February 2016 в 13:33
поделиться

3 ответа

Я обсуждал этот вопрос в следующем вопросе: « Является ли семейство приложений 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 ), а не вывести его.

28
ответ дан 1 December 2019 в 01:30
поделиться

Одним из основных преимуществ функций высшего порядка, таких как 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 в глобальной рабочей области.

6
ответ дан 1 December 2019 в 01:30
поделиться

Вместо фактического изменения mat, lapply просто возвращает измененную версию mat (в виде списка). Вам просто нужно назначить его mat и снова превратить в матрицу, используя as.matrix () .

1
ответ дан 1 December 2019 в 01:30
поделиться
Другие вопросы по тегам:

Похожие вопросы: