J. Doe
J. Doe

Reputation: 619

Efficient way to move specific columns and rows of a matrix at the same time in R

Having a matrix that looks like

  |A|B|C|D|E|F|
|A|_|_|_|_|_|_|
|B|_|_|_|_|_|_|
|C|_|_|_|_|_|_|
|D|_|_|_|_|_|_|
|E|_|_|_|_|_|_|
|F|_|_|_|_|_|_|

and by specifying inside a vector which rows and columns you want to move to the end of the matrix e.i soi <- c("B", "D","E") is there any more efficient way to make this transformation, other than my following code?

The final matrix should look like

  |A|C|F|B|D|E|
|A|_|_|_|_|_|_|
|C|_|_|_|_|_|_|
|F|_|_|_|_|_|_|
|B|_|_|_|_|_|_|
|D|_|_|_|_|_|_|
|E|_|_|_|_|_|_|

I achieved this by using this function

prepare.tm <- function ( tm, soi )
{
  end_sets <- which(row.names(tm) %in% soi)
  ptm <- rbind( cbind(tm[-end_sets, -end_sets], tm[-end_sets, end_sets]) , cbind(tm[end_sets, -end_sets], tm[end_sets, end_sets]) )
  ptm
}

Upvotes: 0

Views: 45

Answers (1)

jogo
jogo

Reputation: 12569

Here is another way:

a <- matrix(1:36, 6)
rownames(a) <- LETTERS[1:6]
colnames(a) <- LETTERS[1:6]
soi <- c("B", "D","E")
not.soi <- !(colnames(a) %in% soi)
ci <- c(colnames(a)[not.soi], soi)
a[ci, ci]
# > a[ci, ci]
#   A  C  F  B  D  E
# A 1 13 31  7 19 25
# C 3 15 33  9 21 27
# F 6 18 36 12 24 30
# B 2 14 32  8 20 26
# D 4 16 34 10 22 28
# E 5 17 35 11 23 29

Here is a variant with integer indizes:

a <- matrix(1:36, 6)
rownames(a) <- LETTERS[1:6]
colnames(a) <- LETTERS[1:6]
soi <- c("B", "D","E")
i <- match(soi, colnames(a))
ci <- c((1:ncol(a))[-i], i)
a[ci, ci]

Here is a benchmark:

jogo.chr <- function ( tm, soi ) {
  not.soi <- !(colnames(tm) %in% soi)
  ci <- c(colnames(tm)[not.soi], soi)
  tm[ci, ci]
}

jogo.int <- function ( tm, soi ) {
  i <- match(soi, colnames(tm))
  ci <- c((1:ncol(tm))[-i], i)
  tm[ci, ci]
}

prepare.tm <- function ( tm, soi )
{
  end_sets <- which(row.names(tm) %in% soi)
  ptm <- rbind( cbind(tm[-end_sets, -end_sets], tm[-end_sets, end_sets]) , cbind(tm[end_sets, -end_sets], tm[end_sets, end_sets]) )
  ptm
}

library("microbenchmark")
N <- 25
a <- matrix(1:(N*N), N)
rownames(a) <- LETTERS[1:N]
colnames(a) <- LETTERS[1:N]
soi <- c("B", "D","E")
microbenchmark(prepare.tm(a, soi), jogo.chr(a, soi), jogo.int(a, soi), unit="relative")
# > microbenchmark(prepare.tm(a, soi), jogo.chr(a, soi), jogo.int(a, soi), unit="relative")
# Unit: relative
#               expr      min       lq     mean   median       uq      max neval cld
# prepare.tm(a, soi) 2.754785 2.670412 2.577385 2.629260 2.597874 2.838851   100   c
#   jogo.chr(a, soi) 1.596205 1.590862 1.645833 1.597474 1.579997 2.241035   100  b 
#   jogo.int(a, soi) 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000   100 a  

Upvotes: 1

Related Questions