Obtención del último valor no nata entre filas en un dataframe de pandas

Tengo un dataframe de forma (40.500). Cada fila en el dataframe tiene algunos valores numéricos hasta el número de columna variable k, y todas las entradas después de eso son nan.

Estoy tratando de obtener el valor de la última columna no nan en cada fila. ¿Hay alguna manera de hacer esto sin recorrer todas las filas del dataframe?

Ejemplo de dataframe:

2016-06-02 7.080 7.079 7.079 7.079 7.079 7.079 nan nan nan 2016-06-08 7.053 7.053 7.053 7.053 7.053 7.054 nan nan nan 2016-06-09 7.061 7.061 7.060 7.060 7.060 7.060 nan nan nan 2016-06-14 nan nan nan nan nan nan nan nan nan 2016-06-15 7.066 7.066 7.066 7.066 nan nan nan nan nan 2016-06-16 7.067 7.067 7.067 7.067 7.067 7.067 7.068 7.068 nan 2016-06-21 7.053 7.053 7.052 nan nan nan nan nan nan 2016-06-22 7.049 7.049 nan nan nan nan nan nan nan 2016-06-28 7.058 7.058 7.059 7.059 7.059 7.059 7.059 7.059 7.059 

Salida requerida

 2016-06-02 7.079 2016-06-08 7.054 2016-06-09 7.060 2016-06-14 nan 2016-06-15 7.066 2016-06-16 7.068 2016-06-21 7.052 2016-06-22 7.049 2016-06-28 7.059 

Necesita last_valid_index con función personalizada, porque si todos los valores son NaN , devuelve KeyError :

 def f(x): if x.last_valid_index() is None: return np.nan else: return x[x.last_valid_index()] df['status'] = df.apply(f, axis=1) print (df) 1 2 3 4 5 6 7 8 9 \ 0 2016-06-02 7.080 7.079 7.079 7.079 7.079 7.079 NaN NaN NaN 2016-06-08 7.053 7.053 7.053 7.053 7.053 7.054 NaN NaN NaN 2016-06-09 7.061 7.061 7.060 7.060 7.060 7.060 NaN NaN NaN 2016-06-14 NaN NaN NaN NaN NaN NaN NaN NaN NaN 2016-06-15 7.066 7.066 7.066 7.066 NaN NaN NaN NaN NaN 2016-06-16 7.067 7.067 7.067 7.067 7.067 7.067 7.068 7.068 NaN 2016-06-21 7.053 7.053 7.052 NaN NaN NaN NaN NaN NaN 2016-06-22 7.049 7.049 NaN NaN NaN NaN NaN NaN NaN 2016-06-28 7.058 7.058 7.059 7.059 7.059 7.059 7.059 7.059 7.059 status 0 2016-06-02 7.079 2016-06-08 7.054 2016-06-09 7.060 2016-06-14 NaN 2016-06-15 7.066 2016-06-16 7.068 2016-06-21 7.052 2016-06-22 7.049 2016-06-28 7.059 

Solución alternativa: fillna con el método de ffill y seleccione la última columna por iloc :

 df['status'] = df.ffill(axis=1).iloc[:, -1] print (df) status 0 2016-06-02 7.079 2016-06-08 7.054 2016-06-09 7.060 2016-06-14 NaN 2016-06-15 7.066 2016-06-16 7.068 2016-06-21 7.052 2016-06-22 7.049 2016-06-28 7.059 

utilizar agg('last')

 df.groupby(['status'] * df.shape[1], 1).agg('last') 

introduzca la descripción de la imagen aquí


‘último’ dentro de agg produce ese último valor válido dentro del grupo. Pasé una lista de longitud igual al número de columnas. Cada valor de esta lista es ‘estado’. Eso significa que estoy agrupando por un grupo. El resultado es un dataframe con una columna llamada ‘estado’

Aquí hay una solución basada en NumPy:

 In [113]: a Out[113]: array([[ 17., 53., nan, 63., 66., nan, nan, nan, nan, nan], [ 54., 96., 71., 20., 70., 58., 91., nan, nan, nan], [ 58., 26., 72., 93., 58., 29., 44., 28., 36., 88.], [ nan, nan, nan, nan, nan, nan, nan, nan, nan, nan], [ 94., 23., nan, nan, 92., 81., 40., 30., 84., nan]]) In [114]: m = ~np.isnan(a) In [115]: a[np.arange(m.shape[0]), m.shape[1]-m[:,::-1].argmax(1)-1] Out[115]: array([ 66., 91., 88., nan, 84.]) 

Para portar esto para el dataframe, primero podemos extraer los valores como una matriz: a = df.values y finalmente hacer el dataframe de salida:

 vals = a[np.arange(m.shape[0]), m.shape[1]-m[:,::-1].argmax(1)-1] df_out = pd.DataFrame(vals,index=df.index)