1

I have a table in R where the rownames are (as per default) A,B,C,... and the column names are 1,2,3,4,... as assigned. For example, the output of

x <- as.table(matrix(c(2,20,3,4,2,5,8,1,3),nrow=3,ncol=3,byrow=TRUE))
colnames(x) <- seq(1,ncol(x))
x

Now I'd like to permute the table by a matrix P, which I've already found, containing only 1s and 0s (the point being that A %*% P will permute the columns of A so as to maximize its diagonal). In this case, for x you can get P as

P <- matrix(c(0,0,1,1,0,0,0,1,0),nrow=3,byrow=T)

Note P will have only one '1' per row and column, the rest '0'. My issue is: if you do something like

Y <- x %*% P

you will see that, while the diagonals are rightly arranged, the column names from x have been replaced by matrix column names from P ([,1] [,2] [,3] in this case).

How can I perform the permutation (x %*% P) while retaining the column names from x in the correct order? That is to say, the column name follows the column when the column moves. So in this case, the column names would be 2 3 1.

Mobeus Zoom
  • 598
  • 5
  • 19

2 Answers2

1

If the intention is to retain the column names, use [], after creating a copy of 'x' to 'Y'

Y <- x
Y[] <- x %*% P
akrun
  • 874,273
  • 37
  • 540
  • 662
  • This just retains the old column names. I wanted to permute them. – Mobeus Zoom May 06 '20 at 12:34
  • @MobeusZoom not clear. Your question seems to be `How can I perform the permutation (x %*% P) while retaining the column names from x in the correct order?` – akrun May 06 '20 at 18:14
  • My question is quite clear. See the last two sentences, where besides describing it (in a way that clearly precludes your interpretation) I also gave the desired order of the columns for the example in my question. – Mobeus Zoom May 06 '20 at 19:13
  • @MobeusZoom ok thanks. anyway you already selected another solution. So, hopefully this is solved. – akrun May 06 '20 at 19:14
  • 1
    Thanks for your input! Very welcome for the info even if it wasn't the exact question, and I'm sure it is helpful for someone – Mobeus Zoom May 06 '20 at 19:24
1

You'll have to permute the column names of x in the same way. For example:

colnames(Y) <- 1:3 %*% P
Y

which prints

   2 3 1
A 20 3 2
B  2 5 4
C  1 3 8

This was extra simple because the original column names were integers 1:3. In general, you'll need something like

colnames(Y) <- colnames(x)[1:3 %*% P]

To check, permute columns of Y:

Z <- Y %*% P
colnames(Z) <- colnames(Y)[1:3 %*% P]
Z

which prints

  3 1  2
A 3 2 20
B 5 4  2
C 3 8  1

Edited to add: As came out in the comments, if P is computed numerically, it might not contain exact 0 and 1 values, so you should use

colnames(Y) <- colnames(x)[1:3 %*% round(P)]

to avoid rounding error.

user2554330
  • 37,248
  • 4
  • 43
  • 90
  • Thanks, good solution. But when I try to use ```colnames(x)[1:nrow(x) %*% P]``` it sometimes gives me an ```Error in dimnames(x) <- dn : length of 'dimnames' [2] not equal to array extent```. Any idea why? When I separately enter ```1:nrow(x) %*% P``` into the console and ```colnames(x)``` I get vectors of the same length but the result from ```colnames(x)[1:nrow(x) %*% P]``` has for some reason dropped one of the items. (If it helps, P is obtained as a solved object (```solution```) from ```lp.assign``` from library ```lpSolve```.) – Mobeus Zoom May 06 '20 at 12:41
  • 1
    Probably rounding error: if `P` contains numbers slightly different from 1 and 0, it will affect the indexing. I'd use `round(P)` instead of `P` in the formula if it's not guaranteed to be integer values by construction. – user2554330 May 06 '20 at 13:01