Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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})
like image 455
polka Avatar asked Oct 12 '16 01:10

polka


2 Answers

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
like image 172
Pierre L Avatar answered Nov 02 '22 07:11

Pierre L


You can use dcast from data.table:

dat$z <- 1
dcast(dat,x~y,fill=0, value="z")

   x B C D G H I J K L M N O P Q T
1  A 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0
2  B 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
3  C 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0
4  D 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
5  F 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0
6  H 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0
7  J 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0
8  K 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1
9  L 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0
10 M 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0
11 N 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0
12 O 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
13 Q 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0
14 R 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0
15 T 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0
like image 38
HubertL Avatar answered Nov 02 '22 08:11

HubertL