【问题标题】:How to replace NaNs by preceding or next values in pandas DataFrame?如何用 pandas DataFrame 中的前一个或下一个值替换 NaN?
【发布时间】:2015-03-10 09:56:52
【问题描述】:

假设我有一个带有 NaNs 的 DataFrame:

>>> import pandas as pd
>>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
>>> df
    0   1   2
0   1   2   3
1   4 NaN NaN
2 NaN NaN   9

我需要做的是将每个NaN 替换为其上方同一列中的第一个非NaN 值。假定第一行永远不会包含NaN。因此,对于前面的示例,结果将是

   0  1  2
0  1  2  3
1  4  2  3
2  4  2  9

我可以逐列、逐个元素地遍历整个 DataFrame 并直接设置值,但有没有一种简单(最好是无循环)的方法来实现这一点?

【问题讨论】:

    标签: python python-3.x pandas dataframe nan


    【解决方案1】:

    您可以使用fillna 删除或替换 NaN 值。

    NaN 删除

    import pandas as pd
    
    df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
    
    df.fillna(method='ffill')
         0    1    2
    0  1.0  2.0  3.0
    1  4.0  2.0  3.0
    2  4.0  2.0  9.0
    

    NaN 替换

    df.fillna(0) # 0 means What Value you want to replace 
         0    1    2
    0  1.0  2.0  3.0
    1  4.0  0.0  0.0
    2  0.0  0.0  9.0
    

    参考pandas.DataFrame.fillna

    【讨论】:

      【解决方案2】:

      只同意ffill 方法,但还有一个额外信息是您可以使用关键字参数limit 限制前向填充。

      >>> import pandas as pd    
      >>> df = pd.DataFrame([[1, 2, 3], [None, None, 6], [None, None, 9]])
      
      >>> df
           0    1   2
      0  1.0  2.0   3
      1  NaN  NaN   6
      2  NaN  NaN   9
      
      >>> df[1].fillna(method='ffill', inplace=True)
      >>> df
           0    1    2
      0  1.0  2.0    3
      1  NaN  2.0    6
      2  NaN  2.0    9
      

      现在使用 limit 关键字参数

      >>> df[0].fillna(method='ffill', limit=1, inplace=True)
      
      >>> df
           0    1  2
      0  1.0  2.0  3
      1  1.0  2.0  6
      2  NaN  2.0  9
      

      【讨论】:

        【解决方案3】:

        只有一栏版本

        • 最后一个有效值填充 NAN
        df[column_name].fillna(method='ffill', inplace=True)
        
        • 下一个有效值填充 NAN
        df[column_name].fillna(method='backfill', inplace=True)
        

        【讨论】:

          【解决方案4】:

          在我的例子中,我们有来自不同设备的时间序列,但有些设备在一段时间内无法发送任何值。所以我们应该为每个设备和时间段创建 NA 值,然后再进行填充。

          df = pd.DataFrame([["device1", 1, 'first val of device1'], ["device2", 2, 'first val of device2'], ["device3", 3, 'first val of device3']])
          df.pivot(index=1, columns=0, values=2).fillna(method='ffill').unstack().reset_index(name='value')
          

          结果:

                  0   1   value
          0   device1     1   first val of device1
          1   device1     2   first val of device1
          2   device1     3   first val of device1
          3   device2     1   None
          4   device2     2   first val of device2
          5   device2     3   first val of device2
          6   device3     1   None
          7   device3     2   None
          8   device3     3   first val of device3
          

          【讨论】:

            【解决方案5】:

            接受的答案是完美的。我有一个相关但略有不同的情况,我必须向前填写,但只能在组内填写。如果有人有同样的需求,请知道 fillna 在 DataFrameGroupBy 对象上工作。

            >>> example = pd.DataFrame({'number':[0,1,2,nan,4,nan,6,7,8,9],'name':list('aaabbbcccc')})
            >>> example
              name  number
            0    a     0.0
            1    a     1.0
            2    a     2.0
            3    b     NaN
            4    b     4.0
            5    b     NaN
            6    c     6.0
            7    c     7.0
            8    c     8.0
            9    c     9.0
            >>> example.groupby('name')['number'].fillna(method='ffill') # fill in row 5 but not row 3
            0    0.0
            1    1.0
            2    2.0
            3    NaN
            4    4.0
            5    4.0
            6    6.0
            7    7.0
            8    8.0
            9    9.0
            Name: number, dtype: float64
            

            【讨论】:

            • 正是我想要的,你
            【解决方案6】:

            ffill 现在有自己的方法pd.DataFrame.ffill

            df.ffill()
            
                 0    1    2
            0  1.0  2.0  3.0
            1  4.0  2.0  3.0
            2  4.0  2.0  9.0
            

            【讨论】:

              【解决方案7】:

              我在尝试此解决方案时注意到的一件事是,如果您在数组的开头或结尾处有 N/A,则 ffill 和 bfill 就不能正常工作。两者都需要。

              In [224]: df = pd.DataFrame([None, 1, 2, 3, None, 4, 5, 6, None])
              
              In [225]: df.ffill()
              Out[225]:
                   0
              0  NaN
              1  1.0
              ...
              7  6.0
              8  6.0
              
              In [226]: df.bfill()
              Out[226]:
                   0
              0  1.0
              1  1.0
              ...
              7  6.0
              8  NaN
              
              In [227]: df.bfill().ffill()
              Out[227]:
                   0
              0  1.0
              1  1.0
              ...
              7  6.0
              8  6.0
              

              【讨论】:

              • 太棒了。我正是需要这个来解决我的问题。前后都填充。非常感谢。
              • 太棒了。我需要这个解决方案。谢谢
              【解决方案8】:

              您可以在 DataFrame 上使用fillna 方法并将该方法指定为ffill(前向填充):

              >>> df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
              >>> df.fillna(method='ffill')
                 0  1  2
              0  1  2  3
              1  4  2  3
              2  4  2  9
              

              这个方法……

              将最后一个有效观察值传播到下一个有效观察值

              相反,还有一个bfill 方法。

              此方法不会就地修改 DataFrame - 您需要将返回的 DataFrame 重新绑定到变量或指定 inplace=True

              df.fillna(method='ffill', inplace=True)
              

              【讨论】:

              • 如果空白单元格在列名索引中怎么办(即,有几列没有名称但有数据。有没有办法使用 bfill 或 ffill 来填充空白列索引单元格与紧随其下的行中的单元格?例如: df = pd.DataFrame({'col1': [2, 4, 8], 'col2': [2, 0, 0], '': [10, 2, 1]}, index=['falcon', 'dog', 'spider'']) 如何使用 bfill 或 ffill 将第三列的名称更改为 10(这是紧接在空白第三列名称下方的行?谢谢!
              【解决方案9】:

              您可以将pandas.DataFrame.fillnamethod='ffill' 选项一起使用。 'ffill' 代表“前向填充”,并将向前传播最后一个有效观察。另一种方法是'bfill',它的工作方式相同,但反向。

              import pandas as pd
              
              df = pd.DataFrame([[1, 2, 3], [4, None, None], [None, None, 9]])
              df = df.fillna(method='ffill')
              
              print(df)
              #   0  1  2
              #0  1  2  3
              #1  4  2  3
              #2  4  2  9
              

              还有一个直接的同义词函数pandas.DataFrame.ffill,可以让事情变得更简单。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2023-03-23
                • 2021-05-28
                • 1970-01-01
                • 2021-02-25
                • 2018-11-14
                • 2012-11-23
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多