I have one dataframe where each row contain weights. I want to multiply a second dataframe by each row of the first one and aggregate the results with rowsumS then cumprod. For each line in the first dataframe, I want to save one element as a result.
I have achieved this using a for loop, however this is fairly inefficient, particularly for a dataframe with many rows.
Is there a way to to this without a for loop? maybe using tidyverse.
x=runif(4*6)
x=matrix(x,nrow=4,ncol=6)
x_df=as.data.frame(x)
y=rnorm(3*6)
y=matrix(y,nrow=3,ncol=6)
y_df=as.data.frame(y)
ret=rep(NA, nrow(x_df))
for (i in 1:nrow(x_df)){
rets=as.data.frame(mapply('*',y_df,x_df[i,]))
rets=tail(cumprod(1 rowSums(rets,na.rm = TRUE)),1)
ret[i]=rets
}
the vector rets
contain the desired result.
CodePudding user response:
Any of the following would work:
Base R:
apply(tcrossprod(y, x) 1, 2, prod)
[1] 0.3222529 0.1435537 -0.3998603 -2.1293011
Using matrixStats
:
matrixStats::rowProds(tcrossprod(x, y) 1)
[1] 0.3222529 0.1435537 -0.3998603 -2.1293011
matrixStats::colProds(tcrossprod(y, x) 1)
[1] 0.3222529 0.1435537 -0.3998603 -2.1293011
your code:
set.seed(1)
x=runif(4*6)
x=matrix(x,nrow=4,ncol=6)
x_df=as.data.frame(x)
y=rnorm(3*6)
y=matrix(y,nrow=3,ncol=6)
y_df=as.data.frame(y)
ret=rep(NA, nrow(x_df))
for (i in 1:nrow(x_df)){
rets=as.data.frame(mapply('*',y_df,x_df[i,]))
rets=tail(cumprod(1 rowSums(rets,na.rm = TRUE)),1)
ret[i]=rets
}
ret
[1] 0.3222529 0.1435537 -0.3998603 -2.1293011