使用dplyr、tidyr、purrr实现多列聚合分组的收集

4
我正在尝试收集涉及两个不同变量的数据,这些变量分散在多个列中,由另外两个变量进行分组。以下是问题所在。我有几个基因和几个样本。每个样本有三种不同的可能基因型,每种基因型都有一个相关频率。我想整理出一个包含基因、样本、基因型、频率的单独列。
我的解决方案是创建列表列,展开它们,然后使用purrr :: map函数提取列。这个方法很丑陋,不太可扩展,并且频率在转换为数字之前被转换为字符,这并不理想。有更好的解决方法吗?
library(tidyverse) 
# or, separately load dplyr, tibble, tidyr, purrr

# Here's what I have
have <- data_frame(gene=rep(c("gX", "gY"), each=2),
                   sample=rep(c("s1", "s2"), 2),
                   genotype1=c("AA", "AA", "GG", "GG"),
                   genotype2=c("AC", "AC", "GT", "GT"),
                   genotype3=c("CC", "CC", "TT", "TT"),
                   freq1=c(.8,.9, .7, .6),
                   freq2=c(.15,.1, .2, .35),
                   freq3=c(.05,0, .1, .05))
have
#> # A tibble: 4 × 8
#>    gene sample genotype1 genotype2 genotype3 freq1 freq2 freq3
#>   <chr>  <chr>     <chr>     <chr>     <chr> <dbl> <dbl> <dbl>
#> 1    gX     s1        AA        AC        CC   0.8  0.15  0.05
#> 2    gX     s2        AA        AC        CC   0.9  0.10  0.00
#> 3    gY     s1        GG        GT        TT   0.7  0.20  0.10
#> 4    gY     s2        GG        GT        TT   0.6  0.35  0.05


# Here's what I want. 
# Do a multicolumn gather grouped by gene and sample
want <- have %>%
  group_by(gene, sample) %>%
  summarize(x1=list(c(genotype=genotype1, freq=freq1)),
            x2=list(c(genotype=genotype2, freq=freq2)),
            x3=list(c(genotype=genotype3, freq=freq3))) %>%
  ungroup() %>%
  gather(key, value, x1, x2, x3) %>%
  mutate(genotype=map_chr(value, "genotype"),
         freq=map_chr(value, "freq") %>% as.numeric) %>%
  select(-key, -value) %>%
  arrange(gene, sample, genotype)
want
#> # A tibble: 12 × 4
#>     gene sample genotype  freq
#>    <chr>  <chr>    <chr> <dbl>
#> 1     gX     s1       AA  0.80
#> 2     gX     s1       AC  0.15
#> 3     gX     s1       CC  0.05
#> 4     gX     s2       AA  0.90
#> 5     gX     s2       AC  0.10
#> 6     gX     s2       CC  0.00
#> 7     gY     s1       GG  0.70
#> 8     gY     s1       GT  0.20
#> 9     gY     s1       TT  0.10
#> 10    gY     s2       GG  0.60
#> 11    gY     s2       GT  0.35
#> 12    gY     s2       TT  0.05

5
我只需执行 library(data.table) ; melt(setDT(have), id = 1:2, measure = patterns("genotype", "freq")),但这并不是由 Hadley 开发的,因此你可以放心忽略。 - David Arenburg
@DavidArenburg 这个工作得非常好。考虑将其作为官方答案。 - Stephen Turner
2个回答

6
您可以使用 sjmisc包 中的 to_long() 函数,它可以一次性收集多个列:
to_long(have, keys = "genos", values = c("genotype", "freq"),
       c("genotype1", "genotype2", "genotype3"),
       c("freq1", "freq2", "freq3"))

##  A tibble: 12 × 5
##     gene sample     genos genotype  freq
##    <chr>  <chr>     <chr>    <chr> <dbl>
## 1     gX     s1 genotype1       AA  0.80
## 2     gX     s2 genotype1       AA  0.90
## 3     gY     s1 genotype1       GG  0.70
## 4     gY     s2 genotype1       GG  0.60
## 5     gX     s1 genotype2       AC  0.15
## 6     gX     s2 genotype2       AC  0.10
## 7     gY     s1 genotype2       GT  0.20
## 8     gY     s2 genotype2       GT  0.35
## 9     gX     s1 genotype3       CC  0.05
## 10    gX     s2 genotype3       CC  0.00
## 11    gY     s1 genotype3       TT  0.10
## 12    gY     s2 genotype3       TT  0.05

to_long()需要键和值列的名称,然后是应该被收集的多个向量的多个列名。


1
完整的tidyverse方法:

<code>want <- have %>%
     gather(variable, value, -gene, -sample) %>% 
     mutate(group = parse_number(variable),
            variable = str_extract(variable,"\\D+")) %>% 
     spread(variable, value) %>% 
     select(-group)
</code>

tidyverse 是一种设计哲学还是一组受限制的软件包? - Daniel
我会说两者都可以,或者至少一个专注于通过管道生成易读代码并专注于整洁数据的工作流程。 - Jake Kaupp
@Daniel 我也同意Jake的观点 - 我会选择两者。这是一个很好的起点:http://vita.had.co.nz/papers/tidy-data.pdf 或 https://vimeo.com/33727555,而继续学习的好地方可能在这里:http://r4ds.had.co.nz/ - leerssej
是的,我知道这些资源。我个人认为_tidyverse_更多地是一种哲学(请参见https://github.com/tidyverse/tidyverse/blob/master/vignettes/manifesto.Rmd),而不是与特定作者(在这种情况下是Hadley)有关。`to_long()`函数遵循与`tidyr::gather()`相同的设计原则,那么为什么它不能符合“整洁宇宙方法”呢?我认为我的观点与@David-Arenburg提到的大致相同:“它不是由Hadley开发的,所以你可以放心忽略”。;-) - Daniel
1
有些人喜欢一种集成的方法,可以减少他们需要学习的模块和软件包的数量。to_long() 函数肯定适用于整洁数据工具和理念。我的回答仅限于使用 tidyverse 软件包集合,而不是引发无谓的讨论关于软件包或作者的争论。 - Jake Kaupp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接