r中的递归和加产品

时间:2014-09-09 20:03:37

标签: r

我在R中有一个数据框,它包含两个(数字)列,比如A和B.我想构造一个由元素组成的列

  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菜鸟并且不熟悉它,但是我已经在某个地方读到它是一种功能语言,所以我猜一个解决方案就折叠而言数据框架会存在吗?

4 个答案:

答案 0 :(得分:3)

这是由于Bram使用Reduce失败而导致的不同答案。它构建一个具有A; B对的列表,然后将累加器的初始值设置为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

答案 1 :(得分:2)

好吧,事实证明我太懒了,我自己弄清楚了(注意:在此之前已经有一个很好的答案使用Rcpp,但我不能在工作中使用它)。基本上只是我在编辑中写的关于如何在F#中执行此操作的R的翻译:

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 by

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

然后折叠:

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

一个人得到了正确的答案(前面有一个1,因为这是累加器的初始值)

答案 2 :(得分: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是加速难以矢量化计算的最简单方法。

答案 3 :(得分: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

与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