• R语言
  • R script运行结果和手工计算的不一样

无论用论坛大佬之前给的代码,还是自己手搓的奇形怪状的轮子运行Tukey法剔除异常值,结果都是一样的:
exampe

大佬的代码:

Tukey_outlier2<-function(x){
  # caculate Tukey quartiles:
  b<-fivenum(x)
  Tukey_Critical<-b[4]+1.5*(b[4]-b[2])
  
  x[x > Tukey_Critical] <- NA
  return(x)
}

手搓的代码:

# Tukey method outlier rmoval
Tukey_outlier<-function(x){
  n<-length(x)
  x<-sort(x, decreasing = TRUE)
  i<-1
  # caculate Tukey quartiles:
  b<-fivenum(x)
  Tukey_Critical<-b[4]+1.5*(b[4]-b[2])
  
  for(i in 1:n){
    if(x[i]>Tukey_Critical){
      x[i]<-NA
      i<-i+1
    }
    else {
      break
      }
  }
  return(x)
}

运行的结果都是剔除后最大值为18.8

> fivenum(d1)
[1]  0.0  1.8  4.6  8.6 86.8
> 8.6+1.5*(8.6-1.8)
[1] 18.8

但是两个R script跑的结果是18.3,即把计算得到的Tukey_Critical也剔除了:

> r1<-sort(r1)
> head(r1)
[1] 0 0 0 0 0 0
> tail(r1)
[1] 17.4 18.0 18.0 18.0 18.3 18.3

但是看两段代码,不应该剔除啊?

    Sylvanas

    浮点数的问题,读取的“18.8”和计算得到的“18.8”实际上并不是完全一致的。

    x <- readxl::read_xlsx("example.xlsx")
    
    tmp <- fivenum(x$age49RBC)
    tukey_critical <- tmp[4] + 1.5 * (tmp[4] - tmp[2])
    
    identical(x$age49RBC[670], 18.8)
    #> [1] TRUE
    
    identical(tukey_critical, 18.8)
    #> [1] FALSE
    
    format(x$age49RBC[670], digits = 22)
    #> [1] "18.80000000000000071054"
    
    format(tukey_critical, digits = 22)
    #> [1] "18.79999999999999715783"

    <sup>Created on 2024-11-06 with reprex v2.1.1</sup>

    0.8 这个小数本身是不能被二进制精确表示的。就算可以,计算tukey边界的过程中的数也不一定都能被精确表示,所以有可能产生这种因为浮点精度导致的问题。可以看到对于计算机而言,你数据中那个“18.8”,确实是大于你计算得到的那个边界的“18.8”。

    如果这个比较非常有必要,并且你对于自己的数据的精度要求本身是比较明确的,可以考虑用signif()来给定一个精度再进行比较。虽然始终无法在计算机中精确表示0.8,但作为此处的比较的目的应该足够了。

    > format(signif(tukey_critical, digits = 10), digits = 22)
    # [1] "18.80000000000000071054"
    > format(signif(x$age49RBC[670], digits = 10), digits = 22)
    # [1] "18.80000000000000071054"
    > identical(signif(x$age49RBC[670], digits = 10), signif(tukey_critical, digits = 10))
    # [1] TRUE

    可以参考这篇关于浮点数比较的blog

      fenguoerbian 多谢!居然能真的遇上。。。。。。。问题是这种问题咋发现啊。。。这次是因为同事用excel的结果和我的结果不一样才发现,看来以后要手工设置精度了。