【问题标题】:add multiple data frames together in a list在列表中添加多个数据框
【发布时间】:2018-09-25 23:21:14
【问题描述】:

我觉得这应该有一个非常简单/优雅的解决方案,但我就是找不到。 (我对 r 比较陌生,所以这并不奇怪。)

我有一个(大)嵌套列表,其中包含我要添加在一起的 data.frames。这是创建一些示例数据的代码:

#Create data frames nested in a list
for (i in 1:6) {
  for (j in 1:4) {
    assign(paste0("v", j), sample.int(100,4))
  }
  assign(paste0("df", i), list(cbind(v1, v2, v3, v4)))
}

inner1 <- list(data1 = df1, data2 = df2)
inner2 <- list(data1 = df3, data2 = df4)
inner3 <- list(data1 = df5, data2 = df6)

outer <- list(group1 = inner1, group2 = inner2, group3 = inner3)

我需要将所有标记为data1 的数据框和所有data2 的数据框加在一起。如果它们不是这种嵌套列表格式,我会这样做:

data1.tot <- df1 + df3 + df5
data2.tot <- df2 + df4 + df6

因为它们在一个列表中,我认为可能有lapply 的解决方案并尝试了:

grp <- c("group1", "group2", "group3") #vector of groups to sum across
datas <- lapply(outer, "[[", "data1") #select "data1" from all groups
tot.datas <- lapply(datas[grp], "+") #to sum across selected data
#I know these last two steps can be combined into one but it helps me keep everything straight to separate them

但它返回Error in FUN(left): invalid argument to unary operator,因为我将数据列表作为x 传递。

我也看过类似的其他解决方案:Adding selected data frames together, from a list of data frames

但是我的数据的嵌套结构让我不确定如何将该解决方案转化为我的问题。

请注意,我使用的数据是 GCHN 每日数据,因此结构不是我的设计。任何帮助将不胜感激。

更新: 我已经使用@Parfait 的Reduce 的建议部分想出了一个修复方法,但现在我需要自动化它。我正在使用for 循环开发解决方案,因为这让我可以更好地控制我正在访问的元素,但我对其他想法持开放态度。这是有效的手动解决方案:

get.df <- function(x, y, z) {
# function to pull out the desired data.frame from the list
# x included as argument to make function applicable to my real data
  output <- x[[y]][[z]]
  output[[1]]
}

output1 <- get.df(x = outer, y = "group1", z = "data1")
output2 <- get.df(x = outer, y = "group2", z = "data1")
data1 <- list(output1, output2)
data1.tot <- Reduce(`+`, data1)

使用我的示例数据,我想在 2 种数据类型(“data1”和“data2”)和 3 个组(“group1”、“group2”、“group3”)上循环。我正在研究for 循环解决方案,但正在努力解决如何将output1output2 保存在列表中。我的循环现在看起来像这样:

dat <- c("data1", "data2")
grp <- c("group1", "group2", "group3")

