2010-04-17 1 views
12

я часто хочу сделать по существу следующее:может lapply не изменять переменные в более высоком объеме

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

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

ответ

26

Я обсуждал этот вопрос в этом смежном вопросе: «Is R’s apply family more than syntactic sugar». Вы заметите, что если вы посмотрите на подпись функции для for и apply, то они имеют одну критическую разницу: цикл for оценивает выражение, а цикл apply оценивает функцию .

Если вы хотите изменить объекты, выходящие за рамки функции приложения, вам необходимо использовать <<- или assign. Или более того, используйте что-то вроде цикла for. Но вам действительно нужно быть осторожным при работе с вещами вне функции, потому что это может привести к неожиданному поведению.

На мой взгляд, одной из основных причин использования функции apply является явно, потому что она не изменяет ничего вне ее. Это основная концепция функционального программирования, в которой функции исключают side effects. Это также является причиной того, что семейство функций 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), а не выводить его.

1

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

5

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

См this post о <<-. Но в данном конкретном примере для контура будет просто сделать больше смысла:

mat <- matrix(0,nrow=10,ncol=1) 
for(i in 1:10) mat[i,] <- rnorm(1,mean=i) 

с незначительной стоимостью создания переменной индексации, i в глобальном рабочем пространстве.

Смежные вопросы