Tren data seri waktu yang tidak teratur

8

Saya memiliki dataset pengukuran suhu air yang diambil dari badan air besar dengan interval tidak teratur selama beberapa dekade. (Galveston Bay, TX jika Anda tertarik)

Inilah kepala data:

  STATION_ID     DATE  TIME LATITUDE LONGITUDE YEAR MONTH DAY SEASON MEASUREMENT
1      13296  6/20/91 11:04 29.50889 -94.75806 1991     6  20 Summer        28.0
2      13296  3/17/92  9:30 29.50889 -94.75806 1992     3  17 Spring        20.1
3      13296  9/23/91 11:24 29.50889 -94.75806 1991     9  23   Fall        26.0
4      13296  9/23/91 11:24 29.50889 -94.75806 1991     9  23   Fall        26.0
5      13296  6/20/91 11:04 29.50889 -94.75806 1991     6  20 Summer        28.0
6      13296 12/17/91 10:15 29.50889 -94.75806 1991    12  17 Winter        13.0

(PENGUKURAN adalah pengukuran suhu yang menarik.)

Set lengkap tersedia di sini: https://github.com/jscarlton/galvBayData/blob/master/gbtemp.csv

Saya ingin menghapus efek variasi musiman untuk mengamati tren (jika ada) pada suhu dari waktu ke waktu. Apakah rangkaian waktu mendekomposisi cara terbaik untuk melakukan ini? Bagaimana saya menangani fakta bahwa pengukuran tidak dilakukan secara berkala? Saya berharap ada paket R untuk jenis analisis ini, meskipun Python atau Stata juga akan baik-baik saja. 

(Catatan: untuk analisis ini, saya memilih untuk mengabaikan variabilitas spasial dalam pengukuran. Idealnya, saya juga akan menjelaskannya, tetapi saya pikir melakukan hal itu akan sangat rumit.)

griseus
sumber

Jawaban:

19

Daripada mencoba menguraikan deret waktu secara eksplisit, saya lebih suka menyarankan Anda memodelkan data spatio-temporal karena, seperti yang akan Anda lihat di bawah ini, tren jangka panjang kemungkinan bervariasi secara spasial, tren musiman bervariasi dengan tren jangka panjang dan secara spasial.

Saya telah menemukan bahwa model aditif umum (GAM) adalah model yang baik untuk pemasangan seri waktu tidak beraturan seperti yang Anda gambarkan.

Di bawah ini saya menggambarkan model cepat yang saya siapkan untuk data lengkap dari formulir berikut

E(ysaya)=α+f1(Rubahsaya)+f2(Doysaya)+f3(Tahunsaya)+f4(xsaya,ysaya)+f5(Doysaya,Tahunsaya)+f6(xsaya,ysaya,Rubahsaya)+f7(xsaya,ysaya,Doysaya)+f8(xsaya,ysaya,Tahunsaya)

dimana

  • α adalah model mencegat,
  • f1(Rubahsaya) adalah fungsi waktu yang lancar,
  • f2(Doysaya) adalah fungsi hari yang lancar,
  • f3(Tahunsaya) adalah fungsi tahun yang lancar,
  • f4(xsaya,ysaya) adalah kelancaran 2D garis bujur dan lintang,
  • f5(Doysaya,Tahunsaya) adalah kelancaran produk tensor dari tahun ke tahun,
  • f6(xsaya,ysaya,Rubahsaya) produk tensor kelancaran lokasi & waktu dalam sehari
  • f7(xsaya,ysaya,Doysaya) kelancaran produk tensor lokasi hari tahun &
  • f8(xsaya,ysaya,Tahunsaya produk tensor kelancaran lokasi & tahun

Secara efektif, empat smooths pertama adalah efek utama

  1. waktu hari,
  2. musim,
  3. tren jangka panjang,
  4. variasi spasial

sementara empat produk tensor yang tersisa memodelkan interaksi yang halus antara kovariat yang dinyatakan, model mana

  1. bagaimana pola musiman suhu bervariasi dari waktu ke waktu,
  2. bagaimana efek waktu hari bervariasi secara spasial,
  3. bagaimana efek musiman bervariasi secara spasial, dan
  4. bagaimana tren jangka panjang bervariasi secara spasial

Data dimuat ke R dan dipijat sedikit dengan kode berikut

library('mgcv')
library('ggplot2')
library('viridis')
theme_set(theme_bw())
library('gganimate')

galveston <- read.csv('gbtemp.csv')
galveston <- transform(galveston,
                       datetime = as.POSIXct(paste(DATE, TIME),
                                             format = '%m/%d/%y %H:%M', tz = "CDT"))
galveston <- transform(galveston,
                       STATION_ID = factor(STATION_ID),
                       DoY = as.numeric(format(datetime, format = '%j')),
                       ToD = as.numeric(format(datetime, format = '%H')) +
                            (as.numeric(format(datetime, format = '%M')) / 60))

Model itu sendiri dilengkapi menggunakan bam()fungsi yang dirancang untuk menyesuaikan GAM ke set data yang lebih besar seperti ini. Anda dapat menggunakan gam()untuk model ini juga, tetapi akan membutuhkan waktu agak lebih lama.

knots <- list(DoY = c(0.5, 366.5))
M <- list(c(1, 0.5), NA)
m <- bam(MEASUREMENT ~
         s(ToD, k = 10) +
         s(DoY, k = 30, bs = 'cc') +
         s(YEAR, k = 30) +
         s(LONGITUDE, LATITUDE, k = 100, bs = 'ds', m = c(1, 0.5)) +
         ti(DoY, YEAR, bs = c('cc', 'tp'), k = c(15, 15)) +
         ti(LONGITUDE, LATITUDE, ToD, d = c(2,1), bs = c('ds','tp'), 
            m = M, k = c(20, 10)) +
         ti(LONGITUDE, LATITUDE, DoY, d = c(2,1), bs = c('ds','cc'),
            m = M, k = c(25, 15)) +
         ti(LONGITUDE, LATITUDE, YEAR, d = c(2,1), bs = c('ds','tp'),
            m = M), k = c(25, 15)),
         data = galveston, method = 'fREML', knots = knots,
         nthreads = 4, discrete = TRUE)

The s()istilah adalah efek utama, sementara ti()istilah yang tensor produk interaksi menghaluskan mana efek utama dari kovariat bernama telah dihapus dari dasar. Ini ti()menghaluskan adalah cara untuk memasukkan interaksi dari variabel yang dinyatakan dengan cara numerik yang stabil.

The knotsobjek hanya pengaturan titik akhir dari siklus yang halus saya gunakan untuk hari berlaku tahun - kami ingin 23:59 pada 31 Desember untuk bergabung dengan lancar dengan 00:01 1 Jan. Ini menyumbang sampai batas tertentu untuk tahun kabisat.

Ringkasan model menunjukkan semua efek ini signifikan;

> summary(m)

Family: gaussian 
Link function: identity 

Formula:
MEASUREMENT ~ s(ToD, k = 10) + s(DoY, k = 12, bs = "cc") + s(YEAR, 
    k = 30) + s(LONGITUDE, LATITUDE, k = 100, bs = "ds", m = c(1, 
    0.5)) + ti(DoY, YEAR, bs = c("cc", "tp"), k = c(12, 15)) + 
    ti(LONGITUDE, LATITUDE, ToD, d = c(2, 1), bs = c("ds", "tp"), 
        m = list(c(1, 0.5), NA), k = c(20, 10)) + ti(LONGITUDE, 
    LATITUDE, DoY, d = c(2, 1), bs = c("ds", "cc"), m = list(c(1, 
        0.5), NA), k = c(25, 12)) + ti(LONGITUDE, LATITUDE, YEAR, 
    d = c(2, 1), bs = c("ds", "tp"), m = list(c(1, 0.5), NA), 
    k = c(25, 15))

Parametric coefficients:
            Estimate Std. Error t value Pr(>|t|)    
(Intercept) 21.75561    0.07508   289.8   <2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Approximate significance of smooth terms:
                                edf  Ref.df        F  p-value    
s(ToD)                        3.036   3.696    5.956 0.000189 ***
s(DoY)                        9.580  10.000 3520.098  < 2e-16 ***
s(YEAR)                      27.979  28.736   59.282  < 2e-16 ***
s(LONGITUDE,LATITUDE)        54.555  99.000    4.765  < 2e-16 ***
ti(DoY,YEAR)                131.317 140.000   34.592  < 2e-16 ***
ti(ToD,LONGITUDE,LATITUDE)   42.805 171.000    0.880  < 2e-16 ***
ti(DoY,LONGITUDE,LATITUDE)   83.277 240.000    1.225  < 2e-16 ***
ti(YEAR,LONGITUDE,LATITUDE)  84.862 329.000    1.101  < 2e-16 ***
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

