Phát hiện thời gian của một chuỗi thời gian chung


53

Bài đăng này là sự tiếp nối của một bài đăng khác liên quan đến một phương pháp chung để phát hiện ngoại lệ trong chuỗi thời gian . Về cơ bản, tại thời điểm này, tôi quan tâm đến một cách mạnh mẽ để khám phá tính định kỳ / tính thời vụ của chuỗi thời gian chung bị ảnh hưởng bởi rất nhiều tiếng ồn. Từ quan điểm của nhà phát triển, tôi muốn một giao diện đơn giản như:

unsigned int discover_period(vector<double> v);

Trường hợp vmảng chứa các mẫu và giá trị trả về là khoảng thời gian của tín hiệu. Điểm chính là, một lần nữa, tôi không thể đưa ra bất kỳ giả định nào về tín hiệu được phân tích. Tôi đã thử một cách tiếp cận dựa trên sự tự tương quan tín hiệu (phát hiện các đỉnh của một biểu đồ tương quan), nhưng nó không mạnh mẽ như tôi muốn.


1
Bạn đã thử xts :: định kỳ chưa?
Fabrício

Câu trả lời:


49

Nếu bạn thực sự không biết tính tuần hoàn là gì, có lẽ cách tiếp cận tốt nhất là tìm tần số tương ứng với mức tối đa của mật độ phổ. Tuy nhiên, phổ ở tần số thấp sẽ bị ảnh hưởng bởi xu hướng, vì vậy bạn cần phải loại bỏ chuỗi đầu tiên. Hàm R sau đây sẽ thực hiện công việc cho hầu hết các chuỗi. Nó không hoàn hảo, nhưng tôi đã thử nghiệm nó trên một vài chục ví dụ và nó có vẻ hoạt động tốt. Nó sẽ trả về 1 cho dữ liệu không có tính tuần hoàn mạnh và độ dài của khoảng thời gian khác.

Cập nhật: Phiên bản 2 của chức năng. Điều này nhanh hơn nhiều và dường như mạnh mẽ hơn.

find.freq <- function(x)
{
    n <- length(x)
    spec <- spec.ar(c(x),plot=FALSE)
    if(max(spec$spec)>10) # Arbitrary threshold chosen by trial and error.
    {
        period <- round(1/spec$freq[which.max(spec$spec)])
        if(period==Inf) # Find next local maximum
        {
            j <- which(diff(spec$spec)>0)
            if(length(j)>0)
            {
                nextmax <- j[1] + which.max(spec$spec[j[1]:500])
                period <- round(1/spec$freq[nextmax])
            }
            else
                period <- 1
        }
    }
    else
        period <- 1
    return(period)
}

Cảm ơn bạn. Một lần nữa, tôi sẽ thử phương pháp này càng sớm càng tốt và sẽ viết vào đây kết quả cuối cùng.
gianluca

2
Ý tưởng của bạn là khá tốt, nhưng trong trường hợp của tôi, nó không phát hiện ra tính định kỳ của một chuỗi thời gian thực sự đơn giản (và không quá ồn ào) như dl.dropbox.com/u/540394/chart.png . Với cách tiếp cận "theo kinh nghiệm" của tôi (dựa trên tự động tương quan), thuật toán đơn giản tôi đã viết trả về khoảng thời gian chính xác là 1008 (có một mẫu cứ sau 10 phút, điều này có nghĩa là 1008/24/6 = 7, do đó, tính tuần hoàn hàng tuần). Vấn đề chính của tôi là: 1) Quá chậm để hội tụ (nó đòi hỏi nhiều dữ liệu lịch sử) và tôi cần một cách tiếp cận trực tuyến, phản ứng; 2) Nó không hiệu quả như địa ngục theo quan điểm sử dụng bộ nhớ; 3) Nó không mạnh mẽ chút nào;
gianluca

