Phil Goetz
Phil Goetz

Reputation: 605

R: Why will as.character convert int matrix to char, but as.integer won't convert char matrix to int?

The "as.X" operators usually convert one type to another, but as.integer fails when applied to an array. Is this a bug? This is Microsoft R Open version 3.3 64-bit, and also R Foundation's R 3.3.1 for i686-pc-cygwin (32-bit).

> m <- matrix(rnorm(25), 5)
> m
           [,1]       [,2]       [,3]       [,4]       [,5]
[1,] -0.5958330 -0.3139274 -0.4746246  0.2431716 -0.5245235
[2,]  0.5677058  0.1944457 -2.3786936  0.2516587 -0.3541963
[3,]  0.6763564 -1.7285476 -0.5878008 -1.2277048  0.7737145
[4,] -1.4607755 -0.4761012  1.0995414  0.6978072  0.6120277
[5,]  0.8593707  0.2962030  1.1791963 -0.2276658  1.1559314
> m[] <- as.integer(m)
> m
     [,1] [,2] [,3] [,4] [,5]
[1,]    0    0    0    0    0
[2,]    0    0   -2    0    0
[3,]    0   -1    0   -1    0
[4,]   -1    0    1    0    0
[5,]    0    0    1    0    1
> m[] <- as.character(m)
> m
     [,1] [,2] [,3] [,4] [,5]
[1,] "0"  "0"  "0"  "0"  "0" 
[2,] "0"  "0"  "-2" "0"  "0" 
[3,] "0"  "-1" "0"  "-1" "0" 
[4,] "-1" "0"  "1"  "0"  "0" 
[5,] "0"  "0"  "1"  "0"  "1" 
> m[] <- as.integer(m)
> m
     [,1] [,2] [,3] [,4] [,5]
[1,] "0"  "0"  "0"  "0"  "0" 
[2,] "0"  "0"  "-2" "0"  "0" 
[3,] "0"  "-1" "0"  "-1" "0" 
[4,] "-1" "0"  "1"  "0"  "0" 
[5,] "0"  "0"  "1"  "0"  "1" 

Upvotes: 0

Views: 319

Answers (3)

Phil Goetz
Phil Goetz

Reputation: 605

Joran's answer gives the rule which causes this behavior. The reason for this rule is that a subassignment sometimes does and sometimes doesn't operate on the entire data structure. In cases when it does, it can't convert an entire vector or matrix's datatype. In the case of m[] = ..., it could, but it's better to behave the same way in all cases. Otherwise, it would introduce bugs in cases where a subassignment by indices just happened to cover an entire vector or matrix.

Upvotes: 0

Ben Bolker
Ben Bolker

Reputation: 226182

If you do want to "downcast" a matrix you might be interested in storage.mode()<-:

> m <- matrix(1:4,2)
> m
     [,1] [,2]
[1,]    1    3
[2,]    2    4
> storage.mode(m) <- "character"
> m
     [,1] [,2]
[1,] "1"  "3" 
[2,] "2"  "4" 
> storage.mode(m) <- "integer"
> m
     [,1] [,2]
[1,]    1    3
[2,]    2    4

Upvotes: 3

joran
joran

Reputation: 173577

The documentation states:

When an index expression appears on the left side of an assignment (known as subassignment) then that part of x is set to the value of the right hand side of the assignment. In this case no partial matching of character indices is done, and the left-hand-side is coerced as needed to accept the values. For vectors, the answer will be of the higher of the types of x and value in the hierarchy raw < logical < integer < double < complex < character < list < expression.

The behavior you see with subassignment on the left is consistent with that documented behavior.

Note that even though as.integer "works" in this case when directly applied to a double matrix, it still follows the type hierarchy and only rounds:

> m <- matrix(rnorm(25), 5)
> str(m)
 num [1:5, 1:5] 1.3807 -0.0858 1.4478 0.9509 0.6397 ...
> typeof(m)
[1] "double"
> m[] <- as.integer(m)
> str(m)
 num [1:5, 1:5] 1 0 1 0 0 0 0 0 -1 -1 ...
> typeof(m)
[1] "double"

Finally, as.integer often does not convert characters to valid integers:

> str(as.integer("a"))
 int NA
Warning message:
In str(as.integer("a")) : NAs introduced by coercion

...except that it results in the integer flavor of NA, namely NA_integer_. But it will convert characters to integers, as long as there is no subassignment:

> str(as.integer("1"))
 int 1

To address the comment about vectors, the documented behavior is the same on regular vectors:

> x <- rnorm(5)
> x[] <- as.character(x)
> x
[1] "0.687551073804054"  "-1.17843752343875"  "0.144747745284427"  "-0.931480738737143" "0.394279275668583" 
> x[] <- as.integer(x)
> x
[1] "0"  "-1" "0"  "0"  "0" 

Upvotes: 6

Related Questions