การตรวจหาช่วงเวลาของอนุกรมเวลาทั่วไป


53

โพสต์นี้เป็นความต่อเนื่องของโพสต์อื่นที่เกี่ยวข้องกับการเป็นวิธีการทั่วไปสำหรับการตรวจสอบค่าผิดปกติในอนุกรมเวลา โดยทั่วไป ณ จุดนี้ฉันสนใจวิธีที่มีประสิทธิภาพในการค้นพบช่วงเวลา / ฤดูกาลของซีรีย์เวลาทั่วไปที่ได้รับผลกระทบจากเสียงรบกวนมากมาย จากมุมมองของนักพัฒนาฉันต้องการอินเทอร์เฟซที่เรียบง่ายเช่น:

unsigned int discover_period(vector<double> v);

vอาร์เรย์ที่มีตัวอย่างอยู่ที่ไหนและค่าส่งคืนคือช่วงเวลาของสัญญาณ ประเด็นหลักคืออีกครั้งฉันไม่สามารถทำการสันนิษฐานเกี่ยวกับสัญญาณที่วิเคราะห์ได้ ฉันลองใช้วิธีการโดยอิงตามสัญญาณอัตโนมัติ (การตรวจจับจุดยอดของ correlogram) แล้ว แต่ก็ไม่แข็งแกร่งเท่าที่ฉันต้องการ


1
คุณเคยลอง xts :: periodicity ไหม?
Fabrício

คำตอบ:


49

หากคุณไม่รู้จริงๆว่าช่วงเวลาเป็นอย่างไรอาจเป็นวิธีที่ดีที่สุดในการหาความถี่ที่สอดคล้องกับความหนาแน่นสเปกตรัมสูงสุด อย่างไรก็ตามสเปกตรัมที่ความถี่ต่ำจะได้รับผลกระทบจากเทรนด์ดังนั้นคุณต้องทำให้ซีรีส์เสียก่อน ฟังก์ชัน R ต่อไปนี้ควรทำงานให้กับซีรี่ส์ส่วนใหญ่ มันไกลจากที่สมบูรณ์แบบ แต่ฉันได้ทดสอบกับตัวอย่างไม่กี่โหลและดูเหมือนว่าจะใช้ได้ มันจะส่งคืน 1 สำหรับข้อมูลที่ไม่มีช่วงเวลาที่แข็งแกร่งและระยะเวลาเป็นอย่างอื่น

อัพเดท:ฟังก์ชั่นเวอร์ชั่น 2 มันเร็วกว่ามากและดูแข็งแกร่งขึ้น

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)
}

ขอขอบคุณ. อีกครั้งฉันจะลองวิธีนี้โดยเร็วที่สุดและจะเขียนผลสุดท้ายที่นี่
gianluca

2
ความคิดของคุณเป็นสิ่งที่ดีมาก แต่ในกรณีของฉันก็ล้มเหลวในการตรวจสอบระยะเวลาของง่ายจริงๆ (และไม่ให้มีเสียงดัง) อนุกรมเวลาเช่นdl.dropbox.com/u/540394/chart.png ด้วยวิธีการ "เชิงประจักษ์" ของฉัน (ขึ้นอยู่กับความสัมพันธ์อัตโนมัติ) อัลกอริทึมแบบง่ายที่ฉันเขียนจะส่งกลับค่าระยะเวลาที่แน่นอนที่ 1,058 (มีตัวอย่างทุก 10 นาทีซึ่งหมายความว่า 1008/24/6 = 7 ดังนั้นระยะเวลารายสัปดาห์) ปัญหาหลักของฉันคือ: 1) มันช้าเกินไปที่จะมาบรรจบกัน (มันต้องมีข้อมูลทางประวัติศาสตร์จำนวนมาก) และฉันต้องการวิธีการตอบโต้ออนไลน์; 2) มันไม่มีประสิทธิภาพเท่านรกจากมุมมองการใช้หน่วยความจำ 3) มันไม่แข็งแกร่งเลย
gianluca

