Feal Feal - 3 months ago 13
R Question

Create numeric square matrix from data frame based on conditions - as.numeric destroys square matrix

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==1) 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?

Minimum 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 )
is.numeric(stored.matrix)
x <- as.numeric(stored.matrix)
x


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

Can anyone help?

Answer

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

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)

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

The problem you encountered, is something known as "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, 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 (class(test)), 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"

The 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