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
?
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