ขอขอบคุณ. น่าเสียดายที่นี่ยังใช้งานไม่ได้อย่างที่ฉันคาดไว้ สำหรับชุดเวลาเดียวกันของความคิดเห็นก่อนหน้านี้จะส่งคืน 166 ซึ่งเป็นเพียงบางส่วนเท่านั้น (จากมุมมองของฉันช่วงเวลารายสัปดาห์ที่เห็นได้ชัดน่าสนใจยิ่งขึ้น) และใช้อนุกรมเวลาที่มีเสียงดังมากเช่นนี้dl.dropbox.com/u/540394/chart2.png (การวิเคราะห์หน้าต่างตัวรับสัญญาณ TCP) ฟังก์ชั่นนี้จะคืนค่า 10 ในขณะที่ฉันคาดหวัง 1 ระยะเวลา) BTW ฉันรู้ว่ามันยากที่จะค้นหาสิ่งที่ฉันกำลังมองหาเนื่องจากฉันกำลังจัดการกับสัญญาณที่แตกต่างกันมากเกินไป
gianluca

166 ไม่ใช่การประเมินที่ไม่ดีที่ 168 ถ้าคุณรู้ว่ามีการสังเกตข้อมูลทุกชั่วโมงด้วยรูปแบบรายสัปดาห์แล้วทำไมจึงประมาณความถี่ด้วยล่ะ
Rob Hyndman

5
รุ่นที่ปรับปรุงแล้วอยู่ในแพ็คเกจพยากรณ์เช่นfindfrequency
Rob Hyndman

10

หากคุณคาดว่ากระบวนการนี้จะคงที่ - ช่วงเวลา / ฤดูกาลจะไม่เปลี่ยนแปลงเมื่อเวลาผ่านไป - บางอย่างเช่น Chi-square periodogram (ดูเช่น Sokolove และ Bushell, 1978) อาจเป็นทางเลือกที่ดี โดยทั่วไปจะใช้ในการวิเคราะห์ข้อมูล circadian ซึ่งอาจมีสัญญาณรบกวนจำนวนมากในนั้น แต่คาดว่าจะมีระยะเวลาที่มั่นคงมาก

วิธีการนี้ทำให้ไม่มีการสันนิษฐานเกี่ยวกับรูปร่างของรูปคลื่น (นอกเหนือจากนั้นจะสอดคล้องกันจากวงจรถึงวัฏจักร) แต่ไม่ต้องการเสียงรบกวนใด ๆ ที่มีค่าเฉลี่ยคงที่และไม่สัมพันธ์กับสัญญาณ

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)

สองบรรทัดสุดท้ายเป็นเพียงตัวอย่างแสดงให้เห็นว่าสามารถระบุช่วงเวลาของฟังก์ชันตรีโกณมิติที่บริสุทธิ์แม้จะมีเสียงรบกวนเพิ่มเติม

ตามที่เขียนไว้อาร์กิวเมนต์สุดท้าย ( alpha) ในการโทรฟุ่มเฟือยฟังก์ชั่นก็จะส่งกลับช่วงเวลาที่ดีที่สุดที่จะหา; uncomment แรกคำสั่งและแสดงความคิดเห็นออกมาที่สองที่จะมีมันกลับรายการของทุกช่วงเวลาอย่างมีนัยสำคัญที่ระดับreturnalpha

ฟังก์ชั่นนี้ไม่ได้ทำการตรวจสอบสติสัมปชัญญะใด ๆ เพื่อให้แน่ใจว่าคุณได้ใส่ช่วงเวลาที่สามารถระบุตัวตนได้และไม่สามารถใช้งานได้กับช่วงเวลาแบบเศษส่วนและไม่มีการควบคุมการเปรียบเทียบหลายแบบในตัวหากคุณตัดสินใจ ดูหลายช่วงเวลา แต่นอกเหนือไปจากนั้นมันควรจะแข็งแกร่งพอสมควร


