MATLAB:对时间序列中的NaN进行插值

7

问题:如何在小范围内对NaN值进行局部插值?

我有一个时间序列(“x”数据均匀采样于“t”时间),其中包含一些NaN值。 例如:

x = [ 1   2   4    2 3 15 10 NaN NaN NaN NaN 2 4 NaN 19 25]
t = [0.1 0.2 0.3 ...etc..]

我希望对NaN执行插值。

最基本的方法是从最左侧的数据点到最右侧的数据点进行线性插值。例如,从x = 10到x = 2的一条直线,4个NaN值将被分配线的值。

时间序列的长度约为150万,其中包含约10000个NaN值,因此我不希望在插值中使用远离NaN位置的数据。一些NaN跨越了1000-2000的长度。

X(isnan(X)) = interp1(find(~isnan(X)), X(~isnan(X)), find(isnan(X)), 'linear'); 

将使用整个时间系列对NaN进行线性插值。

如何进行本地插值?线性插值应该足够了。也许线性插值在NaN块左右几个点(可能是100-200个点)的基础上。自然邻居或样条算法可能更合适;我必须小心,不要向时间序列中添加异常行为(例如插值使频率增加了虚假的“功率”)。

更新: 时间序列记录了一年内每分钟采样的温度数据。线性插值已经足够了;我只需要填补约6-7小时的NaN间隙(我已经有了NaN间隙之前和之后的数据)。


1
线性插值仅使用与插值区域相邻的值,因此无需担心“使用整个时间序列”的问题。或者问题是性能吗? - Jonas
啊,我真是傻了。我以为它是使用最小二乘线性拟合,然后根据拟合结果分配点。 如果interp1的'linear'选项只是连接相邻的左右点并进行插值,那么'cubic'和'pchip'有什么区别呢?例如,它不会在数据上拟合一个三次函数然后进行插值吗? - Justin
2
你是在问什么是最佳插值方法吗?如果是这样,那么最佳方法实际上取决于你的应用。例如,对于某些应用程序,你可能只想使用过去的数据进行插值,因为像线性插值这样的方法意味着你提前知道下一个非NaN观测值将是什么。在另一端,你可以应用EM算法,它用其他每个观测值的联合分布条件期望值替换缺失的观测值。因此,不知道你的应用情况很难回答。 - Colin T Bowers
@JustinChiu:Cubic可以拟合样条曲线,使用相邻的两个数据点来定义插值区域之间的曲线。 - Jonas
2个回答

5
我认为这至少部分符合您的需求:
% example data
x = [ 1   2   4    2 3 15 10 NaN NaN NaN NaN 2 4 NaN 19 25];
t = linspace(0.1, 10, numel(x));

% indices to NaN values in x 
% (assumes there are no NaNs in t)
nans = isnan(x);

% replace all NaNs in x with linearly interpolated values
x(nans) = interp1(t(~nans), x(~nans), t(nans));

请注意,您可以在此轻松切换插值方法:
% cubic splines
x(nans) = interp1(t(~nans), x(~nans), t(nans), 'spline');

% nearest neighbor
x(nans) = interp1(t(~nans), x(~nans), t(nans), 'nearest');

3
考虑使用inpaint_nans,这是一个非常好用的工具,可以插值1维或2维数组中的NaN元素,并利用非NaN元素进行操作。它还可以进行外推,因为它不使用数据的三角剖分。此外,它还允许使用不同的插值方法。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接