Notebook 17 – Math 2121, Fall 2020
In today's class we discussed how to compute a line of best fit by finding a least-squares solution to a certain linear system.
Here we explore the problem of finding a polynomial curve of best fit that passes through some given datapoints, which imagine as having the form
xxxxxxxxxxusing PlotsSuppose xvalues = [x1, x2, ..., xn]. The following method constructs the matrix
This is sometimes called a Vandermonde matrix.
If
is a polynomial satisfying
vandermonde (generic function with 2 methods)xxxxxxxxxxfunction vandermonde(xvalues, m=0) n = length(xvalues) m = m == 0 ? n : m A = zeros(n, m) for i=1:n for j=1:m A[i, j] = xvalues[i]^(j - 1) end end return Aend4×4 Array{Float64,2}:
1.0 1.0 1.0 1.0
1.0 3.0 9.0 27.0
1.0 4.0 16.0 64.0
1.0 5.0 25.0 125.0xxxxxxxxxxvandermonde([1, 3, 4, 5], 4)Any square Vandermonde matrix is invertible. Hence, there is a unique polynomial of degree
equally_spaced_xvalues (generic function with 1 method)xxxxxxxxxxfunction equally_spaced_xvalues(a, b, n) n >= 2 b > a delta = (b - a) / (n - 1) return [i for i=a:delta:b]end-1.0
-0.75
-0.5
-0.25
0.0
0.25
0.5
0.75
1.0
xxxxxxxxxxequally_spaced_xvalues(-1, 1, 9)The following method returns the polynomial of best fit (in the sense of least squares) that agrees in the input function fn at the given xvalues.
If not given, the degree of the returned polynomial is the length of xvalues.
fit_polynomial (generic function with 2 methods)xxxxxxxxxxfunction fit_polynomial(fn, xvalues, degree=0) b = [fn(x) for x=xvalues] A = vandermonde(xvalues, degree) coefficients = A \ b return x -> sum([x^(i - 1) * coefficients[i] for i=1:length(coefficients)])endBelow are some methods to plot our interpolations.
compare_plots (generic function with 2 methods)xxxxxxxxxxfunction compare_plots(fun, pol, xvalues, title="") d = 0.001 rng = xvalues[1]:d:xvalues[end] p = plot(fun, rng, label="function", legend = :outertopright, title=title) plot!(pol, rng, label="polynomial") scatter!(xvalues, zeros(1, length(xvalues)),label=false, color=:grey) return pendpolynomial_iterpolation_anim (generic function with 2 methods)xxxxxxxxxxfunction polynomial_iterpolation_anim(maxpoints, f, a, b, xvalues, degree=0) anim = for npoints=[minimum([i maxpoints]) for i=2:maxpoints + 10] xvals = xvalues(a, b, npoints) compare_plots(f, fit_polynomial(f, xvals, degree), xvals, "Degree $(degree == 0 ? npoints - 1 : degree) interpolation with $(npoints) datapoints") end every 1 gif(anim, "anim_fps15.gif", fps = 2)endHere are methods to measure the error of our interpolations.
error (generic function with 1 method)xxxxxxxxxxfunction error(f, g, a, b) delta = (b - a) / 10000 sum([abs(f(i) - g(i))^2 * delta for i=a:delta:b])endplot_log_error (generic function with 2 methods)xxxxxxxxxxfunction plot_log_error(maxpoints, f, a, b, xvalues, degree=0) plot([ log(error(f, fit_polynomial(f, xvalues(a, b, npoints), degree), a, b)) for npoints = 2:maxpoints ], legend=false, title="Log error in successive polynomial interpolations", xlabel="degree of interpolation", ylabel="error")endConsider the function
#11 (generic function with 1 method)xxxxxxxxxxf = x -> 1 / (1 + 25 * x^2)xxxxxxxxxxbegin npoints = 9 a, b = -1, 1 equally_spaced = equally_spaced_xvalues(a, b, npoints) interpolation = fit_polynomial(f, equally_spaced) compare_plots( f, interpolation, equally_spaced, "Polynomial interpolation with $(npoints) datapoints")endA major problem involved in polynomial interpolation is overfitting.
We see this for the preceding function when we sample evenly spaced points in the interval
As we add more datapoints and compute higher degree polynomials that fit the data, the 'fit' of these polynomials actually becomes worse!
On other intervals, say
xxxxxxxxxxpolynomial_iterpolation_anim(20, f, a, b, equally_spaced_xvalues)xxxxxxxxxxplot_log_error(40, f, a, b, equally_spaced_xvalues)xxxxxxxxxxpolynomial_iterpolation_anim(12, f, -1, 0, equally_spaced_xvalues)xxxxxxxxxxplot_log_error(20, f, -1, 0, equally_spaced_xvalues)One solution to the problem of overfitting is to fix the degree of our polynomial interpolation. This gives a better error that won't explode as we add more datapoints.
On the other hand, the error may have a nontrivial lower bound and may not tend to zero as we add more data.
If the number of datapoints
where
20xxxxxxxxxxfixed_degree = 20xxxxxxxxxxpolynomial_iterpolation_anim(45, f, a, b, equally_spaced_xvalues, fixed_degree)xxxxxxxxxxplot_log_error(60, f, a, b, equally_spaced_xvalues, fixed_degree)Another solution to the overfitting problem is to sample our input function at different
chebyshev_spaced_xvalues (generic function with 1 method)xxxxxxxxxxfunction chebyshev_spaced_xvalues(a, b, n) n >= 2 b > a cheb = [cos((2 * k - 1) / (2 * n) * pi) for k=n:-1:1] return [a + (i + 1) * (b - a) / 2 for i=cheb]endThe
However, if we sample our function at these points, the resulting polynomial interpolation is much more accurate, and we avoid overfitting as the degree of our interpolation increases:
xxxxxxxxxxpolynomial_iterpolation_anim(30, f, a, b, chebyshev_spaced_xvalues)xxxxxxxxxxplot_log_error(30, f, a, b, chebyshev_spaced_xvalues)The error here is better than what we get by fixing the degree of our interpolation and using least-squares.
What are the numbers chebyshev_spaced_xvalues(a, b, n)?
The Chebyshev polynomials
These are the unique polynomials that satisfy
chebyshev (generic function with 1 method)xxxxxxxxxxfunction chebyshev(n) if n == 0 return x -> 1 elseif n == 1 return x -> x else return x -> 2 * x * chebyshev(n - 1)(x) - chebyshev(n - 2)(x) endend xxxxxxxxxxbegin p = plot(title="Chebyshev polynomials of the first kind") for i=1:5 plot!(chebyshev(i), -1, 1, label="T_$(i)(x)", legend=:outerright) end plot(p)endThe values returned by chebyshev_spaced_xvalues(-1, 1, n) are the roots of
plot_chebyshev (generic function with 1 method)xxxxxxxxxxfunction plot_chebyshev(n) q = plot(chebyshev(n), -1, 1, title="Plot of T_$(n)(x) and Chebyshev-spaced x-values", legend=:outerright) xvalues = chebyshev_spaced_xvalues(-1, 1, n) scatter!(xvalues, zeros(1, n), legend=false, color=:grey) plot(q)endxxxxxxxxxxplot_chebyshev(20)It can be shown that using chebyshev_spaced_xvalues(a, b, n) to sample our input function yields the best possible exact polynomial interpolation of degree
See https://en.wikipedia.org/wiki/Chebyshev_nodes for more information.