【问题标题】:How to detect outliers (typo jumps) in time-series data by group and correct/impute them?如何按组检测时间序列数据中的异常值(错别字跳跃)并纠正/估算它们?
【发布时间】:2021-01-08 05:46:35
【问题描述】:

我有一个类似这样的面板数据框:

df <- data.frame(
  year = c(2012L, 2013L, 2014L, 2015L, 2016L, 2017L, 2012L, 2013L, 2014L, 2015L,
           2016L, 2017L),
  id = c(1L, 1L, 1L, 1L, 1L, 1L, 2L, 2L, 2L, 2L, 2L, 2L),
  c = c(7.8L, 8.1L, 51L, 8.2L, 9L, 10L, 7.8L, 8.1L, 8.2L, 0.1L, 9.5L, 10L)
)

df
#    year id    c
# 1  2012  1  7.8
# 2  2013  1  8.1
# 3  2014  1 51.0
# 4  2015  1  8.2
# 5  2016  1  9.0
# 6  2017  1 10.0
# 7  2012  2  7.8
# 8  2013  2  8.1
# 9  2014  2  8.2
# 10 2015  2  0.1
# 11 2016  2  9.5
# 12 2017  2 10.0

我的数据中有某些拼写错误,其中数据中有明显的跳跃或下降,类似于 c 列中的 51 和 0.1。我希望能够识别每个组中的这些错误,并通过取错误前后的平均值来调整它们。我想将这些错误跳跃或下降定义为至少大于周围值的四或小于四分之一的任何值。

【问题讨论】:

    标签: r data-cleaning outliers


    【解决方案1】:

    使用IQR()1.5*(inter quartile range) 之外的值识别为异常值,将它们设置为NA,并使用approx 进行线性插值。 ave 按组执行此操作。

    outfun <- function(x) {
      q <- quantile(x, c(1/4, 3/4))
      bounds <- c(q[1] - IQR(x) * 1.5, IQR(x) * 1.5 + q[2])
      out <- x < bounds[1] | x > bounds[2]
      x[out] <- NA
      approx(seq(x), x, seq(x))$y
    }
    
    df <- transform(df, c.new=ave(c, id, FUN=outfun))
    df
    #    year id    c c.new
    # 1  2012  1  7.8  7.80
    # 2  2013  1  8.1  8.10
    # 3  2014  1 51.0  8.15
    # 4  2015  1  8.2  8.20
    # 5  2016  1  9.0  9.00
    # 6  2017  1 10.0 10.00
    # 7  2012  2  7.8  7.80
    # 8  2013  2  8.1  8.10
    # 9  2014  2  8.2  8.20
    # 10 2015  2  0.1  8.85
    # 11 2016  2  9.5  9.50
    # 12 2017  2 10.0 10.00
    

    如果数据中有缺失,我们只需在quantile()IQR() 中设置na.rm=TRUE。然而,为了避免这些也被插入到结果中(尽管可能是一个特征),我们希望通过简单地预先识别它们来恢复它们。不幸的是,这似乎不适用于ave,但我们可以使用by

    outfun2 <- function(x) {
      na <- is.na(x)
      q <- quantile(x, c(1/4, 3/4), na.rm=TRUE)
      bounds <- c(q[1] - IQR(x, na.rm=TRUE) * 1.5, IQR(x, na.rm=TRUE) * 1.5 + q[2])
      out <- x < bounds[1] | x > bounds[2]
      x[which(out)] <- NA
      res <- approx(seq(x), x, seq(x))$y
      res[na] <- NA
      res
    }
    
    df[8, 3] <- NA  ## produce missing
    
    df <- do.call(rbind, by(df, df$id, function(x) transform(x, c.new=outfun2(x$c))))
    df
    #      year id    c
    # 1.1  2012  1  7.8
    # 1.2  2013  1  8.1
    # 1.3  2014  1 51.0
    # 1.4  2015  1  8.2
    # 1.5  2016  1  9.0
    # 1.6  2017  1 10.0
    # 2.7  2012  2  7.8
    # 2.8  2013  2   NA
    # 2.9  2014  2  8.2
    # 2.10 2015  2  0.1
    # 2.11 2016  2  9.5
    # 2.12 2017  2 10.0
    

    【讨论】:

    • 非常感谢您的回复。在我有超过 80k 个 id 的实际数据集中,每个 id 的长度可能不同,因此每个 id 可以在不同的年份开始和结束。当我尝试应用您的代码时,出现以下错误: xy.coords(x, y, setLab = FALSE) 中的错误:'x' 和 'y' 长度不同
    • 不客气@ErwinRhine,在这种情况下,您介意提供一个模拟原始数据的最小数据集吗?请关注社区的guidelines for R,干杯。
    猜你喜欢
    • 2019-09-25
    • 2015-07-23
    • 1970-01-01
    • 2014-09-05
    • 2021-07-27
    • 1970-01-01
    • 2018-07-11
    • 2021-01-19
    • 2020-09-26
    相关资源
    最近更新 更多