Feal Feal - 3 months ago 10
R Question

Why is this matrix not numeric? Then `as.numeric` destroys the matrix and return a vector

I have a data frame called

input
. The first column refers to an Article ID (
ArtID
), the subsequent columns will be used to create the matrix.

Based on the
ArtID
, I want R to generate a 2x2 matrix (more precise: It needs to be a numeric 2x2 matrix). Specifically, I want to create a matrix for the first row (
ArtID == 1
), the second row(
ArtID == 2
) and so on...

What I came up with so far is this:

for(i in 1:3) {stored.matrix = matrix(input[which(ArtID ==i),-1],nrow = 2)


This gives me a 2x2 matrix, but it is not numeric (which it needs to be).

If I apply
as.numeric
, the matrix is no longer a 2x2 matrix.

How do I get a 2x2 numerical matrix?




Minimal reproducible example:

ArtID = c(1,2,3)
AC_AC = c(1,1,1)
MKT_AC = c(0.5,0.6,0.2)
AC_MKT = c(0.5,0.6,0.2)
MKT_MKT = c(1,1,1)
input = data.frame(ArtID, AC_AC, MKT_AC, AC_MKT, MKT_MKT)

stored.matrix = matrix(input[which(ArtID ==i),-1],nrow = 2)
# [,1] [,2]
#[1,] 1 0.5
#[2,] 0.5 1

is.numeric(stored.matrix)
# [1] FALSE

as.numeric(stored.matrix)
## [1] 1.0 0.5 0.5 1.0


As you can see after applying
as.numeric()
the matrix is no longer 2x2.

Can anyone help?

Answer

when you have only numerical values in your data frame, it is more appropriate to use a matrix. Convert your data frame to a matrix will solve all problem. Also,

input <- data.matrix(input)

ArtID = c(1,2,3)
AC_AC = c(1,1,1)
MKT_AC = c(0.5,0.6,0.2)
AC_MKT = c(0.5,0.6,0.2)
MKT_MKT = c(1,1,1)
input = data.frame(ArtID, AC_AC, MKT_AC, AC_MKT, MKT_MKT)

input <- data.matrix(input)   ## <- this line

stored.matrix = matrix(input[which(ArtID ==i),-1], 2)
is.numeric(stored.matrix)
# [1] TRUE

So what was the problem?

If input is a data frame, input[which(ArtID == i),-1] by row subsetting still returns a data frame. A data frame is a special type of list. When you feed a list to matrix(), you get into a situation of matrix list.

If you read ?matrix for what data it can take, you will see:

data: an optional data vector (including a list or ‘expression’
      vector).  Non-atomic classed R objects are coerced by
      ‘as.vector’ and all attributes discarded.

Note that a list is also of vector data type (e.g., is.vector(list(a = 1)) gives TRUE), so it is legitimate to feed a list to matrix. You can try

test <- matrix(list(a = 1, b = 2, c = 3, d = 4), 2)
#     [,1] [,2]
#[1,] 1    3   
#[2,] 2    4   

This is indeed a matrix in the sense that class(test) give "matrix"), but

str(test)
#List of 4
# $ : num 1
# $ : num 2
# $ : num 3
# $ : num 4
# - attr(*, "dim")= int [1:2] 2 2

typeof(test)
# [1] "list"

so it is not the usual numerical matrix we refer to.

The input list can be ragged, too.

test <- matrix(list(a = 1, b = 2:3, c = 4:6, d = 7:10), 2)
#     [,1]      [,2]     
#[1,] 1         Integer,3
#[2,] Integer,2 Integer,4

str(test)
#List of 4
# $ : num 1
# $ : int [1:2] 2 3
# $ : int [1:3] 4 5 6
# $ : int [1:4] 7 8 9 10
# - attr(*, "dim")= int [1:2] 2 2

And I was wondering why typeof() gives me list... :)

Yes, so had realized something unusual. The storage mode of a matrix is determined by that of its element. For a matrix list, elements are list, hence the matrix has "list" mode.