user67275
user67275

Reputation: 2170

Create element-wise product of matrix columns

x1  x2  x3  x11 x12 x13 x22 x23 x33
1   5   9   1   5   9   25  45  81
2   6   10  4   12  20  36  60  100
3   7   11  9   21  33  49  77  121
4   8   12  16  32  48  64  96  144

When x1, x2, and x3 are given, I would like to create a matrix or data frame x11, x12, x13, x22, x23, and x33 which are element-wise product of vectors x1, x2, and x3.

Actually I would like to to this for more vectors (e.g. x1 ~ x6) to high order (3rd or 4th). Is there an R command which can do this?

Upvotes: 1

Views: 227

Answers (2)

989
989

Reputation: 12937

You could also do this quite vectorized in base R:

# Data
m <- matrix(1:12,4,3)

cl <- ncol(m)
res <- cbind(m, m[,rep(seq(cl), cl:1)] * m[,unlist(Map(":", 1:cl, rep(cl,cl)))])

      # [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8] [,9]
# [1,]    1    5    9    1    5    9   25   45   81
# [2,]    2    6   10    4   12   20   36   60  100
# [3,]    3    7   11    9   21   33   49   77  121
# [4,]    4    8   12   16   32   48   64   96  144

Basically you first select the columns for which you want to have the product and then do them all at once.

Upvotes: 0

akrun
akrun

Reputation: 887118

We can do the combination with expand.grid to find all the combination of columns 1:3, then loop through the rows, subset the dataset and get the * of those

nm1 <- names(df1)[1:3]
apply(expand.grid(nm1, nm1), 1, FUN = function(x) Reduce(`*`, df1[x]))

The above output gives all the combinations, but suppose if we want to remove the combinations that are mirror image

#expand the names to two columns with each combination
d1 <- expand.grid(nm1, nm1)
#remove the rows that are duplicates
d2 <- d1[!duplicated(t(apply(d1, 1, sort))),]
#apply the function and change the column names
d3 <- apply(d2, 1, FUN = function(x) Reduce(`*`, df1[x]))
colnames(d3) <- do.call(paste0, d2)

and if needed cbind with the first 3 columns

cbind(df1[1:3], d3)

Another option is combn

d1 <- as.data.frame(combn(nm1, 2, FUN = function(x) Reduce(`*`, df1[x])))
nm2 <- combn(nm1, 2, FUN = paste, collapse="")
names(d1) <- nm2
d2 <- setNames(as.data.frame(df1[1:3]^2), paste0(nm1, nm1))
cbind(df1[1:3], d1, d2)

Upvotes: 2

Related Questions