R-sq.(adj) =   0.94   Deviance explained = 94.2%
fREML =  29807  Scale est. = 2.6318    n = 15276

Analisis yang lebih hati-hati ingin memeriksa apakah kita memerlukan semua interaksi ini; beberapa ti()istilah spasial hanya menjelaskan sejumlah kecil variasi dalam data, seperti yang ditunjukkan olehFstatistik; ada banyak data di sini sehingga bahkan ukuran efek kecil secara statistik signifikan tetapi tidak menarik.

Namun, sebagai pemeriksaan cepat, menghilangkan tiga ti()smooth spasial ( m.sub), menghasilkan kecocokan yang secara signifikan lebih buruk seperti yang dinilai oleh AIC:

> AIC(m, m.sub)
            df      AIC
m     447.5680 58583.81
m.sub 239.7336 59197.05

Kita dapat memplot efek parsial dari lima smooths pertama menggunakan plot()metode - smooths produk tensor 3D tidak dapat diplot dengan mudah dan tidak secara default.

plot(m, pages = 1, scheme = 2, shade = TRUE, scale = 0)

masukkan deskripsi gambar di sini

The scale = 0argumen di sana menempatkan semua plot pada skala mereka sendiri, untuk membandingkan besaran dampak, kita dapat mematikan ini:

plot(m, pages = 1, scheme = 2, shade = TRUE)

masukkan deskripsi gambar di sini

Sekarang kita dapat melihat bahwa efek musiman mendominasi. Tren jangka panjang (rata-rata) ditunjukkan di plot kanan atas. Untuk benar-benar melihat tren jangka panjang, Anda harus memilih stasiun dan kemudian memprediksi dari model untuk stasiun itu, menetapkan waktu hari dan hari dalam setahun ke beberapa nilai representatif (tengah hari, untuk hari dalam setahun di musim panas) mengatakan). Ada awal atau dua tahun dari seri memiliki beberapa nilai suhu rendah relatif terhadap sisa catatan, yang kemungkinan diambil di semua smooths yang terlibat YEAR. Data-data ini harus dilihat lebih dekat.

Ini bukan tempat yang tepat untuk membahas hal itu, tetapi di sini ada beberapa visualisasi model yang pas. Pertama saya melihat pola suhu spasial dan bagaimana itu bervariasi selama bertahun-tahun seri. Untuk melakukan itu saya memprediksi dari model untuk grid 100x100 di atas domain spasial, pada tengah hari pada hari 180 setiap tahun:

pdata <- with(galveston,
              expand.grid(ToD = 12,
                          DoY = 180,
                          YEAR = seq(min(YEAR), max(YEAR), by = 1),
                          LONGITUDE = seq(min(LONGITUDE), max(LONGITUDE), length = 100),
                          LATITUDE  = seq(min(LATITUDE), max(LATITUDE), length = 100)))
fit <- predict(m, pdata)

kemudian saya set ke missing,, NAnilai prediksi fituntuk semua titik data yang terletak agak jauh dari pengamatan (proporsional; dist)

ind <- exclude.too.far(pdata$LONGITUDE, pdata$LATITUDE,
                       galveston$LONGITUDE, galveston$LATITUDE, dist = 0.1)
fit[ind] <- NA

dan gabungkan prediksi dengan data prediksi

pred <- cbind(pdata, Fitted = fit)

Menetapkan nilai yang diprediksi NAseperti ini akan menghentikan kami melakukan ekstrapolasi di luar dukungan data.

Menggunakan ggplot2

ggplot(pred, aes(x = LONGITUDE, y = LATITUDE)) +
    geom_raster(aes(fill = Fitted)) + facet_wrap(~ YEAR, ncol = 12) +
    scale_fill_viridis(name = expression(degree*C), option = 'plasma',
                       na.value = 'transparent') +
    coord_quickmap() +
    theme(legend.position = 'top', legend.key.width = unit(2, 'cm'))

kami mendapatkan yang berikut ini

masukkan deskripsi gambar di sini

