多个条件的if语句和更多的else if语句哪个更好?

3

我是一名数学家,对IT技术不是很了解。我想知道使用具有多个条件的语句还是更多的if / else if语句(如下例所示)更快。考虑到我有一个非常大的数据表(有数百万行),并且在函数中有这些if语句,我将其应用于一列的每一行,并将结果存储在新列中。我只想找出这两种方法之间是否存在差异(更快/更慢/相同)。

    if (is.na(numerator) == TRUE){
        result = 0
    }  else if (numerator == 0){
        result = 0
    }  else if (is.na(denominator) == TRUE){
        result = max
    }  else if (denominator == 0){
        result = max
    }  else {
        result = numerator/denominator
    }

或者

    if (is.na(numerator) == TRUE || numerator == 0){
        result = 0
    }  else if (is.na(denominator) == TRUE || denominator == 0){
        result = max
    }  else {
        result = numerator/denominator
    }

2
从逻辑上讲,这两个版本是相同的,我也不认为性能会有太大差异。我这么说是因为对于给定的一组条件,在任何一个版本中都需要运行相同数量的逻辑检查。所以...使用你认为更易读的版本。我会选择第二个版本,因为每个“result”结果都与导致该结果的所有条件分组在一起。 - Tim Biegeleisen
2
对于初学者来说,不需要执行 is.na(numerator) == TRUEis.na(numerator) 已经返回了 TRUE/FALSE 值。 - Ronak Shah
好的,谢谢 @TimBiegeleisen - Martina Zapletalová
1
也许在这里可以使用 match%in% - Roman Luštrik
嘿,有两个答案。而且两个观点是不同的。那么哪一个或者没有一个能回答你的问题呢? - Darren Tsai
2个回答

1

你好,

为了改进上面的代码形式,我建议你首先考虑出现最多的if语句。这会稍微加快代码的速度,因为在大多数情况下,if else区域不必一直检查到最后。我对此进行了一个非常小的测试:

df <- data.frame(check = sample(c(0,1),size = 10000, replace = T, prob = c(0.1,0.9)),
                 solution = rep(NA, 10000))

start_t <- Sys.time()
for (idx in seq_len(nrow(df))) {
  if(df[idx, "check"]==0) {
    df[idx, "solution"] <- "zero"
  } else if (df[idx, "check"]==1) {
    df[idx, "solution"] <- "one"
  }
}
print(Sys.time()-start_t)

这段代码在我的系统上需要 0.7524531秒的时间差。你可以看到数据框中出现了更多的1而不是0。因此,我将交换检查语句并将"if check == 1"设置在开头。

df <- data.frame(check = sample(c(0,1),size = 10000, replace = T, prob = c(0.1,0.9)),
                 solution = rep(NA, 10000))

start_t <- Sys.time()
for (idx in seq_len(nrow(df))) {
  if(df[idx, "check"]==1) {
    df[idx, "solution"] <- "one"
  } else if (df[idx, "check"]==0) {
    df[idx, "solution"] <- "zero"
  }
}
print(Sys.time()-start_t)

这段代码只需要0.6977119秒的时间差。它比上面的例子快约8%,并且完成相同的工作。希望你明白我的意思,并祝你的代码好运。

1

让我们做一个简单的实验!

虚拟数据

data <- data.frame(numerator = sample(c(0:9, NA), 10000, replace = T),
                   denominator = sample(c(0:9, NA), 10000, replace = T))

由两个“if”条件组成的两个函数

f1 <- function(x){
  num <- x[1] ; denom <- x[2]
  if (is.na(num)){
    result = 0
  }  else if (num == 0){
    result = 0
  }  else if (is.na(denom)){
    result = Inf
  }  else if (denom == 0){
    result = Inf
  }  else {
    result = num / denom
  }
  return(result)
}

f2 <- function(x){
  num <- x[1] ; denom <- x[2]
  if (is.na(num) || num == 0){
    result = 0
  }  else if (is.na(denom) || denom == 0){
    result = Inf
  }  else {
    result = num / denom
  }
  return(result)
}

基准分析

library(microbenchmark)
library(ggplot2)

res <- microbenchmark(
  type1 = {
    quotient1 <- apply(data, 1, f1)
  }, type2 = {
    quotient2 <- apply(data, 1, f2)
  }, times = 100
)

res
# Unit: milliseconds
#  expr      min       lq     mean   median       uq       max
# type1 21.91925 23.70445 27.16314 25.52339 26.90110 122.91710
# type2 22.00139 23.64297 26.11080 25.04576 26.46136  42.62506

autoplot(res)

enter image description here

结论

您可以多次尝试基准测试,发现两个if条件之间没有明显的差异。


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