Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

We now look at another example for nonlinear regression. The following dataset is downloaded from https://www.sidc.be/SILSO/datafiles (silso stands for sunspot index and long term solar observations). Data description can be found here: https://www.sidc.be/SILSO/infosnytot. There are five columns:

  1. Column 1 is the year (2020.5 refers to the year 2020 for example)

  2. Column 2 is the yearly mean total sunspot number (this is obtained by taking a simple arithmetic mean of the daily sunspot number over all the days for that year)

  3. Column 3 is the yearly mean standard deviation of the input sunspot numbers from individual stations (-1 indicates missing value)

  4. Column 4 is the number of observations used to compute the yearly mean sunspot number (-1 indicates a missing value)

  5. Column 5 is a definitive/provisional marker (1 indicates that the data point is definitive, and 0 indicates that it is still provisional)

We shall work with the data in column 2 (yearly mean total sunspot number).

        0     1    2  3  4
0  1700.5   8.3 -1.0 -1  1
1  1701.5  18.3 -1.0 -1  1
2  1702.5  26.7 -1.0 -1  1
3  1703.5  38.3 -1.0 -1  1
4  1704.5  60.0 -1.0 -1  1
     year  sunspotsmean  sunspotssd  sunspotsnobs  isdefinitive
0  1700.5           8.3        -1.0            -1             1
1  1701.5          18.3        -1.0            -1             1
2  1702.5          26.7        -1.0            -1             1
3  1703.5          38.3        -1.0            -1             1
4  1704.5          60.0        -1.0            -1             1
5  1705.5          96.7        -1.0            -1             1
6  1706.5          48.3        -1.0            -1             1
7  1707.5          33.3        -1.0            -1             1
8  1708.5          16.7        -1.0            -1             1
9  1709.5          13.3        -1.0            -1             1
       year  sunspotsmean  sunspotssd  sunspotsnobs  isdefinitive
316  2016.5          39.8         3.9          9940             1
317  2017.5          21.7         2.5         11444             1
318  2018.5           7.0         1.1         12611             1
319  2019.5           3.6         0.5         12884             1
320  2020.5           8.8         4.1         14440             1
321  2021.5          29.6         7.9         15233             1
322  2022.5          83.2        14.2         15258             1
323  2023.5         125.5        19.2         13286             1
324  2024.5         154.7        22.0         12265             1
325  2025.5         123.2        17.8         12473             1
0     8.3
1    18.3
2    26.7
3    38.3
4    60.0
Name: sunspotsmean, dtype: float64
<Figure size 640x480 with 1 Axes>

We will fit the sinusoidal model:

yt=β0+β1cos⁡(2πft)+β2sin⁡(2πft)+ϵty_t = \beta_0 + \beta_1 \cos(2 \pi f t) + \beta_2 \sin(2 \pi f t) + \epsilon_t

with ϵt\epsilon_t being i.i.d N(0,σ2)N(0, \sigma^2). When ff is known, this is a linear regression model. We can fit this model to the data and see how good the fit is while varying ff. This will give us an idea of which frequencies give good fits to the data. Later we shall consider ff as an unknown parameter and discuss estimation and inference for ff.

                            OLS Regression Results                            
==============================================================================
Dep. Variable:           sunspotsmean   R-squared:                       0.305
Model:                            OLS   Adj. R-squared:                  0.301
Method:                 Least Squares   F-statistic:                     70.85
Date:                Thu, 17 Sep 2026   Prob (F-statistic):           3.08e-26
Time:                        19:27:55   Log-Likelihood:                -1747.8
No. Observations:                 326   AIC:                             3502.
Df Residuals:                     323   BIC:                             3513.
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         78.8672      2.868     27.496      0.000      73.224      84.510
x1           -29.2653      4.058     -7.213      0.000     -37.248     -21.283
x2           -38.2710      4.055     -9.438      0.000     -46.248     -30.293
==============================================================================
Omnibus:                       56.201   Durbin-Watson:                   0.385
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               92.676
Skew:                           1.000   Prob(JB):                     7.51e-21
Kurtosis:                       4.679   Cond. No.                         1.42
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
<Figure size 640x480 with 1 Axes>

As before, we use RSS to calculate goodness of fit. We can vary over the values of ff and find the ff for which RSS is minimized.

1237547.3570884266
1245855.676842052
866137.4198804202
1084321.0991144143
<Figure size 640x480 with 1 Axes>
0.09090454522726137
11.000550055005501

