Row-wise difference between matrix and data frame

Viewed 59

I have 2 objects: m1 is a matrix that increases in rows over time, and m2 is a data frame that decreases in rows over time. Both share common column names (i.e., row, col). What I want is to find the difference between the first row of m1 and each row of m2 and have the output stored as an object in a list. This should continue for the subsequent rows of m1.

I have tried with apply(m1, 1, function(x){x - m2}), but this gives me a result I cannot explain (i.e., the difference doesn't make sense from the second observations onwards). Why is this happenning and what can be done to ensure the difference is returned as desired?

Data, code and current output:

m1 <- matrix(1:4, ncol = 2, byrow = T) 
m2 <- data.frame(matrix(1:10, ncol = 2, byrow = T))
colnames(m1) <- colnames(m2) <- c("row", "col")

> m1
     row col
[1,]   1   2
[2,]   3   4
> m2
  row col
1   1   2
2   3   4
3   5   6
4   7   8
5   9  10
> apply(m1, 1, function(x){x - m2})
[[1]]
  row col
1   0   0
2  -1  -3
3  -4  -4
4  -5  -7
5  -8  -8

[[2]]
  row col
1   2   2
2   1  -1
3  -2  -2
4  -3  -5
5  -6  -6

Desired output:

[[1]]
  row col
1   0   0
2  -2  -2
3  -4  -4
4  -6  -6
5  -8  -8

[[2]]
  row col
1   2   2
2   0   0
3  -2  -2
4  -4  -4
5  -6  -6
2 Answers

We can try the code below

apply(
  m1,
  1,
  function(x) {
    t(x - t(m2))
  },
  simplify = FALSE
)

which gives

[[1]]
     row col
[1,]   0   0
[2,]  -2  -2
[3,]  -4  -4
[4,]  -6  -6
[5,]  -8  -8

[[2]]
     row col
[1,]   2   2
[2,]   0   0
[3,]  -2  -2
[4,]  -4  -4
[5,]  -6  -6

Or, another option using Map + split + rep

Map(
  `-`,
  split(m1[rep(1:nrow(m1), each = nrow(m2)), ], gl(nrow(m1), nrow(m2))),
  list(m2)
)

which gives

$`1`
  row col
1   0   0
2  -2  -2
3  -4  -4
4  -6  -6
5  -8  -8

$`2`
  row col
1   2   2
2   0   0
3  -2  -2
4  -4  -4
5  -6  -6

We could use sweep

my_function <- function(m1, m2){
  x <- as.vector(m1[1,])
  y <- as.vector(m1[2,])
  m2_1 <- sweep(m2, 2, x, `-`)*-1
  m2_2 <- sweep(m2, 2, y, `-`)*-1
  list(m2_1,m2_2)
}

my_function(m1, m2)

my_function(m1, m2)
[[1]]
  X1 X2
1  0  0
2 -2 -2
3 -4 -4
4 -6 -6
5 -8 -8

[[2]]
  X1 X2
1  2  2
2  0  0
3 -2 -2
4 -4 -4
5 -6 -6

Related