在R中遍历一个数据框列表以创建数据框。

3

我有一个问题一直没有找到有效的答案:我有多个数据框(确切地说是35个),我想要在每个数据框中添加包含人口统计信息的另一个数据框。

为了简单起见,这里有一个例子:

df1 <- data.frame(ID = c(1:3), b = c('x', 'y', 'z'), c = c('gh', 'fg', 'xv'), df = c('z', 'x', 'y'))

df2 <- data.frame(ID = c(1:3), v = c('a', 'mm', 'xc'), hg = c('yty', 'zc', 'cx'), fd = c('z', 'x', 'y'))

df3 <- data.frame(ID = c(1:3, t = c('ae', 'yw', 'zs'), j = c('ewr', 'zd', 'x'), sd = c('z', 'x', 'y'))

df4 <- data.frame(ID = c(1:3), u = c('df', 'y', 'z'), k = c('df', 'zs', 'xf'), f = c('z', 'x', 'y'))
.  
.  
.  
df(n) <- ...  


demo <- data.frame(sex = c('m', 'm', 'f'), age = c('30', '50', '62'), vital_sts = c('a', 'a', 'd'))

我想做的是将demo 数据框粘贴到其他每个数据框中。 我尝试过以下方法:

dfList <- list(df1, df2,df3,df4...)  

for (i in 1:length(dfList) {  
     i <- merge(demo,i)  
}

然而,当我检查数据框时,它们并没有合并。非常感谢您的任何帮助。


1
你是如何在全局环境中获得35个独立的数据框的?你应该使用数据框列表,然后迭代以cbind人口统计信息。 - Parfait
在你的代码中,你需要使用 i 作为索引来访问 dfList 而不是作为对象本身。因此,在循环内部应该这样写:dfList[[i]] <- merge(demo, dfList[[i]]) - Dan Adams
这只会修改列表中每个df的副本,而不是全局环境中原始的那个。 - Dan Adams
哦,要使用merge,您需要一些共同的列,因此您应该将ID列添加到demo中。 - Dan Adams
2个回答

2
一种可能的解决方案是,先创建一个包含所有要与demo合并的数据框的列表:
df1 <- data.frame(ID = c(1:3), b = c('x', 'y', 'z'), c = c('gh', 'fg', 'xv'), df = c('z', 'x', 'y'))

df2 <- data.frame(ID = c(1:3), v = c('a', 'mm', 'xc'), hg = c('yty', 'zc', 'cx'), fd = c('z', 'x', 'y'))

demo <- data.frame(sex = c('m', 'm', 'f'), age = c('30', '50', '62'), vital_sts = c('a', 'a', 'd'))

dfs <- list(df1, df2)

l <- lapply(dfs, cbind, demo)
names(l) <-  c("df1", "df2")
list2env(l, .GlobalEnv)

df1

#>   ID b  c df sex age vital_sts
#> 1  1 x gh  z   m  30         a
#> 2  2 y fg  x   m  50         a
#> 3  3 z xv  y   f  62         d

df2

#>   ID  v  hg fd sex age vital_sts
#> 1  1  a yty  z   m  30         a
#> 2  2 mm  zc  x   m  50         a
#> 3  3 xc  cx  y   f  62         d

谢谢你的回答。它确实有帮助,如果我只是打印数据框,它就可以工作。然而,在执行lapply后查看列时,它并未改变实际的数据框。 - EduardoRod
我认为这是一个危险的解决方案,因为 cbind 不能保证“演示”观测值按正确顺序分配。 - jay.sf
1
在我的代码之后,@EduardoRod,请运行以下两行代码:names(l) <- c("df1", "df2")list2env(l, .GlobalEnv)。之后,您可以访问修改后的 df1df2。但在此之前,请将 lapply 的结果分配给 ll <- lapply(dfs, cbind, demo) - PaulS

1

你应该给你的demo数据框一定要加上一个"ID"列!这样,你就不必再指望人口统计信息能正确地分配到观测值上,特别是如果脚本在工作过程中仍在变化。可以使用transform轻松完成这项任务(在此示例中,我只是使用连续的ID 1:3)。

res <- lapply(list(df1, df2, df3, df4), merge, transform(demo, ID=1:3))
res
# [[1]]
#   ID b  c df sex age vital_sts
# 1  1 x gh  z   m  30         a
# 2  2 y fg  x   m  50         a
# 3  3 z xv  y   f  62         d
# 
# [[2]]
#   ID  v  hg fd sex age vital_sts
# 1  1  a yty  z   m  30         a
# 2  2 mm  zc  x   m  50         a
# 3  3 xc  cx  y   f  62         d
# 
# [[3]]
#   ID  t   j sd sex age vital_sts
# 1  1 ae ewr  z   m  30         a
# 2  2 yw  zd  x   m  50         a
# 3  3 zs   x  y   f  62         d
# 
# [[4]]
#   ID  u  k f sex age vital_sts
# 1  1 df df z   m  30         a
# 2  2  y zs x   m  50         a
# 3  3  z xf y   f  62         d

如果你在工作区中有数不清的数据框,看起来是这样的,你可以使用mget(ls(pattern=))按模式列出它们。(或者更好的方法是,在第一次获取时将它们放入一个列表中。)

lapply(mget(ls(pat='^df\\d+')), merge, transform(demo, ID=1:3))

编辑

如果我理解你的评论正确,你有一个大的数据框DAT,想要组装变量组的小型数据框并将demo与它们合并。在这种情况下,我会将这些组的变量名称放在一个命名列表vgroups中。接下来,用"ID"连接并使用"c"同时对dat进行子集处理,然后将其与demo进行merge

demo仍然应该有一个"ID",因为您不希望所有行都按照相同的顺序排序,只需考虑例如sort(c(3, 10, 1, 100))sort(as.character(c(3, 10, 1, 100)))或出于任何原因而省略的行等。

demo <- transform(demo, ID=1:3)  ## identify demo observations

vgroups <- list(g1=c("b", "c", "df"), g2=c("v", "hg", "fd"), g3=c("t", "j", "sd"),
               g4=c("u", "k", "f"))

res1 <- lapply(vgroups, \(x) merge(demo, DAT[, c('ID', x)], by="ID"))  
                          ## saying by ID is even more save --^
res1
# $g1
#   ID sex age vital_sts b  c df
# 1  1   m  30         a x gh  z
# 2  2   m  50         a y fg  x
# 3  3   f  62         d z xv  y
# 
# $g2
#   ID sex age vital_sts  v  hg fd
# 1  1   m  30         a  a yty  z
# 2  2   m  50         a mm  zc  x
# 3  3   f  62         d xc  cx  y
# 
# $g3
#   ID sex age vital_sts  t   j sd
# 1  1   m  30         a ae ewr  z
# 2  2   m  50         a yw  zd  x
# 3  3   f  62         d zs   x  y
# 
# $g4
#   ID sex age vital_sts  u  k f
# 1  1   m  30         a df df z
# 2  2   m  50         a  y zs x
# 3  3   f  62         d  z xf y

访问单个数据框:

res1$g1
#   ID sex age vital_sts b  c df
# 1  1   m  30         a x gh  z
# 2  2   m  50         a y fg  x
# 3  3   f  62         d z xv  y

如果你仍然想在你的环境中保留单独的数据框,可以使用list2env

list2env(res1)
ls()
# [1] "DAT"     "demo"    "res1"    "vgroups"

数据:

DAT <- structure(list(ID = 1:3, b = c("x", "y", "z"), c = c("gh", "fg", 
"xv"), df = c("z", "x", "y"), f = c("z", "x", "y"), fd = c("z", 
"x", "y"), hg = c("yty", "zc", "cx"), j = c("ewr", "zd", "x"), 
    k = c("df", "zs", "xf"), sd = c("z", "x", "y"), t = c("ae", 
    "yw", "zs"), u = c("df", "y", "z"), v = c("a", "mm", "xc"
    ), x1 = c("gs", "gs", "gs"), x2 = c("cs", "cs", "cs"), x3 = c("tv", 
    "tv", "tv"), x4 = c("fb", "fb", "fb")), row.names = c(NA, 
-3L), class = "data.frame")

demo <- data.frame(sex = c('m', 'm', 'f'), age = c('30', '50', '62'), vital_sts = c('a', 'a', 'd'))

嗨。这真的很有帮助,老实说,这是我第一次使用这么多数据框,所以我不确定我是否正确理解了。您是指将数据框放在列表中而不是环境中,然后遍历该列表吗?这个数据框的实际问题是它是一个巨大的数据框,有很多变量(>500),但有一些变量是属于一起的“组”。这就是为什么他们将其拆分成许多小数据框的原因。您建议我从“主”数据框中进行过滤,而不是将其拆分并重新组合吗? - EduardoRod
@EduardoRod 我在工作时尽量保持环境的整洁,这就是为什么我会列出数据框。请查看我的编辑答案,了解一种将组直接放入单独数据框中的方法。 - jay.sf

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