线性插值的解析解(稳定)
假设我们有一些(x, y)
数据。线性插值后找到所有x
使得插值的值等于y0
.
## with default value y0 = 0, it finds all roots of the interpolant
RootLinearInterpolant <- function (x, y, y0 = 0) {
if (is.unsorted(x)) {
ind <- order(x)
x <- x[ind]; y <- y[ind]
}
z <- y - y0
## which piecewise linear segment crosses zero?
k <- which(z[-1] * z[-length(z)] < 0)
## analytically root finding
xk <- x[k] - z[k] * (x[k + 1] - x[k]) / (z[k + 1] - z[k])
xk
}
更复杂的示例和测试。
set.seed(0)
x <- sort(runif(10, 0, 10))
y <- rnorm(10, 3, 1)
y0 <- 2.5
xk <- RootLinearInterpolant(x, y, y0)
#[1] 3.375952 8.515571 9.057991
plot(x, y, "l"); abline(h = y0, lty = 2)
points(xk, rep.int(y0, length(xk)), pch = 19)
非线性插值的数值求根(不一定稳定)
## suppose that f is an interpolation function of (x, y)
## this function finds all x, such that f(x) = y0
## with default value y0 = 0, it finds all roots of the interpolant
RootNonlinearInterpolant <- function (x, y, f, y0 = 0) {
if (is.unsorted(x)) {
ind <- order(x)
x <- x[ind]; y <- y[ind]
}
z <- y - y0
k <- which(z[-1] * z[-length(z)] < 0)
nk <- length(k)
xk <- numeric(nk)
F <- function (x) f(x) - y0
for (i in 1:nk) xk[i] <- uniroot(F, c(x[k[i]], x[k[i] + 1]))$root
xk
}
尝试自然三次样条插值。
## cubic spline interpolation
f <- splinefun(x, y)
xk <- RootNonlinearInterpolant(x, y, f, y0)
#[1] 3.036643 8.953352 9.074306
curve(f, from = min(x), to = max(x))
abline(v = x, lty = 3) ## signal pieces
abline(h = y0)
points(xk, rep.int(y0, length(xk)), pch = 20)
我们看到那RootNonlinearInterpolant
错过了第三块的两个交叉点。
RootNonlinearInterpolant
依靠uniroot
因此搜索受到更多限制。仅当符号为y - y0
相邻结 a 的变化uniroot
叫做。显然这不适用于第三部分。(学习更多关于uniroot
at R 中的 Uniroot 解决方案 https://stackoverflow.com/q/38961221/4891738.)
另请注意uniroot
只返回一个根。因此,最稳定的情况是插值在片段上是单调的,因此存在唯一的根。如果实际上有多个根,uniroot
只会找到其中之一。