rarraysdataframelisttapply

Failed to convert a list returned by tapply into a data.frame


I'm doing some data operation with tapply(), and it returns a list-like object. For example:

x <- 1:10
y <- rep(c('A', 'B'), each = 5)
lst.1 <- tapply(x, y, function(vec) return(vec), simplify = FALSE)
lst.1

# $A
# [1] 1 2 3 4 5
# 
# $B
# [1]  6  7  8  9 10

I want to transform it into a data.frame. An intuition is using as.data.frame(), but it failed.

as.data.frame(lst.1)

#             lst1
# A  1, 2, 3, 4, 5
# B 6, 7, 8, 9, 10

I create another list manually to mimic lst.1, and as.data.frame() works as expedted.

lst.2 <- list(A = 1:5, B = 6:10)
lst.2

# $A
# [1] 1 2 3 4 5
# 
# $B
# [1]  6  7  8  9 10

as.data.frame(lst.2)

#   A  B
# 1 1  6
# 2 2  7
# 3 3  8
# 4 4  9
# 5 5 10

What's the difference between lst.1 and lst.2? And how to correctly convert a list returned by tapply (i.e. lst.1) into a data.frame?


Solution

  • If you take a look at the structure of the list being returned by tapply(), you'll see that it has a dimension attribute and is a list and an array.

    str(lst.1)
    List of 2
     $ A: int [1:5] 1 2 3 4 5
     $ B: int [1:5] 6 7 8 9 10
     - attr(*, "dim")= int 2
     - attr(*, "dimnames")=List of 1
      ..$ : chr [1:2] "A" "B"
    
    is.array(lst.1)
    [1] TRUE
    

    This means when you call as.data.frame() the method being dispatched under the hood is as.data.frame.array() and not as.data.frame.list(). To get around this you can invoke the method you want to use directly:

    as.data.frame.list(lst.1) 
      A  B
    1 1  6
    2 2  7
    3 3  8
    4 4  9
    5 5 10
    

    Or use:

    list2DF(lst.1)
      A  B
    1 1  6
    2 2  7
    3 3  8
    4 4  9
    5 5 10