Search code examples
rdataframematrix-multiplicationrbindcbind

Error “requires numeric/complex matrix/vector arguments”, even when arguments are matrices


I was writing some functions for calculating simple summary statistics, when I encountered an error that I don't understand. Apparently, I create an object of class matrix which throws an error, when I attempt to use it in matrix-multiplication. The MWE below calculates the group-means in the iris data-set (in l.apply.out2) together with the sums of the components of each of the group-means (in l.apply.out1). The two objects are then bound together in a data.frame.

Now, my assumption would be that I could do further computation but converting the data.frame above to a matrix, using as.matrix, but the code below gives the error Error in as.matrix(dat) %*% matrix(1, 3, 1) : requires numeric/complex matrix/vector arguments

data(iris)
s <- split(iris[,1:4],iris[,5])
l.apply.out1 <- lapply(s,function(x) {sum(colMeans(x))})
l.apply.out2 <- lapply(s,colMeans)

dat <- data.frame(rbind(matrix(l.apply.out1,1,3),matrix(unlist(l.apply.out2),4,3)))
as.matrix(dat)%*%matrix(1,3,1)

I can avoid the error by using rbind.data.frame - the following works as intended:

dat <-  rbind.data.frame(l.apply.out1,l.apply.out2)
as.matrix(dat)%*%matrix(1,3,1)

Which is obviously cleaner and better anyway, but I would really like to know what precisely goes wrong in my first example?


Solution

  • Let's take a look at what happens when you do as.matrix(l.apply.out2):

    data(iris)
    s <- split(iris[,1:4], iris[,5])
    l.apply.out1 <- lapply(s, function(x) {sum(colMeans(x))})
    l.apply.out2 <- lapply(s, colMeans)
    
    as.matrix(l.apply.out1)
    #>            [,1]  
    #> setosa     10.142
    #> versicolor 14.292
    #> virginica  17.14
    as.matrix(l.apply.out2)
    #>            [,1]     
    #> setosa     Numeric,4
    #> versicolor Numeric,4
    #> virginica  Numeric,4
    

    Created on 2018-10-08 by the reprex package (v0.2.1)

    That's the source of your problem right there. What I find interesting here is that you're using lapply() at all, when it seems to be counter to what you really want, which sapply() would give you easily:

    (s.apply.out1 <- sapply(s, function(x) {sum(colMeans(x))}))
    #>     setosa versicolor  virginica 
    #>     10.142     14.292     17.140
    (s.apply.out2 <- sapply(s, colMeans))
    #>              setosa versicolor virginica
    #> Sepal.Length  5.006      5.936     6.588
    #> Sepal.Width   3.428      2.770     2.974
    #> Petal.Length  1.462      4.260     5.552
    #> Petal.Width   0.246      1.326     2.026
    
    rbind(s.apply.out1, s.apply.out2) %*% matrix(1,3,1)
    #>                [,1]
    #> s.apply.out1 41.574
    #> Sepal.Length 17.530
    #> Sepal.Width   9.172
    #> Petal.Length 11.274
    #> Petal.Width   3.598
    

    Created on 2018-10-08 by the reprex package (v0.2.1)