繁体   English   中英

Pandas 动态替换 nan 值

[英]Pandas dynamically replace nan values

我有一个看起来像这样的 DataFrame:

df = pd.DataFrame({'a':[1,2,np.nan,1,np.nan,np.nan,4,2,3,np.nan], 
    'b':[4,2,3,np.nan,np.nan,1,5,np.nan,5,8]
})

   a    b
0  1.0  4.0
1  2.0  2.0
2  NaN  3.0
3  1.0  NaN
4  NaN  NaN
5  NaN  1.0
6  4.0  5.0
7  2.0  NaN
8  3.0  5.0
9  NaN  8.0

我想动态替换 nan 值。 我试过做(df.ffill()+df.bfill())/2但这并没有产生所需的输出,因为它一次将填充值转换为整个列,而不是动态地。 我尝试过interpolate ,但它不适用于非线性数据。

我已经看到了这个答案,但没有完全理解它,并且不确定它是否会起作用。

更新值的计算
我希望每个 nan 值都是前一个和下一个非 nan 值的平均值。 如果序列中有超过 1 个 nan 值,我想一次替换一个,然后计算平均值,例如,如果有 1、np.nan、np.nan、4,我首先想要 1 的平均值和 4 (2.5) 为第一个 nan 值 - 获得 1,2.5,np.nan,4 - 然后第二个 nan 将是 2.5 和 4 的平均值,达到 1,2.5,3.25,4

所需的输出是

    a    b
0  1.00  4.0
1  2.00  2.0
2  1.50  3.0
3  1.00  2.0
4  2.50  1.5
5  3.25  1.0
6  4.00  5.0
7  2.00  5.0
8  3.00  5.0
9  1.50  8.0

受到@ye olde noobe 答案的启发(感谢他! ):

我已经对其进行了优化,使其 ≃ 快 100 倍(下面的时间比较):

def custom_fillna(s:pd.Series):
  for i in range(len(s)):
    if pd.isna(s[i]):
      last_valid_number = (s[s[:i].last_valid_index()] if s[:i].last_valid_index() is not None else 0)
      next_valid_numer = (s[s[i:].first_valid_index()] if s[i:].first_valid_index() is not None else 0)
      s[i] = (last_valid_number+next_valid_numer)/2

custom_fillna(df['a'])
df

时间比较:

在此处输入图像描述

也许不是最优化的,但它可以工作(注意:从您的示例中,我假设如果在 NaN 之前或之后没有有效值,如 a 列的最后一行,则使用 0 作为替换):

import pandas as pd

def fill_dynamically(s: pd.Series):
    for i in range(len(s)):
        s[i] = (
            (0 if s[i:].first_valid_index() is None else s[i:][s[i:].first_valid_index()]) +
            (0 if s[:i+1].last_valid_index() is None else s[:i+1][s[:i+1].last_valid_index()])
        ) / 2

像这样使用完整的数据框:

df = pd.DataFrame({'a':[1,2,np.nan,1,np.nan,np.nan,4,2,3,np.nan], 
    'b':[4,2,3,np.nan,np.nan,1,5,np.nan,5,8]
})

df.apply(fill_dynamically)

df 申请后:

      a    b
0  1.00  4.0
1  2.00  2.0
2  1.50  3.0
3  1.00  2.0
4  2.50  1.5
5  3.25  1.0
6  4.00  5.0
7  2.00  5.0
8  3.00  5.0
9  1.50  8.0

如果您有其他列并且不想将其应用于整个数据框,您当然可以在单个列上使用它,如下所示:

df = pd.DataFrame({'a':[1,2,np.nan,1,np.nan,np.nan,4,2,3,np.nan], 
    'b':[4,2,3,np.nan,np.nan,1,5,np.nan,5,8]
})

fill_dynamically(df['a'])

在这种情况下, df 看起来像这样:

      a    b
0  1.00  4.0
1  2.00  2.0
2  1.50  3.0
3  1.00  NaN
4  2.50  NaN
5  3.25  1.0
6  4.00  5.0
7  2.00  NaN
8  3.00  5.0
9  1.50  8.0

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM