18

いくつかの観測値が欠落している時系列の気候データで異常な値を検出しようとしています。ウェブを検索すると、利用可能な多くのアプローチが見つかりました。その中で、トレンドや季節的な要素を取り除いて残りを調べるという意味で、stl 分解は魅力的に思えます。STL: A Seasonal-Trend Decomposition Procedure Based on Loessを読むと、 stl は、変動性を割り当てる設定を柔軟に決定でき、外れ値の影響を受けず、欠損値があっても適用できるように見えます。ただし、4年間の観察とhttp://stat.ethz.ch/R-manual/R-patched/library/stats/html/stl.htmlに従ってすべてのパラメーターを定義して、Rに適用しようとすると、私はエラーが発生しました:

時系列には内部 NA が含まれます

いつna.action = na.omit、そして

シリーズは周期的ではないか、周期が 2 つ未満です

いつna.action = na.exclude

周波数が正しく定義されていることを再確認しました。ブログで関連する質問を見たことがありますが、これを解決できる提案は見つかりませんでした。値が欠落しているシリーズで stl を適用することはできませんか? 私はアーティファクトを導入したくないので(結果として検出...)、それらを補間することに非常に消極的です。同じ理由で、代わりに ARIMA アプローチを使用することがどれほど賢明かはわかりません (また、欠損値が依然として問題になる場合)。

値が欠落しているシリーズで stl を適用する方法を知っている場合、または私の選択が方法論的に適切でないと思われる場合、またはより良い提案がある場合は共有してください。私はこの分野ではまったくの新人で、(一見...) 関連情報の山に圧倒されています。

4

2 に答える 2

20

はじめstl_

x <- na.action(as.ts(x))

そしてその直後

period <- frequency(x)
if (period < 2 || n <= 2 * period) 
    stop("series is not periodic or has less than two periods")

つまり、(そうでない場合) の後にオブジェクトであることがstl期待xされます。まずはチェックしてみましょう。tsna.action(as.ts(x))period == 1na.omitna.exclude

明らかに、getAnywhere("na.omit.ts")私たちが見つけた最後に

if (any(is.na(object))) 
    stop("time series contains internal NAs")

これは簡単で、何もできません (オブジェクトからna.omit除外されません)。観測を除外するようになりましたが、クラスのオブジェクトを返します:NAstsgetAnywhere("na.exclude.default")NAexclude

    attr(omit, "class") <- "exclude"

これは別の状況です。上記のように、 であるとstl予想na.action(as.ts(x))されますtsna.exclude(as.ts(x))、クラスはexcludeです。

したがって、NAs除外に満足している場合は、たとえば

nottem[3] <- NA
frequency(nottem)
# [1] 12
na.new <- function(x) ts(na.exclude(x), frequency = 12)
stl(nottem, na.action = na.new, s.window = "per")

動作します。一般に、は値 (つまり) ではstl機能せず、Fortran ではより深くクラッシュします (完全なソース コードはこちらを参照してください)。NAna.action = na.pass

z <- .Fortran(C_stl, ...

の代替na.newは楽しいものではありません:

  • na.contaguous- 時系列オブジェクト内の非欠損値の最長連続ストレッチを見つけます。
  • na.approxna.locffromzooまたはその他の補間関数。
  • これについてはよくわかりませんが、別の Fortran 実装が Python 用にここにあります。このモジュールが実際に欠損値を許可する場合は、Python を使用して、いくつかの変更後にソースから R をインストールすることができます。

論文でわかるように、 を呼び出す前に時系列に適用できる欠損値の単純な手順 (最初にそれらを概算するなど) はありませんstlしたがって、元の実装が非常に長いという事実を考慮して、まったく新しい実装以外の代替案について考えます。

更新:がからのものであるNAs可能性がある場合、多くの面で非常に最適な選択であるため、そのパフォーマンスを確認してみましょう。つまり、 の結果を完全なデータセットと比較し、いくつかのを使用して を使用した場合の結果を比較します。私は正確さの尺度としてMAPEを使用していますが、季節成分と残りがゼロを横切り、結果を歪めるため、トレンドのみに使用しています. の位置はランダムに選択されます。na.approxzoostlNAsna.approxNAs

library(zoo)
library(plyr)
library(reshape)
library(ggplot2)
mape <- function(f, x) colMeans(abs(1 - f / x) * 100)

stlCheck <- function(data, p = 3, ...){
  set.seed(20130201)
  pos <- lapply(3^(0:p), function(x) sample(1:length(data), x))
  datasetsNA <- lapply(pos, function(x) {data[x] <- NA; data})
  original <- data.frame(stl(data, ...)$time.series, stringsAsFactors = FALSE)
  original$id <- "Original"
  datasetsNA <- lapply(datasetsNA, function(x) 
    data.frame(stl(x, na.action = na.approx, ...)$time.series, 
               id = paste(sum(is.na(x)), "NAs"), 
               stringsAsFactors = FALSE))
  stlAll <- rbind.fill(c(list(original), datasetsNA))
  stlAll$Date <- time(data)
  stlAll <- melt(stlAll, id.var = c("id", "Date"))
  results <- data.frame(trend = sapply(lapply(datasetsNA, '[', i = "trend"), mape, original[, "trend"]))
  results$id <- paste(3^(0:p), "NAs")
  results <- melt(results, id.var = "id")
  results$x <- min(stlAll$Date) + diff(range(stlAll$Date)) / 4
  results$y <- min(original[, "trend"]) + diff(range(original[, "trend"])) / (4 * p) * (0:p)
  results$value <- round(results$value, 2)
  ggplot(stlAll, aes(x = Date, y = value, colour = id, group = id)) + geom_line() + 
    facet_wrap(~ variable, scales = "free_y") + theme_bw() +
    theme(legend.title = element_blank(), strip.background = element_rect(fill = "white")) + 
    labs(x = NULL, y = NULL) + scale_colour_brewer(palette = "Set1") +
    lapply(unique(results$id), function(z)
      geom_text(data = results, colour = "black", size = 3,
                aes(x = x, y = y, label = paste0("MAPE (", id, "): ", value, "%"))))
}

nottem、240回の観測

stlCheck(nottem, s.window = 4, t.window = 50, t.jump = 1)

ここに画像の説明を入力

co2、468回の観測

stlCheck(log(co2), s.window = 21)

ここに画像の説明を入力

mdeaths、72回の観測

stlCheck(mdeaths, s.window = "per")

ここに画像の説明を入力

視覚的にはケース 1 と 3 の傾向にいくつかの違いが見られます。しかし、これらの違いは 1 ではかなり小さく、サンプル サイズ (72) を考慮すると 3 では満足のいくものです。

于 2013-01-31T00:28:24.773 に答える
7

これは古い質問であることを理解stlしてstlplusください。こちらが github のホームページです。を使用して CRAN から、install.packages("stlplus")または を使用して github から直接インストールできdevtools::install_github("hafen/stlplus")ます。

于 2016-04-12T20:56:20.497 に答える