Можете ли вы использовать функцию lapply() для изменения значения ввода?

Мне было интересно, можно ли использовать функцию lapply() для изменения значения ввода, например:

a1<-runif(100)
a2<-function(i){
a1[i]<-a1[i-1]*a1[i];a1[i]
}
a3<-lapply(2:100,a2)

Я ищу что-то похожее на цикл for(), но с использованием инфраструктуры lapply(). Я не смог заставить rapply() сделать это.

Причина в том, что «настоящая» функция a2 является сложной функцией, которую нужно оценивать только в том случае, если значение a1[i-1] соответствует некоторым критериям.

перефразируя: поэтому я пытаюсь заменить for() в приведенном ниже коде на вещь типа lapply():

    a1<-runif(100)
    a2<-function(i, a1){
        a1[i]<-a1[i-1]*2
        a1[i]
    }
    a3<-as.numeric(lapply(2:100, a2, a1=a1))
#compare the output of a3 with that of a1 after the recursive loop
    a2<-a1 #saved for comparison
    for(i in 2:length(a1)){
        a1[i]<-a1[i-1]*2
    }
cbind(a1[2:100],a3)
#actually this is would be like writting a lapply() version of the cumprod() function
cbind(a1,cumprod(a2))

Список рассылки R посоветовал обратить внимание на функцию Reduce()... как в:

a1<-runif(100)
cadd<-function(x) Reduce("*", x, accumulate = TRUE)
cadd(a1)

который дает тот же результат, что и cumprod(a1)... но даже медленнее, чем цикл:

a1<-runif(100000)
cadd<-function(x) Reduce("*", x, accumulate = TRUE)
looop<-function(a1){
j<-length(a1)
    for(i in 2:j){
        a1[i]<-a1[i-1]*a1[i]
    }
a1
}

> system.time(cadd(a1))
   user  system elapsed 
  1.344   0.004   1.353 
> system.time(cumprod(a1))
   user  system elapsed 
  0.004   0.000   0.002 
> system.time(loop(a1))
   user  system elapsed 
  0.772   0.000   0.775 
> 

Есть идеи ?


person user189035    schedule 13.10.2009    source источник
comment
Я не думаю, что следую тому, что вы хотите сделать. Зависит ли a1[i] (то, что вы вычисляете) от a1[i-1]? Если это так, я думаю, что лучше всего использовать циклы. Если нет, то было бы лучше разделить вектор и выполнить функцию в этой части.   -  person Eduardo Leoni    schedule 13.10.2009
comment
Должны ли они быть эквивалентны в вашей последней строке выше: cbind(a1,cumprod(a2))? Насколько я понимаю, они не совпадают.   -  person Shane    schedule 13.10.2009
comment
Шейн: вот в чем проблема: функция looop() (см. пост) дает тот же результат, что и cumprod... но версия lapply() этого не дает. Я хочу рекурсивно применить функцию (более сложную, чем умножение), которая использует значение предыдущей оценки для вектора... и не может найти способ избежать цикла   -  person user189035    schedule 13.10.2009
comment
На самом деле я имел в виду ваш вывод цикла.   -  person Shane    schedule 13.10.2009
comment
Ваша цель — ускорить программу или сделать ее более читабельной? Если вы хотите ускорить его, вашим основным вариантом будет использование C/C++. См. Другой вопрос, который я связал ниже, относительно рекурсивных последовательностей в R.   -  person Shane    schedule 13.10.2009
comment
Шейн: спасибо за ссылку... прямо в цель :) Как пометить вопрос как решенный?   -  person user189035    schedule 14.10.2009
comment
Под значком голосования есть небольшой флажок.   -  person Shane    schedule 14.10.2009


Ответы (1)


Редактировать: После вашего разъяснения: нет, я не верю, что вы можете использовать функцию применения, чтобы делать что-то подобное рекурсивно. Весь смысл функции применения заключается в том, что она применяется к вектору/матрице одновременно.

Вы также можете посмотреть этот связанный вопрос в stackoverflow.

Мой старый ответ:

Попробуй это:

a1<-runif(100)
a2<-function(i, a1){
    a1[i]<-a1[i-1]*a1[i]
    a1[i]
}
a3 <- as.numeric(lapply(2:100, a2, a1=a1))

В отличие от цикла for, вам нужно передать ссылку на все, что вам нужно, в цикле lapply. Возврат также является списком, поэтому вам нужно привести его обратно к любой форме, которую вы хотите.

Вы также можете посмотреть на пакет plyr, чтобы узнать, как это сделать.

Кроме того, вы можете выполнять свою операцию без цикла:

a3 <- a1[-length(a1)] * a1[-1]

Другими словами, эти утверждения полностью эквивалентны:

> all((a1[-length(a1)] * a1[-1]) == as.numeric(lapply(2:100, a2, a1=a1)))
[1] TRUE

Но первый вариант предпочтительнее, так как он не имеет итераций.

person Shane    schedule 13.10.2009