记住序列的最后一个 "correct" 值(用于去除异常值)

Memorize the last "correct" value of a sequence (for removing outliers)

我在函数中遇到了一个小问题。 它的目的是删除我在 data.frame 中检测到的异常值。当与之前的正确值差异太大时(例如 c(1,2,3,20,30,4,5,6):“20”和“30”是异常值),它们就会被检测到。但是我的数据比这复杂得多。

我的想法是将我列的前两个数值视为 "correct"。然后,我想测试每个下一个值:

这是我的函数和假 DF 的示例:

myts <- data.frame(x=c(12,12,35,39,46,45,33,5,26,28,29,34,15,15),z=NA) 

test <- function(x){
st1 = NULL
temp <- st1[1] <- x[1]
st1 <- numeric(length(x))
for (i in 2:(length(x))){ 
    if((!is.na(x[i])) & (!is.na(x[i-1]))& (abs((x[i])-(temp)) > 20)){
st1[i] <- 1
} } 
return(st1)
}

myts[,2] <- apply(as.data.frame(myts[,1]),2,test)  
myts[,2] <- as.numeric(myts[,2]) 

它几乎完成了工作,但问题是没有记住最后一个正确的值。它仍然从第一个正确的值开始进行测试。 因此,未检测到我示例中的第 9 行到第 11 行。我让你想象一下 500,000 行上的问题 data.frame.

我该如何解决这个小问题?其余功能可能没问题。

您只需更新 temp 任何非异常值的指数:

test <- function(x) {
  temp <- x[1]
  st1 <- numeric(length(x))
  for (i in 2:(length(x))){ 
    if(!is.na(x[i]) & !is.na(x[i-1]) & abs(x[i]-temp) > 20) {
      st1[i] <- 1
    } else {
      temp <- x[i]
    }
  } 
  return(st1)
}

myts[,2] <- apply(as.data.frame(myts[,1]),2,test)  
myts[,2] <- as.numeric(myts[,2])
myts
#     x z
# 1  12 0
# 2  12 0
# 3  35 1
# 4  39 1
# 5  46 1
# 6  45 1
# 7  33 1
# 8   5 0
# 9  26 1
# 10 28 1
# 11 29 1
# 12 34 1
# 13 15 0
# 14 15 0

需要注意的一件事是,与向量化函数相比,R 中的 for 循环会非常慢。但是,由于向量中的每个元素都以复杂的方式依赖于之前的元素,因此很难使用 R 的内置向量化函数来有效地计算向量。您可以将此代码几乎逐字地转换为 C++,并使用 Rcpp 包重新获得效率:

library(Rcpp)
test2 <- cppFunction(
"IntegerVector test2(NumericVector x) {
  const int n = x.length();
  IntegerVector st1(n, 0);
  double temp = x[0];
  for (int i=1; i < n; ++i) {
    if (!R_IsNA(x[i]) && !R_IsNA(x[i]) && fabs(x[i] - temp) > 20.0) {
      st1[i] = 1;
    } else {
      temp = x[i];
    }
  }
  return st1;
}")
all.equal(test(myts[,1]), test2(myts[,1]))
# [1] TRUE

# Benchmark on large vector with some NA values:
set.seed(144)
large.vec <- c(0, sample(c(1:50, NA), 1000000, replace=T))
all.equal(test(large.vec), test2(large.vec))
# [1] TRUE
library(microbenchmark)
microbenchmark(test(large.vec), test2(large.vec))
# Unit: milliseconds
#              expr         min          lq       mean     median         uq        max neval
#   test(large.vec) 2343.684164 2468.873079 2667.67970 2604.22954 2747.23919 3753.54901   100
#  test2(large.vec)    9.596752    9.864069   10.97127   10.23011   11.68708   16.67855   100

Rcpp 代码在长度为 100 万的向量上大约快 250 倍。根据您的用例,这种加速可能重要也可能不重要。