插值和外推
插值是一种技术,允许您使用位于样本中可用点之间的点计算的缺失值来补充数据集。 插值可用于填补数据中的空白、平滑异常值、预测过程行为等。 要估计值外实验定义区域,使用外推方法。
与不同类型的回归或多项式近似不同,对于插值,希望源数据位于规则网格上。 换句话说,必须使用数据类型指定函数的参数。 Range. 功能 ,其中执行输出数据插值 y 设置在网格上 x,我们将调用插值函数或插值函数。
网格上的多维插值
有了足够的数据点,您可以在任何中间点获得预测,包括在常规网格或随机点样本上。
Pkg.add(["Interpolations"])
using Interpolations, Plots, Random
Random.seed!(12);
gr( fmt=:png, size=(500,400) );
让我们假设我们的经验数据形成一个4乘4矩阵:
xs = range( 1, 10, length=4 );
ys = range( 1, 10, length=4 );
zs = rand( length(xs), length(ys) );
通过创建我们需要的插值(例如,通过三次样条),我们可以在输入数据范围内的任何点计算其值。:
itp = cubic_spline_interpolation( (xs,ys), zs );
itp( 2, 2 )
这个模型将允许我们计算参数空间内任何点的输出值,以定义经验数据的网格所定义的周长为界。
让我们在点之间的小步长的新网格上绘制插值结果。
scatter( repeat(xs, inner=length(ys)),
repeat(ys, outer=length(xs)),
vec(reshape( zs, (1,:))), markercolor=:red, label="Данные" )
xs_new = range(1, 10, length=30)
ys_new = range(1, 10, length=30)
surface!( xs_new, ys_new, [itp(x,y) for x in xs_new, y in ys_new],
colorbar = false, alpha = 0.5, c=:viridis )
我们使用该命令进行线性插值: cubic_spline_interpolation 当它被创建时,两个参数向量和一个值网格作为输入传递给它。 此函数允许您获取单个参数对的预测或创建整个预测矩阵。
分段线性插值可以以相同的方式执行(linear_interpolation)或"最近邻法"插值(constant_interpolation). 使用这些命令可以实现完全相同的操作 ConstantInterpolation, LinearInterpolation 和 CubicSplineInterpolation. 根据文件,为了方便起见,他们被留在图书馆。
itp0 = constant_interpolation( (xs,ys), zs ); # Константа
itp1 = linear_interpolation( (xs,ys), zs ); # Линейная интерполяция
plot(
(scatter( repeat(xs, inner=length(ys)), repeat(ys, outer=length(xs)), vec(reshape( zs, (1,:))), markercolor=:red );
surface!( xs_new, ys_new, itp0(xs_new, ys_new), colorbar = false, alpha = 0.5, c=:viridis, legend=:none )
),
(scatter( repeat(xs, inner=length(ys)), repeat(ys, outer=length(xs)), vec(reshape( zs, (1,:))), markercolor=:red );
surface!( xs_new, ys_new, itp1(xs_new, ys_new), colorbar = false, alpha = 0.5, c=:viridis, legend=:none )
),
size=(1000,400)
)
插值函数的类型由定义样条的多项式的程度确定: Constant, Linear, Quadratic,或 Cubic. 到目前为止,我们已经使用了这些命令的方便,简化的语法。 但也有一个更复杂的语法。:
# Вычисляем интерполяцию квадратичным сплайном,
# указав граничное условие – отражение (Reflect)
# и интерпретируя точки на периферии как центроиды (OnCell)
# а также дополнительно масштабируем полученный интерполянт, который при таком синтаксисе поначалу имеет единичный диапазон
sitp4 = scale( interpolate(zs, BSpline(Quadratic(Reflect(OnCell())))), (xs, ys,))
# Линейная интерполяция по одной оси, ступенчатая – по другой оси
# аргумент Gridded означает, что точки на периметре интерпретируются как OnGrid()
itp5 = interpolate( (xs, ys), zs, (Gridded(Linear()),Gridded(Constant())) )
plot(
(scatter( repeat(xs, inner=length(ys)), repeat(ys, outer=length(xs)), vec(reshape( zs, (1,:))), markercolor=:red );
surface!( xs_new, ys_new, sitp4(xs_new, ys_new), colorbar = false, alpha = 0.5, c=:viridis, legend=:none )
),
(scatter( repeat(xs, inner=length(ys)), repeat(ys, outer=length(xs)), vec(reshape( zs, (1,:))), markercolor=:red );
surface!( xs_new, ys_new, itp5(xs_new, ys_new), colorbar = false, alpha = 0.5, c=:viridis, legend=:none )
),
size=(1000,400)
)
并非所有条件组合都能产生结果。 例如,二次插值和三次插值需要从列表中指定边界条件。 Flat, Line (同 Natural), Free, Periodic 或 Reflect. 网格周长上的点可以通过插值算法解释为边界点(OnGrid())或位于前一行和虚构的下一行点之间的中间(OnCell()).
在不规则网格上的数据集插值可以使用分段线性样条和使用常数来执行。
有关其他参数和插值模式的信息可以在[文档]中找到(https://engee.com/helpcenter/stable/julia/Interpolations/interpolations.html )。
外推法
如果有必要预测可用实验数据范围之外的数据,我们需要为插值参数添加另一个假设–在我们看来,函数如何在可用数据之外表现,在这里我们有选择。 Throw (发出错误), Flat, Line, Periodic 和 Reflect,或者您可以将常量作为参数传递,其值将在插值期间被替换。
我们将使用一维信号示例演示不同的外推方法。
x = 1:5;
y = [2,7,3,8,6];
使用参数设置不同的边界条件(boundary conditions) extrapolation_bc.
new_x = range(-2, 8, length=100)
plot(
plot(x, y, title="Исходные данные"),
plot(new_x, cubic_spline_interpolation(x, y, extrapolation_bc=Line())(new_x), title="Line()"),
plot(new_x, cubic_spline_interpolation(x, y, extrapolation_bc=Flat())(new_x), title="Flat()"),
plot(new_x, cubic_spline_interpolation(x, y, extrapolation_bc=Periodic())(new_x), title="Periodic()"),
plot(new_x, cubic_spline_interpolation(x, y, extrapolation_bc=Reflect())(new_x), title="Reflect()"),
plot(new_x, cubic_spline_interpolation(x, y, extrapolation_bc=5)(new_x), title="fill(5)"),
size=(1000,400), layout=(2,3)
)
当然,这些相同的方法允许更高维数据的插值和外推。 例如,让我们在3维空间中放置64个数据点,并根据它们构造一个平滑函数。
a = range( 1, 10, length=4 );
b = range( 1, 10, length=4 );
c = range( 1, 10, length=4 );
d = rand( length(a), length(b), length(c) );
# 3D-интерполяция (легко записать в одну строку)
itp = extrapolate(
scale(
interpolate( d, BSpline(
Quadratic(
Reflect(OnCell())
)
)
), (a,b,c,)
), Flat() )
# Задаем новую сетку
new_a = new_b = -2:0.1:13; new_c = 1:10;
vPlots = [ contour( new_a, new_b, itp(new_a, new_b, ic), colorbar = false, alpha = 0.5, c=:viridis, legend=:none, title="c = $ic", titlefont = font(8)) for ic in new_c ]
plot!( vPlots..., layout=(2,:), size=(1000,400) )
结论
我们已经回顾了几种可用于任何维度数据的数据插值方法。 我们研究的插值方法使我们能够处理网格上的源数据集。 对于非有序数据,最好使用经典的机器学习方法或高级可视化方法(例如,通过Delaunay三角测量)。
Julia生态系统中还有几十个软件包用于其他问题设置中的数据插值,在[此页面]上给出了它们的列表(https://juliamath.github.io/Interpolations.jl/stable/other_packages /)。




