Relation of Number of Parameters and Error:
Contradicting trends depend on how to measure
Brunton & Kutz (2019) explain that error becomes larger as number of parameters increases beyond the true number of parameters. But, this increase is against the naïve intuition, because a model with larger number of parameters includes that with smaller number of parameters. To investigate their counter-intuitive explanation, I wrote a Python script shown in Listing 1, which is based on Code 4.14 in Brunton & Kutz (2019). In the script, the true model is given by a quadratic function:
Data are given with a Guassian noise
Models are
In explaining the counter-intuitive trend, Brunton & Kutz (2019) defined the error as difference between the true model and the estimated model.
But, is unobservable, so cannot be calculated. Empirically, we can calculate error by the following
By running the script in Listing 1, we can get relations between number of parameters of and the errors En and Err.
Run the script in Listing 1, then the graphs in Figure 1 will be shown. (The script was run in Python 3.11.8/Anaconda)
Figure 1 Relations between number of parameters and errors.
Errors En between the true values and the estimated models are shown by red triangles, which show the increasing trend explained by Brunton & Kutz (2019).
Green inverted triangles show observable errors and exhibit decreasing trend.
Criteria used in model selection are explained by Brunton & Kutz (2019). To study on the criteria, simple scripts were prepared at this website.
Listing 1 Script to investigate relation between number of parameters and error.
import numpy as np
import matplotlib.pyplot as plt
M = 20
n = 1000
L = 4
n_pnts = 100
x = np.linspace(0, L, n_pnts)
En = np.empty((n, M))
Err = np.empty((n, M))
for jj in range(M):
A = np.empty((n_pnts, jj+1))
for j in range(jj+1):
A[:,j] = x ** j
f = x**2
# True value
for j in range(n):
# True value +
Noise
fn =
f + 0.1 * np.random.normal(size=n_pnts)
An =
np.linalg.pinv(A) @ fn
fna
= A @ An
# Error from the
true values
En[j, jj] = np.linalg.norm(f - fna) / np.linalg.norm(f)
# Error fron the
givendata
Err[j, jj] = np.linalg.norm(fn - fna) / np.linalg.norm(fn)
plt.figure(figsize=(12,5))
plt.subplot(1,2,1)
Mean_En = np.mean(En, axis=0)
plt.plot(range(M), Mean_En, '^',
c='r', lw=0, label='w.r.t. True values')
Mean_Err = np.mean(Err, axis=0)
plt.plot(range(M), Mean_Err, 'v', c =
'g', lw=0, label='w.r.t. Data')
plt.boxplot(En,
positions=np.arange(0,M))
plt.boxplot(Err,
positions=np.arange(0,M))
plt.xticks(np.arange(0, M))
plt.xlabel('Polynomial
Degree',fontsize=14)
plt.ylabel('Error', fontsize=14)
plt.title('Degree >= 0',
fontsize=16)
plt.legend(fontsize=14)
#lt.tight_layout()
#plt.show()
plt.subplot(1,2,2)
plt.plot(np.arange(M)[2:],
Mean_En[2:], '^-', c='r', lw=1, label='w.r.t. True values')
plt.plot(np.arange(M)[2:],
Mean_Err[2:], 'v-', c = 'g', lw=1, label='w.r.t. Data')
plt.xticks(np.arange(2, M))
plt.xlabel('Polynomial Degree',
fontsize=14)
plt.ylabel('Error', fontsize=14)
plt.boxplot(En[:,2:],
positions=np.arange(2, M))
plt.boxplot(Err[:,2:],
positions=np.arange(2, M))
plt.title('Degree >= 2',
fontsize=16)
plt.legend()
plt.tight_layout()
plt.show()
S. L. Brunton and J. N. Kutz (2019) Data-driven science and engineering: Machine learning, dynamical systems, and control. Cambridge University Press.