【问题标题】:Making more complex tables using dplyr and tidyr使用 dplyr 和 tidyr 制作更复杂的表
【发布时间】:2017-12-21 14:06:27
【问题描述】:

我有一个看起来像这样的数据集,尽管实际示例有更多列。只有一排(目前)。

Results <- structure(list(PCV2_CT_Min = 7.15, PPV2_CT_Min = 11.4, PPV3_CT_Min = 8.6, 
PPV4_CT_Min = 16.3, PPV_CT_Min = 29.58, NI_BOCA_CT_Min = 20.51, 
SW_BOCA_CT_Min = 23.49, PCV2_CT_Count = 695L, PPV2_CT_Count = 695L, 
PPV3_CT_Count = 695L, PPV4_CT_Count = 695L, PPV_CT_Count = 695L, 
NI_BOCA_CT_Count = 695L, SW_BOCA_CT_Count = 695L),
.Names = c("PCV2_CT_Min", "PPV2_CT_Min", "PPV3_CT_Min", "PPV4_CT_Min", "PPV_CT_Min", "NI_BOCA_CT_Min", "SW_BOCA_CT_Min", "PCV2_CT_Count", "PPV2_CT_Count", "PPV3_CT_Count", "PPV4_CT_Count", "PPV_CT_Count", "NI_BOCA_CT_Count", "SW_BOCA_CT_Count"),
row.names = c(NA, -1L), class = c("tbl_df", "tbl", "data.frame"))

每个列名由一个变量名和一个函数名组成,所以PCV2_CT_Min是PCV2病毒测试的最小计数(CT); PCV_CT_Count 是测试的动物总数,以此类推。

它是通过在另一个数据集上运行 dplyr 中的 summarize_all 生成的,该数据集是对猪的个体病毒测试,使用的是此代码的更长版本:-

V <- Pig %>%
     select(ends_with('CT')) %>% 
     summarise_all(funs(Min = min(.,na.rm=TRUE),
     Count = n()))

在实际示例中,有更多的函数,并且它们采用不同的参数。我想最终得到的是这样的数据框:-

Parameter PCV_CT PPV2_CT PPV3_CT PPV4_CT PPV_CT NI_BOCA_CT SW_BOCA_CT
Min       7.15   11.4    8.6     16.3    29.58  20.51     23.49
Count     695    695     695     695     695    695       695 

我原以为有一种简单的方法可以做到这一点,也许可以使用 tidyr 中的 seperate 命令,但我绞尽脑汁,搜索了 SO,然后更广泛的网络,并查看了 tidyr 文档,但均无济于事。我认为答案应该很明显,但我看不到。

我将不胜感激。

【问题讨论】:

    标签: r dplyr reshape


    【解决方案1】:

    你需要把gather所有的列,separate的名字改成你想要的相关部分,然后spread把数据改成宽格式:

    library(tidyverse)
    Results %>% 
      gather(var, val, everything()) %>% 
      extract(var, into = c("var", "measure"), regex = "(.*)_(Min|Count)") %>% 
      spread(var, val)
    # # A tibble: 2 x 8
    #   measure NI_BOCA_CT PCV2_CT PPV_CT PPV2_CT PPV3_CT PPV4_CT SW_BOCA_CT
    # *   <chr>      <dbl>   <dbl>  <dbl>   <dbl>   <dbl>   <dbl>      <dbl>
    # 1   Count     695.00  695.00 695.00   695.0   695.0   695.0     695.00
    # 2     Min      20.51    7.15  29.58    11.4     8.6    16.3      23.49
    

    要拆分的更通用的正则表达式可能是regex = "(.*)_(.*)",如果您使用了多个其他摘要函数,这可能会很有用。


    我知道您有理由以这种形式保存您的数据,但这与您实际应该查看的内容有些相反。理想情况下,让您的列包含所有相同类型度量的数据更有意义....

    【讨论】:

    • 使用tidyr::extract 比使用tidyr::separate 有什么优势?
    • 数据很混乱,但在 R 中不容易生成这类表格的一个领域是,这或它的一些变体似乎是最简单的方法。你的回答很有帮助,我会继续努力的。谢谢!
    • @jdobres, extract 将允许您指定不同的捕获组,而separate 更像是strsplit 进入新列。如果所有变量都有相同数量的下划线,则使用separate 会更容易。
    【解决方案2】:

    使用基数 R/reshape2 的两个不同想法可能是:

    拆分和堆叠:

    dfs <- lapply(c("Min", "Count"), function(x) {
            res <- Results[, grepl(x, names(Results))]
            res <- setNames(res, gsub(paste0("_", x), "", names(res)))
            res$measure <- x
            return(res)
          })
    do.call(rbind, dfs)
    
    # A tibble: 2 x 8
    #  PCV2_CT PPV2_CT PPV3_CT PPV4_CT PPV_CT NI_BOCA_CT SW_BOCA_CT measure
    #    <dbl>   <dbl>   <dbl>   <dbl>  <dbl>      <dbl>      <dbl>   <chr>
    #1    7.15    11.4     8.6    16.3  29.58      20.51      23.49     Min
    #2  695.00   695.0   695.0   695.0 695.00     695.00     695.00   Count
    

    融化和 dcast:

    library(reshape2)
    melted <- melt(data.frame(Results))
    melted$measure <- gsub(".*_(Min|Count)", "\\1", melted$variable)
    melted$variable <- gsub("_(Min|Count)", "", melted$variable)
    dcast(melted, measure ~ variable)
    
    #  measure NI_BOCA_CT PCV2_CT PPV_CT PPV2_CT PPV3_CT PPV4_CT SW_BOCA_CT
    #1   Count     695.00  695.00 695.00   695.0   695.0   695.0     695.00
    #2     Min      20.51    7.15  29.58    11.4     8.6    16.3      23.49
    

    【讨论】:

      猜你喜欢
      • 2016-12-21
      • 2016-07-05
      • 2016-06-05
      • 1970-01-01
      • 2017-12-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多