Cảm ơn bạn. Thật không may, điều này vẫn không hoạt động như tôi mong đợi. Đối với chuỗi thời gian tương tự của nhận xét trước đó, nó trả về 166, chỉ đúng một phần (theo quan điểm của tôi, khoảng thời gian hàng tuần rõ ràng là thú vị hơn). Và sử dụng chuỗi thời gian rất ồn ào, như thế này dl.dropbox.com/u/540394/chart2.png (phân tích cửa sổ nhận TCP), hàm trả về 10, trong khi tôi mong đợi 1 (tôi không thể thấy rõ ràng định kỳ). BTW Tôi biết rằng sẽ rất khó để tìm thấy những gì tôi đang tìm kiếm, vì tôi đang xử lý các tín hiệu quá khác nhau.
gianluca

166 không phải là ước tính tồi của 168. Nếu bạn biết dữ liệu được quan sát hàng giờ với mẫu hàng tuần, thì tại sao lại ước tính tần suất?
Rob Hyndman

5
Một phiên bản cải tiến nằm trong gói dự báo làfindfrequency
Rob Hyndman

10

Nếu bạn mong đợi quá trình đứng yên - tính định kỳ / tính thời vụ sẽ không thay đổi theo thời gian - thì một cái gì đó giống như biểu đồ Chi-vuông (xem ví dụ: Sokolove và Bushell, 1978) có thể là một lựa chọn tốt. Nó thường được sử dụng trong phân tích dữ liệu sinh học có thể có lượng nhiễu cực lớn trong đó, nhưng dự kiến ​​sẽ có các chu kỳ rất ổn định.

Cách tiếp cận này không đưa ra giả định về hình dạng của dạng sóng (ngoài việc nó phù hợp từ chu kỳ này sang chu kỳ khác), nhưng không yêu cầu bất kỳ nhiễu nào có giá trị trung bình không đổi và không tương thích với tín hiệu.

chisq.pd <- function(x, min.period, max.period, alpha) {
N <- length(x)
variances = NULL
periods = seq(min.period, max.period)
rowlist = NULL
for(lc in periods){
    ncol = lc
    nrow = floor(N/ncol)
    rowlist = c(rowlist, nrow)
    x.trunc = x[1:(ncol*nrow)]
    x.reshape = t(array(x.trunc, c(ncol, nrow)))
    variances = c(variances, var(colMeans(x.reshape)))
}
Qp = (rowlist * periods * variances) / var(x)
df = periods - 1
pvals = 1-pchisq(Qp, df)
pass.periods = periods[pvals<alpha]
pass.pvals = pvals[pvals<alpha]
#return(cbind(pass.periods, pass.pvals))
return(cbind(periods[pvals==min(pvals)], pvals[pvals==min(pvals)]))
}

x = cos( (2*pi/37) * (1:1000))+rnorm(1000)
chisq.pd(x, 2, 72, .05)

Hai dòng cuối cùng chỉ là một ví dụ, cho thấy nó có thể xác định khoảng thời gian của hàm lượng giác thuần túy, thậm chí có rất nhiều nhiễu phụ.

Như đã viết, đối số cuối cùng ( alpha) trong cuộc gọi là không cần thiết, hàm chỉ đơn giản trả về khoảng thời gian 'tốt nhất' mà nó có thể tìm thấy; bỏ ghi chú đầu tiên returnvà nhận xét thứ hai để nó trả về một danh sách tất cả các giai đoạn có ý nghĩa ở cấp độ alpha.

Hàm này không thực hiện bất kỳ loại kiểm tra độ tỉnh táo nào để đảm bảo rằng bạn đã đặt trong các khoảng thời gian có thể xác định được, nó cũng không hoạt động với các giai đoạn phân số, cũng như không có bất kỳ loại điều khiển so sánh nào được tích hợp nếu bạn quyết định nhìn vào nhiều thời kỳ. Nhưng khác hơn là nó phải mạnh mẽ hợp lý.