To estimate β0,β1,β2\beta_0, \beta_1, \beta_2 and σ\sigma, we simply run linear regression with f=f^f = \hat{f}:

                            OLS Regression Results                            
==============================================================================
Dep. Variable:           sunspotsmean   R-squared:                       0.305
Model:                            OLS   Adj. R-squared:                  0.301
Method:                 Least Squares   F-statistic:                     70.85
Date:                Thu, 17 Sep 2026   Prob (F-statistic):           3.07e-26
Time:                        19:32:19   Log-Likelihood:                -1747.8
No. Observations:                 326   AIC:                             3502.
Df Residuals:                     323   BIC:                             3513.
Df Model:                           2                                         
Covariance Type:            nonrobust                                         
==============================================================================
                 coef    std err          t      P>|t|      [0.025      0.975]
------------------------------------------------------------------------------
const         78.8668      2.868     27.496      0.000      73.224      84.510
x1           -38.4278      4.055     -9.477      0.000     -46.405     -30.450
x2           -29.0623      4.058     -7.163      0.000     -37.045     -21.080
==============================================================================
Omnibus:                       56.220   Durbin-Watson:                   0.385
Prob(Omnibus):                  0.000   Jarque-Bera (JB):               92.706
Skew:                           1.001   Prob(JB):                     7.40e-21
Kurtosis:                       4.679   Cond. No.                         1.42
==============================================================================

Notes:
[1] Standard Errors assume that the covariance matrix of the errors is correctly specified.
const    78.866776
x1      -38.427771
x2      -29.062340
dtype: float64 51.78304255870164

Let us now do uncertainty quantification for ff. We use the posterior formula:

posterior(f)∝I{0<f<1/2}∣XfTXf∣−1/2(1RSS(f))(n−p)/2\begin{align*} \text{posterior}(f) \propto I\{0 < f < 1/2 \} |X_f^T X_f|^{-1/2} \left(\frac{1}{RSS(f)} \right)^{(n-p)/2} \end{align*}

The main role in this calculation is played by the RSS(f)RSS(f) term. The other term ∣XfTXf∣−1/2|X_f^T X_f|^{-1/2} generally does not vary much with ff. This is demonstrated below.

While evaluating the log-posterior, we remove values of ff that are too close to 0 or 0.5 (because otherwise the determinant term ∣XfTXf∣|X_f^T X_f| might be too close to zero).

Below we plot the log-posterior with the determinant term (which is the correct formula), and without the determinant term.

<Figure size 640x480 with 1 Axes>

The two curves above look largely parallel (except for frequencies ff which are close to the endpoints). This suggests that the determinant has minimal impact on the posterior. Below we plot their difference.

<Figure size 640x480 with 1 Axes>

Again the determinant term is only having an effect near the endpoints. This shows that the main term in the posterior is the term involving the RSS.

<Figure size 640x480 with 1 Axes>

The above plot looks similar to the plot of RSS(f)RSS(f) (except it is upside down). The maximizer of the posterior density here is exactly the same as the MLE.

0.09090454522726137
0.09090454522726137
11.000550055005501
11.000550055005501

Below we plot the posterior. This curve is much more peaked than the log posterior plot. In fact, only one peak is visible in the posterior.

<Figure size 640x480 with 1 Axes>

To better visualize the structure of the posterior, we can zoom near the maximizer.

<Figure size 640x480 with 1 Axes>

Below we find 95% Bayesian uncertainty interval for ff. We calculate the posterior probability around the posterior maximizer, and keep expanding the region until the probability is 0.95.

0.07106153136554949
0.21091870883723826
0.6723787250751743
0.7522883959745028
[0.09090455 0.09075454 0.09105455]

To get the interval for the period (which is the inverse of frequency), do the following.

[11.00055006 10.98242724 11.01873278]

This interval is highly concentrated around 11 years. To better interpret the uncertainty interval, we can convert the uncertainty gap into days as follows:

array([6.61482829, 6.63669549])

So the uncertainty period can be summarized as:

[11 years−13 days,11 years+13 days]\begin{align*} [11~\text{years} - 13~\text{days}, 11~\text{years} + 13~\text{days}] \end{align*}

The reason for such tight concentration is that RSS(f)RSS(f) significantly increases even if ff changes slightly from 11.

866137.4198804202 887297.8910230198 891246.0938016074

The above clearly shows that the RSS increases significantly even if ff moves slightly away from 1/111/11. This is the reason why we get such a narrow uncertainty interval for ff around 1/111/11.

