【问题标题】:Elegant, functional way to extract data from this nested R list从这个嵌套的 R 列表中提取数据的优雅、实用的方法
【发布时间】:2020-06-19 15:07:52
【问题描述】:

给定以下配置对象:

sourceClust = list(
  clust1 = list(
    prop = 0.25,
    Dim1 = list(
      mean = 2,
      sd   = 0.05
    ) ,
    Dim2 = list(
     mean = 3,
     sd = .1
    )
  ),
  clust2 = list(
    Dim1 = list(
      mean = 4,
      sd   = .1
    ),
    Dim2 = list(
      mean = 3,
      sd = 0.2
    ),
    prop = 0.75
  )
);

是否有一种优雅、实用的方法来提取以下格式的数据?

clusterMeans = data.frame(Dim1=c(2,4),Dim2=c(3,3));
clusterSD = data.frame(Dim1 = c(0.05,0.1), Dim2 = c(0.1,0.2));
clusterProp = c(0.25, 0.75);

我知道上面可以通过一些嵌套循环来完成,但我正在尝试看看我是否可以使用函数式样式来完成这项任务。我正在寻找基本 R 中的解决方案或使用库(tidyverse 很棒)。

【问题讨论】:

    标签: r functional-programming config tidyverse


    【解决方案1】:

    你可以的

    order_df <- function(x) unlist(x)[order(names(unlist(x)))]
    df <- as.data.frame(do.call(rbind, lapply(sourceClust, order_df)))
    df
    #>        Dim1.mean Dim1.sd Dim2.mean Dim2.sd prop
    #> clust1         2    0.05         3     0.1 0.25
    #> clust2         4    0.10         3     0.2 0.75
    

    然后将列子集化:

    clusterMeans <- df[grepl("mean", names(df))]
    clusterSD    <- df[grepl("sd", names(df))]
    clusterProp  <- df[[grep("prop", names(df))[1]]]
    

    或者以管道形式,产生一个命名的数据框列表:

    sourceClust %>% 
      lapply(function(x) unlist(x)[order(names(unlist(x)))]) %>%
      {do.call(rbind, .)} %>%
      as.data.frame() %>%
      {lapply(c("mean", "sd", "prop"), function(x) .[grep(x, names(.))])} %>%
      `names<-`(c("mean", "sd", "prop"))
    ># $mean
    >#        Dim1.mean Dim2.mean
    ># clust1         2         3
    ># clust2         4         3
    ># 
    ># $sd
    >#        Dim1.sd Dim2.sd
    ># clust1    0.05     0.1
    ># clust2    0.10     0.2
    ># 
    ># $prop
    >#        prop
    ># clust1 0.25
    ># clust2 0.75
    

    【讨论】:

    • 哇,这是一个非常有趣的解决方案。起初我持怀疑态度,但我发现一旦应用了您的解决方案,我可以使用 dplyr 库在最后按名称和维度动态拉取列(如果我有多个维度)。我会牢记这个想法,以备将来之用。取消列出,将 do.call(rbind) 转换为 df,然后使用正则表达式选择列。
    • @Battlefrisk 是的,你甚至不需要 dplyr。示例已更新。
    • 很抱歉要求这么多,但您能建议一个使用管道重写它的好方法吗?
    • @Battlefrisk 我认为它不那么优雅,但我添加了一个管道版本
    • 你说得对。但这对于以两种方式完成复杂的事情非常有帮助。感谢您的宝贵时间!
    【解决方案2】:

    purrr 包有一些辅助函数,例如 mappluck,它们可以提供帮助。例如

    clusterProp <- map_dbl(sourceClust, "prop")
    

    map_dbl(sourceClust, ~pluck(., "Dim1", "sd"))
    

    你也可以这样做

    cols <- c("Dim1", "Dim2")
    clusterMeans <- map(cols, function(col) map_dbl(sourceClust, ~pluck(., col, "mean"))) %>%
      set_names(cols) %>% as_tibble()
    clusterSD  <- map(cols, function(col) map_dbl(sourceClust, ~pluck(., col, "sd"))) %>%
      set_names(cols) %>% as_tibble()
    

    但既然你做了这么多的重塑,它并不完全是“优雅”的。

    【讨论】:

    • 这很有趣,我没有意识到 map 可以用作那样的吸气剂。我认为它需要传递一个函数来将每一行减少为一个值。我认为这里的困难部分是双重嵌套的手段和 sd。我正在寻找一种独立于 Dims 数量的解决方案,所以我可能需要一些 RegExp。
    • 如果 prop=Dim*= 处于同一级别,则在不知道要操作的具体名称的情况下很难区别对待它们。
    猜你喜欢
    • 2017-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-29
    相关资源
    最近更新 更多