填充二维数组的空隙
Fill in the gaps of a 2D array
我有一个如下所示的稀疏数组。是否有一种算法可以用线性有意义的值填充所有空白? IE。从周围的原始值推导出来。
我看过双线性插值和双三次插值,还有其他的吗?
| 1 | 2 | 3 | 4 | 5 | 6 | 7
---------------------------------------------------------------------------------
1 |
2 |
3 | 55
4 | 50 12 6
5 | 45 19
6 | xxx
7 | 35 45 50 yyy
8 |
9 |
10 |
11 |
12 | zzz
13 |
14 |
15 |
例如,我希望 xxx 在 40 附近,yyy 在 50 附近。但是 zzz 可能有一个更随机的值。但请注意:我想填充每个空白 space,而不仅仅是 xxx、yyy 和 zzz。并且能够对任何人口稀少的阵列这样做。
有这样的算法吗?
存在一百万个这样的算法。所以首先你有一些像这样的已知值的字典:
known_values = {
(2, 3): 55.0,
(2, 4): 50.0,
(2, 5): 45.0,
(2, 7): 35.0,
(3, 7): 45.0,
(4, 7): 50.0,
(6, 4): 12.0,
(7, 4): 6.0,
(7, 5): 19.0,
}
最简单的方法是说任何一点的值都是所有填充点的加权平均值。按 1/距离平方加权。所以在你上面的例子中,你会有这样的代码:
def interpolate(known_values, p):
total_weight = 0.0
total_sum = 0.0
for q, value in known_values:
if p == q:
return value
d_square = (p[0] - q[0])**2 + (p[1] - q[1])**2
total_weight = total_weight + 1.0 / d_square
total_sum = total_sum + value / d_square
return total_sum/total_weight
只要矩阵中有任何填充数据,此解决方案就有效。
但是从你问问题的方式来看,你可能想要一个在任何小区域近似线性的平滑插值。一种方法是寻找 (a, b, c)
使得函数 a*x + b*y + c
最小化误差平方的加权和,权重是从所需点到已知点的距离的 4 次方观点。 (前2次方为面积的平方,后2次为附近的点加权重。)
此处对误差使用最小二乘法的原因是数学计算简单。当 a
、b
或 c
的微小变化不会使值发生太大变化时,您将精确地最小化,这意味着偏导数为 0。因此,三个偏导数给您 3线性方程组。求解 3 个变量的 3 个方程相当容易。
然而推导又长又乱。如果你想尝试一下,你应该看看通常的最小二乘推导,并尝试研究细节。然后尝试实现它。但是只有当你真的想要尝试做一个线性投影到远离你有数据的地方时才尝试。
这个问题可以看作是一个 "bivariate interpolation" 问题,在这方面有大量的研究。您可以在 Wiki 中搜索 "Multivariate interpolation" 并在“二维”部分下查找算法。
在各种方法中,bilinear/bicubic插值需要数据形成网格,而您的数据不是这样。根据您的情况,Delaunay 三角测量方法不适合外推。反加权距离法易于实现,适用于外推,但结果往往不尽如人意。我个人会推荐使用径向基函数,只要你没有太多的数据点(比如数千)。
我已经在 GitHub 上上传了我自己的解决方案,它使用薄板样条方法:
我有一个如下所示的稀疏数组。是否有一种算法可以用线性有意义的值填充所有空白? IE。从周围的原始值推导出来。
我看过双线性插值和双三次插值,还有其他的吗?
| 1 | 2 | 3 | 4 | 5 | 6 | 7
---------------------------------------------------------------------------------
1 |
2 |
3 | 55
4 | 50 12 6
5 | 45 19
6 | xxx
7 | 35 45 50 yyy
8 |
9 |
10 |
11 |
12 | zzz
13 |
14 |
15 |
例如,我希望 xxx 在 40 附近,yyy 在 50 附近。但是 zzz 可能有一个更随机的值。但请注意:我想填充每个空白 space,而不仅仅是 xxx、yyy 和 zzz。并且能够对任何人口稀少的阵列这样做。
有这样的算法吗?
存在一百万个这样的算法。所以首先你有一些像这样的已知值的字典:
known_values = {
(2, 3): 55.0,
(2, 4): 50.0,
(2, 5): 45.0,
(2, 7): 35.0,
(3, 7): 45.0,
(4, 7): 50.0,
(6, 4): 12.0,
(7, 4): 6.0,
(7, 5): 19.0,
}
最简单的方法是说任何一点的值都是所有填充点的加权平均值。按 1/距离平方加权。所以在你上面的例子中,你会有这样的代码:
def interpolate(known_values, p):
total_weight = 0.0
total_sum = 0.0
for q, value in known_values:
if p == q:
return value
d_square = (p[0] - q[0])**2 + (p[1] - q[1])**2
total_weight = total_weight + 1.0 / d_square
total_sum = total_sum + value / d_square
return total_sum/total_weight
只要矩阵中有任何填充数据,此解决方案就有效。
但是从你问问题的方式来看,你可能想要一个在任何小区域近似线性的平滑插值。一种方法是寻找 (a, b, c)
使得函数 a*x + b*y + c
最小化误差平方的加权和,权重是从所需点到已知点的距离的 4 次方观点。 (前2次方为面积的平方,后2次为附近的点加权重。)
此处对误差使用最小二乘法的原因是数学计算简单。当 a
、b
或 c
的微小变化不会使值发生太大变化时,您将精确地最小化,这意味着偏导数为 0。因此,三个偏导数给您 3线性方程组。求解 3 个变量的 3 个方程相当容易。
然而推导又长又乱。如果你想尝试一下,你应该看看通常的最小二乘推导,并尝试研究细节。然后尝试实现它。但是只有当你真的想要尝试做一个线性投影到远离你有数据的地方时才尝试。
这个问题可以看作是一个 "bivariate interpolation" 问题,在这方面有大量的研究。您可以在 Wiki 中搜索 "Multivariate interpolation" 并在“二维”部分下查找算法。
在各种方法中,bilinear/bicubic插值需要数据形成网格,而您的数据不是这样。根据您的情况,Delaunay 三角测量方法不适合外推。反加权距离法易于实现,适用于外推,但结果往往不尽如人意。我个人会推荐使用径向基函数,只要你没有太多的数据点(比如数千)。
我已经在 GitHub 上上传了我自己的解决方案,它使用薄板样条方法: