Idiomatic matrix type conversion, say convert Integer (0/1) matrix to boolean matrix

后端 未结 2 1276
渐次进展
渐次进展 2021-01-21 06:39

I have:

 B <- matrix(c(1, 0, 0, 1, 1, 1), 
             nrow=3, 
             ncol=2)

and I want:

 B
      [,1] [,2]
[1,]           


        
相关标签:
2条回答
  • 2021-01-21 07:10

    A matrix is a vector with dim attributes. When we apply as.logical, the dim attributes are lost. It can be assigned with dim<-

    `dim<-`(as.logical(B), dim(B))
    #      [,1] [,2]
    #[1,]  TRUE TRUE
    #[2,] FALSE TRUE
    #[3,] FALSE TRUE
    

    Or another option is create a logical condition that preserves the attribute structure

    B != 0
    

    Or

    !!B
    
    0 讨论(0)
  • 2021-01-21 07:30

    mode(B) <- "logical" or "mode<-"(B, "logical"). We can also use storage.mode function.

    This workaround is good for two reasons:

    1. the code is much readable;
    2. the logic works in general (see examples below).

    I learnt this trick when reading source code of some packages with compiled code. When passing R data structures to C or FORTRAN functions, some type coercion may be required and they often use mode or storage.mode for this purpose. Both functions preserve attributes of R objects, like "dim" and "dimnames" of matrices.

    ## an integer matrix
    A <- matrix(1:4, nrow = 2, dimnames = list(letters[1:2], LETTERS[1:2]))
    #  A B
    #a 1 3
    #b 2 4
    

    "mode<-"(A, "numeric")
    #  A B
    #a 1 3
    #b 2 4
    
    "mode<-"(A, "logical")
    #     A    B
    #a TRUE TRUE
    #b TRUE TRUE
    
    "mode<-"(A, "chracter")
    #  A   B  
    #a "1" "3"
    #b "2" "4"
    
    "mode<-"(A, "complex")
    #     A    B
    #a 1+0i 3+0i
    #b 2+0i 4+0i
    
    str("mode<-"(A, "list"))  ## matrix list
    #List of 4
    # $ : int 1
    # $ : int 2
    # $ : int 3
    # $ : int 4
    # - attr(*, "dim")= int [1:2] 2 2
    # - attr(*, "dimnames")=List of 2
    #  ..$ : chr [1:2] "a" "b"
    #  ..$ : chr [1:2] "A" "B"
    

    Note that mode changing is only possible between legitimate modes of vectors (see ?vector). There are many modes in R, but only some are allowed for a vector. I covered this in my this answer.

    In addition, "factor" is not a vector (see ?vector), so you can't do mode change on a factor variable.

    f <- factor(c("a", "b"))
    
    ## this "surprisingly" doesn't work
    mode(f) <- "character"
    #Error in `mode<-`(`*tmp*`, value = "character") : 
    #  invalid to change the storage mode of a factor
    
    ## this also doesn't work
    mode(f) <- "numeric"
    #Error in `mode<-`(`*tmp*`, value = "numeric") : 
    #  invalid to change the storage mode of a factor
    
    ## this does not give any error but also does not change anything
    ## because a factor variable is internally coded as integer with "factor" class
    mode(f) <- "integer"
    f
    #[1] a b
    #Levels: a b
    
    0 讨论(0)
提交回复
热议问题