在R中,根据元素名称(rbind和指示符变量)重新组织列表

时间:2015-10-06 13:22:39

标签: r rbind

我正在尝试重新组织我的数据,基本上是data.frames列表。 其元素代表感兴趣的主题(A和B),对x和y的观察,两次收集(1和2)。 我试图使这个列表包含引用主题的data.frames,收集x和y的场合的信息作为新变量存储在相应的data.frames中,而不是元素名称:

library('rlist')

A1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
A2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))

list <- list(A1=A1,A2=A2,B1=B1,B2=B2)

A <- do.call(rbind,list.match(list,"A"))
B <- do.call(rbind,list.match(list,"B"))

list <- list(A=A,B=B)
list <- lapply(list,function(x) {
      y <- data.frame(x)
      y$class <- c(rep.int(1,2),rep.int(2,2))
      return(y)
})

> list
$A
      x  y class
A1.1 66 96     1
A1.2 76 58     1
A2.1 50 93     2
A2.2 57 12     2

$B
      x  y class
B1.1 58 56     1
B1.2 69 15     1
B2.1 77 77     2
B2.2  9  9     2

在我的现实世界问题中,大约有500个科目,而不是总是两次,不同的观察数量。

所以我上面的例子只是为了说明我想要获得的内容,而且我仍然坚持如何传递给do.call-rbind它应该根据元素名称将特定于主题的元素绑定为新的列表元素在分配新变量的同时。

对我来说,这是一个有点模糊的任务,我得到的最接近的是rlist包。 This问题是相关的,但使用unique来识别元素,而在我的情况下,它似乎更像是一个正则表达式问题。

即使有关如何使用谷歌,任何关键词进行进一步研究等的说明,我也会很高兴。

2 个答案:

答案 0 :(得分:2)

根据您提供的数据:

subj <- sub("[A-Z]*", "", names(lst))
newlst <- Map(function(x, y) {x[,"class"] <- y;x}, lst, subj)

首先,我们执行正则表达式调用以隔离class列中的数字。在这种情况下,我匹配大写字母并删除它们留下数字。因此,"A1"变为"1"。请注意,真实姓名将表示不同的正则表达式。

然后我们使用Map为每个数据框创建一个新列,并保存到名为newlst的新列表中。 Map获取每个参数的第一个元素并执行该函数,然后继续使用每个对象元素。因此,首先使用lst中的第一个数据帧和subj中的第一个数字。我使用的匿名函数是function(x,y) {x[, "class"] <- y; x}。它需要两个参数。第一个是数据框,第二个是列值。

现在向前迈进会容易得多。我们可以创建一个名为uniq.nmes的向量来获取我们将要组合的数据帧的名称。 "A1"将成为"A"的位置。然后我们可以对那场比赛进行讨论:

uniq.nmes <- unique(sub("\\d", "", names(lst)))
lapply(uniq.nmes, function(x) {
  do.call(rbind, newlst[grep(x, names(newlst))])
})
# [[1]]
#       x  y class
# A1.1  1 79     1
# A1.2 30 13     1
# A2.1 90 39     2
# A2.2 43 22     2
# 
# [[2]]
#       x  y class
# B1.1 54 59     1
# B1.2 83 90     1
# B2.1 85 36     2
# B2.2 91 28     2

数据

A1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
A2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B1 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))
B2 <- data.frame(x=sample(1:100,2),y=sample(1:100,2))

lst <- list(A1=A1,A2=A2,B1=B1,B2=B2)

答案 1 :(得分:0)

听起来你正在做很多体操,因为你有一个特定的形式。我建议首先尝试制作数据tidy。在不阅读链接的情况下,快速摘要是将您的数据放入单个数据框中,以便轻松处理。

答案的快速版本(此处我使用lst而不是list作为名称以避免与内置list混淆)就是这样做:

do.call(rbind,
  lapply(seq(lst), function(i) {
    lst[[i]]$type <- names(lst)[i]; lst[[i]]
  })
)

这样做会创建一个数据框,其中包含一列&#34; type&#34;,其中包含该行所在列表项的名称。

使用初始数据的略微简化版本:

lst <- list(A1=data.frame(x=rnorm(5)), A2=data.frame(x=rnorm(3)), B=data.frame(x=rnorm(5)))
lst
$A1
           x
1  1.3386071
2  1.9875317
3  0.4942179
4 -0.1803087
5  0.3094100

$A2
           x
1 -0.3388195
2  1.1993115
3  1.9524970

$B
           x
1 -0.1317882
2 -0.3383545
3  0.8864144
4  0.9241305
5 -0.8481927

然后应用魔术功能

df <- do.call(rbind,
   lapply(seq(lst), function(i) {
     lst[[i]]$type <- names(lst)[i]; lst[[i]]
   })
 )
df
            x type
1   1.3386071   A1
2   1.9875317   A1
3   0.4942179   A1
4  -0.1803087   A1
5   0.3094100   A1
6  -0.3388195   A2
7   1.1993115   A2
8   1.9524970   A2
9  -0.1317882    B
10 -0.3383545    B
11  0.8864144    B
12  0.9241305    B
13 -0.8481927    B

从这里我们可以处理我们的心灵内容;使用df$subject <- gsub("[0-9]*", "", df$type)等操作来提取type的非数字部分,split等工具可用于生成您在问题中提到的子列表。

此外,一旦采用此格式,您可以使用byaggregate等函数或dplyrdata.table等库来执行更高级的拆分应用 - 用于数据分析的组合操作。