Trông có vẻ thú vị nhưng tôi không hiểu đầu ra, nó không cho tôi biết thời gian bắt đầu và hầu hết các giá trị của 1.
Herman Toothrot

3

Bạn có thể muốn xác định những gì bạn muốn rõ ràng hơn (với chính mình, nếu không ở đây). Nếu những gì bạn đang tìm kiếm là khoảng thời gian đứng yên có ý nghĩa thống kê nhất có trong dữ liệu ồn ào của bạn, thì về cơ bản có hai tuyến đường cần thực hiện:

1) tính toán ước lượng tự tương quan mạnh và lấy hệ số tối đa
2) tính toán ước tính mật độ phổ công suất mạnh và lấy cực đại của phổ

Vấn đề với # 2 là đối với bất kỳ chuỗi thời gian ồn ào nào, bạn sẽ nhận được một lượng điện năng lớn ở tần số thấp, gây khó khăn cho việc phân biệt. Có một số kỹ thuật để giải quyết vấn đề này (ví dụ như làm trắng trước, sau đó ước tính PSD), nhưng nếu khoảng thời gian thực từ dữ liệu của bạn đủ dài, phát hiện tự động sẽ là iffy.

Đặt cược tốt nhất của bạn có lẽ là thực hiện một thói quen tự tương quan mạnh mẽ như có thể được tìm thấy trong chương 8.6, 8.7 trong Thống kê mạnh mẽ - Lý thuyết và Phương pháp của Maronna, Martin và Yohai. Tìm kiếm Google cho "durbin-levinson mạnh mẽ" cũng sẽ mang lại một số kết quả.

Nếu bạn chỉ tìm kiếm một câu trả lời đơn giản, tôi không chắc là nó tồn tại. Phát hiện thời gian trong chuỗi thời gian có thể phức tạp và yêu cầu một thói quen tự động có thể thực hiện phép thuật có thể là quá nhiều.


Cảm ơn bạn đã cung cấp thông tin quý giá của bạn, tôi sẽ xem cuốn sách đó cho chắc chắn.
gianluca

3

Bạn có thể sử dụng Chuyển đổi Hilbert từ lý thuyết DSP để đo tần số tức thời của dữ liệu của bạn. Trang web http://ta-lib.org/ có mã nguồn mở để đo thời gian chu kỳ chi phối của dữ liệu tài chính; chức năng liên quan được gọi là HT_DCPERIOD; bạn có thể sử dụng mã này hoặc điều chỉnh mã theo mục đích của mình.


3

Một cách tiếp cận khác nhau có thể là Phân rã chế độ theo kinh nghiệm. Gói R được gọi là EMD được phát triển bởi người phát minh ra phương pháp:

require(EMD)
ndata <- 3000  
tt2 <- seq(0, 9, length = ndata)  
xt2 <- sin(pi * tt2) + sin(2* pi * tt2) + sin(6 * pi * tt2) + 0.5 * tt2  
try <- emd(xt2, tt2, boundary = "wave")  
### Ploting the IMF's  
par(mfrow = c(try$nimf + 1, 1), mar=c(2,1,2,1))  
rangeimf <- range(try$imf)  
for(i in 1:try$nimf) {  
plot(tt2, try$imf[,i], type="l", xlab="", ylab="", ylim=rangeimf, main=paste(i, "-th IMF", sep="")); abline(h=0)  
}  
plot(tt2, try$residue, xlab="", ylab="", main="residue", type="l", axes=FALSE); box()

Phương pháp này được gắn nhãn 'Thực nghiệm' vì một lý do chính đáng và có nguy cơ các Hàm Chế độ Nội tại (các thành phần phụ gia riêng lẻ) bị lẫn lộn. Mặt khác, phương pháp này rất trực quan và có thể hữu ích cho việc kiểm tra trực quan nhanh chóng về chu kỳ.


0

Để tham khảo bài đăng của Rob Hyndman ở trên https://stats.stackexchange.com/a/1214/70282

