Как найти подходящую для полусинусоидальной модели модель R?

37

Я хочу предположить, что температура поверхности моря в Балтийском море один и тот же год за годом, а затем описать это с помощью функции / линейной модели. У меня была идея просто ввести год в виде десятичного числа (или num_months / 12) и узнать, какой должна быть температура в это время. Бросив его в функцию lm () в R, он не распознает синусоидальные данные, поэтому просто создает прямую линию. Поэтому я поместил функцию sin () в скобку I () и попробовал несколько значений, чтобы вручную подогнать функцию, и это приближается к тому, что я хочу. Но море нагревается быстрее летом, а осенью остывает медленнее ... Итак, модель неверна в первый год, затем становится более правильной через пару лет, а потом, я думаю, в будущем она станет более и еще раз неправильно.

Как я могу получить R, чтобы оценить модель для меня, чтобы мне не приходилось угадывать числа самостоятельно? Ключевым моментом здесь является то, что я хочу, чтобы год за годом он давал одни и те же значения, а не был бы верным в течение одного года. Если бы я знал больше о математике, возможно, я мог бы предположить, что это что-то вроде Пуассона или Гаусса вместо греха (), но я тоже не знаю, как это сделать. Любая помощь, чтобы приблизиться к хорошему ответу будет принята с благодарностью.

Вот данные, которые я использую, и код для отображения результатов:

# SST from Bradtke et al 2010
ToY <- c(1/12,2/12,3/12,4/12,5/12,6/12,7/12,8/12,9/12,10/12,11/12,12/12,13/12,14/12,15/12,16/12,17/12,18/12,19/12,20/12,21/12,22/12,23/12,24/12,25/12,26/12,27/12,28/12,29/12,30/12,31/12,32/12,33/12,34/12,35/12,36/12,37/12,38/12,39/12,40/12,41/12,42/12,43/12,44/12,45/12,46/12,47/12,48/12)
Degrees <- c(3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5)
SST <- data.frame(ToY, Degrees)
SSTlm <- lm(SST$Degrees ~ I(sin(pi*2.07*SST$ToY)))
summary(SSTlm)
plot(SST,xlim=c(0,4),ylim=c(0,17))
par(new=T)
plot(data.frame(ToY=SST$ToY,Degrees=8.4418-6.9431*sin(2.07*pi*SST$ToY)),type="l",xlim=c(0,4),ylim=c(0,17))
GaRyu
источник

Ответы:

44

Это можно сделать с помощью линейной регрессии -

Вам просто нужен и и термин cos на каждой частоте.грехсоз

Причина, по которой вы можете использовать термин и cos в линейной регрессии для обработки сезонности с любой амплитудой и фазой, заключается в следующей тригонометрической идентичности :грехсоз

А «вообще» синусоидальная волна с с амплитудой и фазой ф , А грех ( х + φ ) , можно записать в виде линейной комбинации грех х + Ь соз х , где и б таковы , что = AφAгрех(Икс+φ)aгрехИкс+бсозИксaб иsinφ=bAзнак равноa2+б2 . Давайте посмотрим, что два эквивалентны:грехφзнак равнобa2+б2

aгрех(Икс)+бсоз(Икс)знак равноa2+б2(aa2+б2грех(Икс)+бa2+б2соз(Икс))знак равноA[грех(Икс)соз(φ)+соз(Икс)грех(φ)]знак равноAгрех(Икс+φ),

Вот «базовая» модель:

 SSTlm <- lm(Degrees ~ sin(2*pi*ToY)+cos(2*pi*ToY),data=SST)
 summary(SSTlm)

[Надрез]

Coefficients:
                      Estimate Std. Error t value Pr(>|t|)    
(Intercept)              8.292      0.135   61.41   <2e-16 *** 
sin(2 * pi * ToY)       -5.916      0.191  -30.98   <2e-16 ***  
cos(2 * pi * ToY)       -4.046      0.191  -21.19   <2e-16 *** 
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1   1 

Residual standard error: 0.9355 on 45 degrees of freedom
Multiple R-squared: 0.969,      Adjusted R-squared: 0.9677 
F-statistic: 704.3 on 2 and 45 DF,  p-value: < 2.2e-16 

 plot(Degrees~ToY,ylim=c(1.5,16.5),data=SST)
 lines(SST$ToY,SSTlm$fitted,col=2)

