scs
scs

Reputation: 575

Add multiple copies of row to matrix

Is there an elegant way to add multiple copies of the same row to a matrix ? Below is an example that solves the problem. However, this example is slow and not elegant coding.

m <- matrix(c(1,2,3,4,5,6,7,8,9),ncol=3)
m0 <- m

r <- c(10,20,30)

#Correct example
for (i in c(1,2))
  m[i,] <- r

print(m)

#    [,1] [,2] [,3]
#[1,]   10   20   30
#[2,]   10   20   30
#[3,]    3    6    9


#Attempts below look straightforward but lead to incorrect results
m <- m0

m[1:2,] <- apply(m[1:2,],1,function(x)r)
print(m)

#  [,1] [,2] [,3]
#[1,]   10   30   20
#[2,]   20   10   30
#[3,]    3    6    9

m <- m0
m[1:2,] <- r
print(m)

#  [,1] [,2] [,3]
#[1,]   10   30   20
#[2,]   20   10   30
#[3,]    3    6    9

Upvotes: 0

Views: 73

Answers (2)

scs
scs

Reputation: 575

As to my knowledge, the for-loop is the fastest way to solve the problem. A faster solution would be to select a different data structure in R, where the records are in the columns instead of in the rows.

Below are speed measurements for the solutions by @docendo-discimus and me and an additional example where the records are in the columns instead of in the rows. Direct assignment works without errors in that case.

m <- matrix(c(1,2,3,4,5,6,7,8,9),ncol=3)
m0 <- m

r <- c(10,20,30)

#For loop
print(
  system.time(
    for (k in 1:100000){  
      for (i in c(1,2))
        m[i,] <- r
    }))
print(m)

#     User      System verstrichen 
#     0.524       0.011       0.552 

#     [,1] [,2] [,3]
#     [1,]   10   20   30
#     [2,]   10   20   30
#     [3,]    3    6    9


#@docendo-discimus: Create new matrix
m <- m0
print(
  system.time(
  for (k in 1:100000){
    m[1:2, ] <- matrix(r, ncol = 3, nrow = 2, byrow = TRUE)})
)
print(m)

#     User      System verstrichen 
#     0.818       0.011       0.833 

#     [,1] [,2] [,3]
#     [1,]   10   20   30
#     [2,]   10   20   30
#     [3,]    3    6    9

#@docendo-discimus Transpose, modify columns, transpose again
m <- m0
print(
  system.time(
    for (k in 1:100000){
      m <- t(m)
      m[, 1:2] <- r
      m <- t(m)
      m}))

print(m)

#     User      System verstrichen 
#     1.870       0.010       1.895 

#     [,1] [,2] [,3]
#     [1,]   10   20   30
#     [2,]   10   20   30
#     [3,]    3    6    9

#Usage of different data structure with a transposed matrix
m <- matrix(c(1,2,3,4,5,6,7,8,9),nrow=3)
m0 <- m
print(m)

#     [,1] [,2] [,3]
#     [1,]    1    4    7
#     [2,]    2    5    8
#     [3,]    3    6    9

print(
  system.time(
    for (k in 1:100000){
      m[,1:2] <- r
    }))

print(m)

#     User      System verstrichen 
#     0.241       0.013       0.255

#     [,1] [,2] [,3]
#     [1,]   10   10    7
#     [2,]   20   20    8
#     [3,]   30   30    9

Upvotes: 0

talat
talat

Reputation: 70256

You could construct a second matrix from the vector r and insert it into m as follows:

m[1:2, ] <- matrix(r, ncol = 3, nrow = 2, byrow = TRUE)
m
#     [,1] [,2] [,3]
#[1,]   10   20   30
#[2,]   10   20   30
#[3,]    3    6    9

Another option is to transpose m, insert r and transpose again:

m <- t(m)
m[, 1:2] <- r
m <- t(m)
m
#     [,1] [,2] [,3]
#[1,]   10   20   30
#[2,]   10   20   30
#[3,]    3    6    9

I haven't benchmarked the performance, though.

Upvotes: 1

Related Questions