The assumptions of the model (specifically ϵt∼i.i.dN(0,σ2)\epsilon_t \overset{\text{i.i.d}}{\sim} N(0, \sigma^2)) also contribute to getting such a narrow interval. Below is a plot of the residuals for this model (with ff fixed at the estimated frequency).

<Figure size 1000x400 with 1 Axes>

From the above residual plot, it appears that assuming that the residuals have zero mean is probably not a good assumption. We can try to fit the model: β0+β1cos⁡(2πft)+β2sin⁡(2πft)+ϵt\beta_0 + \beta_1 \cos(2 \pi f t) + \beta_2 \sin(2 \pi f t) + \epsilon_t to the residuals of the previous model. We can see what estimate of ff we will be getting.

<Figure size 640x480 with 1 Axes>
0.09980998099809982
10.019038076152304

The estimate of ff is somewhat close to but different from the previous ff (which corresponds to 1/11). Overall, the model we have now is:

yt=β0+β11cos⁡(2πf1t)+β12sin⁡(2πf1t)+β21cos⁡(2πf2t)+β22sin⁡(2πf2t)+ϵt.\begin{align*} y_t = \beta_0 + \beta_{11} \cos(2 \pi f_1 t) + \beta_{12} \sin(2 \pi f_1 t) + \beta_{21} \cos(2 \pi f_2 t) + \beta_{22} \sin(2 \pi f_2 t) + \epsilon_t. \end{align*}

We shall revisit such models next week.

Efficient Computation of RSS(f) at Fourier Frequencies

Given a time series dataset y1,…,yny_1, \dots, y_n, the quantity RSS(f)RSS(f) is defined by

RSS(f):=min⁡β0,β1,β2∑t=1n(yt−β0−β1cos⁡(2πft)−β2sin⁡(2πft))2RSS(f) := \min_{\beta_0, \beta_1, \beta_2} \sum_{t=1}^n \left(y_t - \beta_0 - \beta_1 \cos (2 \pi f t) - \beta_2 \sin(2 \pi f t) \right)^2

For each frequency ff, RSS(f)RSS(f) tells us how well the best sinusoid at frequency ff fits the data. This is used for identifying periodicities present in the data.

Computing RSS(f)RSS(f) for each ff in a grid (as above) can be quite time-consuming if the sample size nn is large. For example, consider the following audio dataset. The "Hear Piano Note - Middle C.mp3$ is an audio file consisting of about 14 seconds. It contains the sound of the Middle C note in the piano. The python library “Librosa” will be used for loading the audio file (see https://librosa.org/doc/latest/index.html for instructions on installing librosa, and tutorials etc.)

301272
22050
13.66312925170068
Loading...

This dataset has n=301272n = 301272 points. Clearly this is a time series dataset of a large size. The data (sound waveform) is plotted below.

<Figure size 640x480 with 1 Axes>

The full plot of the data is not very revealing as the data size is very long. But if we restrict to a smaller portion of the dataset, we can visualize the cyclical behavior more easily.

<Figure size 640x480 with 1 Axes>

In order to figure out the main frequencies present in the data, we can fit the sinusoidal model to this dataset. As before, we can compute RSS(f)RSS(f) for each ff in a grid of frequencies in [0,1/2][0, 1/2], and then find the best ff with the smallest RSS(f)RSS(f). However this code will take way too long to run because of the large sample size.

<Figure size 640x480 with 1 Axes>
0.011801180118011801

The frequency corresponding to the middle CC note on the piano is approximately 261.63 Hz (see e.g., C (musical note)). How does 261.63 Hz relate to the periodogram maximizing frequency (or, equivalently, RSS minimizing frequency) above? The connection between the two is obtained by multiplication by the sampling rate srsr. The sinusoid cos⁡(2πft)\cos (2 \pi f t) completes ff cycles in unit time. In this dataset, one unit of time is given by 1/sr1/sr seconds. So this sinusoid completes f×srf \times sr cycles in one sec which means that, in Hertz (which is the number of cycles per second), the frequency ff corresponds to f×srf \times sr.

260.2160216021602

There is a different and much more efficient way of calculating the RSS, using the grid given by Fourier frequencies, and the FFT algorithm. We shall study the details behind this method in the next lecture.

0.011799968135107145
260.18929737911253

This method also works if some noise is added to the original audio file. Check thi by going back and changing the sig_noise parameter. For this example, the correct note is recovered even when sig_noise is as high as 1.4 (maybe even slightly larger). You can also verify that the method breaks down when sig_noise is much larger.