具有或不具有for的双阈值(开/关)

时间:2009-12-03 14:01:24

标签: r

我正在编写的函数指定物理开关的行为:如果值超过上限阈值,则应该打开;如果值低于下限阈值,则可以再次关闭。类似的逻辑将描述家用烤箱中的普通恒温器。显然我希望它能够用于向量,这就是重点!

所以,如果我有数据

S <- c(50, 100, 150, 180, 210, 200, 190, 182, 175, 185, 195, 205)

我的功能告诉烤箱温度是否正常。 “打开烤箱”的逻辑反转。

R> thresholdOnOff(S, 180, 200)
 [1] FALSE FALSE FALSE FALSE  TRUE  TRUE  TRUE  TRUE FALSE FALSE FALSE  TRUE

关于编程风格的问题:我首先尝试使用'apply'函数编写它但我忘记考虑环境...所以我写了一个带有'for'循环的工作版本 - 我不喜欢,然后记得环境,我不确定这两个版本:

thresholdOnOff <- local( {
  ## following the R inferno
  f <- function(series, lower, upper, initialValue=FALSE) {
    status <<- initialValue

    switchOnOff <- function(x) {
      if(x > upper)
        status <<- TRUE
      if(x < lower)
        status <<- FALSE
      return(status)
    }

    sapply(series, switchOnOff)
  }
} )


thresholdOnOff <- function(series, lower, upper, initialValue=FALSE) {
  ## just guessing and reading from the documentation
  status <- initialValue

  switchOnOff <- function(x) {
    if(x > upper)
      assign('status', TRUE, inherits=TRUE)
    if(x < lower)
      assign('status', FALSE, inherits=TRUE)
    return(status)
  }

  sapply(series, switchOnOff)
}

2 个答案:

答案 0 :(得分:1)

这是一个没有循环的有效解决方案:

library("zoo")
S <- c(50, 100, 150, 180, 210, 200, 190, 182, 175, 185, 195, 205)

thresholdOnOff <- function(x, low, high, initial.value=FALSE) {
    require("zoo")
    s <- rep(NA, length(x))
    s[1] <- initial.value
    s[x > high] <- TRUE
    s[x < low] <- FALSE
    return(na.locf(s))
}

thresholdOnOff(S, 180, 200)

或者,您可以在一行中使用ifelse来解决此问题,但如果您拥有大数据,那么速度会慢得多:

na.locf(ifelse(S > 200, TRUE, ifelse(S < 180, FALSE, NA)))

答案 1 :(得分:1)

坚持使用for循环。如果这些值不是独立的,则使用apply没有任何优势。

除非你有充分的理由,否则你应该避免在功能上产生副作用。