Phù hợp với một thuật ngữ hình sin cho dữ liệu


26

Mặc dù tôi đã đọc bài đăng này , tôi vẫn không biết làm thế nào để áp dụng điều này vào dữ liệu của riêng tôi và hy vọng rằng ai đó có thể giúp tôi.

Tôi có các dữ liệu sau:

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

Và bây giờ tôi chỉ đơn giản là muốn phù hợp với một làn sóng hình sin

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

với bốn ẩn số , , và với nó.ω ϕ CAωϕC

Phần còn lại của mã của tôi trông như sau

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

Nhưng kết quả thực sự rất kém.

Phù hợp với sin

Tôi sẽ rất đánh giá cao bất kỳ sự giúp đỡ.

Chúc mừng.


Bạn đang cố gắng khớp một sóng hình sin với dữ liệu hay bạn đang cố gắng khớp một loại mô hình hài nào đó với một thành phần sin và cos? Có một chức năng điều hòa trong gói TSA trong R mà bạn có thể muốn kiểm tra. Điều chỉnh mô hình của bạn bằng cách sử dụng và xem loại kết quả bạn nhận được.
Eric Peterson

5
Bạn đã thử các giá trị bắt đầu khác nhau? Hàm mất mát của bạn là không lồi, vì vậy các giá trị bắt đầu khác nhau có thể dẫn đến các giải pháp khác nhau.
Stefan Wager

1
Hãy cho chúng tôi biết thêm về dữ liệu. Thông thường có một chu kỳ đã biết, do đó không cần phải ước tính từ dữ liệu. Đây là một chuỗi thời gian hay cái gì khác? Sẽ dễ dàng hơn nhiều nếu bạn có thể điều chỉnh các thuật ngữ sin và cosin riêng biệt bằng một mô hình tuyến tính.
Nick Cox

2
Có một khoảng thời gian không xác định làm cho mô hình của bạn trở nên phi tuyến (một sự kiện như vậy được ám chỉ trong câu trả lời được chọn tại bài đăng được liên kết). Cho rằng, các tham số khác là tuyến tính có điều kiện; đối với một số thói quen LS phi tuyến mà thông tin là quan trọng và có thể cải thiện hành vi. Một lựa chọn có thể là sử dụng các phương pháp phổ để có được khoảng thời gian và điều kiện trên đó; một cách khác là cập nhật thời gian và các tham số khác thông qua tối ưu hóa phi tuyến tính và tuyến tính tương ứng theo kiểu lặp.
Glen_b -Reinstate Monica

(Tôi vừa chỉnh sửa câu trả lời ở đó để biến trường hợp cụ thể trong khoảng thời gian không xác định thành một ví dụ rõ ràng về những gì có thể khiến nó trở thành phi tuyến.)
Glen_b -Reinstate Monica

Câu trả lời:


18

ω

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

cốt truyện hình sin

(Một sự phù hợp tốt hơn có lẽ vẫn sẽ giải thích cho các ngoại lệ trong chuỗi đó theo một cách nào đó, làm giảm ảnh hưởng của chúng.)

---

ω

(Ngoài ra, bạn có thể cung cấp các ước tính này vào nls ... và bắt đầu nó đã được hội tụ.)


