2014-09-09 5 views
2

У меня есть кадр данных в R, который состоит из двух (числовых) столбцов, скажем А и В. Я хотел бы конструктору столбец, состоящий из элементоврекурсивная сумма плюс произведение в г

A1+B1 
(A1+B1)*A2+B2 
((A1+B1)*A2+B2)*A3+B3 
    ... 

Это, вероятно, это простой однострочный, но я этого не вижу.

Редактировать: удалил слово, обозначенное в заголовке, так как меня просто интересует любое элегантное решение (тупые, которые я могу сделать сам). В F # - который я больше знакомы с - это было бы что-то вроде (предполагается, что элементы будут находиться в списке как кортежей, который был бы более идиоматических):

ABlist |> List.fold (fun acc (a,b) -> acc*a+b) 1 

Что еще что-то очень коротко и ясно , Я перетаскиваю это, потому что я R noob и не знаком с ним, но я где-то читал, что это функциональный язык, поэтому я бы предположил, что решение с точки зрения фрейма над кадром данных будет существовать?

+0

Игнорирование вашего двусмысленного использования круглых скобок 'cumprod (A + B)'? – joran

+0

Я проверю.Если это не сначала добавит элемент мудрый, а затем вычислит кумулятивный продукт из добавленного вектора, это может быть правильно. Почему мои круглые скобки неоднозначны? – Bram

+0

Я вроде как предполагал, что вы _meant_ (A1 + B1) * (A2 + B2), но если нет, то то, что вы описываете, не может быть векционируемым. – joran

ответ

3

Это другой ответ обусловлен провалом усилий Брэма в использовании Сокращения. Он строит список, который имеет A, B пару, а затем устанавливает intial значения для аккумулятора на 1, так что первое умножение не получает обнуляется:

abList <- mapply(c, A,B, SIMPLIFY=FALSE) # keeps as a list 
Reduce(function(acc,x) {acc*x[1]+x[2]}, 
     abList,init=c(1,0), 
     accumulate=TRUE)[-1]    # removes the initialization value 
#-------- 
[[1]] 
[1] 4 3 

[[2]] 
[1] 10 8 

[[3]] 
[1] 31 25 

[[4]] 
[1] 128 104 

[[5]] 
[1] 645 525 

может занять некоторую дальнейшую работу с s/lapply(..., "[", 1) тянуть из аккумулятора

> sapply(Reduce(function(acc,x) {acc*x[1]+x[2]}, 
+   abList,init=c(1,0), 
+   accumulate=TRUE)[-1], "[", 1) 
[1] 4 10 31 128 645 
+0

Просто установите 'init = 1', и вы получите скалярный вывод. Часть документа 'Reduce', описывающая' init' как «объект R того же типа, что и элементы x», не очень точна. – flodel

+0

Да, это довольно интересно. Итак, каковы же эти элементы второго списка? –

+0

Это потому, что 'length (acc * x [1] + x [2])' равно 'length (acc)'. Если вы начинаете 'acc' с' c (1, 0) ', вы всегда получите вывод длины 2. – flodel

1

Это является относительно простым в Rcpp, который не будет иметь проблем с производительностью вы увидели бы, если вы попытаетесь реализовать это с петлями в R.

library(Rcpp) 
sum.prod <- cppFunction(
"NumericVector sum_prod(NumericVector x, NumericVector y) { 
    NumericVector result(x.size()); 
    result[0] = x[0] + y[0]; 
    for (int i=1; i < x.size(); ++i) result[i] = result[i-1]*x[i] + y[i]; 
    return result; 
}") 
sum.prod(c(1, 2, 3, 4, 5), c(3, 2, 1, 4, 5)) 
# [1] 4 10 31 128 645 

Я нашел Rcpp быть самым простым способом для ускорения вычислений с большой точностью для векторизации.

+0

Возможно, это работает. Я буду проверять дома, потому что на моем компьютере на работе мне не разрешено устанавливать инструменты или пакеты, которые мне нужно будет скомпилировать выше. Если появится ответ на родной R, я, вероятно, выберу его как правильный, если не буду отмечать это как ответ после тестирования дома – Bram

2

Хорошо, оказалось, что я был слишком ленив, я сам это понял (заметьте: перед этим был хороший ответ, используя Rcpp уже, но я не могу использовать это на работе). В основном только перевод на R, что я написал в моем редактирования того, как я хотел бы сделать это в F #:

a <- c(1,2,3) 
b <- c(4,5,6) 
abList <- list(a,b) 
Reduce(function(acc,x) {acc*x[[1]]+x[[2]]}, 
     abList, 
     accumulate=TRUE) 

ли трюк. Изменить: согласно приведенному ниже комментарию, на самом деле это не делает трюк. Если одна сборка abList по

abList <- apply(rbind(a,b),2,as.pairlist) 

, а затем складывает по:

Reduce(function(acc,x) {(acc*x[[1]])+x[[2]]},abList,1,accumulate=TRUE) 

Один получает правильный ответ (с 1 вставляться перед, потому что это intial значение для аккумулятора)

+0

Я не получаю правильные результаты с этим (хотя это и происходит выглядит хорошо). Первый элемент должен быть 1 + 4, но аккумулятор равен 9. –

+0

Вы правы, что-то подозрительное. Позвольте мне попытаться исправить это, потому что из описания «Уменьшить» это должно работать (хотя опять же, я R noob) – Bram

+0

Обратите внимание, что 'Reduce' - это не то же самое, что' mapply'. Чтобы использовать «Уменьшить», я думаю, вам нужно будет создать свой abList по-другому, так что c (1,4) будет первым элементом, c (2,5) вторым .... –

1
X = 1; for (i in seq(length(A))) { X= B[i]+A[i]*X; print(X) } 
[1] 4 
[1] 10 
[1] 31 
[1] 128 
[1] 645 

Если вы хотите скопировать, а не повторить:

X = 1; for (i in seq(length(A))) { X[1+i]= B[i]+A[i]*X[i] }; X[-1] 
#[1] 4 10 31 128 645 

Будет ploddingly медленным по сравнению с раствором Rcpp, но если вам нужно сделать шаг компиляции на лету это только тогда, когда длина более чем 1000, которые вы можете даже заметить разницу:

> A <- sample(1:10000, 1000); B <- sample(1:10000, 1000) 
> system.time({X = 1; for (i in seq(length(A))) { X[1+i]= B[i]+A[i]*X[i] }; X[-1]}) 
    user system elapsed 
    0.014 0.002 0.017 
> library(Rcpp) 
> system.time({sum.prod <- cppFunction(
+ "NumericVector sum_prod(NumericVector x, NumericVector y) { 
+ NumericVector result(x.size()); 
+ result[0] = x[0] + y[0]; 
+ for (int i=1; i < x.size(); ++i) result[i] = result[i-1]*x[i] + y[i]; 
+ return result; 
+ }") 
+ sum.prod(A,B) }) 
    user system elapsed 
    0.012 0.002 0.014 
Смежные вопросы