序列数据缺失值插补(线性插值)

  (时间)序列数据处理过程中往往会有缺失值(例如9999、NaN或其他的异常值),对这些数据的处理是下一步分析、研究和应用的基础。

  本文以 2018年 MOD09A01 地表反射率数据计算的 8天合成 46期 NDVI 数据为基础(已完成去云处理,有云时段的数据已赋值为 NaN,部分数据做了微调,以符合本文的内容),选取 一个样点(样点经度:123°4′0.87″,纬度:42°56′45.75″),完成时序有云数据(缺失值)的插补。

0 基本思路

开始
读取时序NDVI数据
标记缺失值
缺失值插补
结束

1 读取数据

  本文的样例数据为EXECL格式,已上传至百度网盘,下载链接如下:

链接:https://pan.baidu.com/s/1PR4MXMIIihRyv_7GQMl9VQ
提取码:ynyv

  目标:将需要插补的原始数据读取为数组。

# 导入库
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
# 读取原始数据
InFile = r'D:\xxxx\NDVI.xlsx'
Data = pd.read_excel(InFile)['NDVI'].values
print(Data)
[     nan      nan 0.223985 0.233396 0.227466 0.229259      1.2 0.231399
 0.22672       nan 0.224726 0.212029 0.236226 0.229548 0.236484 0.248894
 0.266551 0.275269 0.274135 0.270156      nan 0.478553 0.590506 0.721067
      nan 0.799064 0.742108 0.804224 0.83514  0.777888 0.734315 0.700915
 0.602857 0.553114 0.397294 0.318083 0.289676 0.253421  0.25891  0.24601
 0.23812  0.238319 0.238759 0.232261 0.253731 0.236231]

  简单做个图,我们看一下原始数据的样式。

# 定义一个横坐标
X = np.array(range(len(Data)))

plt.plot(X, Data, color = 'r')

在这里插入图片描述

  其中截断的部分是有缺失值的部分(即NaN)。下一步,我们对缺失值进行插值填充。

2 缺失值插补

2.1 标记异常值

  由于NDVI的最大值不可能大于1,则原始数据中 第 7 个值 1.2 明显为异常值。我们将异常值统一标记为缺失值。

Data[6] = np.nan
print(Data)
[     nan      nan 0.223985 0.233396 0.227466 0.229259      nan 0.231399
  0.22672      nan 0.224726 0.212029 0.236226 0.229548 0.236484 0.248894
 0.266551 0.275269 0.274135 0.270156      nan 0.478553 0.590506 0.721067
      nan 0.799064 0.742108 0.804224 0.83514  0.777888 0.734315 0.700915
 0.602857 0.553114 0.397294 0.318083 0.289676 0.253421  0.25891  0.24601
 0.23812  0.238319 0.238759 0.232261 0.253731 0.236231]

  简单做个图,我们看一下标记完异常值后的结果。

plt.plot(X, Data, color = 'y')

在这里插入图片描述

2.2 处理首末端缺失值

  首末端缺失值我们采用最邻近法填充(当然,也可以采用其他方法,这里不做示例)。

# 标记正常数据的位置
ValidDataIndex = X[np.where(np.isnan(Data) == 0)]

# 如果最后一个正常数据的序号比序列长度小,则表明最后一个正常数据后存在缺失数据
if ValidDataIndex[-1] < len(Data) - 1: 
    Data[ValidDataIndex[-1] + 1:] = Data[ValidDataIndex[-1]]  
    
# 如果第一个正常数据的序号不是0,则表明第一个正常数据前存在缺失数据
if ValidDataIndex[0] >= 1:
    Data[:ValidDataIndex[0]] = Data[ValidDataIndex[0]] 
print(Data)
[0.223985 0.223985 0.223985 0.233396 0.227466 0.229259      nan 0.231399
 0.22672       nan 0.224726 0.212029 0.236226 0.229548 0.236484 0.248894
 0.266551 0.275269 0.274135 0.270156      nan 0.478553 0.590506 0.721067
      nan 0.799064 0.742108 0.804224 0.83514  0.777888 0.734315 0.700915
 0.602857 0.553114 0.397294 0.318083 0.289676 0.253421 0.25891  0.24601
 0.23812  0.238319 0.238759 0.232261 0.253731 0.236231]

  简单做个图,我们看一下首末端缺失值处理后的结果。