(+1) câu trả lời hay. Tôi đã cố gắng để phù hợp với mô hình tuyến tính lm(y~sin(2*pi*t)+cos(2*pi*t)nhưng điều này không hoạt động ( costhuật ngữ luôn luôn là 1). Chỉ tò mò thôi: hai dòng đầu tiên làm gì (tôi biết rằng spectrumước tính mật độ quang phổ)?
COOLSerdash

1
t2*pi*t

1
@COOLSerdash (ctd) - Dòng thứ 2 tìm tần số liên quan đến cực đại lớn nhất trong phổ và đảo ngược để xác định khoảng thời gian. Ít nhất là trong trường hợp này (nhưng tôi nghi ngờ rộng rãi hơn), mặc định về cơ bản xác định khoảng thời gian tối đa hóa khả năng chặt chẽ đến mức tôi đã xóa các bước tôi có để tối đa hóa khả năng hồ sơ trong khu vực trong khoảng thời gian đó. Chức năng spectrong TSA có thể tốt hơn (dường như có nhiều tùy chọn hơn, một trong số đó đôi khi có thể quan trọng), nhưng trong trường hợp này, đỉnh chính nằm ở cùng một vị trí với spectrumvì vậy tôi không bận tâm.
Glen_b -Reinstate Monica

@Glen_b phương pháp này hoạt động kỳ diệu cho trường hợp sử dụng của tôi. Tôi cũng cần điều chỉnh đường cong cos (x), nhưng nó cũng không hoạt động ... Tôi đã thay đổi reslmthành reslm <- lm(y ~ cos(2*pi/per*t)+tan(2*pi/per*t))nhưng điều đó có vẻ không ổn. Có gợi ý nào không?
Amit Kohli

Tại sao bạn có một thuật ngữ tan trong đó?
Glen_b -Reinstate Monica

15

2π/20

Khi tôi đặt đó vào nls's startdanh sách, tôi nhận được một đường cong đó là nhiều hơn nữa hợp lý, mặc dù nó vẫn có một số những thành kiến có hệ thống.

Tùy thuộc vào mục tiêu của bạn là gì với tập dữ liệu này, bạn có thể cố gắng cải thiện mức độ phù hợp bằng cách thêm các thuật ngữ bổ sung hoặc sử dụng phương pháp tiếp cận không tham số như quy trình Gaussian với hạt nhân định kỳ.

Phù hợp với sin

Tự động chọn giá trị bắt đầu

Nếu bạn muốn chọn tần số chi phối, bạn có thể sử dụng biến đổi Fourier nhanh (FFT). Đây là cách ra khỏi lĩnh vực chuyên môn của tôi, vì vậy tôi sẽ để những người khác điền thông tin chi tiết nếu họ muốn (đặc biệt là về bước 2 và 3), nhưng Rmã dưới đây sẽ hoạt động.

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

Bạn cũng có thể vẽ abs(truncated.fft)để xem liệu có các tần số quan trọng khác không, nhưng bạn sẽ phải mân mê tỷ lệ của trục x một chút.

Ngoài ra, tôi tin rằng @Glen_b là chính xác rằng vấn đề là lồi một khi bạn biết omega (hoặc có thể bạn cũng cần biết phi? Tôi không chắc chắn). Trong mọi trường hợp, việc biết các giá trị bắt đầu cho các tham số khác không nên quan trọng như đối với omega nếu chúng ở đúng sân bóng. Bạn có thể có thể nhận được ước tính khá của các tham số khác từ FFT, nhưng tôi không chắc nó sẽ hoạt động như thế nào.


1
Cảm ơn gợi ý đó. Chỉ cần làm rõ một chút: dữ liệu là một phần của microarray trong đó tính chu kỳ của gen được đo theo thời gian, tức là dữ liệu hiển thị là dữ liệu biểu hiện của một gen. Vấn đề bây giờ là tôi muốn áp dụng phương pháp này cho khoảng 40 nghìn gen, tất cả đều có chu kỳ và biên độ khác nhau. Vì vậy, điều khá quan trọng là một sự phù hợp tốt được tìm thấy độc lập với các điều kiện ban đầu.
Pascal

1
@Pascal Xem các cập nhật của tôi ở trên để biết khuyến nghị tự động chọn giá trị khởi đầu cho omega.
David J. Harris

2
φmộtb

Tôi tự hỏi nơi các giá trị x đi vào chơi ở đây. Chắc chắn nó tạo ra sự khác biệt cho omega, cho dù các giá trị y đã cho được phân tách bằng 1 hoặc 5 x bước, phải không?
quỳ

1
Mẹo lập trình không liên quan đến câu hỏi: thận trọng khi đặt tên các đối tượng R là foo.bar. Điều này là do cách R chỉ định các phương thức cho các lớp .
Bọ lửa

10

Thay thế cho những gì đã được nói, có thể đáng chú ý rằng một mô hình AR (2) từ lớp mô hình ARIMA có thể được sử dụng để tạo dự báo với mô hình sóng hình sin.

yt= =C+φ1yt-1+φ2yt-2+mộtt
Cφ1φ2mộtt

φ12+4φ2<0.

Panratz (1991) cho chúng ta biết những điều sau đây về chu kỳ ngẫu nhiên:

Một mô hình chu kỳ ngẫu nhiên có thể được nghĩ đến một mẫu sóng hình sin bị biến dạng trong mẫu dự báo: Đó là một sóng hình sin với chu kỳ ngẫu nhiên (xác suất), biên độ và góc pha.

Để xem liệu một mô hình như vậy có thể được trang bị cho dữ liệu tôi đã sử dụng auto.arima()chức năng từ gói dự báo để tìm hiểu xem liệu nó có gợi ý mô hình AR (2) không. Hóa ra auto.arima()hàm này gợi ý một mô hình ARMA (2,2); không phải là một mô hình AR (2) thuần túy, nhưng điều này là ổn. Không sao vì mô hình ARMA (2,2) chứa thành phần AR (2), do đó áp dụng quy tắc tương tự (về chu kỳ ngẫu nhiên). Đó là, chúng ta vẫn có thể kiểm tra điều kiện đã nói ở trên để xem liệu dự báo sóng hình sin sẽ được tạo ra.

Các kết quả auto.arima(y)được hiển thị dưới đây.

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)<0-0,3202914<0

