20

What I want to do is multiply all the values in column 1 of a data.frame by the first element in a vector, then multiply all the values in column 2 by the 2nd element in the vector, etc...

c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)

  c1 c2 c3
1  1  4  7
2  2  5  8
3  3  6  9

v1 <- c(1,2,3)

So the result is this:

  c1  c2  c3
1  1  8   21
2  2  10  24
3  3  12  27

I can do this one column at a time but what if I have 100 columns? I want to be able to do this programmatically.

4 Answers4

17

Or simply diagonalize the vector, so that each row entry is multiplied by the corresponding element in v1:

c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- as.matrix(cbind(c1,c2,c3))
v1 <- c(1,2,3)

d1%*%diag(v1)

     [,1] [,2] [,3]
[1,]    1    8   21
[2,]    2   10   24
[3,]    3   12   27
Antoni Parellada
  • 4,253
  • 6
  • 49
  • 114
8

Transposing the dataframe works.

c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)
v1 <- c(1,2,3)
t(t(d1)*v1)
#     c1 c2 c3
#[1,]  1  8 21
#[2,]  2 10 24
#[3,]  3 12 27

EDIT: If all columns are not numeric, you can do the following

c1 <- c(1,2,3)
c2 <- c(4,5,6)
c3 <- c(7,8,9)
d1 <- data.frame(c1,c2,c3)

# Adding a column of characters for demonstration
d1$c4 <- c("rr", "t", "s")

v1 <- c(1,2,3)

#Choosing only numeric columns
index <- which(sapply(d1, is.numeric) == TRUE)
d1_mat <- as.matrix(d1[,index])

d1[,index] <- t(t(d1_mat)*v1)
d1
#  c1 c2 c3 c4
#1  1  8 21 rr
#2  2 10 24  t
#3  3 12 27  s
user2100721
  • 3,557
  • 2
  • 20
  • 29
Greenparker
  • 272
  • 1
  • 11
8

We can also replicate the vector to make the lengths equal and then multiply

d1*v1[col(d1)]
#  c1 c2 c3
#1  1  8 21
#2  2 10 24
#3  3 12 27

Or use sweep

sweep(d1, 2, v1, FUN="*")

Or with mapply to multiply the corresponding columns of 'data.frame' and elements of 'vector'

mapply(`*`, d1, v1)
akrun
  • 874,273
  • 37
  • 540
  • 662
  • 1
    Sweep worked really well to multiple each column of matrix A by elements of coefficient matrix, and return matrix of similar dimension of matrix A – Masood Sadat Jan 27 '20 at 15:11
1

Here are a few possibilities not mentioned yet:

Base R

t(replicate(nrow(d1), v1)) * d1

purrr

purrr::map2_dfc(d1, v1, `*`)

Note: as of purrr 1.0.0 *_dfr and *_dfc have been superseded so you can do:

purrr::map2(d1, v1, `*`) |> data.frame()

collapse

collapse::TRA(d1, v1, "*") # note quotes not backticks

The above is based on a numeric data frame. If you have other columns types, as mentioned in the comments, here are some options:

By order

If your numeric columns are in the same order as your vector, you can use the above, but subset for numeric columns first (just using my replicate answer as an example, but answers should work there too):

library(dplyr)

v1 <- c(-1, 0, 1, 100)
iris %>% 
  mutate(t(replicate(nrow(.), v1)) * pick(where(is.numeric)))

Named vector

Otherwise if you have name-value pairs where the names are the same as the columns that is easier:

v1 <- setNames(c(-1, 0, 1, 100), names(Filter(is.numeric, iris)))
iris %>% 
  mutate(across(all_of(names(v1)), ~ . * v1[cur_column()]))
LMc
  • 12,577
  • 3
  • 31
  • 43