Verilere sinüzoidal bir terim takın


26

Okuduğum rağmen bu yazı, hala nasıl kendi veri ve birisi bana yardımcı olabilir umuduyla bu uygulamak için hiçbir fikrim yok.

Aşağıdaki verilere sahibim:

y <- c(11.622967, 12.006081, 11.760928, 12.246830, 12.052126, 12.346154, 12.039262, 12.362163, 12.009269, 11.260743, 10.950483, 10.522091,  9.346292,  7.014578,  6.981853,  7.197708,  7.035624,  6.785289, 7.134426,  8.338514,  8.723832, 10.276473, 10.602792, 11.031908, 11.364901, 11.687638, 11.947783, 12.228909, 11.918379, 12.343574, 12.046851, 12.316508, 12.147746, 12.136446, 11.744371,  8.317413, 8.790837, 10.139807,  7.019035,  7.541484,  7.199672,  9.090377,  7.532161,  8.156842,  9.329572, 9.991522, 10.036448, 10.797905)
t <- 18:65

Ve şimdi sadece bir sinüs dalgasına uymak istiyorum.

y(t)=Asin(ωt+ϕ)+C.

Dört bilinmeyenli , , ve .ω ϕ CAωϕC

Kodumun geri kalanı şöyle:

res <- nls(y ~ A*sin(omega*t+phi)+C, data=data.frame(t,y), start=list(A=1,omega=1,phi=1,C=1))
co <- coef(res)

fit <- function(x, a, b, c, d) {a*sin(b*x+c)+d}

# Plot result
plot(x=t, y=y)
curve(fit(x, a=co["A"], b=co["omega"], c=co["phi"], d=co["C"]), add=TRUE ,lwd=2, col="steelblue")

Ancak sonuç gerçekten kötüdür.

Sinüs uyum

Herhangi bir yardım için çok minnettar olurum.

Şerefe.


Verilere sinüs dalgası sığdırmaya mı çalışıyorsunuz yoksa sinüs ve kosinüs bileşenli bir tür harmonik modele mi uyuyorsunuz? TSA paketinde R'de kontrol etmek isteyebileceğiniz harmonik bir fonksiyon var. Bunu kullanarak modelinizi takın ve ne tür sonuçlar elde ettiğinizi görün.
Eric Peterson

5
Farklı başlangıç ​​değerleri denediniz mi? Kayıp fonksiyonunuz dışbükey değildir, bu nedenle farklı başlangıç ​​değerleri farklı çözümlere yol açabilir.
Stefan Wager

1
Bize veriler hakkında daha fazla bilgi verin. Genellikle bilinen bir periyodiklik vardır, bu nedenle verilerden tahmin edilmesine gerek yoktur. Bu bir zaman serisi mi yoksa başka bir şey mi? Lineer bir modele göre ayrı sinüs ve kosinüs terimlerini sığdırabilirseniz çok daha kolaydır.
Nick Cox,

2
Bilinmeyen bir süreye sahip olmak, modelinizi doğrusal olmayan hale getirir (böyle bir olay, bağlı gönderideki seçilen cevapta belirtilir). Verilen, diğer parametreler koşullu olarak doğrusaldır; Bazı doğrusal olmayan LS rutinleri için bu bilgi önemlidir ve davranışı iyileştirebilir. Bir seçenek, bunun üzerine dönem ve koşulu elde etmek için spektral yöntemler kullanmak olabilir; bir diğeri, periyodu ve diğer parametreleri, sırasıyla yinelemeli bir şekilde doğrusal olmayan ve doğrusal bir optimizasyonla güncellemek olacaktır.
Glen_b -Reinstate Monica