Kita dapat melihat variasi suhu tahun-ke-tahun dengan sedikit lebih detail jika kita menghidupkan daripada melihat sisi plotnya

p <- ggplot(pred, aes(x = LONGITUDE, y = LATITUDE, frame = YEAR)) +
    geom_raster(aes(fill = Fitted)) +
    scale_fill_viridis(name = expression(degree*C), option = 'plasma',
                       na.value = 'transparent') +
    coord_quickmap() +
    theme(legend.position = 'top', legend.key.width = unit(2, 'cm'))+
    labs(x = 'Longitude', y = 'Latitude')

gganimate(p, 'galveston.gif', interval = .2, ani.width = 500, ani.height = 800)

masukkan deskripsi gambar di sini

Untuk melihat tren jangka panjang secara lebih rinci, kami dapat memprediksi stasiun tertentu. Misalnya, untuk STATION_ID13364 dan prediksi hari di empat kuartal, kita dapat menggunakan yang berikut untuk menyiapkan nilai kovariat yang ingin kita prediksi pada (tengah hari, pada hari tahun 1, 90, 180, dan 270, di stasiun yang dipilih , dan mengevaluasi tren jangka panjang pada 500 nilai yang berjarak sama)

pdata <- with(galveston,
              expand.grid(ToD = 12,
                          DoY = c(1, 90, 180, 270),
                          YEAR = seq(min(YEAR), max(YEAR), length = 500),
                          LONGITUDE = -94.8751,
                          LATITUDE  = 29.50866))

Kemudian kami memperkirakan dan meminta kesalahan standar, untuk membentuk perkiraan interval kepercayaan 95%

fit <- data.frame(predict(m, newdata = pdata, se.fit = TRUE))
fit <- transform(fit, upper = fit + (2 * se.fit), lower = fit - (2 * se.fit))
pred <- cbind(pdata, fit)

yang kami plot

ggplot(pred, aes(x = YEAR, y = fit, group = factor(DoY))) +
    geom_ribbon(aes(ymin = lower, ymax = upper), fill = 'grey', alpha = 0.5) +
    geom_line() + facet_wrap(~ DoY, scales = 'free_y') +
    labs(x = NULL, y = expression(Temperature ~ (degree * C)))

memproduksi

masukkan deskripsi gambar di sini

Jelas, ada lebih banyak untuk memodelkan data ini daripada yang saya tunjukkan di sini, dan kami ingin memeriksa autokorelasi residu dan overfitting dari splines, tetapi mendekati masalah sebagai salah satu pemodelan fitur data memungkinkan untuk lebih detail pemeriksaan tren.

Anda tentu saja bisa hanya memodelkan masing STATION_ID- masing secara terpisah, tetapi itu akan membuang data, dan banyak stasiun memiliki beberapa pengamatan. Di sini model meminjam dari semua informasi stasiun untuk mengisi kekosongan dan membantu memperkirakan tren bunga.

Beberapa catatan bam()

The bam()model menggunakan semua mgcv trik 's untuk memperkirakan model cepat (beberapa benang 4 ), REML cepat pemilihan kelancaran ( method = 'fREML'), dan diskritisasi kovariat. Dengan opsi ini diaktifkan, model ini dapat digunakan dalam waktu kurang dari satu menit pada workstation Xeon dual-core Xeon dual-core 2013 saya dengan 64Gb RAM.

Gavin Simpson
sumber
0

Anda bisa menggunakan fungsi decomposeyang memisahkan deret waktu Anda dalam tiga komponen, tren, musiman dan acak. Anda juga dapat mengekstraksi nilai yang berbeda dari hasil dan memplotnya. Pastikan Anda menetapkan data sebagai rangkaian waktu. Fungsi stlini pada dasarnya melakukan hal yang sama tetapi memberi Anda lebih banyak fleksibilitas dalam bagaimana Anda dapat menguraikan data Anda.

Saya juga merekomendasikan situs web berikut

https://www.otexts.org/fpp/6

Apakah ini membantu?

burton030
sumber
Terima kasih atas jawabannya. Saya mencari melalui situs web sekarang. Tantangannya adalah ini: ada kesenjangan dalam data yang berlangsung berbulan-bulan atau bahkan sepanjang musim di mana mereka tidak mengumpulkan data apa pun, yang menyulitkan saya untuk memikirkan bagaimana menghadapi perubahan waktu.
griseus