lassence.net

Field notes from the AI frontier

Forward- or back-fill NA values in DataFrames

--- archive: codebook, 2020–2023 · topic: Pandas ---

Handling missing data is an important step in the data preprocessing pipeline. In many scenarios, filling NA values with meaningful data can lead to more robust models. Two common techniques are forward-filling and back-filling, where missing values are filled with adjacent non-NA values.

Back-filling replaces NaN with the next non-NA value, while forward-filling takes the previous non-NA value. In pandas, this can be be done with fillna(method=bfill|ffill) or with the shortcuts bfill() and ffill().

First, let's create a sample DataFrame with random integer values and some missing data:

# Import libraries
import pandas as pd
import numpy as np
from numpy.random import randint

# Set seed
np.random.seed(21)

# Create sample data
df = (
    pd.DataFrame({
        'group': list('ABCDE'), 
        'value': [randint(1000, 20000, randint(2, 5)) for i in range(5)]
    })
    .explode('value')
    .reset_index(drop=True)
)
df.loc[df.sample(frac=0.5).index, 'value'] = np.nan
df
groupvalue
0A6327
1ANaN
2ANaN
3BNaN
4B13898
5CNaN
6C18224
7C2646
8DNaN
9D16613
10E17118
11ENaN
12E3352

Back-fill and forward-fill

Pandas provides the fillna(method=bfill|ffill) function, as well as shortcuts bfill() and ffill(), to perform these operations.

This code snippet adds two new columns to the DataFrame, 'value_bfill' and 'value_ffill', representing the back-filled and forward-filled 'value' feature, respectively.

# Back-fill and forward-fill
df.assign(
    value_bfill=df['value'].bfill(),
    value_ffill=df['value'].ffill()
)
groupvaluevalue_bfillvalue_ffill
0A632763276327
1ANaN138986327
2ANaN138986327
3BNaN138986327
4B138981389813898
5CNaN1822413898
6C182241822418224
7C264626462646
8DNaN166132646
9D166131661316613
10E171181711817118
11ENaN335217118
12E335233523352

Forward- or back-fill within groups

In some cases, you may want to apply these fill methods within specific groups. This can be done using the groupby method in Pandas.

This code snippet demonstrates how to apply both back-fill and forward-fill within each group, and also how to combine both methods to fill all NA values:

# Backfill and foward-fill within each group
df.assign(
    # Back-fill
    value_bfill=df.groupby('group').transform(lambda x: x.bfill()),
    # Forward-fill
    value_ffill=df.groupby('group').transform(lambda x: x.ffill()),
    # Get back- or forward-filled value
    value_filled=lambda x: x['value_bfill'].fillna(x['value_ffill'])
)
groupvaluevalue_bfillvalue_ffillvalue_filled
0A63276327.06327.06327.0
1ANaNNaN6327.06327.0
2ANaNNaN6327.06327.0
3BNaN13898.0NaN13898.0
4B1389813898.013898.013898.0
5CNaN18224.0NaN18224.0
6C1822418224.018224.018224.0
7C26462646.02646.02646.0
8DNaN16613.0NaN16613.0
9D1661316613.016613.016613.0
10E1711817118.017118.017118.0
11ENaN3352.017118.03352.0
12E33523352.03352.03352.0