【问题标题】:Replace for-loop using apply in data-frame在数据框中使用 apply 替换 for 循环
【发布时间】:2016-03-31 16:14:24
【问题描述】:

我正在尝试提高我必须相对经常运行的基本任务的性能。我有一个看起来像这样的数据框“测试”:

        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 <- 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”,哪一个为空(如果有),并返回一个可以分配给第三列的值。

现在我一直在使用 for 循环在“测试”中使用它:

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

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

【问题讨论】:

    标签: r performance for-loop apply


    【解决方案1】:

    你可以使用应用函数

    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"
    

    【讨论】:

      【解决方案2】:

      感谢所有给出答案的人。实际上,我使用 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 的建议。

      【讨论】:

        【解决方案3】:

        您可能想试试这个。它应该会给您带来性能提升。

        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"))))

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2019-03-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多