Groupby fillna with 0 after first observation per group

196 views Asked by At

Question

Is there a way to fill missing values with 0 using groupby, but only after an observation appears for the first time?

E.g. Start

       id   spiq  nopiq   spiq  pstkq  dvy  dvpq  mibq  xidoq   miiq
2014    1   NaN   NaN     NaN   0.0   NaN   0.0   0.0 -0.122  0.000
2015    1   0.01  0.003   0.1   0.10  NaN   NaN   NaN -1.309  0.000
2016    1   0.04  0.003   NaN   0.10  NaN   0.10  0.10  NaN   NaN
2017    1   NaN   0.000   NaN   NaN   20    NaN   NaN  0.000  NaN
2018    1   0.05  0.000   NaN   0.0   NaN   0.0   0.0  0.000  0.000
2014    2   NaN   NaN     NaN   0.0   NaN   0.0   0.0 -0.122  0.000
2015    2   0.01  0.003   0.1   0.10  NaN   NaN   NaN -1.309  0.000
2016    2   0.04  0.003   NaN   0.10  NaN   0.10  0.10  NaN   NaN
2017    2   NaN   0.000   NaN   NaN   20    NaN   NaN  0.000  NaN
2018    2   0.05  0.000   NaN   0.0   NaN   0.0   0.0  0.000  0.000
2014    3   NaN   NaN     NaN   0.0   NaN   0.0   0.0 -0.122  0.000
2015    3   0.01  0.003   0.1   0.10  NaN   NaN   NaN -1.309  0.000
2016    3   0.04  0.003   NaN   0.10  NaN   0.10  0.10  NaN   NaN
2017    3   NaN   0.000   NaN   NaN   20    NaN   NaN  0.000  NaN
2018    3   0.05  0.000   NaN   0.0   NaN   0.0   0.0  0.000  0.000

Desired

    id   spiq  nopiq   spiq  pstkq  dvy  dvpq  mibq  xidoq   miiq
2014    1   NaN   NaN     NaN   0.0   NaN   0.0   0.0  -0.122  0.000
2015    1   0.01  0.003   0.1   0.10  NaN   0.0   0.0  -1.309  0.000
2016    1   0.04  0.003   0.0   0.10  NaN   0.10  0.10  0.0    0.0
2017    1   0.0   0.000   0.0   0.0   20    0.0   0.0   0.0    0.0
2018    1   0.05  0.000   0.0   0.0   0.0   0.0   0.0   0.0    0.000
2014    2   NaN   NaN     NaN   0.0   NaN   0.0   0.0  -0.122  0.000
2015    2   0.01  0.003   0.1   0.10  NaN   0.0   0.0  -1.309  0.000
2016    2   0.04  0.003   0.0   0.10  NaN   0.10  0.10  0.0    0.0
2017    2   0.0   0.000   0.0   0.0   20    0.0   0.0   0.000  0.0
2018    2   0.05  0.000   0.0   0.0   0.0   0.0   0.0   0.000  0.000
2014    3   NaN   NaN     NaN   0.0   NaN   0.0   0.0  -0.122  0.000
2015    3   0.01  0.003   0.1   0.10  NaN   0.0   0.0  -1.309  0.000
2016    3   0.04  0.003   0.0   0.10  NaN   0.10  0.10  0.0    0.0
2017    3   0.0   0.000   0.0   0.0   20    0.0   0.0   0.000  0.0
2018    3   0.05  0.000   0.0   0.0   0.0   0.0   0.0   0.000  0.000
1

There are 1 answers

1
Scott Boston On BEST ANSWER

IIUC, here is one way since you can't forward fill with a zero.

df.mask((df.groupby('id').ffill().notna() & 
         df.isna()).fillna(False), 0)

Output:

      id  spiq  nopiq  spiq.1  pstkq   dvy  dvpq  mibq  xidoq  miiq
2014   1   NaN    NaN     NaN    0.0   NaN   0.0   0.0 -0.122   0.0
2015   1  0.01  0.003     0.1    0.1   NaN   0.0   0.0 -1.309   0.0
2016   1  0.04  0.003     0.0    0.1   NaN   0.1   0.1  0.000   0.0
2017   1  0.00  0.000     0.0    0.0  20.0   0.0   0.0  0.000   0.0
2018   1  0.05  0.000     0.0    0.0   0.0   0.0   0.0  0.000   0.0
2014   2   NaN    NaN     NaN    0.0   NaN   0.0   0.0 -0.122   0.0
2015   2  0.01  0.003     0.1    0.1   NaN   0.0   0.0 -1.309   0.0
2016   2  0.04  0.003     0.0    0.1   NaN   0.1   0.1  0.000   0.0
2017   2  0.00  0.000     0.0    0.0  20.0   0.0   0.0  0.000   0.0
2018   2  0.05  0.000     0.0    0.0   0.0   0.0   0.0  0.000   0.0
2014   3   NaN    NaN     NaN    0.0   NaN   0.0   0.0 -0.122   0.0
2015   3  0.01  0.003     0.1    0.1   NaN   0.0   0.0 -1.309   0.0
2016   3  0.04  0.003     0.0    0.1   NaN   0.1   0.1  0.000   0.0
2017   3  0.00  0.000     0.0    0.0  20.0   0.0   0.0  0.000   0.0
2018   3  0.05  0.000     0.0    0.0   0.0   0.0   0.0  0.000   0.0

Details:

Use ffill after groupby to fill NaN with the last valid value with each group, then check that new created dataframe to see where all the non-NaN values and the NaN values in the original df and fill those with 0 using mask.