Существует немало пакетов R, доступных для нелинейного анализа временных рядов, но иногда вам нужно кодировать собственные модели. Вот простой пример, чтобы показать, как это можно сделать.
Модель представляет собой пороговую авторегрессию первого порядка:
где гауссовский ряд белого шума с дисперсией . Следующая функция будет генерировать случайные данные из этой модели.
simnlts <- function(n, alpha, beta, r, sigma, gamma, burnin=100) { # Generate noise e <- rnorm(n+burnin, 0, sigma) # Create space for y y <- numeric(n+burnin) # Generate time series for(i in 2:(n+burnin)) { if(y[i-1] <= r) y[i] <- alpha*y[i-1] + e[i] else y[i] <- beta*y[i-1] + gamma*e[i] } # Throw away first burnin values y <- ts(y[-(1:burnin)]) # Return result return(y) }
Параметр «прожигания» позволяет первому значению ряда быть случайным извлечением из стационарного распределения процесса (при условии, что оно стационарно).
Мы оценим модель путем минимизации суммы квадратов ошибок в обоих режимах. Другие подходы, которые учитывают различные отклонения в двух режимах, могут быть лучше, но полезно сохранить их простыми, по крайней мере, на начальном этапе. Следующая функция использует нелинейный оптимизатор для оценки , и . Чтобы обеспечить хорошие начальные значения, мы начинаем оптимизацию с и устанавливаем начальное значение как среднее из наблюдаемых данных.
fitnlts <- function(x) { ss <- function(par,x) { alpha <- par[1] beta <- par[2] r <- par[3] n <- length(x) # Check that each regime has at least 10% of observations if(sum(x<=r) < n/10 | sum(x>r) < n/10) return(1e20) e1 <- x[2:n] - alpha*x[1:(n-1)] e2 <- x[2:n] - beta*x[1:(n-1)] regime1 <- (x[1:(n-1)] <= r) e <- e1*(regime1) + e2*(!regime1) return(sum(e^2)) } fit <- optim(c(0,0,mean(x)),ss,x=x,control=list(maxit=1000)) if(fit$convergence > 0) return(rep(NA,3)) else return(c(alpha=fit$par[1],beta=fit$par[2],r=fit$par[3])) }
Здесь есть несколько вещей, на которые стоит обратить внимание.
- Я использовал функцию внутри функции.
ss
Функция вычисляет сумму квадратов ошибок. Было бы возможно определить это снаружиfitnlts
, но, поскольку я не нуждаюсь в этом для каких-либо других целей, лучше определить его локально. - Иногда оптимизатор не сходится, а затем
fitnlts
возвращает пропущенные значения. - Я избегал использования цикла, вычисляя ошибки в обоих режимах. Это намного быстрее, чем альтернативы.
- Если за пределами диапазона данных, либо либо будет неопознанным. Чтобы избежать этой проблемы, я заставляю быть таким, чтобы каждый режим содержал не менее 10% данных. Это произвольное значение, но оно делает оценку более стабильной.
- Оптимизируемая функция не является непрерывной в направлении. Это приведет к сбою оптимизаторов на основе градиента, но используемый здесь оптимизатор Nelder-Mead относительно устойчив к таким проблемам.
- Эта конкретная модель может быть более эффективно оценена путем использования условной линейности. Например, мы можем зациклить сетку значений (например, в середине между последовательными упорядоченными наблюдениями) и использовать линейную регрессию для других параметров. Но приведенный выше подход носит более общий характер и может быть адаптирован к другим нелинейным моделям временных рядов.
Функции можно использовать следующим образом (с некоторыми примерами параметров):
y <- simnlts(100, 0.5, -1.8, -1, 1, 2) fitnlts(y)
Аналогичный подход может быть использован для других моделей временных рядов.