Hàm find.freq hoạt động rực rỡ. Trên tập dữ liệu hàng ngày tôi đang sử dụng, nó hoạt động chính xác với tần số là 7.

Khi tôi thử nó chỉ trong những ngày trong tuần, nó đã đề cập đến tần suất là 23, gần đáng kể với 21.42857 = 29,6 * 5/7, đây là số ngày làm việc trung bình trong một tháng. (Hoặc ngược lại 23 * 7/5 là 32.)

Nhìn lại dữ liệu hàng ngày của tôi, tôi đã thử nghiệm một linh cảm của việc thực hiện giai đoạn đầu tiên, tính trung bình theo đó và sau đó tìm giai đoạn tiếp theo, v.v. Xem bên dưới:

find.freq.all = function (x) {  
  f = find.freq (x);
  freqs = c (f);  
  trong khi (f> 1) {
    bắt đầu = 1; # cũng thử bắt đầu = f;
    x = period.apply (x, seq (bắt đầu, chiều dài (x), f), trung bình); 
    f = find.freq (x);
    freqs = c (freqs, f);
  }
  if (length (freqs) == 1) {return (freqs); }
  for (i in 2: length (freqs)) {
    freqs [i] = freqs [i] * freqs [i-1];
  }
  freqs [1: (chiều dài (freqs) -1)];
}
find.freq.all (Dailyts) #use dữ liệu hàng ngày

Ở trên cho (7,28) hoặc (7,35) tùy thuộc vào việc seq bắt đầu bằng 1 hay f. (Xem bình luận ở trên.)

Điều đó có nghĩa là các giai đoạn theo mùa cho msts (...) nên là (7,28) hoặc (7,35).

Logic có vẻ nhạy cảm với các điều kiện ban đầu với độ nhạy của các tham số thuật toán. Giá trị trung bình của 28 và 35 là 31,5 gần với độ dài trung bình của một tháng.

Tôi nghi ngờ tôi đã phát minh lại bánh xe, tên của thuật toán này là gì? Có một thực hiện tốt hơn trong R ở đâu đó?

Sau đó, tôi đã chạy đoạn mã trên trong việc thử tất cả bắt đầu từ 1 đến 7 và tôi đã nhận được 35,35,28,28,28,28,28 cho giai đoạn thứ hai. Trung bình làm việc đến 30, đó là số ngày trung bình trong một tháng. Hấp dẫn...

Bất kỳ suy nghĩ hoặc ý kiến?


0

Người ta cũng có thể sử dụng thử nghiệm Ljung-Box để tìm ra sự khác biệt theo mùa nào đạt đến mức ổn định tốt nhất. Tôi đã làm việc về một chủ đề khác và tôi đã sử dụng nó thực sự cho cùng một mục đích. Hãy thử các khoảng thời gian khác nhau như 3 đến 24 cho dữ liệu hàng tháng. Và kiểm tra từng người trong số họ bằng Ljung-Box và lưu trữ kết quả Chi-Square. Và chọn khoảng thời gian có giá trị chi bình phương thấp nhất.

Đây là một mã đơn giản để làm điều đó.

minval0 <- 5000 #assign a big number to be sure Chi values are smaller
minindex0 <- 0
periyot <- 0

for (i in 3:24) { #find optimum period by Qtests over original data

        d0D1 <- diff(a, lag=i)

        #store results
        Qtest_d0D1[[i]] <- Box.test(d0D1, lag=20, type = "Ljung-Box")

        #store Chi-Square statistics
        sira0[i] <- Qtest_d0D1[[i]][1]
}
#turn list to a data frame, then matrix
datam0 <- data.frame(matrix(unlist(sira0), nrow=length(Qtest_d0D1)-2, byrow = T))
datamtrx0 <- as.matrix(datam0[])
#get min value's index
minindex0 <- which(datamtrx0 == min(datamtrx0), arr.ind = F)
periyot <- minindex0 + 2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.