polka polka - 1 month ago 14
R Question

Assign 1 in a matrix from a list of coordinates

I want to take a list of coordinates. For every location in the coordinates, I want to assign 1 to the matrix. The final matrix should look like this. I want to use a fast vectorized method instead of a for loop.

> sample.matrix
A B C D E F G H I J K L M N O P Q R S T
A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
B 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
C 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
D 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
E 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
F 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
G 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
H 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
I 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
J 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
K 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
L 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
M 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
N 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
O 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
P 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
Q 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
R 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
S 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
T 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0


Sample data:

set.seed(15)
dat <- data.frame(x=sample(LETTERS[1:20], 15,set.seed(15)),y=sample(LETTERS[1:20], 15,set.seed(15)), stringsAsFactors = FALSE)
sample.matrix <- matrix(data=0, nrow = 20, ncol = 20, dimnames = list(LETTERS[1:20],LETTERS[1:20]))


What I tried that worked.

for ( n in 1:15){
sample.matrix[dat[n,]$x,dat[n,]$y] =1
}


What I tried that isn't working.

by(dat, 1:15, function(a.row){sample.matrix[a.row$x, a.row$y]=1})

Answer

This a cool programming aspect of the language. In R we can subset using a two column matrix:

sample.matrix[as.matrix(dat)] <- 1

More on How it Works

From the help for ?Extract (bolded text is my emphasis):

A third form of indexing is via a numeric matrix with the one column for each dimension: each row of the index matrix then selects a single element of the array, and the result is a vector. Negative indices are not allowed in the index matrix. NA and zero values are allowed: rows of an index matrix containing a zero are ignored, whereas rows containing an NA produce an NA in the result.

Indexing via a character matrix with one column per dimensions is also supported if the array has dimension names. As with numeric matrix indexing, each row of the index matrix selects a single element of the array. Indices are matched against the appropriate dimension names. NA is allowed and will produce an NA in the result. Unmatched indices as well as the empty string ("") are not allowed and will result in an error.

In your case you have a matrix with letters that represent dimension names.

     x   y  
[1,] "B" "C"
[2,] "S" "S"
[3,] "L" "B"
[4,] "N" "L"
[5,] "E" "G"
[6,] "M" "A"

When we insert this matrix into a set of brackets [as.matrix(dat)], the evaluator will detect a matrix and use a special type of subsetting. The first column will represent the rows, and the second column will represent the columns.

head(sample.matrix)
  A B C D E F G H I J K L M N O P Q R S T
A 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
B 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
C 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
D 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
E 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
F 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0