ดูน่าสนใจ แต่ฉันไม่เข้าใจผลลัพธ์มันไม่ได้บอกฉันว่าช่วงเวลาดังกล่าวเริ่มต้นที่ใดและมีค่ามากที่สุด 1
Herman Toothrot

3

คุณอาจต้องการกำหนดสิ่งที่คุณต้องการให้ชัดเจนยิ่งขึ้น (สำหรับตัวคุณเองหากไม่อยู่ที่นี่) หากสิ่งที่คุณกำลังมองหาคือช่วงเวลาที่นิ่งที่สุดที่มีนัยสำคัญทางสถิติซึ่งมีอยู่ในข้อมูลที่มีเสียงดังของคุณ

1) คำนวณการประมาณค่าออโตคอร์เรชั่นที่มีประสิทธิภาพและใช้ค่าสัมประสิทธิ์สูงสุด
2) คำนวณค่าความหนาแน่นสเปกตรัมพลังงานที่แข็งแกร่งและใช้ช่วงสูงสุดของสเปกตรัม

ปัญหาของ # 2 คือสำหรับอนุกรมเวลาที่มีเสียงดังคุณจะได้รับพลังงานจำนวนมากในความถี่ต่ำทำให้แยกแยะได้ยาก มีเทคนิคบางอย่างสำหรับการแก้ไขปัญหานี้ (เช่น pre-whiteen จากนั้นประมาณค่า PSD) แต่ถ้าระยะเวลาจริงจากข้อมูลของคุณยาวพอการตรวจจับอัตโนมัติจะไม่แน่นอน

ทางออกที่ดีที่สุดของคุณน่าจะนำไปใช้เป็นชุดคำสั่งอัตโนมัติที่มีประสิทธิภาพเช่นในบทที่ 8.6, 8.7 ในสถิติที่แข็งแกร่ง - ทฤษฎีและวิธีการโดย Maronna, Martin และ Yohai การค้นหา Google เพื่อหา "durbin-levinson ที่มีประสิทธิภาพ" จะให้ผลลัพธ์เช่นกัน

หากคุณกำลังมองหาคำตอบง่ายๆฉันไม่แน่ใจว่ามีคำตอบอยู่ การตรวจหาระยะเวลาในอนุกรมเวลาอาจมีความซับซ้อนและการขอรูทีนอัตโนมัติที่สามารถแสดงเวทย์มนตร์นั้นอาจมากเกินไป


ขอบคุณสำหรับข้อมูลอันมีค่าของคุณฉันจะดูหนังสือเล่มนั้นอย่างแน่นอน
gianluca

3

คุณสามารถใช้การเปลี่ยนแปลงฮิลแบร์ตจากทฤษฎี DSP เพื่อวัดความถี่ของข้อมูลของคุณได้ทันที เว็บไซต์http://ta-lib.org/มีรหัสโอเพ่นซอร์สสำหรับการวัดรอบระยะเวลาที่สำคัญของข้อมูลทางการเงิน ฟังก์ชันที่เกี่ยวข้องเรียกว่า HT_DCPERIOD คุณอาจจะสามารถใช้สิ่งนี้หรือปรับเปลี่ยนรหัสเพื่อวัตถุประสงค์ของคุณ


3

วิธีการที่แตกต่างกันอาจเป็นโหมดการสลายตัวของประจักษ์ แพคเกจ R ที่เรียกว่าเมอร์ได้รับการพัฒนาโดยนักประดิษฐ์ของวิธีการ:

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()

วิธีการดังกล่าวมีชื่อว่า 'Empirical' ด้วยเหตุผลที่ดีและมีความเสี่ยงที่ฟังก์ชั่นโหมด Intrinsic (ส่วนประกอบเสริมแต่ละตัว) จะปะปนกัน ในทางกลับกันวิธีการนี้ใช้งานง่ายมากและอาจเป็นประโยชน์สำหรับการตรวจสอบวงจรอย่างรวดเร็วด้วยสายตา


