我们有一个包含一些 NaN 值的 2D 数组。我们希望使用具有数据的那些位置来对这些 NaN 值进行插值(内插)。数组如下所示:
array([[ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
[ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
[ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
[ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan],
[ 1. , 0. , 1. , 0. , 0.25 , nan, 0. , nan, nan, nan],
[ nan, 0. , nan, 0.25 , 0.66666667, 0.25 , 0.66666667, 0. , 1. , nan],
[ 0. , 0.5 , 0.66666667, 0.8 , 0.66666667, 0.8 , 0.5 , 0.83333333, nan, nan],
[ 0.625 , 0.5625 , 0.9 , 0.8 , 0.8 , 0.83333333, 0.57142857, 0.66666667, 0.5 , nan],
[ nan, 1. , 0.71428571, 0.85714286, 1. , 1. , 1. , nan, nan, nan],
[ nan, nan, nan, nan, 1. , 1. , nan, nan, nan, nan]])
我们希望通过插值,使远离非 NaN 值的位置逐渐接近 0。
2. 解决方案
有多种可能的方法可以根据想要使用的插值技术来实现。事实上,由于数据周围都是 NaN 值,我们更倾向于将其视为函数平滑而不是插值。如果希望远离 2D 地图上的非 NaN 值时更接近 0,我们建议使用如下方法:
将每个非 NaN 数据点 X[i,j] 视为以 [i,j] 为中心的正态分布,方差=1,缩放比例使其 pdf( [i,j] ) = X[i,j],即 f_ij( [a,b] ) = X[i,j] * exp( -|| [a,b] - [i,j] ||^2/2 )。 对于每个 NaN 数据点 X[a,b],将 X[a,b] 设置为 sum( f_ij( [a,b] ) ),其中求和在所有非 NaN 数据点的 [i,j] 索引上进行。
这样,我们可以得到一个类似“密度估计”的结果,并且可以通过改变方差(我们建议使用 =1)来调整值的“消失速度”。 因此,代码只循环遍历所有 NaN 值,然后在每个 NaN 值上循环遍历所有非 NaN 值并对高斯值求和。 代码如下:
import numpy as np
def inpaint_nans_gaussian(X):
"""
Inpaint NaN values in a 2D array using a Gaussian function.
Args:
X: The 2D array with NaN values.
Returns:
The 2D array with NaN values inpainted.
"""
# Get the indices of the NaN values
nans = np.array(np.where(np.isnan(X))).T
# Get the indices of the non-NaN values
notnans = np.array(np.where(~np.isnan(X))).T
# Loop over the NaN values
for p in nans:
# Sum the Gaussian values for all non-NaN values
X[p[0], p[1]] = sum(
X[q[0], q[1]] * np.exp(-(sum((p - q) ** 2)) / 2) for q in notnans
)
return X
# Example usage
X = np.array([[np.nan, np.nan, np.nan, np.nan, np.nan],
[np.nan, np.nan, np.nan, np.nan, np.nan],
[np.nan, np.nan, np.nan, np.nan, np.nan],
[np.nan, np.nan, np.nan, np.nan, np.nan],
[1., 0., 1., 0., 0.25],
[np.nan, 0., np.nan, 0.25, 0.66666667],
[0., 0.5, 0.66666667, 0.8, 0.66666667],
[0.625, 0.5625, 0.9, 0.8, 0.8],
[np.nan, 1., 0.71428571, 0.85714286, 1.],
[np.nan, np.nan, np.nan, np.nan, 1.],
[np.nan, np.nan, np.nan, np.nan, 1.]])
# Inpaint the NaN values
X_inpainted = inpaint_nans_gaussian(X)
# Print the inpainted array
print(X_inpainted)