Coalesce valores de 2 columnas en una sola columna en un dataframe de pandas

Estoy buscando un método que se comporte de manera similar a unirse en T-SQL. Tengo 2 columnas (columnas A y B) que están pobladas escasamente en un dataframe de pandas. Me gustaría crear una nueva columna usando las siguientes reglas:

  1. Si el valor en la columna A no es nulo , use ese valor para la nueva columna C
  2. Si el valor en la columna A es nulo , use el valor en la columna B para la nueva columna C

Como mencioné, esto se puede lograr en MS SQL Server a través de la función de fusión. No he encontrado un buen método pythonico para esto; ¿existe uno?

utilizar combine_first () :

In [16]: df = pd.DataFrame(np.random.randint(0, 10, size=(10, 2)), columns=list('ab')) In [17]: df.loc[::2, 'a'] = np.nan In [18]: df Out[18]: ab 0 NaN 0 1 5.0 5 2 NaN 8 3 2.0 8 4 NaN 3 5 9.0 4 6 NaN 7 7 2.0 0 8 NaN 6 9 2.0 5 In [19]: df['c'] = df.a.combine_first(df.b) In [20]: df Out[20]: abc 0 NaN 0 0.0 1 5.0 5 5.0 2 NaN 8 8.0 3 2.0 8 2.0 4 NaN 3 3.0 5 9.0 4 9.0 6 NaN 7 7.0 7 2.0 0 2.0 8 NaN 6 6.0 9 2.0 5 2.0 

Intenta esto también … más fácil de recordar:

 df['c'] = np.where(df["a"].isnull(), df["b"], df["a"] ) 

Esto es ligeramente más rápido: df['c'] = np.where(df["a"].isnull() == True, df["b"], df["a"] )

 %timeit df['d'] = df.a.combine_first(df.b) 1000 loops, best of 3: 472 µs per loop %timeit df['c'] = np.where(df["a"].isnull(), df["b"], df["a"] ) 1000 loops, best of 3: 291 µs per loop 

combine_first es la opción más sencilla. Hay un par de otros que describo a continuación. Voy a esbozar algunas soluciones más, algunas aplicables a diferentes casos.

Caso # 1: NaNs no mutuamente excluyentes

No todas las filas tienen NaN, y estos NaN no se excluyen mutuamente entre columnas.

 df = pd.DataFrame({ 'a': [1.0, 2.0, 3.0, np.nan, 5.0, 7.0, np.nan], 'b': [5.0, 3.0, np.nan, 4.0, np.nan, 6.0, 7.0]}) df ab 0 1.0 5.0 1 2.0 3.0 2 3.0 NaN 3 NaN 4.0 4 5.0 NaN 5 7.0 6.0 6 NaN 7.0 

Vamos a combinar primero en a .

Series.mask

 df['a'].mask(pd.isnull, df['b']) # df['a'].mask(df['a'].isnull(), df['b']) 
 0 1.0 1 2.0 2 3.0 3 4.0 4 5.0 5 7.0 6 7.0 Name: a, dtype: float64 

Series.where

 df['a'].where(pd.notnull, df['b']) 0 1.0 1 2.0 2 3.0 3 4.0 4 5.0 5 7.0 6 7.0 Name: a, dtype: float64 

Puedes usar una syntax similar usando np.where .

Alternativamente, para combinar primero en b , cambia las condiciones alrededor.


Caso # 2: NaNs posicionados mutuamente excluyentes

Todas las filas tienen NaN que son mutuamente excluyentes entre columnas.

 df = pd.DataFrame({ 'a': [1.0, 2.0, 3.0, np.nan, 5.0, np.nan, np.nan], 'b': [np.nan, np.nan, np.nan, 4.0, np.nan, 6.0, 7.0]}) df ab 0 1.0 NaN 1 2.0 NaN 2 3.0 NaN 3 NaN 4.0 4 5.0 NaN 5 NaN 6.0 6 NaN 7.0 

Series.update

Este método funciona in situ, modificando el DataFrame original. Esta es una opción eficiente para este caso de uso.

 df['b'].update(df['a']) # Or, to update "a" in-place, # df['a'].update(df['b']) df ab 0 1.0 1.0 1 2.0 2.0 2 3.0 3.0 3 NaN 4.0 4 5.0 5.0 5 NaN 6.0 6 NaN 7.0 

Series.add

 df['a'].add(df['b'], fill_value=0) 0 1.0 1 2.0 2 3.0 3 4.0 4 5.0 5 6.0 6 7.0 dtype: float64 

DataFrame.fillna + DataFrame.sum

 df.fillna(0).sum(1) 0 1.0 1 2.0 2 3.0 3 4.0 4 5.0 5 6.0 6 7.0 dtype: float64