Cốt truyện dưới đây cho thấy loạt ban đầu, y, sự phù hợp của mô hình ARMA (2,2) và 14 dự báo ngoài mẫu. Có thể thấy, các dự báo ngoài mẫu theo mô hình sóng hình sin.

nhập mô tả hình ảnh ở đây

Hãy ghi nhớ hai điều. 1) Đây chỉ là một phân tích rất nhanh (sử dụng một công cụ tự động) và một phương pháp điều trị thích hợp sẽ liên quan đến phương pháp Box-Jenkins. 2) Dự báo ARIMA rất tốt trong dự báo ngắn hạn, vì vậy bạn có thể thấy rằng dự báo dài hạn từ các mô hình trong câu trả lời của @David J. Harris và @Glen_b đáng tin cậy hơn.

Cuối cùng, hy vọng đây là một bổ sung tốt đẹp cho một số câu trả lời đã rất nhiều thông tin.

Tham khảo : Dự báo với các mô hình hồi quy động: Alan Pankratz, 1991, (John Wiley and Sons, New York), ISBN 0-471-61528-5


1

Các phương thức hiện tại để khớp đường cong sin với một tập dữ liệu nhất định đòi hỏi phải đoán trước các tham số, sau đó là một quá trình tương tác. Đây là một vấn đề hồi quy phi tuyến tính. Một phương pháp khác bao gồm chuyển đổi hồi quy phi tuyến tính thành hồi quy tuyến tính nhờ một phương trình tích phân thuận tiện. Sau đó, không cần dự đoán ban đầu và không cần quá trình lặp lại: sự phù hợp được lấy trực tiếp. Trong trường hợp hàm y = a + r * sin (w * x + phi) hoặc y = a + b * sin (w * x) + c * cos (w * x), xem trang 35-36 của bài báo "Réupion sinusoidale" được xuất bản trên Scribd: http://www.scribed.com/JJacquelin/document Trong trường hợp hàm y = a + p * x + r * sin (w * x + phi): trang 49-51 của chương "Hồi quy tuyến tính và hình sin hỗn hợp". Trong trường hợp các hàm phức tạp hơn, quy trình chung được giải thích trong chương "Hồi quy hình sin tổng quát" trang 54-61, tiếp theo là một ví dụ bằng số y = r * sin (w * x + phi) + (b / x) + c * ln (x), trang 62-63


0

Nếu bạn biết điểm thấp nhất và cao nhất của dữ liệu tìm kiếm cosin của mình, bạn có thể sử dụng hàm đơn giản này để tính tất cả các hệ số cosin:

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

Dưới đây, nó được sử dụng để mô phỏng sự thay đổi nhiệt độ trong suốt cả ngày với chức năng cosin, bằng cách nhập giá trị giờ và nhiệt độ cho giờ thấp nhất và ấm nhất:

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

Đầu ra dưới đây: Cosine tính từ điểm thấp nhất và cao nhất


3
Cách tiếp cận này dường như đặc biệt nhạy cảm với bất kỳ sự khởi hành trông ngẫu nhiên nào từ hành vi hình sin thuần túy, điều này sẽ khiến nó không thể áp dụng được cho hầu hết mọi bộ dữ liệu như được minh họa trong câu hỏi. Có thể hiểu được, nó có thể được sử dụng để cung cấp các giá trị khởi đầu cho một số phương pháp lặp khác được đề xuất trong luồng này.
whuber

đồng ý, đó là cách đơn giản nhất, sẽ tốt cho việc xấp xỉ đơn giản theo các giả định nhất định
IVIM

0

Một lựa chọn khác là sử dụng một hàm tổng quát optim hoặc nls. Tôi đã thử cả hai không ai trong số họ là hoàn toàn mạnh mẽ

Các hàm sau lấy dữ liệu theo y và tính toán các tham số.

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

việc sử dụng là như sau:

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)

Đoạn mã sau so sánh dữ liệu

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