【问题标题】:R unpack a list of vectors in a dataframeR解压缩数据框中的向量列表
【发布时间】:2021-03-11 20:20:37
【问题描述】:

开始:我见过this post,不,tidyrunnest 在这里不起作用。我正在做一个lapply,其中返回函数返回一个包含命名条目的列表(为清楚起见,请参阅底部的示例func):

ls <- lapply(x, func) 

现在,如果我查看 ls,它是一个列表列表,在 R Studio 数据查看器中,它显示为具有 NameTypeValue 列。

现在,如果我使用

df <- bind_rows(ls)

我得到正是我想要的,除了我需要将包含x 的数据框绑定到df。这就是问题所在,因为对于每个 xfunc 将返回可变数量的行,这意味着在我已经将 ls 附加到我的数据帧之后,我需要运行等效的 bind_rows

一个例子如下:

func <- function(x){
  res <- list()
  res$name <- 1:x 
  res$val <- 1:x
  return(res)
}

df <- data.frame(nums <- c(1:3), letters <- c("A", "B", "C"))
ls <- lapply(df$nums, func)

bind_rows(ls) 给出:

   name   val
  <int> <int>
1     1     1
2     1     1
3     2     2
4     1     1
5     2     2
6     3     3

所需的输出是:

   name   val  nums letters
  <int> <int> <dbl> <chr>  
1     1     1     1 A      
2     1     1     2 B      
3     2     2     2 B      
4     1     1     3 C      
5     2     2     3 C      
6     3     3     3 C  

注意func 在这里创建n 给定x = n 的行。我的 actual 函数不是这种情况。 func(n) 可以产生任意正数的行。

【问题讨论】:

    标签: r dataframe


    【解决方案1】:

    也许您正在寻找更“罐装”的东西,但您可以编写一个产生所需输出的函数,如下所示:

    out <- function(data, varname){
      l <- lapply(data[[varname]], func)
      l <- lapply(1:length(l), function(x)do.call(data.frame, c(l[[x]], zz_obs=x)))
      l <- do.call(rbind, l)
      data$zz_obs <- 1:nrow(data)
      if(!all(data$obs %in% l$obs))warning("Not all rows of data in output\n")
      data <- dplyr::full_join(l, data, by="zz_obs")
      data[,-which(names(data) ==  "zz_obs")]
    }
    
    out(df, "nums")
    #   name val nums letters
    # 1    1   1    1       A
    # 2    1   1    2       B
    # 3    2   2    2       B
    # 4    1   1    3       C
    # 5    2   2    3       C
    # 6    3   3    3       C
    
    

    【讨论】:

      【解决方案2】:

      您可以尝试mapply,它类似于lapply,但允许传递多个向量或列表来迭代它们的值:

      library(dplyr)
      func <- function(x, y){
        res <- list()
        res$name <- 1:x 
        res$val <- 1:x
        res$let <- rep(y, x)
        return(res)
      }
      df <- data.frame(nums <- c(1:3), letters <- c("A", "B", "C"))
      
      ls <- mapply(
        func, 
        x = df$nums, 
        y =df$letters, 
        SIMPLIFY = FALSE
      )
      bind_rows(ls)
      
      # A tibble: 6 x 3
      #   name   val let  
      #  <int> <int> <chr>
      # 1     1     1 A    
      # 2     1     1 B    
      # 3     2     2 B    
      # 4     1     1 C    
      # 5     2     2 C    
      # 6     3     3 C    
      
      

      【讨论】:

      • 这是一个聪明的解决方案,但它需要我编辑func 或将func 包装在另一个函数中(在这种情况下我必须这样做,因为我没有写func),这使得它无法重复使用。
      • 包装器不是一个糟糕的选择,如果你需要的话。您还可以运行 lapply 两次并 cbind 输出
      【解决方案3】:

      在此期间,我将使用的函数是:

      merge_and_flatten <- function(x, y){
        for (i in 1:nrow(x)){
          y[[i]][names(x)] <- lapply(x[i, ], rep, times = length(y[[i]][[1]]))
        }
        return(bind_rows(y))
      }
      

      这是我能想到的最干净的解决方案。在这里,x 服务,我的dfy 服务为ls。它通过将问题减少到bind_rows 来工作:它只是将元素添加到ls,其中包含x 中的列。我绝对想要一个更清洁的解决方案,但这适用于任何需要它的人。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-03-12
        • 1970-01-01
        • 2018-07-04
        • 1970-01-01
        • 1970-01-01
        • 2021-05-19
        • 1970-01-01
        • 2019-11-19
        相关资源
        最近更新 更多