보간·근사·수치적분
먼저 읽을 장 9.2 조건수·안정성·수렴
측정값은 언제나 띄엄띄엄 있다. 기상 관측소는 10분마다, 센서는 불규칙한 시각에, 시뮬레이터는 격자점에서만 값을 준다. 그 사이의 값을 채우는 일(보간), 잡음 섞인 점들을 매끄러운 함수로 요약하는 일(근사), 점들로부터 넓이나 기댓값을 계산하는 일(수치적분)은 데이터 전처리부터 손실 함수 계산까지 거의 모든 과학 계산의 바닥에 있다.
이 세 작업은 같은 질문을 공유한다. 유한한 점들만 보고 함수 전체에 대해 무엇을 말할 수 있는가. 점 사이에서는 꽤 많은 것을 보장할 수 있지만, 점의 범위를 벗어나면 거의 아무것도 보장할 수 없다. 이 장은 그 경계가 어디인지, 그리고 경계 안에서 오차를 어떻게 재는지 다룬다.
학습 목표
- 다항식 보간의 Runge 현상과 외삽의 위험을 설명하고, 노드 선택과 spline으로 대응한다
- 잡음 있는 데이터에서 보간과 최소제곱 근사를 구분해 고른다
- 수치적분 방법을 문제에 맞게 고르고, 수렴 차수를 실험으로 측정한다
보간
왜 필요한가. 불규칙한 시각에 측정한 신호를 균일한 격자로 옮겨야 FFT를 쓰거나 다른 신호와 나란히 놓을 수 있다. 시뮬레이터가 격자점에서만 준 값을 임의의 위치에서 읽어야 할 때도 있다. 둘 다 점들 사이의 값을 채우는 문제다.
정의. 서로 다른 노드(node) 과 값 가 주어졌을 때, 모든 노드를 정확히 지나는 함수 , 즉 인 를 찾는 일을 보간(interpolation)이라 한다. 를 차 이하 다항식으로 제한하면 그런 다항식은 정확히 하나 있다. 노드 범위 안의 값을 구하면 보간, 밖의 값을 구하면 외삽(extrapolation)이다.
오차 공식. 가 번 미분 가능하면, 보간 다항식의 오차는 어떤 점 (노드 범위와 를 포함하는 구간 안)에 대해
이다. 오른쪽은 두 부분으로 나뉜다. 앞의 분수는 함수가 얼마나 구불구불한지를, 뒤의 곱 (노드 다항식)는 노드가 어떻게 놓였는지를 나타낸다. 등간격 노드에서 노드 다항식은 구간 가운데에서 작고 양 끝에서 크다. 그리고 가 노드 범위를 벗어나면 모든 인수 가 같은 부호로 커지므로 곱이 폭발한다. 외삽이 위험한 이유가 이 식에 그대로 있다.
Runge 현상. 매끄러워 보이는 함수 를 의 등간격 노드로 보간하면, 노드를 늘릴수록 양 끝의 진동이 커진다. 이를 Runge 현상이라 한다. 이 함수는 복소평면의 에 극을 가져서 고계 도함수가 보다 빠르게 커지고, 등간격 노드 다항식은 양 끝에서 그것을 상쇄할 만큼 작지 않다.
대응은 두 가지다. 첫째, 노드를 양 끝에 몰아 배치한다. Chebyshev 노드 는 단위원 위의 등간격 점을 축에 내린 것으로, 노드 다항식의 최대 크기를 가능한 가장 작게() 만든다. 둘째, 다항식 하나로 전체를 덮지 않고 구간마다 낮은 차수의 다항식을 이어 붙인다. cubic spline은 이웃한 노드 사이마다 3차식을 쓰고, 노드에서 값·1계·2계 도함수가 연속이도록 이은 함수다. 차수가 고정되어 있으므로 노드를 늘려도 진동이 커지지 않고, 매끄러운 함수에 대해 오차가 노드 간격 의 4제곱에 비례해 준다.
import numpy as np
from scipy.interpolate import BarycentricInterpolator, CubicSpline
def runge(x):
return 1.0 / (1.0 + 25.0 * x**2)
x_test = np.linspace(-1, 1, 2001) # (2001,)
for n in [5, 10, 15, 20]:
x_eq = np.linspace(-1, 1, n + 1) # (n+1,) 등간격
x_ch = np.cos(np.pi * (2 * np.arange(n + 1) + 1) / (2 * n + 2)) # (n+1,) Chebyshev
err_eq = np.max(np.abs(BarycentricInterpolator(x_eq, runge(x_eq))(x_test) - runge(x_test)))
err_ch = np.max(np.abs(BarycentricInterpolator(x_ch, runge(x_ch))(x_test) - runge(x_test)))
err_sp = np.max(np.abs(CubicSpline(x_eq, runge(x_eq))(x_test) - runge(x_test)))
print(f"n = {n:2d} 등간격 {err_eq:9.2e} Chebyshev {err_ch:8.2e} spline {err_sp:8.2e}")n = 5 등간격 4.33e-01 Chebyshev 5.56e-01 spline 4.32e-01 n = 10 등간격 1.92e+00 Chebyshev 1.09e-01 spline 2.20e-02 n = 15 등간격 2.11e+00 Chebyshev 8.31e-02 spline 3.09e-02 n = 20 등간격 5.98e+01 Chebyshev 1.53e-02 spline 3.18e-03
등간격 보간의 최대 오차는 에서 60에 이른다. 같은 수의 Chebyshev 노드는 오차를 꾸준히 줄이고, 등간격 노드 그대로의 cubic spline은 더 빨리 줄인다. 여기서 다항식 계산에 쓴 BarycentricInterpolator는 보간 다항식을 계수로 펼치지 않고 무게중심(barycentric) 공식으로 계산해 반올림 오차에 강하다. 즉 위의 60은 반올림 탓이 아니라 등간격 보간 다항식 자체의 오차다.
보간 안과 밖. 같은 다항식이라도 노드 범위 안과 밖에서의 성질은 전혀 다르다. 에서 잡음(표준편차 0.01)이 섞인 측정값 11개를 10차 다항식과 cubic spline으로 보간하고, 구간 안팎에서 참값과 비교한다.
rng = np.random.default_rng(0)
x_in = np.linspace(0, 1, 11) # (11,) 측정 구간 [0, 1]
y_in = np.sin(2 * np.pi * x_in) + 0.01 * rng.normal(size=11) # 측정 잡음 0.01
for x_out in [0.5, 0.95, 1.05, 1.1, 1.2]:
p10 = BarycentricInterpolator(x_in, y_in)(x_out) # 10차 다항식
sp = CubicSpline(x_in, y_in)(x_out)
print(f"x = {x_out:4.2f} 참값 {np.sin(2 * np.pi * x_out):7.3f} 10차 다항식 {p10:7.3f} spline {sp:7.3f}")x = 0.50 참값 0.000 10차 다항식 0.004 spline 0.004 x = 0.95 참값 -0.309 10차 다항식 -0.309 spline -0.322 x = 1.05 참값 0.309 10차 다항식 0.140 spline 0.325 x = 1.10 참값 0.588 10차 다항식 -0.295 spline 0.651 x = 1.20 참값 0.951 10차 다항식 -7.771 spline 1.196
구간 안()에서는 두 방법 모두 잡음 수준의 오차를 낸다. 구간 끝에서 0.05만 나가도 10차 다항식은 참값의 절반도 맞추지 못하고, 0.2 나가면 로 부호까지 틀린다. 잡음 0.01이 노드 다항식의 큰 인수와 곱해져 증폭된 결과다. spline은 덜 나쁘지만 역시 구간 밖에서는 오차가 거리와 함께 커진다. 어떤 보간법도 외삽을 보장하지 않는다. 차이는 얼마나 빨리 나빠지느냐뿐이다.
어떤 보간법을 쓸까. 실무의 기본 선택지는 다음과 같다.
| 방법 | 매끄러움 | 특징 | 주의 |
|---|---|---|---|
선형(np.interp) |
연속 | 값의 범위를 넘지 않는다. 빠르다 | 오차 , 꺾인 점이 생긴다 |
cubic spline(CubicSpline) |
2계 도함수까지 연속 | 매끄러운 함수에 오차 | 급변하는 데이터에서 overshoot |
PCHIP(PchipInterpolator) |
1계 도함수까지 연속 | 단조 데이터의 단조성을 보존 | 매끄러운 함수에는 spline보다 덜 정확 |
| 고차 다항식 | 무한히 매끄러움 | Chebyshev 노드를 직접 고를 수 있을 때 매우 정확 | 등간격·잡음 데이터에서 위험 |
농도·확률처럼 음수가 될 수 없거나 단조여야 하는 양을 보간할 때 cubic spline은 노드 사이에서 음수나 역전을 만들 수 있다. 이때는 PCHIP을 쓴다.
근사
왜 필요한가. 측정값에는 잡음이 있다. 모든 점을 정확히 지나는 보간 함수는 잡음까지 따라가므로, 점 사이와 바깥에서 참함수와 크게 어긋난다. 잡음 있는 데이터에서 원하는 것은 점을 지나는 함수가 아니라 점들에 가까운 단순한 함수다.
정의. 기저 함수 ()의 결합 중에서 제곱 오차의 합
을 최소로 하는 계수 를 고르는 것을 최소제곱 근사(least-squares approximation)라 한다. 는 행렬이고, 기저가 단항식 이면 Vandermonde 행렬이다. 보간은 인 특수한 경우로, 잔차가 0이 된다.
직관. 차수 은 모델의 유연성이다. 너무 낮으면 참함수의 모양을 따라가지 못하고(편향), 너무 높으면 잡음을 따라간다(분산). 데이터 잔차는 차수를 올릴수록 줄어들기만 하므로, 잔차만 보고 차수를 고르면 항상 가장 높은 차수를 고르게 된다.
기저의 선택. 같은 다항식 공간이라도 어떤 기저로 표현하느냐에 따라 의 조건수가 크게 달라진다. 단항식 는 에서 가 커질수록 서로 비슷한 모양(양 끝에서만 크고 가운데에서 평평)이 되어 열들이 거의 평행해진다. Chebyshev 다항식 나 Legendre 다항식 같은 직교다항식(orthogonal polynomials)은 서로 직교하도록 만든 기저라 이 문제가 훨씬 덜하다. 9.2장에서 본 것처럼 조건수가 크면 같은 데이터에서도 계수가 반올림 오차에 민감해진다.
rng = np.random.default_rng(1)
x = np.linspace(-1, 1, 21) # (21,)
y = np.exp(x) + 0.05 * rng.normal(size=x.size) # 잡음 표준편차 0.05
x_fine = np.linspace(-1, 1, 1001) # (1001,)
for deg in [2, 4, 8, 20]:
p = np.polynomial.Chebyshev.fit(x, y, deg)
rms_fit = np.sqrt(np.mean((p(x) - y) ** 2))
err = np.max(np.abs(p(x_fine) - np.exp(x_fine)))
print(f"차수 {deg:2d} 데이터 잔차 RMS {rms_fit:.4f} 참함수와 최대 오차 {err:.4f}")
V_mono = np.vander(x, 21, increasing=True) # (21, 21) 단항식 기저
V_cheb = np.polynomial.chebyshev.chebvander(x, 20) # (21, 21) Chebyshev 기저
print(f"cond: 단항식 {np.linalg.cond(V_mono):.1e} Chebyshev {np.linalg.cond(V_cheb):.1e}")차수 2 데이터 잔차 RMS 0.0411 참함수와 최대 오차 0.0828 차수 4 데이터 잔차 RMS 0.0261 참함수와 최대 오차 0.0267 차수 8 데이터 잔차 RMS 0.0240 참함수와 최대 오차 0.0365 차수 20 데이터 잔차 RMS 0.0000 참함수와 최대 오차 148.7384 cond: 단항식 8.3e+08 Chebyshev 8.6e+03
이 결과는 세 가지를 보여 준다.
- 데이터 잔차는 차수와 함께 단조롭게 줄어 20차(보간)에서 0이 된다. 참함수와의 오차는 4차에서 가장 작고, 20차에서는 148로 폭발한다. 데이터에 잘 맞는 것과 참함수에 가까운 것은 다르다.
- 4차 이후 잔차가 거의 줄지 않는다(0.026 → 0.024). 잔차가 잡음 수준에서 멈추는 지점이 적절한 차수의 신호다. 실제로는 교차검증(16장)이나 정보 기준으로 고른다.
- 같은 21개 점에서 단항식 기저의 조건수는 , Chebyshev 기저는 이다.
np.polyfit대신np.polynomial.Chebyshev.fit을 쓰는 이유다. 다만 기저를 바꿔도 21개 점을 지나는 20차 다항식은 하나뿐이므로, 20차의 폭발 자체는 기저로 해결되지 않는다.
연구에서의 의미. 다항식 근사는 신경망 회귀의 가장 단순한 친척이다. 모델 유연성과 잡음 사이의 균형, 학습 데이터 잔차가 일반화 오차를 말해 주지 않는다는 사실, 기저(특징 표현)가 수치적 안정성을 좌우한다는 사실은 그대로 이어진다. 차이는 다항식에서는 이 모든 것을 정확한 식으로 계산할 수 있다는 점이다.
수치적분
왜 필요한가. 대부분의 적분은 원시함수를 식으로 쓸 수 없다. 측정 데이터의 적분(스펙트럼 피크의 넓이, 누적 강수량, 전류를 적분한 전하량)은 애초에 함수식이 없다. 8.3장에서 scipy.integrate.quad를 블랙박스로 썼다면, 이 절은 그 안에서 무슨 일이 일어나는지와 언제 믿을 수 있는지를 다룬다.
정의. 구적 규칙(quadrature rule)은 적분을 함숫값의 가중합으로 근사한다.
노드 와 가중치 를 고르는 방법에 따라 규칙이 달라진다. 구간을 폭 인 작은 구간으로 나누어 같은 규칙을 반복 적용한 것을 합성(composite) 규칙이라 한다.
- 사다리꼴 규칙(trapezoidal rule): 작은 구간마다 양 끝을 잇는 직선 아래 넓이. 합성 규칙의 오차는 , 즉 다.
- Simpson 규칙: 이웃한 두 구간마다 세 점을 지나는 2차식 아래 넓이. 가중치는 이고, 합성 규칙의 오차는 , 즉 다. 2차식으로 맞췄는데도 대칭성 덕분에 3차 다항식까지 정확하다.
- Gauss 구적(Gauss quadrature): 노드를 등간격으로 고정하지 않고 노드와 가중치를 모두 최적화한다. 점 Gauss–Legendre 규칙은 자유도 개로 차 다항식까지 정확히 적분한다. 노드는 Legendre 다항식 의 근이다.
수렴 차수(order of convergence)는 이 오차식의 지수다. 오차가 이면 를 절반으로 할 때 오차는 분의 1이 된다. 그래서 두 해상도의 오차 비율로 를 실험적으로 잴 수 있다.
from scipy.integrate import simpson, trapezoid
f, exact = np.exp, np.e - 1.0 # ∫_0^1 e^x dx
print(" n 사다리꼴 Simpson Gauss(n점)")
for n in [4, 8, 16]:
x = np.linspace(0, 1, n + 1) # (n+1,) 등간격 n구간
xg, wg = np.polynomial.legendre.leggauss(n) # [-1, 1]의 노드·가중치
gauss = 0.5 * np.sum(wg * f(0.5 * (xg + 1))) # [0, 1]로 옮김
e_g = abs(gauss - exact)
e_g = f"{e_g:.2e}" if e_g > 1e-13 else "< 1e-13" # 반올림 한계 아래는 판정만
print(f"{n:2d} {abs(trapezoid(f(x), x=x) - exact):.2e} "
f"{abs(simpson(f(x), x=x) - exact):.2e} {e_g}")n 사다리꼴 Simpson Gauss(n점) 4 8.94e-03 3.70e-05 9.33e-10 8 2.24e-03 2.33e-06 < 1e-13 16 5.59e-04 1.46e-07 < 1e-13
을 두 배로 할 때 사다리꼴 오차는 4.0배, Simpson 오차는 15.9배 줄어 각각 , 를 확인한다. Gauss 구적은 점 4개(7차 다항식까지 정확)로 , 점 8개로 이미 배정밀도의 반올림 한계에 닿는다(그 아래의 값은 기계마다 달라지므로 판정만 찍었다). 매끄러운(해석적인) 함수에서 Gauss 구적의 오차는 의 거듭제곱이 아니라 점 수에 대해 지수적으로 준다.
차수는 가정 위에 서 있다. 위의 오차식은 , 가 유계라는 가정에서 나온다. 가정이 깨지면 차수도 깨진다. 는 에서 도함수가 무한대라 Simpson 규칙도 로 느려지고, 불연속인 피적분함수에서는 어떤 고차 규칙도 를 넘지 못한다. 반대로 매끄러운 주기함수를 한 주기에 걸쳐 적분하면 사다리꼴 규칙이 지수적으로 수렴한다. 이론 차수를 믿지 말고, 를 바꾸어 관측 차수를 재는 습관이 필요하다.
적응 구적. scipy.integrate.quad는 Fortran 라이브러리 QUADPACK을 감싼 것으로, Gauss–Kronrod 규칙(Gauss 노드에 점을 추가해 두 근사의 차이로 오차를 추정하는 규칙)을 쓰고, 오차 추정이 큰 구간만 반복해서 나눈다. 그래서 특이점이나 급변 구간이 있어도 그곳에 점을 모은다. 반환값의 두 번째 원소는 추정 오차이고, 보장된 오차 한계가 아니다. 피적분함수에 좁은 피크가 있는데 처음 표본점이 피크를 모두 비켜 가면, quad는 틀린 값과 작은 오차 추정을 함께 돌려준다. 예를 들어 폭 0.001인 가우시안 피크 를 에서 적분하면 quad는 값 0과 오차 추정 0을 돌려준다(정확값 ). 피크 위치를 알면 피크를 감싸는 좁은 구간의 경계를 points=[7.29, 7.3, 7.31]처럼 알려 주어야 정확한 값이 나온다. 피크 중심 하나만 points=[7.3]으로 주면 여전히 틀린다. Gauss 계열 노드는 구간 끝점을 쓰지 않으므로, 피크가 넓은 구간의 끝에 붙어 있으면 여전히 노드가 피크를 비켜 가기 때문이다.
고차원 적분
왜 필요한가. 확률모형의 기댓값, 베이즈 추론의 주변우도, 통계역학의 분배함수는 수십에서 수백만 차원의 적분이다. 1차원 구적 규칙을 각 축에 적용하는 방식(텐서곱 격자)은 이 영역에서 무너진다.
차원의 저주. 축마다 점을 쓰면 차원 격자의 점은 개다. 점 예산 이 정해져 있으면 축당 점 수는 이고, 차 규칙의 오차는
이다. 가 커지면 지수 가 0에 가까워져 점을 아무리 늘려도 오차가 거의 줄지 않는다. 이를 차원의 저주(curse of dimensionality)라 한다.
Monte Carlo 적분. 균등분포에서 뽑은 개의 점 로
를 계산하면, 중심극한정리에 의해 오차의 표준편차는 이다(는 의 표준편차). 수렴은 느리지만( 대신 ) 비율에 가 없다. 또한 같은 표본의 표준편차로 오차를 추정할 수 있다. 같은 점 4096개로 (정확값을 식으로 알 수 있다)를 계산해 비교한다.
def exact_cos_sum(d): # ∫ cos(x_1+…+x_d) dx
return (((np.exp(1j) - 1) / 1j) ** d).real
N = 4096
rng = np.random.default_rng(0)
for d in [1, 2, 3, 4, 6, 12]:
m = round(N ** (1 / d)) # 축마다 m점 (m^d = N)
g = (np.arange(m) + 0.5) / m # 중점 규칙 노드
grid = np.stack(np.meshgrid(*[g] * d), axis=-1).reshape(-1, d) # (N, d)
ex = exact_cos_sum(d)
err_mid = abs(np.mean(np.cos(grid.sum(axis=1))) - ex)
mc = [np.mean(np.cos(rng.random((N, d)).sum(axis=1))) for _ in range(20)]
err_mc = np.sqrt(np.mean((np.array(mc) - ex) ** 2)) # 20회 반복의 RMS 오차
print(f"d = {d:2d} 축당 {m:4d}점 중점격자 오차 {err_mid:.1e} MC 오차(RMS) {err_mc:.1e}")d = 1 축당 4096점 중점격자 오차 2.1e-09 MC 오차(RMS) 2.4e-03 d = 2 축당 64점 중점격자 오차 1.0e-05 MC 오차(RMS) 4.7e-03 d = 3 축당 16점 중점격자 오차 3.0e-05 MC 오차(RMS) 7.6e-03 d = 4 축당 8점 중점격자 오차 9.2e-04 MC 오차(RMS) 5.3e-03 d = 6 축당 4점 중점격자 오차 1.2e-02 MC 오차(RMS) 4.4e-03 d = 12 축당 2점 중점격자 오차 7.7e-02 MC 오차(RMS) 4.1e-03
격자의 오차는 1차원 에서 12차원 로 일곱 자릿수 이상 나빠진다. MC 오차는 모든 차원에서 수준에 머문다. 이 함수에서는 4차원과 6차원 사이에서 MC가 앞선다. 교차점은 함수의 매끄러움과 규칙의 차수에 따라 달라지지만, 차원이 커지면 결국 MC 계열 방법이 이긴다는 결론은 일반적이다. MC 오차를 한 번의 실행이 아니라 20번 반복의 RMS로 잰 점에 주의한다. 한 번의 MC 결과는 운 좋게 작을 수 있다.
중간 영역에는 두 가지 절충이 있다. 준몬테카를로(quasi-Monte Carlo)는 무작위 점 대신 공간을 고르게 채우는 저불일치(low-discrepancy) 수열(Sobol 수열 등, scipy.stats.qmc)을 써서, 매끄러운 함수에서 오차를 대략 으로 줄인다(Caflisch, 1998). sparse grid는 텐서곱 격자에서 기여가 작은 점들을 덜어 내 점 수의 증가를 늦춘다. 수백 차원 이상의 확률 모형에서는 균등 표본 대신 중요도 표집이나 MCMC(13장)를 쓴다.
실습
불규칙하게 측정한 감쇠 진동 신호(참값 , 잡음 표준편차 0.01, 측정점 40개, s)를 다섯 가지 방법으로 0.05 s 간격 격자에 재표본화하고, 측정 구간 안의 오차와 구간 밖( s) 외삽 오차를 비교한다. 코드는 labs/numerical-methods/interpolation-and-quadrature/resample_signal.py다. 집필 시점의 실행 결과는 다음과 같다.
측정점 40개, 간격 최소 0.002 s, 최대 0.941 s 방법 안 RMS 안 최대 t=10.25s t=10.50s t=11.00s 선형(np.interp) 8.7e-02 2.8e-01 4.6e-03 3.0e-02 1.3e-01 cubic spline 3.3e-02 1.4e-01 5.9e-01 2.5e+00 1.3e+01 PCHIP 7.0e-02 2.4e-01 5.5e+00 4.4e+01 3.4e+02 Akima 1.9e-02 5.6e-02 4.4e+00 3.6e+01 2.9e+02 고차 다항식 2.2e+08 1.2e+09 1.0e+11 7.3e+12 6.3e+13 20회 반복의 중앙값 선형(np.interp) 안 RMS 5.8e-02 t=10.50s 오차 1.6e-02 cubic spline 안 RMS 3.6e-02 t=10.50s 오차 1.6e+00 PCHIP 안 RMS 3.5e-02 t=10.50s 오차 1.9e-01 Akima 안 RMS 2.3e-02 t=10.50s 오차 3.0e-01 고차 다항식 안 RMS 2.4e+09 t=10.50s 오차 3.8e+12
결과를 읽는 법은 다음과 같다.
- 구간 안에서는 3차 계열(spline·PCHIP·Akima)이 선형보다 정확하다. 측정 간격이 최대 0.94 s로 진동 주기( s)에 비해 넓은 곳이 있어, 직선으로 이으면 봉우리를 깎아 먹는다.
- 불규칙 노드 40개를 지나는 39차 다항식은 구간 안에서도 쓸 수 없다. Runge 현상이 불규칙 노드와 잡음을 만나 극단적으로 나타난 것이다.
- 구간 밖에서는 순위가 뒤집힌다. 끝값을 고정하는 선형 보간이 가장 작은 외삽 오차를 냈는데, 이는 선형 보간이 좋아서가 아니라 이 신호가 s 이후 거의 평평하게 감쇠하기 때문이다. 3차 계열은 마지막 몇 점의 잡음 섞인 기울기를 연장해, 0.5 s만 나가도 오차가 수에서 수십(신호 크기의 수십 배)으로 커진다. 특히 첫 실행에서 간격이 0.002 s인 두 측정점처럼 아주 가까운 점들은 잡음을 큰 기울기로 바꾼다.
- 한 번의 결과에 기대지 않는다. 측정 시각을 바꾼 20번 반복의 중앙값으로 보면 경향은 같지만 숫자는 달라진다.
스크립트를 고쳐 다음을 직접 확인한다. (1) 잡음을 0으로 하면 순위가 어떻게 바뀌는가. (2) CubicSpline(..., extrapolate=False)로 바꾸면 구간 밖에서 무엇이 나오는가. (3) 재표본화한 신호를 simpson으로 적분하고, 방법에 따른 적분값의 차이가 보간 오차보다 작은지 큰지 본다.
이어서 연습문제를 푼다. 테스트가 바로 채점한다.
실패 사례
- 고차 다항식으로 외삽하는 것. 측정 구간 안에서 잘 맞는 다항식이 구간 밖에서도 맞을 것이라고 가정한다. 보간 오차식의 노드 다항식은 구간 밖에서 모든 인수가 같은 부호로 커지므로, 잡음과 모델 오차가 증폭된다. 외삽이 필요하면 물리 모델이나 불확실성을 표시하는 방법을 쓰고, 외삽값임을 결과에 밝힌다.
- 보간 객체의 조용한 외삽을 모르고 쓰는 것. 재표본화 격자가 측정 범위를 조금만 넘어도 SciPy 보간기는 경고 없이 값을 낸다. 시계열의 시작·끝 근처에서 이상한 값이 보이면 이것부터 의심한다.
- 잡음 데이터를 보간하는 것. 잔차 0을 정확도로 착각한다. 잡음이 있으면 최소제곱 근사나 smoothing spline(
scipy.interpolate.make_smoothing_spline)을 쓴다. - 이론 차수를 확인 없이 믿는 것. 특이점·꺾인 점·불연속이 있는 피적분함수에서 Simpson이나 Gauss 규칙은 약속한 차수를 내지 못한다. 해상도를 두 배로 바꾸어 관측 차수를 재 본다.
quad의 오차 추정을 보장으로 읽는 것. 반환된 오차는 추정값이다. 좁은 피크나 진동이 심한 피적분함수에서는 틀릴 수 있다.
통과 기준
- 측정 데이터를 재표본화할 보간법을 고르고, 구간 안 오차와 외삽 구간 오차를 나누어 정량화한 표를 만든다.
- 사다리꼴·Simpson 규칙의 관측 수렴 차수를 해상도 세 개 이상으로 측정하고, 특이점이 있는 피적분함수에서 차수가 떨어지는 것을 보인다.
- 연습문제
composite-simpson의 테스트를 통과한다.
참고 문헌
- Trefethen, L. N. (2020). Approximation Theory and Approximation Practice, Extended Edition. SIAM. ISBN 978-1-61197-593-2. — Chebyshev 보간, Runge 현상, 무게중심 공식, 보간과 구적의 수렴 이론
- Trefethen, L. N. (2008). Is Gauss quadrature better than Clenshaw–Curtis? SIAM Review, 50(1), 67–87. doi:10.1137/060659831 — Gauss 구적과 Chebyshev 점 기반 구적의 실제 정확도 비교
- Caflisch, R. E. (1998). Monte Carlo and quasi-Monte Carlo methods. Acta Numerica, 7, 1–49. doi:10.1017/S0962492900002798 — Monte Carlo 적분의 수렴과 준몬테카를로 방법