在数据框中使用应用替换 for 循环

Replace for-loop using apply in data-frame

我正在尝试提高我必须经常 运行 完成的基本任务的性能。我有一个数据框 'test',看起来像这样:

        pair_id rr  im  db
    1   A0A0B5JQ66_A0A0B5JFG2   NA  yes NA
    2   A0A024RA76_A0A024RA76   NA  yes NA
    3   A0A068F1B9_A0A068F1B9   NA  yes NA
    4   A0A098_A0A098   NA  yes NA
    5   A0A0B5JJY8_A0A0B5JFB4   yes NA  NA
    6   A0A0B5JK11_A0A0B5JK11   yes NA  NA
    7   A0A0B5JK74_A0A0B5JFG2   yes NA  NA
    8   A0A0B5JK74_A0A0B5JK74   yes NA  NA
    9   A0A0B5JKA2_A0A0B5JF96   NA  yes NA
    10  A0A0B5JKA2_A0A0B5JK74   NA  yes NA
    11  A0A0B5JPZ7_A0A0B5JFG2   yes yes NA
    12  A0A0B5JPZ7_A0A0B5JK74   NA  yes NA
    13  A0A0B5JPZ7_A0A0B5JKA2   NA  yes NA
    14  A0A0B5JPZ7_A0A0B5JPZ7   NA  yes NA
    15  A0A0B5JQ10_A0A0B5JK95   yes yes NA
    16  A0A0B5JQ14_A0A0B5JFB4   NA  yes NA
    17  A0A0B5JQ25_A0A0B5JFB4   NA  yes NA
    18  A0A0B5JQ25_A0A0B5JFB8   NA  yes NA
    19  A0A0B5JQ25_A0A0B5JK29   NA  yes NA
    20  A0A0B5JQ29_A0A0B5JQ14   yes NA  NA

我需要比较第 2 列和第 3 列('rr' 和 'im'),然后根据此比较为第 4 列设置一个值。为此,我创建了以下名为 'compare' 的函数:

compare <- function(v){
  if (v[1]=="yes" & is.na(v[2])){
    db <- "rr"
  }
  else if (v[2]=="yes" & is.na(v[1])){
    db <- "im"
  }
  else if (v[1]=="yes" & v[2]=="yes"){
    db <- "both"
  }
  else {
    db <- "check"
  }
  db
}

它只需要一个包含两个元素的向量作为输入,检查哪个元素的值为 "yes",哪个元素为空(如果有的话),returns 一个可以赋给的值第三列。

现在我一直在 'test' 使用 for 循环来使用它:

for (i in 1:nrow(test)){
        test[i,]$db <- compare(test[i,2:3])
} 

然而,当我的数据帧变大时(我必须管理一些超过 700000 行的数据)并且需要花费大量时间来计算时,此解决方案效率非常低。我一直在尝试在 'apply' 系列的不同变体下使用我的函数,但无法使其工作,因为我是 R 的新手并且我对这组函数没有太多经验。关于可以提高性能的替代方案的任何提示?

您可以使用应用函数

test$db <- apply(test[, 2:3], compare)

但这不会快很多

更快的解决方案是使用矢量化

test$db <- "check" #make column of default values
test$db[test$rr == "yes" & is.na(test$im)] <- "rr"
test$db[test$im == "yes" & is.na(test$rr)] <- "im"
test$db[test$rr == "yes" & test$im == "yes"] <- "both"

您可能想试试这个。它应该可以提升您的性能。

library(dplyr) test <- mutate(test, db = ifelse(rr == "yes" & is.na(im), "rr", ifelse(is.na(rr) & im == "yes", "im", ifelse(rr == "yes" & im == "yes", "both", "check"))))

感谢所有给出答案的人。实际上,我使用 10000 行长的测试数据帧尝试并比较了原始 for 循环建议的不同方法。这是我得到的:

                   user   system elapsed
    ptm_loop      4.831    0.551   5.390
    ptm_apply     0.055    0.002   0.056
    ptm_vect      0.046    0.001   0.046
    ptm_dplyr     0.009    0.000   0.009

ptm 当然是处理时间的缩写,每个建议的解决方案都带有描述性缩写。所有这些都显着提高了性能,但到目前为止,最快的解决方案似乎是 Psidom 提出的基于 dplyr 的建议。