pandas, how only fillna for last row with preceding line closest non-nan value

Question:

import pandas as pd
import numpy as np

df = pd.DataFrame(np.random.randint(0, 10, (10, 10)), columns=list('ABCDEFGHIJ'))
df[df > 5] = np.nan

for i in range(10):
    df.iloc[i, i % 10] = np.nan

print(df)

origin df is:

     A    B    C    D    E    F    G    H    I    J
0  NaN  2.0  NaN  0.0  5.0  4.0  1.0  NaN  NaN  0.0
1  3.0  NaN  NaN  NaN  2.0  0.0  1.0  1.0  NaN  1.0
2  NaN  5.0  NaN  5.0  NaN  0.0  5.0  0.0  4.0  NaN
3  2.0  NaN  NaN  NaN  3.0  5.0  NaN  NaN  NaN  5.0
4  NaN  2.0  NaN  0.0  NaN  NaN  2.0  NaN  2.0  0.0
5  NaN  NaN  NaN  2.0  NaN  NaN  NaN  NaN  0.0  5.0
6  NaN  NaN  0.0  NaN  2.0  NaN  NaN  1.0  NaN  NaN
7  NaN  5.0  1.0  2.0  4.0  NaN  3.0  NaN  3.0  2.0
8  1.0  5.0  1.0  NaN  3.0  NaN  1.0  NaN  NaN  5.0
9  0.0  NaN  NaN  NaN  3.0  NaN  2.0  3.0  5.0  NaN

I only want to fillna for last row with preceding line closest non-nan value, I hava a big dataframe, so I want ot use the fastest way to save the most memory, to become to:

     A    B    C    D    E    F    G    H    I    J
0  NaN  2.0  NaN  0.0  5.0  4.0  1.0  NaN  NaN  0.0
1  3.0  NaN  NaN  NaN  2.0  0.0  1.0  1.0  NaN  1.0
2  NaN  5.0  NaN  5.0  NaN  0.0  5.0  0.0  4.0  NaN
3  2.0  NaN  NaN  NaN  3.0  5.0  NaN  NaN  NaN  5.0
4  NaN  2.0  NaN  0.0  NaN  NaN  2.0  NaN  2.0  0.0
5  NaN  NaN  NaN  2.0  NaN  NaN  NaN  NaN  0.0  5.0
6  NaN  NaN  0.0  NaN  2.0  NaN  NaN  1.0  NaN  NaN
7  NaN  5.0  1.0  2.0  4.0  NaN  3.0  NaN  3.0  2.0
8  1.0  5.0  1.0  NaN  3.0  NaN  1.0  NaN  NaN  5.0
9  0.0  5.0  1.0  2.0  3.0  5.0  2.0  3.0  5.0  5.0
Asked By: Zheng Xiaodong

||

Answers:

You can do a forward fill and assign the last row

df.iloc[-1] = df.ffill().iloc[-1]
print(df)

     A    B    C    D    E    F    G    H    I    J
0  NaN  2.0  NaN  0.0  5.0  4.0  1.0  NaN  NaN  0.0
1  3.0  NaN  NaN  NaN  2.0  0.0  1.0  1.0  NaN  1.0
2  NaN  5.0  NaN  5.0  NaN  0.0  5.0  0.0  4.0  NaN
3  2.0  NaN  NaN  NaN  3.0  5.0  NaN  NaN  NaN  5.0
4  NaN  2.0  NaN  0.0  NaN  NaN  2.0  NaN  2.0  0.0
5  NaN  NaN  NaN  2.0  NaN  NaN  NaN  NaN  0.0  5.0
6  NaN  NaN  0.0  NaN  2.0  NaN  NaN  1.0  NaN  NaN
7  NaN  5.0  1.0  2.0  4.0  NaN  3.0  NaN  3.0  2.0
8  1.0  5.0  1.0  NaN  3.0  NaN  1.0  NaN  NaN  5.0
9  0.0  5.0  1.0  2.0  3.0  5.0  2.0  3.0  5.0  5.0

You can also consider filter column where the last row is not NaN.

df.loc[df.index[-1], df.iloc[-1].isna()] = df.loc[:, df.iloc[-1].isna()].ffill().iloc[-1]

Or only find the last non nan value with last_valid_index

df.iloc[-1] = df.apply(lambda s: s[s.last_valid_index()])
# or
df.loc[df.index[-1], df.iloc[-1].isna()] = df.loc[:, df.iloc[-1].isna()].apply(lambda s: s[s.last_valid_index()])
Answered By: Ynjxsjmh

Fast solution

v = df.values
ix = len(df) - 1 - (~np.isnan(v))[::-1].argmax(0)

df.iloc[-1, :] = v[ix, range(df.shape[1])]

Result

     A    B    C    D    E    F    G    H    I    J
0  NaN  2.0  NaN  0.0  5.0  4.0  1.0  NaN  NaN  0.0
1  3.0  NaN  NaN  NaN  2.0  0.0  1.0  1.0  NaN  1.0
2  NaN  5.0  NaN  5.0  NaN  0.0  5.0  0.0  4.0  NaN
3  2.0  NaN  NaN  NaN  3.0  5.0  NaN  NaN  NaN  5.0
4  NaN  2.0  NaN  0.0  NaN  NaN  2.0  NaN  2.0  0.0
5  NaN  NaN  NaN  2.0  NaN  NaN  NaN  NaN  0.0  5.0
6  NaN  NaN  0.0  NaN  2.0  NaN  NaN  1.0  NaN  NaN
7  NaN  5.0  1.0  2.0  4.0  NaN  3.0  NaN  3.0  2.0
8  1.0  5.0  1.0  NaN  3.0  NaN  1.0  NaN  NaN  5.0
9  0.0  5.0  1.0  2.0  3.0  5.0  2.0  3.0  5.0  5.0
Answered By: Shubham Sharma
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.