plt.plot(X, Data, color = 'g')

在这里插入图片描述

2.3 缺失值插补

  插值过程我们使用scipy库插值模块的一维插值interp1d方法进行拟合,然后填充缺失值。

# 引入库(方法)
from scipy.interpolate import interp1d

  缺失数据不参与拟合,首先把缺失数据去除,对正常数据进行拟合。

# 步骤1:提取参与拟合的数据(X_0,Y_0)。由于缺失数据不能参与拟合,在拟合前,拟合数据需要先剔除异常值。
Y_0 = Data[np.where(np.isnan(Data) != 1)]
print(Y_0)
[0.223985 0.223985 0.223985 0.233396 0.227466 0.229259 0.231399 0.22672
 0.224726 0.212029 0.236226 0.229548 0.236484 0.248894 0.266551 0.275269
 0.274135 0.270156 0.478553 0.590506 0.721067 0.799064 0.742108 0.804224
 0.83514  0.777888 0.734315 0.700915 0.602857 0.553114 0.397294 0.318083
 0.289676 0.253421 0.25891  0.24601  0.23812  0.238319 0.238759 0.232261
 0.253731 0.236231]
X_0 = X[np.where(np.isnan(Data) != 1)]
print(X_0)
[ 0  1  2  3  4  5  7  8 10 11 12 13 14 15 16 17 18 19 21 22 23 25 26 27
 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45]

  利用拟合函数,根据缺失数据的标签,拟合缺失位置的数据。

# 步骤2:构造拟合函数,这里使用线性插值('linear')
IRFunction = interp1d(X_0, Y_0, kind = 'linear')

# 步骤3:提取缺失值数据的标签值
Fill_X = X[np.where(np.isnan(Data) == 1)]

# 步骤4:拟合缺失数据,并用拟合值替换缺失值
Fill_Y = IRFunction(Fill_X)
Data[Fill_X] = Fill_Y 

print(Data)
[0.223985  0.223985  0.223985  0.233396  0.227466  0.229259  0.230363
 0.231399  0.22672   0.225723  0.224726  0.212029  0.236226  0.229548
 0.236484  0.248894  0.266551  0.275269  0.274135  0.270156  0.3743545
 0.478553  0.590506  0.721067  0.7600655 0.799064  0.742108  0.804224
 0.83514   0.777888  0.734315  0.700915  0.602857  0.553114  0.397294
 0.318083  0.289676  0.253421  0.25891   0.24601   0.23812   0.238319
 0.238759  0.232261  0.253731  0.236231 ]

  简单做个图,我们看一下插值结果。

plt.plot(X, Data, color = 'b')

在这里插入图片描述

3 利用gma.math.FillNoData进行插补

  gma为自建的一个Python库,并已上传至pypi。详见:自建 | 地理与气象数据分析(geographic and meteorological data analysis)(gma)的说明与使用。欢迎大家下载试用。

  首先查看函数帮助

import gma
help(gma.math.FillNoData)
Help on function FillNoData in module gma.math:

