在R中拼接不规则数组

3

我经常处理这种形式的对象:

v <- list(one = c(a = 1, b = 2, c = 3), two = c(a = 10, b = 20, d = 30, c = 40))

我希望您能通过元素名称进行向外连接这些向量,以获得以下结果:
  index value.x value.y
1     a       1      10
2     b       2      20
3     c       3      40
4     d      NA      30

我已经编写了代码来实现这个目标。简而言之,将向量转换为数据框,并通过连续的合并进行缩减。但我想知道是否有在某个软件包或R基础中包含的功能可以做到这一点,可能进行了优化。这似乎是一个非常普遍的任务。


在您的实际应用场景中,我假设您的列表包含超过两个项目。这正确吗? - A5C1D2H2I1M1N2O1R2T1
3个回答

2

我不确定我的方法是否比你的更简单,但你可以使用reshape2lapplyas.list。我认为使用meltdcast会更好。

library(reshape2)
dcast(melt(lapply(v, as.list)), L2 ~L1)
##   L2 one two
## 1  a   1  10
## 2  b   2  20
## 3  c   3  40
## 4  d  NA  30

2

以下是基于R语言的两种选项。它们需要先将您的list转换为data.frame

v2 <- data.frame(do.call(rbind, 
                         strsplit(names(unlist(v)), "\\.")), 
                 unlist(v))
names(v2) <- c("time", "id", "value")
xtabs(value ~ id + time, v2)
#     time
#  id  one two
#    a   1  10
#    b   2  20
#    c   3  40
#    d   0  30
reshape(v2, direction="wide", idvar="id", timevar="time")
#       id value.one value.two
# one.a  a         1        10
# one.b  b         2        20
# one.c  c         3        40
# two.d  d        NA        30

我不知道有更直接的方法来拆分使用unlist后得到的names,但一旦完成,你尝试做的操作就会变得更容易。为了使输出更加“整洁”,可以进行新名称的分配。

1
这是一个基本解决方案:
> do.call( merge,  list(v[[1]], v[[2]], by="row.names", all=TRUE))
  Row.names  x  y
1         a  1 10
2         b  2 20
3         c  3 40
4         d NA 30

如果您需要一个长度大于2的列表,您可以使用as.data.frame.table将命名向量转换为两列的data.frame

> v <- list(one = c(a = 1, b = 2, c = 3), 
           two = c(a = 10, b = 20, d = 30, c = 40), 
           three = c(a = 1, b = 2, c = 3))
> setNames(Reduce(function(x,y) {
        merge(x,y,all=T, by ='Var1')},lapply(v, as.data.frame.table)),
         c('index', names(v)))

  index one two three
1     a   1  10     1
2     b   2  20     2
3     c   3  40     3
4     d  NA  30    NA

不错!在看完这个解决方案后,我意识到你也可以使用 Reduce(function(x, y) merge(x, y, by="row.names", all=TRUE), v)然而,似乎只有当你有两个列表项时才有效。是否可能调整此方法以处理更长的列表?我之所以问是因为我怀疑OP在他们的列表中有超过两个项目(他们提到了“连续合并”)。 - A5C1D2H2I1M1N2O1R2T1
3
Reduce(function(x,y) {merge(x,y,all=T, by ='index')},lapply(v, function(x) data.frame(x, index = names(x)))) 可以用于长度大于2的更多列表。 - mnel
@mnel,很好的想法,在那里添加一个转换为data.frame来解决问题。美化结果名称也很容易:v2 <- Reduce(...etc...); names(v2)[-1] <- names(v)。就处理速度而言,这比dcast更快(但对我来说这并不奇怪)。 - A5C1D2H2I1M1N2O1R2T1
你也可以使用 as.data.frame.table 将命名向量转换为两列数据框,如下所示:setNames(Reduce(function(x,y) {merge(x,y,all=T, by ='Var1')},lapply(v, as.data.frame.table)), c('index', names(v))) - mnel
@mnel:你应该把第二部分作为你自己的答案添加进去。 - IRTFM

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