从存在/不存在将具有相同ID的两行连接为0,1,2

时间:2019-05-14 11:44:21

标签: r subset

我试图记录一个原始表,其中行std::cin,列中示例SNP ID

到目前为止,我只设法将数据转换为0和1。

我尝试了一些简单的代码来进行进一步的转换,但是找不到我想要的代码。

原始表格如下

ID

我想将分数记录为0/0 = NA,0/1 = 0,1 / 1 = 2,1 / 0 = 1,所以乘积看起来像这样。

snpID   Cal_X1  Cal_X2  Cal_X3  Cal_X4  Cal_X5  Cal_X6  Cal_X7  Cal_X8
A_001   0   1   1   1   0   0   1   0
A_001   0   0   1   0   1   0   1   1
A_002   1   1   0   1   1   1   0   0
A_002   0   1   1   0   1   0   1   1
A_003   1   0   0   1   0   1   1   0
A_003   1   1   0   1   1   0   0   1
A_004   0   0   1   0   0   1   0   0
A_004   1   0   0   1   0   1   1   0

这只是一个例子。我的snpID Cal_X1 Cal_X2 Cal_X3 Cal_X4 Cal_X5 Cal_X6 Cal_X7 Cal_X8 A_001 NA 1 2 1 0 NA 2 0 A_002 1 2 0 1 2 1 0 0 A_003 2 0 NA 2 0 1 1 0 A_004 0 NA 1 0 NA 2 0 NA 总数约为96000,而示例snpID列的总数约为500。

任何帮助编写此代码的人都会非常感激。

2 个答案:

答案 0 :(得分:1)

以下是一些基于dplyr的示例,每个示例都在单个管道中工作并获得相同的输出。第一步是按ID分组,然后用/折叠所有列。然后,您可以使用mutate_at选择以Cal_开头的所有列-如果您除了不想想要执行的ID之外还有其他列,这可能会很有用操作。

第一个方法是case_when

library(dplyr)

dat %>%
  group_by(snpID) %>%
  summarise_all(paste, collapse = "/") %>%
  mutate_at(vars(starts_with("Cal_")), ~case_when(
    . == "0/1" ~ 0,
    . == "1/1" ~ 2,
    . == "1/0" ~ 1,
    TRUE ~ NA_real_
  ))
#> # A tibble: 4 x 9
#>   snpID Cal_X1 Cal_X2 Cal_X3 Cal_X4 Cal_X5 Cal_X6 Cal_X7 Cal_X8
#>   <chr>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>  <dbl>
#> 1 A_001     NA      1      2      1      0     NA      2      0
#> 2 A_002      1      2      0      1      2      1      0      0
#> 3 A_003      2      0     NA      2      0      1      1      0
#> 4 A_004      0     NA      1      0     NA      2      0     NA

但是,(我认为)case_when读起来有些棘手,但这并不能显示其真正的功能,它是在对多个变量进行if / else检查。 dplyr::recode更适合一次检查一个变量:

dat %>%
  group_by(snpID) %>%
  summarise_all(paste, collapse = "/") %>%
  mutate_at(vars(starts_with("Cal_")), 
            ~recode(., 
                    "0/1" = 0,
                    "1/1" = 2,
                    "1/0" = 1,
                    "0/0" = NA_real_))
# same output as above

或者,为了获得更大的灵活性和可读性,请创建一个小的查找对象。这样,您可以重用重新编码逻辑并轻松更改它。 recode带有一组命名参数;使用tidyeval,您可以传递命名的向量,然后使用!!!取消命名(在recode文档中有一个类似的示例):

lookup <- c("0/1" = 0, "1/1" = 2, "1/0" = 1, "0/0" = NA_real_)

dat %>%
  group_by(snpID) %>%
  summarise_all(paste, collapse = "/") %>%
  mutate_at(vars(starts_with("Cal_")), recode, !!!lookup)
# same output

答案 1 :(得分:0)

您可以使用aggregate连接每个snpID的值,然后在case_when的{​​{1}}的帮助下根据需要替换这些值。

dplyr

现在重新编码列

(out <- aggregate(.~ snpID, dat, toString))
#  snpID Cal_X1 Cal_X2 Cal_X3 Cal_X4 Cal_X5 Cal_X6 Cal_X7 Cal_X8
#1 A_001   0, 0   1, 0   1, 1   1, 0   0, 1   0, 0   1, 1   0, 1
#2 A_002   1, 0   1, 1   0, 1   1, 0   1, 1   1, 0   0, 1   0, 1
#3 A_003   1, 1   0, 1   0, 0   1, 1   0, 1   1, 0   1, 0   0, 1
#4 A_004   0, 1   0, 0   1, 0   0, 1   0, 0   1, 1   0, 1   0, 0

结果

library(dplyr)
out[-1] <- case_when(out[-1] == "0, 0" ~ NA_integer_,
                     out[-1] == "0, 1" ~ 0L,
                     out[-1] == "1, 0" ~ 1L,
                     TRUE ~ 2L)

数据

out
#  snpID Cal_X1 Cal_X2 Cal_X3 Cal_X4 Cal_X5 Cal_X6 Cal_X7 Cal_X8
#1 A_001     NA      1      2      1      0     NA      2      0
#2 A_002      1      2      0      1      2      1      0      0
#3 A_003      2      0     NA      2      0      1      1      0
#4 A_004      0     NA      1      0     NA      2      0     NA