在滑动/平铺窗口上应用时间序列分解(和异常检测)

时间:2019-05-21 12:57:04

标签: r time-series tidyverse purrr anomaly-detection

twitter发布并现已放弃的异常检测方法已分别分叉并维护在anomalize packagehrbrmstr/AnomalyDetection fork中。两者都实现了“整洁”的功能。

工作静态版本

tidyverse_cran_downloads %>% 
  filter(package == "tidyr") %>% 
  ungroup() %>% 
  select(-package) -> one_package_only

one_package_only %>% 
  anomalize::time_decompose(count,
                 merge = TRUE,
                 method = "twitter",
                 frequency = "7 days") -> one_package_only_decomp

one_package_only_decomp %>%
  anomalize::anomalize(remainder, method = "iqr") %>%
  anomalize::time_recompose()


one_package_only_decomp %>% 
  select(date, remainder) %>%
  AnomalyDetection::ad_ts(max_anoms = 0.02,
        direction = 'both')

这些工作符合预期。

我想将平铺窗口上的twitter异常检测过程应用于我的数据集,该结构与anomalize::tidyverse_cran_downloads数据集的结构类似。定期对值进行100多个观察,并按类别定义分组。

tsibble包(代替了旧的tibbletime)具有一种通过slide,tile and stretch以类似purrr的语法应用函数的方法。这可以包括根据purrr返回一个完整的数据帧状对象,另一个对象之内。 (这句话!)

我经历过window function vignette,但是运气不高。

尝试1 slide2

anomalize::decompose_twitter函数接受两个参数,datatarget

tidyverse_cran_downloads %>%
  mutate(
    Monthly_MA = slide2_dfr(
      .x = .,
      .y = count,
      ~ anomalize::decompose_twitter,
      .size = 5
    )
  )

Error: Element 1 has length 3, not 1 or 425. Call rlang :: last_error()to see a backtrace

也许我误解了.x .y语法的工作原理?

尝试2:pmap

my_diag <- function(...) {
  data <- tibble(...)
  fit <- anomalize::decompose_twitter(data = data, target = count)
}

tidyverse_cran_downloads %>%
  nest(-package) %>%
  filter(package %in% c("tidyr", "lubridate")) %>%  # just to make it quick
  mutate(diag = purrr::map(data, ~ pslide_dfr(., my_diag, .size = 7)))

Error in stats::stl(., s.window = "periodic", robust = TRUE) : series is not periodic or has less than two periods

似乎正在运行,但是观察之间的时间间隔因某种原因而消失或未解析?

尝试3:ad_ts

ad_ts仅接受一个参数,因此忽略了我们尚未找到一种分解后计算余数的事实,我应该能够通过slide使用它。它还期望x为:

  

作为两列数据帧的时间序列,其中第一列由时间戳组成,第二列由观测组成。

因此,在嵌套数据后,我们不必对数据做很多事情。

tidyverse_cran_downloads %>%
  nest(-package, .key = "my_data") %>%
  mutate(
    Daily_MA = slide_dfr(
      .f = AnomalyDetection::ad_ts,
      .x = my_data
    )
  )

Error in .f(.x[[i]], ...) : data must be a single data frame.

那么至少要调用该函数,但是要被多个数据帧调用?

我要:

  • 通过twitter算法应用分解过程,然后对其余部分进行异常检测
  • 使用两个异常检测程序包之一或两者结合
  • 将其应用于时间窗口
  • 在分类的分类数据上

我的数据集唯一不同的方法是,我在多个月的期间内,每半小时观察一次 值,实际上我只需要每天重新计算一次异常(即每48次观察一次),窗口会在过去的 30天中进行回顾,以进行分解和检测。

(注:我本来会标记tsibbleanomalize,但我没有代表来制作这些标记)

1 个答案:

答案 0 :(得分:1)

方法2应该能按预期工作?该错误消息与stl()有关,该stl()至少需要两个季节来估算。例如,要运行.size = 7 * 3,每日数据至少需要进行14次观察。增大窗口大小my_decomp <- function(...) { data <- tibble(...) anomalize::decompose_twitter(data, count) } library(dplyr) library(anomalize) tidyverse_cran_downloads %>% group_by(package) %>% tidyr::nest() %>% mutate(diag = purrr::map(data, ~ tsibble::pslide_dfr(., my_decomp, .size = 7 * 3))) #> # A tibble: 15 x 3 #> package data diag #> <chr> <list> <list> #> 1 tidyr <tibble [425 × 2]> <tibble [8,506 × 5]> #> 2 lubridate <tibble [425 × 2]> <tibble [8,506 × 5]> #> 3 dplyr <tibble [425 × 2]> <tibble [8,506 × 5]> #> 4 broom <tibble [425 × 2]> <tibble [8,506 × 5]> #> 5 tidyquant <tibble [425 × 2]> <tibble [8,506 × 5]> #> 6 tidytext <tibble [425 × 2]> <tibble [8,506 × 5]> #> 7 ggplot2 <tibble [425 × 2]> <tibble [8,506 × 5]> #> 8 purrr <tibble [425 × 2]> <tibble [8,506 × 5]> #> 9 glue <tibble [425 × 2]> <tibble [8,506 × 5]> #> 10 stringr <tibble [425 × 2]> <tibble [8,506 × 5]> #> 11 forcats <tibble [425 × 2]> <tibble [8,506 × 5]> #> 12 knitr <tibble [425 × 2]> <tibble [8,506 × 5]> #> 13 readr <tibble [425 × 2]> <tibble [8,506 × 5]> #> 14 tibble <tibble [425 × 2]> <tibble [8,506 × 5]> #> 15 tidyverse <tibble [425 × 2]> <tibble [8,506 × 5]> 很好。

mapper.py