在 R 中切换 DataFrame 中的列值,基于两列的组合

switch column values in dataframe in R based in combination of two columns

提问人:user2380782 提问时间:11/16/2023 更新时间:11/17/2023 访问量:57

问:

我有一个关于根据基于两列的组合更改 data.frame 中的字符值的问题。我将尝试举一个例子来说明 de data.frame 的外观

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,这些值与列和 和 的可能组合不匹配,例如在第一行中,是 和 是 ,因此可能的组合将是 、 (组合基于 和 按该顺序)。因此,Ind2 应代替 .A1A2A1AA2CAAACCCA1A2ACCA

所需的输出将是这样的:

> 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

R 数据帧

评论


答:

5赞 Peter 11/16/2023 #1

如果我正确理解了这个问题,并且假设您只有两个字母要处理,那么只有一个情况需要编辑;也就是说,当字母的顺序相反时,即“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

作为对OP评论的回应,使用“真实”数据:


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

评论

0赞 user2380782 11/17/2023
谢谢@Peter,我尝试了一些真实数据,但它似乎不起作用,我不知道为什么。一个真实的例子是 GTEX-111CU' = “TT”, = “CT”, = “TC”, = “TC”, = “TC”, = “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)))'dput(df2) structure(list(chr = "chr11", pos = "74565122", snp_id = "chr11_74565122_C_T_b38", Allele1 = "C", Allele2 = "T", GTEX-111YSGTEX-1122OGTEX-117XSGTEX-117YXGTEX-11DXXGTEX-11DXZ, I have tried:
0赞 Peter 11/17/2023
对不起,评论中的对我不起作用。我收到“错误:意外的符号......”dput(df2)
0赞 user2380782 11/17/2023
请试试这个: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))
0赞 Peter 11/17/2023
似乎对我来说工作得很好。请参阅更新的答案。
0赞 user2380782 11/17/2023
谢谢@Peter,它奏效了。这是一些软件包冲突的问题。我重新启动了 R 会话并像魅力一样工作
3赞 Maël 11/16/2023 #2

除了 Peter 非常聪明的技巧之外,如果你想在 base R 中寻求一个更硬编码的解决方案,你可以按照 A1 和 A2 中的顺序逐行处理字符串,然后返回。这与要订购的字母数量无关:splitsortpaste

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赞 Gregor Thomas 11/16/2023 #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