【问题标题】:Create data frame, matching based on first elements of a list创建数据框,根据列表的第一个元素进行匹配
【发布时间】:2019-06-26 22:25:44
【问题描述】:

我想根据列表的第一个元素创建一个数据框。具体来说,我有

  • 一个包含变量 (names1) 的向量;
  • 一个包含两个变量(一些 vars1 和值)的列表;
  • 最终产品应该是一个带有“names1”的data.frame,其中包含与匹配的案例一样多的行。
  • 如果特定列表和向量之间不匹配,则应为 NA。
  • 这些值也可以是因子或字符串。
  • names1 <- c("a", "b", "c")
    dat1 <- data.frame(names1 =c("a", "b", "c", "f"),values= c("val1", 13, 11, 0))
       dat1$values <- as.factor(dat1$values)
    dat2 <- data.frame(names1 =c("a", "b", "x"),values= c(12, 10, 2))
       dat2$values <- as.factor(dat2$values)
    list1 <- list(dat1, dat2)
    

    结果应该是一个新的数据框,其中包含变量“名称”和与每个列表部分匹配的所有值:

     a      b    c
     val1   13   11
     12     10   NA
    

    【问题讨论】:

    • 一个data.table 解决方案:library(data.table); rbindlist(lapply(list1, function(x) setNames(transpose(x)[2,], x$names)), use.names=TRUE, fill=TRUE)[,.SD, .SDcols=(a:c)]

    标签: r list dataframe match


    【解决方案1】:

    一种选择是循环遍历list ('list1')、filter 基于“names”向量的“names”列,将其转换为单个数据集,同时使用@987654323 创建标识列@, spread 从 'long' 到 'wide' 并删除 'grp' 列

    library(tidyverse)
    map_df(list1, ~   .x %>% 
                         filter(names %in% !! names), .id = 'grp') %>%           
          spread(names, values) %>% 
          select(-grp)   
    #      a     b     c    
    #1    25    13    11
    #2    12    10    NA
    

    或者另一种选择是将数据集与bind_rows 绑定在一起,创建一个分组ID 'grp' 来指定list 元素,filter 通过只选择与'names' 匹配的'names' 列来指定行' vectorspread 从“长”到“宽”

    bind_rows(list1, .id = 'grp') %>%
       filter(names %in% !! names) %>% 
       spread(names, values)
    

    注意:最好不要使用保留关键字来指定对象名称 (names)。此外,为避免混淆,该对象应与数据框对象的列名不同。


    也可以只使用base R。通过仅保留“名称”vectorreshape 从“长”到“宽'

    df1 <- subset(do.call(rbind, Map(cbind, list1, 
              ind = seq_along(list1))), names %in% .GlobalEnv$names)   
    reshape(df1, idvar = 'ind', direction = 'wide', timevar = 'names')[-1]
    

    【讨论】:

    • 对于因素也可以做到这一点吗? (即,如果 values 是一个因素或一个字符串?)
    • 我意识到它有效,但前提是数值和因子值不混合!非常感谢,阿克伦!!!太棒了!
    • @tobiassch 谢谢。这有点奇怪。你可以试试filter(as.character(names) %in% !! names)
    【解决方案2】:

    基础 R 和 dplyr 的混合。对于每个列表元素,我们创建一个包含 1 行的数据框。使用dplyrrbind_list 行将它们绑定在一起,然后使用names 仅对我们需要的那些列进行子集化。

    library(dplyr)
    
    rbind_list(lapply(list1, function(x) 
            setNames(data.frame(t(x$values)), x$names)))[names]
    
    #     a     b     c
    #   <dbl> <dbl> <dbl>
    #1    25    13    11
    #2    12    10    NA
    

    没有子集的输出看起来像这样

    rbind_list(lapply(list1, function(x) setNames(data.frame(t(x$values)), x$names)))
    
    #     a     b     c     x
    #   <dbl> <dbl> <dbl> <dbl>
    #1    25    13    11    NA
    #2    12    10    NA     2
    

    【讨论】:

      【解决方案3】:

      在基础 R

      t(sapply(list1, function(x) setNames(x$values, names)[match(names, x$names)]))
      #       a  b  c
      # [1,] 25 13 11
      # [2,] 12 10 NA
      

      【讨论】:

      • 非常感谢,这很好用——是否还有因子值的解决方案? (如果值是一个因素)?
      【解决方案4】:

      仅使用基础 R

      body <- do.call('rbind', lapply(list1, function(list.element){
        element.vals <- list.element[['values']]
        element.names <- list.element[['names']]
        names(element.vals) <- element.names
        return.vals <- element.vals[names]
        if(all(is.na(return.vals))) NULL else return.vals
      }))
      
      df <- as.data.frame(body)
      names(df) <- names
      df
      

      【讨论】:

        【解决方案5】:

        为了完整起见,这里是使用dcast()rowid() 方法:

        library(data.table)
        nam <- names1   # avoid name conflict with column name
        rbindlist(list1)[names1 %in% nam, dcast(.SD, rowid(names1) ~ names1)][, names1 := NULL][]
        
              a  b    c
        1: val1 13   11
        2:   12 10 <NA>
        

        或者,更简洁地说,在整形后选择列:

        library(data.table)
        rbindlist(list1)[, dcast(.SD, rowid(names1) ~ names1)][, .SD, .SDcols = names1]
        

        【讨论】:

          猜你喜欢
          • 2020-04-11
          • 2020-12-10
          • 1970-01-01
          • 1970-01-01
          • 2022-07-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多