(Ben sadece bilinmeyen dönemin belirli bir vakasını doğrusal olmayan kılan şeyin açık bir örneği olması için
cevabı değiştirdim

Yanıtlar:


18

Yalnızca iyi bir tahmin yapmak istiyorsanız ve standart hatasıyla pek ilgilenmiyorsanız:ω

ssp <- spectrum(y)  
per <- 1/ssp$freq[ssp$spec==max(ssp$spec)]
reslm <- lm(y ~ sin(2*pi/per*t)+cos(2*pi/per*t))
summary(reslm)

rg <- diff(range(y))
plot(y~t,ylim=c(min(y)-0.1*rg,max(y)+0.1*rg))
lines(fitted(reslm)~t,col=4,lty=2)   # dashed blue line is sin fit

# including 2nd harmonic really improves the fit
reslm2 <- lm(y ~ sin(2*pi/per*t)+cos(2*pi/per*t)+sin(4*pi/per*t)+cos(4*pi/per*t))
summary(reslm2)
lines(fitted(reslm2)~t,col=3)    # solid green line is periodic with second harmonic

sinüs arsa

(Daha iyi bir uyum, belki de bu serideki aykırı değerleri bir şekilde etkileyerek etkilerini azaltır.)

---

Omega'daki belirsizlik hakkında bir fikir edinmek istiyorsanız , profil olasılığını kullanabilirsiniz ( pdf1 , pdf2 - profil olasılığından yaklaşık CI veya SE elde etmeyle ilgili referanslar veya varyantlarını bulmak zor değildir)ω

(Alternatif olarak, bu tahminleri nls'ye besleyebilir ve çoktan bir araya gelmeye başlayabilirsiniz.)


(+1) güzel cevap. Doğrusal modele uymaya çalıştım lm(y~sin(2*pi*t)+cos(2*pi*t)ama bu işe yaramadı ( costerim her zaman 1 idi). Sadece meraktan: ilk iki satır ne yapar ( spectrumspektral yoğunluğu tahmin ettiğini biliyorum )?
COOLSerdash

1
Evet @COOLSerdash, sen birimleri olması (o bağlantılı söz konusu olduğu gibi) için süre olan çalışmalara. Geri dönüp diğer cevabında bunu vurgulamalıyım. ( t2*pi*t
ctd

1
@ COOLSerdash (ctd) - İkinci satır, spektrumdaki en büyük tepe ile ilişkili frekansı bulur ve süreyi tanımlamak için tersine çevirir. En azından bu durumda (ancak daha yaygın olarak şüpheleniyorum), buradaki varsayılanlar, esasen olasılığını en üst düzeye çıkaran süreyi, o zamanki bölgede bölgedeki profil olasılığını en üst seviyeye çıkarmak için attığım adımları silmeme neden oldu. specTSA'daki işlev daha iyi olabilir (birinin bazen önemli olabileceği daha fazla seçeneğe sahip görünüyor), ancak bu durumda ana tepe noktası tam olarak aynı yerdeydi, spectrumbu yüzden rahatsız etmedim.
Glen_b -Reinstate Monica,

@Glen_b bu yöntem benim kullanım durumum için harikalar yaratıyor. Değiştim ... Ben de bir cos (x) eğrisi uyacak gerekir, ama aynı zamanda işi değil reslmhiç reslm <- lm(y ~ cos(2*pi/per*t)+tan(2*pi/per*t))ama bu doğru görünmüyor. herhangi bir ipucu?
Amit Kohli

Neden orada ten rengi bir terim var?
Glen_b -Reinstate Monica

15

@Stefan'ın önerdiği gibi, farklı başlangıç ​​değerleri, uyumu dramatik şekilde iyileştiriyor gibi görünüyor. Zirveler yaklaşık 20 birim gibi gözüktüğü için omega'nın yaklaşık olması gerektiğini gösteren verilere göz kulak oldum .2π/20

Ben içine koyduğunuzda nls'ın startlistesinde hala bazı sistematik önyargıları sahip olmasına rağmen, çok daha makul bir eğri var.

Bu veri seti ile hedefinizin ne olduğuna bağlı olarak, ek terimler ekleyerek veya periyodik bir çekirdekli Gauss süreci gibi parametrik olmayan bir yaklaşım kullanarak uyumu iyileştirmeyi deneyebilirsiniz.

Sinüs uyum

Otomatik olarak bir başlangıç ​​değeri seçme

Baskın frekansı seçmek istiyorsanız, hızlı bir Fourier dönüşümü (FFT) kullanabilirsiniz. Bu benim uzmanlık alanımın dışında, bu yüzden diğer kişilerin de isterlerse (özellikle 2. ve 3. adımlar hakkında) ayrıntıları doldurmalarına izin vereceğim, ancak aşağıdaki Rkod çalışmalı.

# Step 1: do the FFT
raw.fft = fft(y)

# Step 2: drop anything past the N/2 - 1th element.
# This has something to do with the Nyquist-shannon limit, I believe
# (https://en.wikipedia.org/wiki/Nyquist%E2%80%93Shannon_sampling_theorem)
truncated.fft = raw.fft[seq(1, length(y)/2 - 1)]

# Step 3: drop the first element. It doesn't contain frequency information.
truncated.fft[1] = 0

# Step 4: the importance of each frequency corresponds to the absolute value of the FFT.
# The 2, pi, and length(y) ensure that omega is on the correct scale relative to t.
# Here, I set omega based on the largest value using which.max().
omega = which.max(abs(truncated.fft)) * 2 * pi / length(y)

Ayrıca abs(truncated.fft), başka önemli frekanslar olup olmadığını görmek için komplo kurabilirsiniz , ancak x-ekseni biraz ölçeklenmeli.

Ayrıca, @Glen_b'nin omega öğrendikten sonra sorunun dışbükey olduğuna inanıyorum (ya da belki phi'yi de bilmelisin? Emin değilim). Her durumda, diğer parametrelerin başlangıç ​​değerlerini bilmek, doğru basketbol sahasındalarsa, omega kadar önemli olmamalıdır. Muhtemelen FFT'den diğer parametrelerin iyi tahminlerini alabilirsiniz, ancak bunun nasıl işe yarayacağından emin değilim.


1
Bu ipucu için teşekkürler. Sadece biraz açıklığa kavuşturmak için: veri, genlerin periyodikliğinin zaman içinde ölçüldüğü, yani gösterilen veriler bir genin ekspresyon verileri olduğu bir mikro-dizinin bir parçasıdır. Şimdi sorun şu ki, bu metodu farklı periyodiklik ve amplitüdlere sahip yaklaşık 40k genine uygulamak istiyorum. Bu nedenle, başlangıç ​​koşullarından bağımsız olarak iyi bir uyum bulunması oldukça önemlidir.
Pascal,

1
@Pascal Omega için başlangıç ​​değerini otomatik olarak seçme önerisi için yukarıdaki güncellemeleri görün.
David J. Harris,

2
ϕab

Burada x değerlerinin nerede devreye girdiğini merak ediyorum. Tabii omega için bir fark yaratıyor, verilen y değerlerinin 1 veya 5 x adımlarla ayrılıp ayrılmadığı, değil mi?
Ocak'ta

1
Programlama ipucu soruya bağlı değil: R nesnelerini farklı şekilde adlandırırken dikkatli olun foo.bar. Bu, R'nin sınıflar için yöntemleri nasıl belirttiğinden kaynaklanmaktadır .
Firebug

10

Daha önce söylenenlere bir alternatif olarak, ARIMA model sınıfından bir AR (2) modelinin bir sinüs dalga modeline sahip tahminler üretmek için kullanılabileceğini belirtmek faydalı olabilir.

yt=C+ϕ1yt1+ϕ2yt2+at
Cϕ1ϕ2at

ϕ12+4ϕ2<0.

Panratz (1991) stokastik çevrimler hakkında bize şunları söyler:

Stokastik döngü paterni tahmin paterninde çarpık sinüs dalga paterni düşünülebilir: Stokastik (olasılıksal) periyot, genlik ve faz açısına sahip bir sinüs dalgasıdır.

Böyle bir modelin verilere uygun olup olmadığını görmek için, auto.arima()AR (2) modelini önerip önermeyeceğini bulmak için tahmin paketindeki işlevi kullandım . auto.arima()Fonksiyonun bir ARMA (2,2) modeli önerdiği ortaya çıktı ; saf bir AR (2) modeli değil, ama bu sorun değil. Tamam, çünkü bir ARMA (2,2) modelinde bir AR (2) bileşeni var, bu yüzden aynı kural (stokastik çevrimler hakkında) uygulanıyor. Yani, sinüs dalgası tahminlerinin üretilip üretilmeyeceğini görmek için yukarıda belirtilen durumu hala kontrol edebiliriz.

Sonuçları auto.arima(y)aşağıda gösterilmiştir.

Series: y 
ARIMA(2,0,2) with non-zero mean 

Coefficients:
         ar1      ar2      ma1     ma2  intercept
      1.7347  -0.8324  -1.2474  0.6918    10.2727
s.e.  0.1078   0.0981   0.1167  0.1911     0.5324

sigma^2 estimated as 0.6756:  log likelihood=-60.14
AIC=132.27   AICc=134.32   BIC=143.5

ϕ12+4ϕ2<01.73472+4(0.8324)<00.3202914<0

Aşağıdaki grafik orijinal seriyi y, ARMA (2,2) modelinin uygunluğunu ve 14 örneklem dışı tahminini göstermektedir. Görülebileceği gibi, örnek dışı tahminler sinüs dalgası düzenini takip eder.

görüntü tanımını buraya girin

Aklında iki şey var. 1) Bu sadece çok hızlı bir analizdir (otomatik bir araç kullanarak) ve Box-Jenkins metodolojisini izlemenin uygun bir tedavisi olacaktır. 2) ARIMA tahminleri kısa vadeli tahminlerde iyidir, bu nedenle @David J. Harris ve @Glen_b tarafından verilen cevaplardaki modellerden uzun vadeli tahminlerin daha güvenilir olduğunu görebilirsiniz.

Son olarak, umarım bu zaten çok bilgilendirici bazı cevaplar için güzel bir ektir.

Referans : Dinamik regresyon modelleriyle tahmin: Alan Pankratz, 1991, (John Wiley ve Sons, New York), ISBN 0-471-61528-5


1

Bir sinüs eğrisini belirli bir veri setine sığdırmak için mevcut yöntemler parametrelerin ilk tahminini ve ardından etkileşimli bir işlemi gerektirir. Bu doğrusal olmayan bir regresyon problemidir. Farklı bir yöntem, doğrusal bir regresyonun uygun bir integral denklemi sayesinde doğrusal bir regresyona dönüştürülmesinden oluşur. Daha sonra, ilk tahminde bulunmaya gerek yoktur ve yinelemeli sürece gerek yoktur: montaj doğrudan elde edilir. Y = a + r * sin (w * x + phi) işlevi veya y = a + b * sin (w * x) + c * cos (w * x) işlevi durumunda, kağıdın 35-36. Sayfalarına bakın. Scribd'de yayınlanan "Régression sinusoidale": http://www.scribd.com/JJacquelin/documents Fonksiyonun çalışması durumunda y = a + p * x + r * sin (w * x + phi): "Karışık doğrusal ve sinüzoidal regresyon" bölümünün 49-51. Daha karmaşık fonksiyonlarda, genel işlem "Genelleştirilmiş sinüzoidal regresyon" sayfa 54-61 bölümünde açıklanır, ardından sayısal bir örnek y = r * sin (w * x + phi) + (b / x) + c * ln (x), sayfa 62-63


0

Kosinüs görünümlü verilerinizin en düşük ve en yüksek noktasını biliyorsanız, tüm kosinüs katsayılarını hesaplamak için bu basit işlevi kullanabilirsiniz:

getMyCosine <- function(lowest_point=c(pi,-1), highest_point=c(0,1)){
  cosine <- list(
    T = pi / abs(highest_point[1] - lowest_point[1]),
    b = - highest_point[1],
    k = (highest_point[2] + lowest_point[2]) / 2,
    A = (highest_point[2] - lowest_point[2]) / 2
  )
  return(cosine)
}

Aşağıda, en düşük ve en sıcak saat için saat ve sıcaklık değerlerini girerek, bir kosinüs işleviyle gün boyunca sıcaklık değişimini simüle etmek için kullanılır:

c <- getMyCosine(c(4,10),c(17,25)) 
# lowest temprature at 4:00 (10 degrees), highest at 17:00 (25 degrees)

x = seq(0,23,by=1);  y = c$A*cos(c$T*(x +c$b))+c$k ; 
library(ggplot2);   qplot(x,y,geom="step")

Çıktı aşağıdadır: En düşük ve en yüksek noktalardan hesaplanan kosinüs


3
Bu yaklaşım, saf sinüzoidal davranıştan rastgele görünen herhangi bir ayrılmaya karşı özellikle duyarlı gibi görünmektedir; bu da, soruyu anlattığı gibi neredeyse tüm veri kümeleri için geçerli değildir. Muhtemelen, bu konuda önerilen diğer yinelemeli yaklaşımların bazıları için başlangıç ​​değerleri sağlamak için kullanılabilir.
whuber

katılıyorum, en basit olanı, bazı varsayımlar altında basit bir yaklaşım için iyi olurdu
IVIM

0

Diğer bir seçenek ise, optim veya nls genel fonksiyonunu kullanmaktır . İkisini de denedim, hiçbiri tamamen sağlam değil

Aşağıdaki işlevler verileri y cinsinden alır ve parametreleri hesaplar.

calc.period <- function(y,t)
{     
   fs <- 1/(t[2]-t[1])
   ssp <- spectrum(y,plot=FALSE )  
   fN <- ssp$freq[which.max(ssp$spec)]
   per <- 1/(fN*fs)
   return(per)
 }

fit.sine<- function(y, t)
{ 
  data <- data.frame(x = as.vector(t), y=as.vector(y))
  min.RSS <- function (data, par){
    with(data, sum((par[1]*sin(2*pi*par[2]*x + par[3])+par[4]-y )^2))
  }  
  amp = sd(data$y)*2.**0.5
  offset = mean(data$y)
  fest <- 1/calc.period(y,t)
  guess = c( amp, fest,  0,   offset)
  #res <- optim(par=guess, fn = min.RSS, data=data ) 
  r<-nls(y~offset+A*sin(2*pi*f*t+phi), 
     start=list(A=amp, f=fest, phi=0, offset=offset))
  res <- list(par=as.vector(r$m$getPars()))
  return(res)
}

 genSine <- function(t, params)
     return( params[1]*sin(2*pi*params[2]*t+ params[3])+params[4])

kullanım şudur:

t <- seq(0, 10, by = 0.01)
A <- 2 
f <- 1.5
phase <- 0.2432
offset <- -2

y <- A*sin(2*pi*f*t +phase)+offset + rnorm(length(t), mean=0, sd=0.2)

reslm1 <- fit.sine(y = y, t= t)

Aşağıdaki kod verileri karşılaştırır

ysin <- genSine(as.vector(t), params=reslm1$par)
ysin.cor <- genSine(as.vector(t), params=c(A, f, phase, offset))

plot(t, y)
lines(t, ysin, col=2)
lines(t, ysin.cor, col=3)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.