0

ในการอ้างอิงถึงโพสต์ของ Rob Hyndman ด้านบนhttps://stats.stackexchange.com/a/1214/70282

ฟังก์ชัน find.freq ทำงานได้อย่างยอดเยี่ยม ในชุดข้อมูลรายวันที่ฉันกำลังใช้จะทำให้ความถี่เป็น 7 ได้อย่างถูกต้อง

เมื่อฉันลองใช้เพียงแค่วันในสัปดาห์ก็กล่าวถึงความถี่คือ 23 ซึ่งใกล้เคียงกับ 21.42857 = 29.6 * 5/7 ซึ่งเป็นจำนวนวันทำงานเฉลี่ยในหนึ่งเดือน (หรือตรงกันข้าม 23 * 7/5 คือ 32)

เมื่อมองย้อนกลับไปที่ข้อมูลรายวันของฉันฉันได้ทดลองกับช่วงเวลาแรก ๆ โดยเฉลี่ยแล้วหาช่วงเวลาถัดไปเป็นต้นดูที่ด้านล่าง:

find.freq.all = function (x) {  
  f = find.freq (x);
  freqs c = (ฉ);  
  ในขณะที่ (ฉ> 1) {
    เริ่มต้น = 1; #also ลองเริ่ม = f;
    x = period.apply (x, seq (เริ่มต้นความยาว (x), ฉ) ค่าเฉลี่ย); 
    f = find.freq (x);
    freqs c = (freqs ฉ);
  }
  if (length (freqs) == 1) {return (freqs); }
  สำหรับ (ฉันใน 2: ความยาว (ความถี่)) {
    freqs [ผม] = freqs [ผม] * freqs [I-1];
  }
  freqs [1: (ความยาว (freqs) -1)];
}
find.freq.all (dailyts) #using ข้อมูลรายวัน

ข้างต้นให้ (7,28) หรือ (7,35) ขึ้นอยู่กับว่า seq เริ่มต้นด้วย 1 หรือ f (ดูความคิดเห็นด้านบน)

ซึ่งจะแปลว่าช่วงเวลาตามฤดูกาลสำหรับ msts (... ) ควรเป็น (7,28) หรือ (7,35)

ตรรกะนั้นอ่อนไหวต่อสภาวะเริ่มต้นเนื่องจากความไวของพารามิเตอร์อัลกอริธึม ค่าเฉลี่ยของ 28 และ 35 คือ 31.5 ซึ่งใกล้เคียงกับความยาวเฉลี่ยของเดือน

ฉันสงสัยว่าฉันสร้างใหม่ล้อแล้วชื่อของอัลกอริทึมนี้คืออะไร? มีการใช้งานที่ดีขึ้นใน R แห่งหนึ่งหรือไม่?

ต่อมาฉันรันโค้ดข้างต้นในการพยายามเริ่มต้นทั้งหมดตั้งแต่ 1 ถึง 7 และฉันได้ 35,35,28,28,28,28,28 สำหรับช่วงที่สอง ค่าเฉลี่ยทำงานได้ถึง 30 ซึ่งเป็นจำนวนวันเฉลี่ยในหนึ่งเดือน ที่น่าสนใจ ...

ความคิดหรือความคิดเห็นใด ๆ


0

ท่านสามารถใช้การทดสอบ Ljung-Box เพื่อหาว่าความแตกต่างของฤดูกาลมาถึงความคงที่ที่ดีที่สุด ฉันทำงานในวิชาอื่นและฉันใช้สิ่งนี้เพื่อจุดประสงค์เดียวกัน ลองใช้ช่วงเวลาอื่นเช่น 3 ถึง 24 สำหรับข้อมูลรายเดือน และทดสอบแต่ละรายการโดย Ljung-Box และเก็บผลลัพธ์ Chi-Square และเลือกช่วงเวลาที่มีค่าไคสแควร์ต่ำที่สุด

นี่คือรหัสง่ายๆที่จะทำ

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
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.