грех подходит

Изменить: Важное примечание - Термин t работает, потому что период функции был настроен так, что один период = 1 единица t . Если период отличается от 1, скажем, период ω , то вам нужно ( 2 π / ω )2πTTω вместо(2π/ω)T

Вот модель со второй гармоникой:

 SSTlm2 <- lm(Degrees ~ sin(2*pi*ToY)+cos(2*pi*ToY)
                        +sin(4*pi*ToY)+cos(4*pi*ToY),data=SST)
 summary(SSTlm2)

[Надрез]

Coefficients:
                  Estimate Std. Error  t value Pr(>|t|)    
(Intercept)        8.29167    0.02637  314.450  < 2e-16 ***  
sin(2 * pi * ToY) -5.91562    0.03729 -158.634  < 2e-16 ***  
cos(2 * pi * ToY) -4.04632    0.03729 -108.506  < 2e-16 ***  
sin(4 * pi * ToY)  1.21244    0.03729   32.513  < 2e-16 ***  
cos(4 * pi * ToY)  0.33333    0.03729    8.939 2.32e-11 ***  
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1   1 

Residual standard error: 0.1827 on 43 degrees of freedom
Multiple R-squared: 0.9989,     Adjusted R-squared: 0.9988 
F-statistic:  9519 on 4 and 43 DF,  p-value: < 2.2e-16 

 plot(Degrees~ToY,ylab="Degrees",xlab="ToY",ylim=c(1.5,16.5),data=SST)
 lines(SSTlm2$fitted~ToY,col=2,data=SST)

грех подходит 2

... и т. д., 6*pi*ToYи т. д. Если бы в данных было немного шума, я бы, вероятно, остановился на этой второй модели.

С достаточным количеством терминов вы можете точно подобрать асимметричные и даже зубчатые периодические последовательности, но получающиеся совпадения могут «покачиваться». Вот асимметричная функция (это пилообразная пилообразный), добавленная к уменьшенной версии вашей периодической функции) с третьей (красной) и четвертой (зеленой) гармониками. Зеленая подгонка в среднем немного ближе, но «волнистая» (даже когда подгонка проходит через каждую точку, подгонка может быть очень волнистой между точками).

грех подходит 3 и 4

созгрех

Если вы хотите, чтобы подгонки были более гладкими, чем этот подход для негладких рядов, вы можете рассмотреть периодические подгонки сплайнов .

Еще один подход заключается в использовании сезонных манекенов, но подход sin / cos часто лучше, если это гладкая периодическая функция.

Такой подход к сезонности может также адаптироваться к ситуациям, когда меняется сезонность, например, с использованием тригонометрической или фиктивной сезонности с моделями пространства состояний.


Хотя подход линейной модели, обсуждаемый здесь, прост в использовании, одно из преимуществ подхода нелинейной регрессии @ COOLSerdash заключается в том, что он может работать в гораздо более широком диапазоне ситуаций - вам не нужно сильно менять, прежде чем вы окажетесь в ситуации, когда линейный регрессия больше не подходит, но все еще можно использовать нелинейные наименьшие квадраты ( одним из таких случаев может быть наличие неизвестного периода ).

Glen_b - Восстановить Монику
источник
Потрясающе! Спасибо, я действительно должен попытаться узнать больше о методах работы с частотами. Я не совсем понимаю, зачем нужна часть cos, но знание этого принципа облегчает реализацию.
GaRyu
@COOLSerdash - на самом деле, я бы хотел, чтобы вы не удалили свой ответ (действительно, я проголосовал за него); у него есть преимущество работы в более широком диапазоне обстоятельств; подправьте несколько вещей о проблеме, и вы можете потерять линейность - и тогда мой подход бесполезен, но ваш все еще работает. Я думаю, что так много можно сказать, чтобы быть в состоянии сделать это таким образом.
Glen_b
@Glen_b Извините, я подумал, что ваше сообщение сделало мое излишним, потому что я не использовал стандартный способ решения проблемы. Я восстановил это.
COOLSerdash
соз
1
Это был не я ... Вы говорите смещение фазы, как будто это назвало то, что происходит, и это происходит математически. Но для вас ключевым моментом, скорее всего, будет то, что 31 декабря / 1 января является произвольным источником времени года, учитывая запаздывание в реакции температуры на изменения в приеме излучения. Таким образом, фазовый сдвиг - это также название для чего-то климатологического, времени минимальной и максимальной температуры относительно вашей системы записи. (Это небольшая деталь, но я предпочитаю количественно определять время года за 12 месяцев как 1/24, 3/24, ..., 23/24.)
Ник Кокс
10

