【问题标题】:Imputation of Missing Value on Python for Consecutive NaN连续 NaN 在 Python 上的缺失值插补
【发布时间】:2021-05-21 01:51:13
【问题描述】:

编辑:我现在正在寻找一种干净的方法来在 Python 上估算我的数据集的缺失值

     a       b         c
0    1       2         Falcon

1    np.nan   3        Falcon

2    np.nan   np.nan   Falcon
  
3    np.nan    4       Bird

4    np.nan   5        Bird
 
5    5        np.nan   Bird

6    6        7        Bird

我需要根据他们的个人组使用以下条件进行估算。
(1) 对于在其前 前一行中具有值的缺失值,通过插值填充它
(2) 对于在其前行有值的缺失值,用前行或上一行的值填充
(3)对于不满足(1)和(2)的缺失值,填0


结果示例如下:

     a   b      c
0    1   2      Falcon

1    1   3      Falcon

2    0   3      Falcon
  
3    0   4      Bird

4    5   5      Bird

5    5   6      Bird

6    6   7      Bird

我已经尝试了下面评论中提供的代码,但是我未能通过其各自的组进行设置。我该如何在 Python 中进行操作?

【问题讨论】:

  • 你有不那么干净的代码吗?什么样的插值?
  • 线性插值。我不确定如何为 python 创建一个函数/循环来仅检测满足 3 个条件的字段。我已经尝试过“dataset.fillna(method='ffill', inplace=True, limit=1)”来满足条件2,但是当我使用它时,它还填充了第5行np.nan的缺失值

标签: python numpy imputation


【解决方案1】:

这还不是完整的答案,但有一些提示。假设我们在这里处理一个数组(例如,a)。

首先,在a的开头和结尾连接[nan]得到a1。这将简化应用插补规则。

其次,您现在可以使用三个数组 a1[:-2]、a1[1:-1]、a1[2:] 来获得所有三个移动窗口值。

当然,您需要编写一个函数来根据这三个值估算值,但这很简单:

def impute(xprev, x, xnext):
   if not isnan(x):
      return x
   # the rest of the logic here left as an exercise

提示 2:可能有更有效的构造(如 np.stack),但拥有所有三个值的一种简单方法是正常的 zip

result_list = [impute(prev, this, next) for (prev, this, next) in zip(a1[:-2], a1[1:-1], a1[2:])]
# turn list to array or you can use np.fromiter(( impute(...) for ... ), np.float64) to make array directly from iterable

我希望这些提示足以构建解决方案。

在上面的解决方案中,我应用了几个通用模式,我发现它们是在练习编程时发现的:

  1. 使用方便的停止值填充而不是检查边界索引
  2. 使用zip 拥有小尺寸的移动窗口

注意。也可以为扩展数组 (a1) 生成索引,而不是使用 zip 或堆栈。所以我相信会有更多优化的其他答案,因为 Numpy 有很多功能可以提供。此外,上面的 impute 也可能被制成 ufunc 并应用于堆叠移位数组 - 但是,如果不进行分析,很难判断它是否会比上面的简单列表理解或带有索引的相应解决方案更有效。

【讨论】:

    【解决方案2】:

    我无法想象一种直接的方式,所以我会为您的每个要求使用一次。好消息是,由于每次传递都会填充一些值,因此后续传递不会尝试填充它们:

    1. 对于在其前一行和上一行中具有值的缺失值,通过插值填充它

       df[df.isna()&(~df.shift().isna())&(~df.shift(-1).isna())] = df.interpolate()
      
    2. 对于在其前一行或上一行中具有值的缺失值,用前一行或上一行值填充它

       df[df.isna()&(~df.shift().isna())] = df.ffill()
       df[df.isna()&(~df.shift(-1).isna())] = df.bfill()
      
    3. 对于不满足(1)和(2)的缺失值,用0填充

       df.fillna(0)
      

    使用您的示例数据,它按预期提供:

         a    b
    0  1.0  2.0
    1  1.0  3.0
    2  0.0  3.5
    3  0.0  4.0
    4  5.0  5.0
    5  5.0  6.0
    6  6.0  7.0
    

    确实需要4个操作,但都是向量化的,所以全局处理时间应该可以忍受。

    【讨论】:

    • 嗨,Serge,感谢您的解决方案。但是,我可以检查下面的代码是什么意思。我知道 df.shift 意味着按指定的时间段移动索引,但是令人困惑的部分是为什么通过移动数据帧,它将满足条件“对于在其前一行和前一行中具有值的缺失值,填充它通过插值”:df[df.isna()&(~df.shift().isna())&(~df.shift(-1).isna())]
    • shift 将行向下或向上移动一个位置(使用 -1),isna 测试值是否为 nan,~ 否定测试。最后& 是合乎逻辑的...
    • 我已按问题编辑。我意识到我必须根据他们的个人群体来估算缺失值。我可以知道如何在插值之前先对数据框进行分组吗?我尝试使用 df.group('c')。但是,这不会给我返回一个数据框。
    猜你喜欢
    • 2018-05-21
    • 1970-01-01
    • 2018-08-14
    • 2013-07-08
    • 1970-01-01
    • 1970-01-01
    • 2017-05-04
    • 2020-02-05
    相关资源
    最近更新 更多