column names when using `as.data.frame` over nested list

Viewed 66

Assuming we have a nested list lst like below

lst <- list(
  A = list(a.x = 1:5, a.y = 6:10),
  B = list(b.x = -(1:5), b.y = -(6:10), b.z = -(11:15))
)

> lst
$A
$A$a.x
[1] 1 2 3 4 5

$A$a.y
[1]  6  7  8  9 10


$B
$B$b.x
[1] -1 -2 -3 -4 -5

$B$b.y
[1]  -6  -7  -8  -9 -10

$B$b.z
[1] -11 -12 -13 -14 -15

When I use df <- as.data.frame(lst), we get

> df
  A.a.x A.a.y B.b.x B.b.y B.b.z
1     1     6    -1    -6   -11
2     2     7    -2    -7   -12
3     3     8    -3    -8   -13
4     4     9    -4    -9   -14
5     5    10    -5   -10   -15

As you can see, the names of different layers of lst are concatenated by . to produce the column names, e.g., A.a.x. Since I already have . in the deeper layer of lst, e.g., a.x, the column name like A.a.x looks a bit confusing.

I am wondering if . is the default connecting symbol when using as.data.frame over list. Otherwise, is there any optional argument that allows users define their own symbol (instead of .) when using as.data.frame?

2 Answers

The line that changes the name is line no: 68 in data.frame

paste(vnames[[i]], namesi, sep = ".")

If we use some print statements, it becomes clear. As the sep is hardcoded, it can be changed only if we change the body of the function

do.call(f2, lst)
#[1] "before change"
#[1] "A"
#[1] "A"
#[1] "after change"
#[1] "A.a.x" "A.a.y"
#[1] "before change"
#[1] "B"
#[1] "B"
#[1] "after change"
#[1] "B.b.x" "B.b.y" "B.b.z"

where 'f2' is the changed function with print statements

As a follow-up to akrun's excellent answer, here's a simple wrapper you can use to specify the separator:

as_data_frame <- function(lst, sep = ".")
{
   setNames(as.data.frame(lst),
   unlist(mapply(function(x, y) paste(x, y, sep = sep), 
                 names(lst), lapply(lst, names))))
}

So you can have:

as_data_frame(lst, "->")
#>   A->a.x A->a.y B->b.x B->b.y B->b.z
#> 1      1      6     -1     -6    -11
#> 2      2      7     -2     -7    -12
#> 3      3      8     -3     -8    -13
#> 4      4      9     -4     -9    -14
#> 5      5     10     -5    -10    -15
Related