将列表转换为数据框并保留列表元素名称

17

我有一个列表,其中元素名称是ID标签,包含一个数字值向量。 这些向量长度不相等。

我想将其转换为数据框,其中一个列中有ID,另一个列中有数字值。 例如:

$`1`  
[1] 1 2   
$`2`  
[1] 1 2 3 
$`3`  
[1] 1   

收件人:

ID   Obs  
1    1  
1    2
2    1
2    2
2    3
3    1
4个回答

21

以下是一种方法:

## your list
ll <- list("1" = 1:2, "2" = 1:3, "3" = 1:2)
## convert to data.frame
dl <- data.frame(ID = rep(names(ll), sapply(ll, length)),
                 Obs = unlist(ll))

这会得到:

> dl
   ID Obs
11  1   1
12  1   2
21  2   1
22  2   2
23  2   3
31  3   1
32  3   2

data.frame()调用中的第一行只是一些代码,重复列表的names()所需的次数。第二行将列表展开为向量。


我给了你正确的答案,因为你的方法是最快的:<br/>
system.time(melt(X))<br/> user system elapsed <br/> 3.12 0.11 3.24 <br/> system.time(data.frame(ID = rep(names(X), sapply(X, length)), Obs = unlist(X)))<br/> user system elapsed <br/> 0.08 0.00 0.07<br/>
- ego_
我似乎无法添加换行符,抱歉造成混乱 :S - ego_
你可以使用lengths来避免使用rep(sapply()) - sebastian-c
@sebastian-c 说得好,我不认为lengths()在2012年是语言的一部分,但现在会更好。 - Gavin Simpson

10

使用reshape2melt,其中包含melt.list方法。

.list <- list(`1` = 1:2, `2` = 1:3, `3` = 1:2)
library(reshape2)
melt(.list)
##   value L1
## 1     1  1
## 2     2  1
## 3     1  2
## 4     2  2
## 5     3  2
## 6     1  3
## 7     2  3

7
一个好的且之前未提及的解决方案是使用stack函数:
df <- stack(ll)[2:1]

给出的结果如下:
> df
  ind values
1   1      1
2   1      2
3   2      1
4   2      2
5   2      3
6   3      1
7   3      2
使用setNames,您可以获得精确的所需格式:
df <- setNames(stack(ll)[2:1], c('ID','Obs'))

这将会给出:

> df
  ID Obs
1  1   1
2  1   2
3  2   1
4  2   2
5  2   3
6  3   1
7  3   2

使用的数据:

ll <- list("1" = 1:2, "2" = 1:3, "3" = 1:2)

1
一个使用基本函数的解决方案。
List <- list('1'=c(1,2), '2'= c(1,2,3), '3'=1)
x <- unlist(List)  # as suggested by Gavin Simpson
data.frame(ID=substr(names(x),1,1), Obs=x)
   ID Obs
11  1   1
12  1   2
21  2   1
22  2   2
23  2   3
3   3   1

如果您想要rownames为1,2,3,4,5,6,那么可以尝试使用setNames函数:
data.frame(ID=substr(names(x),1,1), Obs=setNames(x, NULL))
  ID Obs
1  1   1
2  1   2
3  2   1
4  2   2
5  2   3
6  3   1

这个解决方案仅在所有名称具有相同长度时才有效,否则它将失败,并且最好使用Gavin的解决方案。例如:

List2 <- list('week1'=c(1,2), 'week2'= c(1,2,3), 'week3'=1)
x <- unlist(List2)  
data.frame(ID=substr(names(x),1,nchar(names(x)[1])-1), Obs=setNames(x, NULL))

    ID   Obs
1 week1   1
2 week1   2
3 week2   1
4 week2   2
5 week2   3
6 week3   1

我认为你可以直接使用 x <- unlist(List),不是吗? - Gavin Simpson
@Gavin Simpson,你是对的,现在我刚刚编辑了我的答案,包括你的评论。 - Jilber Urbina
似乎当我取消列表时,它会向元素名称添加一个数字,导致脚本的其余部分无法满足我的需求 :S - ego_
@Jilber,非常抱歉,但现在它将所有名称更改为“2”或“5”。元素名称是由ID.Seasons.Week组成的因子,例如2225.Winter.1,如果这有所帮助的话。我喜欢尽可能使用基本函数的角度,所以如果这也可以工作的话那就太好了。 - ego_

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接