Температура, которую вы указываете в своем вопросе, повторяется ровно каждый год. Я подозреваю, что это не очень измеренные температуры за четыре года. В вашем примере вам не понадобится модель, потому что температура точно повторяется. Но в противном случае вы можете использовать nlsфункцию, чтобы соответствовать синусоиде:

ToY <- c(1/12,2/12,3/12,4/12,5/12,6/12,7/12,8/12,9/12,10/12,11/12,12/12,13/12,14/12,15/12,16/12,17/12,18/12,19/12,20/12,21/12,22/12,23/12,24/12,25/12,26/12,27/12,28/12,29/12,30/12,31/12,32/12,33/12,34/12,35/12,36/12,37/12,38/12,39/12,40/12,41/12,42/12,43/12,44/12,45/12,46/12,47/12,48/12)
Degrees <- c(3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5,3,2,2.2,4,7.6,13,16,16.1,14,10.1,7,4.5)
SST <- data.frame(ToY, Degrees)

par(cex=1.5, bg="white")
plot(Degrees~ToY,xlim=c(0,4),ylim=c(0,17), pch=16, las=1)

nls.mod <-nls(Degrees ~ a + b*sin(2*pi*c*ToY), start=list(a = 1, b = 1, c=1))

co <- coef(nls.mod) 
f <- function(x, a, b, c) {a + b*sin(2*pi*c*x) }

curve(f(x, a=co["a"], b=co["b"], c=co["c"]), add=TRUE ,lwd=2, col="steelblue")

NLS подходит

Но подгонка не очень хорошая, особенно в начале. Кажется, что ваши данные не могут быть адекватно смоделированы простой синусоидой. Может быть, более сложная тригонометрическая функция сработает?

nls.mod2 <-nls(Degrees ~ a + b*sin(2*pi*c*ToY)+d*cos(2*pi*e*ToY), start=list(a = 1, b = 1, c=1, d=1, e=1))

co2 <- coef(nls.mod2) 
f <- function(x, a, b, c, d, e) {a + b*sin(2*pi*c*x)+d*cos(2*pi*e*x) }

curve(f(x, a=co2["a"], b=co2["b"], c=co2["c"], d=co2["d"], e=co2["e"]), add=TRUE ,lwd=2, col="red")

NLS подходит 2

Красная кривая лучше соответствует данным. С помощью этой nlsфункции вы можете указать модель, которая вам подходит.

Или, может быть, вы могли бы использовать forecastпакет. В приведенном ниже примере я предположил, что временной ряд начался в январе 2010 года:

library(forecast)

Degrees.ts <- ts(Degrees, start=c(2010,1), frequency=12)

Degree.trend <- auto.arima(Degrees.ts)

degrees.forecast <- forecast(Degree.trend, h=12, level=c(80,95), fan=F)

plot(degrees.forecast, las=1, main="", xlab="Time", ylab="Degrees")

ARIMA

Поскольку данные являются детерминированными, доверительные интервалы не отображаются.

COOLSerdash
источник
4
Здесь нет никаких причин для нелинейных наименьших квадратов, не то, что это не будет работать достаточно хорошо. Вычислите заранее sin (2 * pi * ToY), cos (2 * pi * ToY) и введите их, lm()как и любые другие предикторы. Другими словами, lm()не нужно видеть никакой тригонометрии вообще. Однако вам может понадобиться другая модель, чтобы хорошо зафиксировать отмеченную асимметрию. Я не обычный пользователь R, но я часто использовал этот подход в другом месте (см. Stata-journal.com/sjpdf.html?articlenum=st0116 ).
Ник Кокс
@NickCox Спасибо, Ник, это очень полезный совет. Я обновлю свой ответ немного.
COOLSerdash
Глен был быстрее :)
COOLSerdash
1
@COOLserdash Я даже не видел там комментария Ника Кокса; это пришло, когда я генерировал свой ответ. (Этот подход довольно очевиден, если вы видели какой-либо ряд Фурье.)
Glen_b
2
Как подразумевает @Glen_b, это стандартный подход, просто не общеизвестный.
Ник Кокс