for(i in 1:length(dat)) {
  for(j in 1:length(grp)) {
    assign(paste0("out", j), get.df(x = outer, y = grp[j], z = dat[i]))
  }
list(??? #clearly this is where I'm stuck!
}

关于for 循环问题或更好的方法有什么建议吗?

【问题讨论】:

  • data1.tot &lt;- df1[[1]] + df3[[1]] + df5[[1]] 怎么样。这就是你要找的吗?
  • 谢谢。但是总共有 158 x 14 df,所以我正在寻找一种不需要全部输入的解决方案。
  • 我使用@Parfait 对Reduce 的建议取得了一些进展,但仍然遇到一些问题。我在上面发布了更新。
  • 对我来说,最终的输出应该是什么样子还不清楚。是清单吗?是单数吗?请提供硬编码输出,以便我们了解您的目标。

标签: r list


【解决方案1】:

考虑一下Reduce,它在列表中起作用。这个高阶函数是运行嵌套调用的一种紧凑方式:((df1 + df2) + df3) + ...

data1.tot <- Reduce(`+`, lapply(outer, "[[", "data1"))

data2.tot <- Reduce(`+`, lapply(outer, "[[", "data2"))

用随机数据演示

数据

set.seed(9262018)

dfList <- setNames(replicate(6, data.frame(NUM1=runif(50),
                                           NUM2=runif(50),
                                           NUM3=runif(50)), simplify = FALSE),
                   paste0("df", 1:6))

list2env(dfList, .GlobalEnv)

inner1 <- list(data1 = df1, data2 = df2)
inner2 <- list(data1 = df3, data2 = df4)
inner3 <- list(data1 = df5, data2 = df6)

outer <- list(group1 = inner1, group2 = inner2, group3 = inner3)

输出

data1.tot <- Reduce(`+`, lapply(outer, "[[", "data1"))
head(data1.tot, 10)
#         NUM1      NUM2      NUM3
# 1  2.0533870 1.3821609 1.0702992
# 2  2.6046584 1.7260646 1.9699774
# 3  2.2510810 1.6690353 1.4495476
# 4  1.7636879 1.2357098 1.9483906
# 5  1.0189969 2.1191041 1.7466040
# 6  1.3933982 0.7541027 1.0971724
# 7  1.8058803 2.4608417 0.7291335
# 8  1.0763517 1.2494739 1.0480818
# 9  0.7069873 1.5496575 1.2264486
# 10 0.9522526 2.1407523 1.2597422

data2.tot <- Reduce(`+`, lapply(outer, "[[", "data2"))
head(data2.tot, 10)    
#         NUM1      NUM2      NUM3
# 1  1.7568578 0.9322930 1.5579897
# 2  0.9455063 0.9211592 1.7067779
# 3  1.2698614 0.4623059 0.9426310
# 4  1.6791964 1.4304953 1.2435480
# 5  0.8088625 2.6107952 1.2308862
# 6  1.8202400 2.3511104 1.5676112
# 7  0.9765578 0.8870206 0.6725699
# 8  2.6448770 1.8931751 1.8188512
# 9  1.6114870 1.8632245 0.7452924
# 10 0.9710550 1.8367305 2.0994788

平等检验

all.equal(data1.tot, df1 + df3 + df5)
# [1] TRUE
all.equal(data2.tot, df2 + df4 + df6)
# [1] TRUE

identical(data1.tot, df1 + df3 + df5)
# [1] TRUE
identical(data2.tot, df2 + df4 + df6)
# [1] TRUE

【讨论】:

  • 我不熟悉Reduce。这似乎是正确的方向,但是,当我在我的示例数据上尝试它时,我收到了错误Error in f(init, x[[i]]): non-numeric argument to binary operator。 lapply 的输出是不同数据帧的列表。似乎它需要另一个命令来提取 data1 中 dfs 中的实际数据。我真的不擅长访问嵌套列表中的内容。
  • 再一次,要使用加号运算符+Reduce,数据框必须是相同的结构(相同的列数和行数)——所有数字类型。请参阅带有可重现示例的编辑,该示例显示我的答案有效,并且返回就像您将 dfs 加在一起一样。
  • 您的错误实际上表明 dfs 的列表结构与您的帖子不一致。请出示您的Reduce 尝试和dput(head(outer)) 的输出,以便我们重现您的实际数据。
  • 我在我在原始问题中提供代码的示例数据上测试了您的解决方案。我不确定为什么会失败,因为所有 df 都是以相同的方式创建的。但是,我能够让它与您的示例数据一起使用。我认为我的实际数据具有相同的维度,但它们没有,所以我要解决这个问题,在我的实际数据上尝试您的解决方案,如果它不起作用,请回复您。再次感谢!
  • 这个解决方案似乎确实有效。我现在遇到的问题是+ 没有办法忽略我能找到的 NA。有没有办法做到这一点并且仍然使用Reduce
【解决方案2】:

如果每个内部列表只包含几个数据框,这是一个可以正常工作的解决方案:

sum_df1 <- sum(unlist(lapply(outer, "[[", 1)))
sum_df2 <- sum(unlist(lapply(outer, "[[", 2)))

如果每个内部列表都包含 e。 G。 1000 个数据帧,使用:

dfs <- seq(1 : 1000)
lapply(dfs, function(x) sum(unlist(lapply(outer, "[[", x))))

这将为您提供一个列表,其中每个元素都是内部数据框的总和。

【讨论】:

  • 谢谢。由于sum 函数,这似乎将内部数据帧中的所有值加在一起,为每个集合返回一个值。我需要输出是与输入数据帧具有相同维度的数据帧。并且值来自不同列表中相同位置的数据帧(即group1,group2)。
【解决方案3】:

这是你想要的吗?

sapply(
  X = names(outer[[1]]),
  FUN = function(d) {
    Reduce(x = unlist(lapply(outer, "[[", d), recursive = F), f = "+")
  },
  simplify = F,
  USE.NAMES = T
)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-10
    • 2022-06-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-09
    • 1970-01-01
    相关资源
    最近更新 更多