FillNoData(Data, FillValue=None, Method='linear', **kwargs)
    '''
    简介
    ----------
    对缺失值或异常值值进行【插补】。

    参数
    ----------
    Data: list, tuple, Series, DataFrame。需要插补的数据。

    **可选参数
    ----------
    FillValue = number 或 list。标记需要进行插补的缺失值。可为数字(number)或数字列表(list)。默认不标记缺失值(None)。

        注:1.当 FillValue 为列表时,列表内所有值都将被插补。2.数据内原有的NAN、INF以及不能被转化为数字的字符串等异常值也将被插补。

    Method = str。插补方法。默认线性插值('linear')。其他的插补方法还包括:

        'time'(时间), 'index'(索引), 'values'(序列值), 'pad'(前向填充), 'nearest'(最邻近), 
        'zero'(零值), 'slinear'(滑动线性), 'quadratic'(2次插值), 'cubic'(3次插值), 'spline'(样条函数),
        'barycentric'(重心), 'polynomial'(分段多项式), 'from_derivatives'(衍生), 'krogh'(克罗格), 
        'piecewise_polynomial'(分段多项式),'pchip'(分段三次Hermite多项式插值), 'akima'(akima光滑插值), 
        'cubicspline'(3次样条)。

    **kwargs。传递给插值函数的其他参数。例如: Method 为 'polynomial' 或 'spline' 需要设置 order(阶数),默认阶数为 3。

    返回
    ----------
    类型: Series,DataFrame 返回输入类型;list, tuple 返回 array。

    '''

  根据帮助说明,我们只需带入原始数据(Data),设置异常值(FillValue)和插值方法(Method)即可获得相应结果。

Data = gma.math.FillNoData(Data, FillValue = 1.2, Method = 'linear')
print(Data)

  插值结果与 < 2 缺失值插补 > 结果一致。

[0.223985  0.223985  0.223985  0.233396  0.227466  0.229259  0.230329
 0.231399  0.22672   0.225723  0.224726  0.212029  0.236226  0.229548
 0.236484  0.248894  0.266551  0.275269  0.274135  0.270156  0.3743545
 0.478553  0.590506  0.721067  0.7600655 0.799064  0.742108  0.804224
 0.83514   0.777888  0.734315  0.700915  0.602857  0.553114  0.397294
 0.318083  0.289676  0.253421  0.25891   0.24601   0.23812   0.238319
 0.238759  0.232261  0.253731  0.236231 ]

  简单做个图,我们看一下插值结果。

plt.plot(X, Data, color = 'gray')

在这里插入图片描述

4 总结

  本文使用了简单的 interp1d(scipy) 的插值方法(不考虑gma),当然,如果专门做数据处理,其实pandas的interpolate也非常好用。

相关链接:
1、自建 | 地理与气象数据分析(geographic and meteorological data analysis)(gma)的说明与使用
2、自建 | gma库详细帮助
3、自建 | gma库更新日志

### 线性插值充空缺值原理 线性插值是一种简单而有效的方法,用于估计两个已知数据点之间的未知数值。这种方法假设在这两点之间存在线性关系。 对于给定的时间序列或其他有序的数据集中的缺失值线性插值通过连接相邻的有效观测值得到一条直线,并沿这条直线上找到对应于缺失位置处的新值作为填结果[^1]。 具体来说,在Python中可以使用`scipy.interpolate.interp1d`函数来创建一个线性的内器对象,该对象接受输入数组的索引及其对应的值,指定kind参数为'linear'表示采用线性方式计算: ```python from scipy import interpolate def fill_missing_linear(data_series): # 创建线性插值器 f = interpolate.interp1d( data_series.dropna().index, # 排除NaN后的索引 data_series.dropna().values, # 排除NaN后的实际值 bounds_error=False, fill_value="extrapolate", kind='linear' ) # 对整个序列应用值 filled_data = pd.Series(f(range(len(data_series))), index=data_series.index) return filled_data ``` 此代码片段展示了如何定义一个名为`fill_missing_linear()`的功能,它接收带有潜在NA/NaN条目的Pandas Series `data_series`作为参数;接着构建了一个基于非缺失部分建立起来的一维线性插值模型;最后返回一个新的Series实例,其中所有的原始缺失项都被相应位置上的预测值所替代。 当面对更复杂的情况比如分布式环境下的大数据集时,则可能需要用到像Apache Spark这样的框架来进行高效运算。此时可以通过自定义转换逻辑配合RDD API完成相似的任务[^2]。 值得注意的是,虽然线性插值易于理解和实现,但在某些情况下可能会引入偏差特别是当真实世界现象并不遵循严格的线性趋势的时候。因此,在选择合适的填策略之前应当充分考虑目标变量特性以及应用场景需求[^3]。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

洛的地理研学

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值