使用dplyr和tidyr制作更复杂的表格

问题描述 投票:2回答:2

我有一个看起来像这样的数据集,虽然真实的例子有更多的列。只有一行(目前)。

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的单独命令,但是我绞尽脑汁,搜索SO,以及更广泛的网络,并查看了tidyr文档,但都无济于事。我认为答案应该是显而易见的,但我看不出来。

我将不胜感激任何和所有的帮助。

r dplyr reshape
2个回答
3
投票

你需要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 = "(.*)_(.*)",如果您使用了多个其他摘要函数,这可能很有用。


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


1
投票

使用基础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

融化和播客:

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
© www.soinside.com 2019 - 2024. All rights reserved.