首页 > 解决方案 > R:如何将每 5 行的选择转换为单行?

问题描述

我有以下(整洁)格式的数据集:

SAMPLE, MARKER, ALLELE, LENGTH, PEAK
BRIS01, B100, allele 1, NA, 126.95
BRIS01, B100, allele 2, 160, 159.72
BRIS01, B100, allele 3, 162, 162.01
BRIS02, B100, allele 1, 152, 151.4
BRIS02, B100, allele 2, NA, NA
BRIS02, B100, allele 3, NA, NA

总的来说,每个样本都有 14 个标记的条目,每个标记都有 5 个等位基因的条目,即使条目只是“NA”。我不确定有多少样本。

我花了一整天的时间尝试将其重组为以下格式,以便每个样本的所有等位基因值对于每个标记都彼此相邻,但无济于事:

                MARKER 1                              MARKER 2      MARKER 3
      SAMPLE 1, NA, 126.95, 160, 159.72, 162, 162.01, LENGTH, PEAK, LENGTH, PEAK
      SAMPLE 2, 152, 151.4, NA, NA, NA, NA,           LENGTH, PEAK, LENGTH, PEAK

如果格式看起来有点乱,希望这可能会有所帮助:在每一行中,应该有 141 列;第一列应该包含样本名称,然后是每个标记的 5 个等位基因的等位基因长度和峰值大小。例如,Sample,marker 1 length 1,marker 1 peak 1,marker 1 length 2,marker 1 peak 2,marker 2 length 1,marker 2 peak 2 等等。这有点违反直觉,但想象一下有列标题每个标记,然后是每个等位基因的大小和峰的子列。

我尝试过使用 dpylr、tidy data、melt、cast、dcast、reshape、reshape2、transpose ......但我对 R 不是很好,也没有任何运气。在实践中使用长度和峰值作为子列可能不是很好/整洁的数据,但这是我的老板要求解释数据的。任何反馈表示赞赏!

谢谢!

编辑:我按照建议运行了以下代码:

ultra_wide <-
  wide %>%
  group_by(SAMPLE, MARKER) %>%
  gather(key = "VARS", value = "VALS", c(LENGTH, PEAK)) %>%
  spread(MARKER, VALS) %>%
  summarize(MARKER1 = paste(c(B100), collapse = ", "), 
            MARKER2 = paste(c(B132), collapse = ", "),
            MARKER3 = paste(c(BL13), collapse = ", "),
            MARKER4 = paste(c(BT06), collapse = ", "),
            MARKER5 = paste(c(BT09), collapse = ", "),
            MARKER6 = paste(c(BT30), collapse = ", "),
            MARKER7 = paste(c(BTMS0044), collapse = ", "),
            MARKER8 = paste(c(BTMS0067), collapse = ", "),
            MARKER9 = paste(c(BTMS0106), collapse = ", "),
            MARKER10 = paste(c(B116), collapse = ", "),
            MARKER11 = paste(c(B118), collapse = ", "),
            MARKER12 = paste(c(B119), collapse = ", "),
            MARKER13 = paste(c(BT20), collapse = ", "),
            MARKER14 = paste(c(BTMS0114), collapse = ", "))

但是,由于发生以下错误,该命令没有执行任何操作:

错误:行标识符重复(76、77、78、79、80)、(30671、30672、30673、30674、30675)、(81、82、83、84、85)、(30676、30677、30678、30679) , 30680)

之后又持续了几行。

标签: rdataframedata-structuresdplyrreshape

解决方案


数据输入

首先,请提交重新创建数据框的代码,以便下一个人可以轻松复制并粘贴代码并自己查看数据框。在这里,我只是尝试根据您的规范重新创建数据框,特别是您提到每个标记有五个等位基因的部分。

# Vectors for dataframe

library(tidyverse)

SAMPLE <- c(rep("BRIS01", 5), rep("BRIS02", 5))
MARKER <- c(rep("B100", 5), rep("B200", 5))
ALLELE <- rep(paste("allele",1:5), times = 2)
LENGTH <- c(NA, 160, 162, 152, NA, NA, 160:163)
PEAK <- c(126.95,   159.72, 162.01, 151.4,  NA, NA, 150:153)

marker_data <- data.frame(SAMPLE, MARKER, ALLELE, LENGTH, PEAK, stringsAsFactors = FALSE)

marker_data
#>    SAMPLE MARKER   ALLELE LENGTH   PEAK
#> 1  BRIS01   B100 allele 1     NA 126.95
#> 2  BRIS01   B100 allele 2    160 159.72
#> 3  BRIS01   B100 allele 3    162 162.01
#> 4  BRIS01   B100 allele 4    152 151.40
#> 5  BRIS01   B100 allele 5     NA     NA
#> 6  BRIS02   B200 allele 1     NA     NA
#> 7  BRIS02   B200 allele 2    160 150.00
#> 8  BRIS02   B200 allele 3    161 151.00
#> 9  BRIS02   B200 allele 4    162 152.00
#> 10 BRIS02   B200 allele 5    163 153.00

请注意,在data.frame我传递选项时,stringsAsFactors = FALSE因为处理因子变量往往非常棘手

“传播”您的数据

至于您的输出,我将您以表格形式显示的内容作为您想要的结果输出。如果没有更多数据,很难获得每行所需的 141 列。获得答案的关键是MARKER在“收集”(或更常用的“熔化”)具有“值”的列之后“展开”列,即LENGTHPEAK列。传播前;但是,您应该创建一个具有唯一值的列,以防传播遇到相同的行。最后,您必须汇总以获取每个样本的一行,尽管您希望循环遍历 MARKER1-MARKER14 列以获得更优化/有效的代码。无论如何,我希望这会有所帮助。

marker_m <- 
  marker_data %>% 
  group_by(SAMPLE, MARKER) %>%
  gather(VARS, VALS, c(LENGTH, PEAK)) %>%
  mutate(i = row_number()) %>%
  spread(MARKER, VALS) %>% 
  summarize(MARKER1 = paste(c(B100), collapse = ", "), MARKER2 = paste(c(B200), collapse = ", "))

marker_m
#> # A tibble: 2 x 3
#>   SAMPLE MARKER1                                                  MARKER2 
#>   <chr>  <chr>                                                    <chr>   
#> 1 BRIS01 NA, 126.95, 160, 159.72, 162, 162.01, 152, 151.4, NA, NA NA, NA,~
#> 2 BRIS02 NA, NA, NA, NA, NA, NA, NA, NA, NA, NA                   NA, NA,~

推荐阅读