根据两列的组合,在R中交换数据框中的列值。

4
我有一个关于根据两列的组合来更改数据框中字符值的问题。我将尝试给出一个数据框的示例。
data <- data.frame(A1 = c("A", "T", "C"), A2 = c("C", "G", "T"), 
                   Ind1 = c("AA", "TG", "TT"), Ind2 = c("CA", "GT", "CT"),
                   Ind3 = c("AC", "GG", "TC"))

> data
  A1 A2 Ind1 Ind2 Ind3
1  A  C   AA   CA   AC
2  T  G   TG   GT   GG
3  C  T   TT   CT   TC


我想要更改从Ind1到Ind3列中与列A1和A2的可能组合不匹配的值,例如在第一行中,A1是A,A2是C,所以可能的组合是AA,AC,CC(基于A1和A2的顺序)。因此,Ind2应该是AC而不是CA。
期望的输出应该是这样的:
> data
  A1 A2 Ind1 Ind2 Ind3
1  A  C   AA   AC   AC
2  T  G   TG   TG   GG
3  C  T   TT   CT   CT

我尝试使用switch,但它不起作用。希望能得到帮助,谢谢。
3个回答

5
如果我理解问题正确,并且假设您只有两个字母需要处理,那么只有一种情况需要进行编辑,即当字母的顺序相反时,例如'A2A1'。其他所有情况都是正确的。因此,您可以通过一个简单的ifelse变异来处理这个问题。
data <- data.frame(A1 = c("A", "T", "C"), A2 = c("C", "G", "T"), 
                   Ind1 = c("AA", "TG", "TT"), Ind2 = c("CA", "GT", "CT"),
                   Ind3 = c("AC", "GG", "TC"))

library(dplyr)

data |> 
  mutate(across(starts_with("Ind"), ~ ifelse(.x == paste0(A2, A1), paste0(A1, A2), .x)))
#>   A1 A2 Ind1 Ind2 Ind3
#> 1  A  C   AA   AC   AC
#> 2  T  G   TG   TG   GG
#> 3  C  T   TT   CT   CT

回应楼主的评论,使用“真实”数据:

df2 <- structure(list(chr = "chr11", pos = "74565122", snp_id = "chr11_74565122_C_T_b38",     Allele1 = "C", Allele2 = "T", GTEX_111CU = "TT", GTEX_111YS = "CT",     GTEX_1122O = "TC", GTEX_117XS = "TC", GTEX_117YX = "TC"), class = "data.frame", row.names = c(NA, -1L))

df2
#>     chr      pos                 snp_id Allele1 Allele2 GTEX_111CU GTEX_111YS
#> 1 chr11 74565122 chr11_74565122_C_T_b38       C       T         TT         CT
#>   GTEX_1122O GTEX_117XS GTEX_117YX
#> 1         TC         TC         TC

mutate(df2, across(starts_with("GTEX"), ~ ifelse(.x %in% paste0(Allele2, Allele1), paste0(Allele1, Allele2), .x)))
#>     chr      pos                 snp_id Allele1 Allele2 GTEX_111CU GTEX_111YS
#> 1 chr11 74565122 chr11_74565122_C_T_b38       C       T         TT         CT
#>   GTEX_1122O GTEX_117XS GTEX_117YX
#> 1         CT         CT         CT

谢谢@Peter,我已经尝试了一些真实数据,但似乎不起作用,我不知道为什么。一个真实的例子就是这个dput(df2) structure(list(chr = "chr11", pos = "74565122", snp_id = "chr11_74565122_C_T_b38", Allele1 = "C", Allele2 = "T", GTEX-111CU= "TT",GTEX-111YS= "CT",GTEX-1122O= "TC",GTEX-117XS= "TC",GTEX-117YX= "TC",GTEX-11DXX= "TC",GTEX-11DXZ = "CC"), class = "data.frame", row.names = c(NA, -1L)),我尝试过:df2 %>% mutate(across(starts_with("GTEX"), ~ ifelse(.x %in% paste0(Allele2, Allele1), paste0(Allele1, Allele2), .x))) - undefined
抱歉,评论中的 dput(df2) 对我来说不起作用。我收到了 "错误:...中的意外符号"。 - undefined
请尝试这个:structure(list(chr = "chr11", pos = "74565122", snp_id = "chr11_74565122_C_T_b38", Allele1 = "C", Allele2 = "T", GTEX_111CU = "TT", GTEX_111YS = "CT", GTEX_1122O = "TC", GTEX_117XS = "TC", GTEX_117YX = "TC"), class = "data.frame", row.names = c(NA, -1L)) - undefined
对我来说似乎运行良好。请查看更新的答案。 - undefined
谢谢 @Peter,它起作用了。这是一些软件包冲突的问题。我重新启动了 R 会话,结果非常顺利。 - undefined

3
除了Peter非常聪明的技巧之外,如果你想采用一种更加硬编码的基本R解决方案,你可以逐行“分割”字符串,根据A1和A2中的顺序“排序”,然后“粘贴”回去。这种方法不受字母排序数量的影响。
cols <- grep("Ind", colnames(data))
data[cols] <- 
  apply(data, 1, \(x){
    strsplit(x[cols], "") |> 
      sapply(\(y) factor(y, levels = x[-cols]) |> 
               sort() |> 
               paste(collapse = ""))
  })) |> 
  t()

#   A1 A2 Ind1 Ind2 Ind3
# 1  A  C   AA   AC   AC
# 2  T  G   TG   TG   GG
# 3  C  T   TT   CT   CT

3
我们可以使用正则表达式模式来测试组合的有效性,如果无效,则反转字符串。
library(dplyr)
library(stringr)
data |>
  mutate(across(starts_with("Ind"), \(x) ifelse(
    str_detect(x, pattern = sprintf("^%s{0,2}%s{0,2}$", A1, A2)),
    x,
    stringi::stri_reverse(x))
  ))
#   A1 A2 Ind1 Ind2 Ind3
# 1  A  C   AA   AC   AC
# 2  T  G   TG   TG   GG
# 3  C  T   TT   CT   CT

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