Pandas Fusionando 101

Dec 06 2018
  • ¿Cómo realizar un ( INNER| ( LEFT| RIGHT| FULL) OUTER) JOINcon pandas?
  • ¿Cómo agrego NaN para las filas que faltan después de la combinación?
  • ¿Cómo me deshago de los NaN después de la fusión?
  • ¿Puedo fusionarme en el índice?
  • ¿Cruzar unirse con pandas?
  • ¿Cómo fusiono varios DataFrames?
  • merge? join? concat? update? ¿OMS? ¿Qué? ¡¿Por qué?!

... y más. He visto estas preguntas recurrentes sobre varias facetas de la funcionalidad de fusión de pandas. La mayor parte de la información sobre la fusión y sus diversos casos de uso en la actualidad está fragmentada en docenas de publicaciones mal redactadas e inescrutables. El objetivo aquí es recopilar algunos de los puntos más importantes para la posteridad.

Esta QnA está destinada a ser la próxima entrega de una serie de útiles guías de usuario sobre modismos comunes de los pandas (consulte esta publicación sobre pivotar y esta publicación sobre concatenación , que abordaré más adelante).

Tenga en cuenta que esta publicación no pretende ser un reemplazo de la documentación , ¡así que léala también! Algunos de los ejemplos se toman de ahí.

Respuestas

696 cs95 Dec 06 2018 at 13:41

Esta publicación tiene como objetivo brindar a los lectores una introducción a la fusión con sabor SQL con pandas, cómo usarlo y cuándo no usarlo.

En particular, esto es lo que atravesará esta publicación:

  • Conceptos básicos: tipos de uniones (IZQUIERDA, DERECHA, EXTERIOR, INTERIOR)

    • fusionando con diferentes nombres de columna
    • evitando la columna de clave de combinación duplicada en la salida
  • Fusión con índice en diferentes condiciones

    • utilizando eficazmente su índice nombrado
    • fusionar clave como índice de uno y columna de otro
  • Multiway se fusiona en columnas e índices (únicos y no únicos)

  • Alternativas a notables mergeyjoin

Por lo que no pasará esta publicación:

  • Debates y horarios relacionados con el rendimiento (por ahora). Sobre todo menciones notables de mejores alternativas, cuando corresponda.
  • Manejo de sufijos, eliminación de columnas adicionales, cambio de nombre de salidas y otros casos de uso específicos. Hay otras publicaciones (léase: mejores) que tratan con eso, ¡así que descúbrelo!

Nota
La mayoría de los ejemplos utilizan de forma predeterminada las operaciones INNER JOIN mientras se muestran varias funciones, a menos que se especifique lo contrario.

Además, todos los DataFrames aquí se pueden copiar y replicar para que pueda jugar con ellos. Además, vea esta publicación sobre cómo leer DataFrames desde su portapapeles.

Por último, toda la representación visual de las operaciones JOIN se ha dibujado a mano con Dibujos de Google. Inspiración de aquí .

Basta de hablar, ¡enséñame cómo usarlo merge!

Preparar

np.random.seed(0)
left = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'value': np.random.randn(4)})    
right = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'value': np.random.randn(4)})
  
left

  key     value
0   A  1.764052
1   B  0.400157
2   C  0.978738
3   D  2.240893

right

  key     value
0   B  1.867558
1   D -0.977278
2   E  0.950088
3   F -0.151357

En aras de la simplicidad, la columna clave tiene el mismo nombre (por ahora).

Una INNER JOIN está representada por

Tenga en cuenta que
esto, junto con las próximas cifras, siguen esta convención:

  • azul indica filas que están presentes en el resultado de la combinación
  • rojo indica filas que están excluidas del resultado (es decir, eliminadas)
  • verde indica valores perdidos que se reemplazan con NaNs en el resultado

Para realizar una INNER JOIN, llame mergeal DataFrame izquierdo, especificando el DataFrame derecho y la clave de combinación (como mínimo) como argumentos.

left.merge(right, on='key')
# Or, if you want to be explicit
# left.merge(right, on='key', how='inner')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278

Esto devuelve solo filas de lefty rightque comparten una clave común (en este ejemplo, "B" y "D).

UN LEFT OUTER JOIN o LEFT JOIN está representado por

Esto se puede realizar especificando how='left'.

left.merge(right, on='key', how='left')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278

Observe cuidadosamente la ubicación de los NaN aquí. Si lo especifica how='left', solo leftse utilizan las claves de y los datos faltantes de rightse reemplazan por NaN.

Y de manera similar, para un RIGHT OUTER JOIN , o RIGHT JOIN que es ...

... especificar how='right':

left.merge(right, on='key', how='right')

  key   value_x   value_y
0   B  0.400157  1.867558
1   D  2.240893 -0.977278
2   E       NaN  0.950088
3   F       NaN -0.151357

Aquí, rightse utilizan claves de y los datos faltantes de leftse reemplazan por NaN.

Finalmente, para el FULL OUTER JOIN , dado por

especificar how='outer'.

left.merge(right, on='key', how='outer')

  key   value_x   value_y
0   A  1.764052       NaN
1   B  0.400157  1.867558
2   C  0.978738       NaN
3   D  2.240893 -0.977278
4   E       NaN  0.950088
5   F       NaN -0.151357

Esto usa las claves de ambos marcos y se insertan NaN para las filas faltantes en ambos.

La documentación resume muy bien estas diversas fusiones:

Otras UNIONES: IZQUIERDA-Excluyendo, DERECHA-Excluida y COMPLETA-Excluyendo / ANTI JOIN

Si necesita JOINs LEFT-Excluyendo y JOINs RIGHT-Excluyendo en dos pasos.

Para LEFT-Excluyendo JOIN, representado como

Comience realizando una LEFT OUTER JOIN y luego filtre (¡excluyendo!) Las filas que provienen leftsolo,

(left.merge(right, on='key', how='left', indicator=True)
     .query('_merge == "left_only"')
     .drop('_merge', 1))

  key   value_x  value_y
0   A  1.764052      NaN
2   C  0.978738      NaN

Dónde,

left.merge(right, on='key', how='left', indicator=True)

  key   value_x   value_y     _merge
0   A  1.764052       NaN  left_only
1   B  0.400157  1.867558       both
2   C  0.978738       NaN  left_only
3   D  2.240893 -0.977278       both

Y de manera similar, para un JOIN que excluye el DERECHO,

(left.merge(right, on='key', how='right', indicator=True)
     .query('_merge == "right_only"')
     .drop('_merge', 1))

  key  value_x   value_y
2   E      NaN  0.950088
3   F      NaN -0.151357

Por último, si debe realizar una combinación que solo retiene las claves de la izquierda o la derecha, pero no ambas (IOW, realizar un ANTI-JOIN ),

Puedes hacer esto de manera similar:

(left.merge(right, on='key', how='outer', indicator=True)
     .query('_merge != "both"')
     .drop('_merge', 1))

  key   value_x   value_y
0   A  1.764052       NaN
2   C  0.978738       NaN
4   E       NaN  0.950088
5   F       NaN -0.151357

Diferentes nombres para columnas clave

Si las columnas de claves se nombran de manera diferente, por ejemplo, lefttiene keyLefty righttiene en keyRightlugar de, keyentonces tendrá que especificar left_ony right_oncomo argumentos en lugar de on:

left2 = left.rename({'key':'keyLeft'}, axis=1)
right2 = right.rename({'key':'keyRight'}, axis=1)

left2
 
  keyLeft     value
0       A  1.764052
1       B  0.400157
2       C  0.978738
3       D  2.240893

right2

  keyRight     value
0        B  1.867558
1        D -0.977278
2        E  0.950088
3        F -0.151357
left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')

  keyLeft   value_x keyRight   value_y
0       B  0.400157        B  1.867558
1       D  2.240893        D -0.977278

Evitar la columna de clave duplicada en la salida

Al fusionar keyLeftdesde lefty keyRightdesde right, si solo desea uno de los keyLefto keyRight(pero no ambos) en la salida, puede comenzar estableciendo el índice como un paso preliminar.

left3 = left2.set_index('keyLeft')
left3.merge(right2, left_index=True, right_on='keyRight')
    
    value_x keyRight   value_y
0  0.400157        B  1.867558
1  2.240893        D -0.977278

Compare esto con la salida del comando justo antes (es decir, la salida de left2.merge(right2, left_on='keyLeft', right_on='keyRight', how='inner')), notará keyLeftque falta. Puede averiguar qué columna conservar en función del índice de fotograma establecido como clave. Esto puede ser importante cuando, por ejemplo, se realiza alguna operación OUTER JOIN.

Fusionando solo una columna de uno de los DataFrames

Por ejemplo, considere

right3 = right.assign(newcol=np.arange(len(right)))
right3
  key     value  newcol
0   B  1.867558       0
1   D -0.977278       1
2   E  0.950088       2
3   F -0.151357       3

Si debe fusionar solo "new_val" (sin ninguna de las otras columnas), normalmente puede crear subconjuntos de columnas antes de fusionar:

left.merge(right3[['key', 'newcol']], on='key')

  key     value  newcol
0   B  0.400157       0
1   D  2.240893       1

Si está haciendo una LEFT OUTER JOIN, una solución más eficaz implicaría map:

# left['newcol'] = left['key'].map(right3.set_index('key')['newcol']))
left.assign(newcol=left['key'].map(right3.set_index('key')['newcol']))

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

Como se mencionó, esto es similar, pero más rápido que

left.merge(right3[['key', 'newcol']], on='key', how='left')

  key     value  newcol
0   A  1.764052     NaN
1   B  0.400157     0.0
2   C  0.978738     NaN
3   D  2.240893     1.0

Fusionar en varias columnas

Para unirse en más de una columna, especifique una lista para on(o left_ony right_on, según corresponda).

left.merge(right, on=['key1', 'key2'] ...)

O, en caso de que los nombres sean diferentes,

left.merge(right, left_on=['lkey1', 'lkey2'], right_on=['rkey1', 'rkey2'])

Otras merge*operaciones y funciones útiles

Esta sección solo cubre los conceptos básicos y está diseñada para abrirle el apetito. Para más ejemplos y casos, consulte la documentación sobre merge, joinyconcat así como los enlaces a las especificaciones de función.


Basado en índice * -JOIN (+ columnas de índice merge)

Preparar

np.random.seed([3, 14])
left = pd.DataFrame({'value': np.random.randn(4)}, index=['A', 'B', 'C', 'D'])    
right = pd.DataFrame({'value': np.random.randn(4)}, index=['B', 'D', 'E', 'F'])
left.index.name = right.index.name = 'idxkey'

left
           value
idxkey          
A      -0.602923
B      -0.402655
C       0.302329
D      -0.524349

right
 
           value
idxkey          
B       0.543843
D       0.013135
E      -0.326498
F       1.385076

Normalmente, una fusión en el índice se vería así:

left.merge(right, left_index=True, right_index=True)


         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Soporte para nombres de índice

Si su índice tiene un nombre, los usuarios de la versión 0.23 también pueden especificar el nombre del nivel on(o left_ony right_onsegún sea necesario).

left.merge(right, on='idxkey')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Fusión en el índice de una, columna (s) de otra

Es posible (y bastante simple) utilizar el índice de uno y la columna de otro para realizar una fusión. Por ejemplo,

left.merge(right, left_on='key1', right_index=True)

O viceversa ( right_on=...y left_index=True).

right2 = right.reset_index().rename({'idxkey' : 'colkey'}, axis=1)
right2
 
  colkey     value
0      B  0.543843
1      D  0.013135
2      E -0.326498
3      F  1.385076

left.merge(right2, left_index=True, right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

En este caso especial, el índice para leftse nombra, por lo que también puede usar el nombre del índice con left_on, así:

left.merge(right2, left_on='idxkey', right_on='colkey')

    value_x colkey   value_y
0 -0.402655      B  0.543843
1 -0.524349      D  0.013135

DataFrame.join
Además de estos, hay otra opción sucinta. Puede usar DataFrame.joinqué valores predeterminados se unen en el índice. DataFrame.joinhace un LEFT OUTER JOIN de forma predeterminada, por lo que how='inner'es necesario aquí.

left.join(right, how='inner', lsuffix='_x', rsuffix='_y')

         value_x   value_y
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Tenga en cuenta que necesitaba especificar los argumentos lsuffixy rsuffixya que, de joinlo contrario, se produciría un error:

left.join(right)
ValueError: columns overlap but no suffix specified: Index(['value'], dtype='object')
 

Dado que los nombres de las columnas son los mismos. Esto no sería un problema si tuvieran otro nombre.

left.rename(columns={'value':'leftvalue'}).join(right, how='inner')

        leftvalue     value
idxkey                     
B       -0.402655  0.543843
D       -0.524349  0.013135

pd.concat
Por último, como alternativa a las combinaciones basadas en índices, puede utilizar pd.concat:

pd.concat([left, right], axis=1, sort=False, join='inner')

           value     value
idxkey                    
B      -0.402655  0.543843
D      -0.524349  0.013135

Omita join='inner'si necesita un COMPLETO EXTERIOR JOIN (predeterminado):

pd.concat([left, right], axis=1, sort=False)

      value     value
A -0.602923       NaN
B -0.402655  0.543843
C  0.302329       NaN
D -0.524349  0.013135
E       NaN -0.326498
F       NaN  1.385076

Para obtener más información, consulte esta publicación canónica pd.concatde @piRSquared .


Generalización: mergeing múltiples DataFrames

A menudo, surge la situación cuando se deben fusionar varios DataFrames. Ingenuamente, esto se puede hacer encadenando mergellamadas:

df1.merge(df2, ...).merge(df3, ...)

Sin embargo, esto rápidamente se sale de control para muchos DataFrames. Además, puede ser necesario generalizar para un número desconocido de DataFrames.

Aquí presento pd.concatpara uniones de múltiples vías en claves únicas y DataFrame.joinpara uniones de múltiples vías en claves no únicas . Primero, la configuración.

# Setup.
np.random.seed(0)
A = pd.DataFrame({'key': ['A', 'B', 'C', 'D'], 'valueA': np.random.randn(4)})    
B = pd.DataFrame({'key': ['B', 'D', 'E', 'F'], 'valueB': np.random.randn(4)})
C = pd.DataFrame({'key': ['D', 'E', 'J', 'C'], 'valueC': np.ones(4)})
dfs = [A, B, C] 

# Note, the "key" column values are unique, so the index is unique.
A2 = A.set_index('key')
B2 = B.set_index('key')
C2 = C.set_index('key')

dfs2 = [A2, B2, C2]

Fusión múltiple en claves únicas (o índice)

Si sus claves (aquí, la clave podría ser una columna o un índice) son únicas, entonces puede usar pd.concat. Tenga en cuenta que se pd.concatune a DataFrames en el índice .

# merge on `key` column, you'll need to set the index before concatenating
pd.concat([
    df.set_index('key') for df in dfs], axis=1, join='inner'
).reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# merge on `key` index
pd.concat(dfs2, axis=1, sort=False, join='inner')

       valueA    valueB  valueC
key                            
D    2.240893 -0.977278     1.0

Omitir join='inner'para una UNIÓN EXTERIOR COMPLETA. Tenga en cuenta que no puede especificar uniones LEFT o RIGHT OUTER (si las necesita, utilice las que se joindescriben a continuación).

Fusión múltiple en claves con duplicados

concates rápido, pero tiene sus defectos. No puede manejar duplicados.

A3 = pd.DataFrame({'key': ['A', 'B', 'C', 'D', 'D'], 'valueA': np.random.randn(5)})
pd.concat([df.set_index('key') for df in [A3, B, C]], axis=1, join='inner')
ValueError: Shape of passed values is (3, 4), indices imply (3, 2)

En esta situación, podemos usar joinya que puede manejar claves no únicas (tenga en cuenta que se joinune a DataFrames en su índice; llama mergebajo el capó y hace un LEFT OUTER JOIN a menos que se especifique lo contrario).

# join on `key` column, set as the index first
# For inner join. For left join, omit the "how" argument.
A.set_index('key').join(
    [df.set_index('key') for df in (B, C)], how='inner').reset_index()

  key    valueA    valueB  valueC
0   D  2.240893 -0.977278     1.0

# join on `key` index
A3.set_index('key').join([B2, C2], how='inner')

       valueA    valueB  valueC
key                            
D    1.454274 -0.977278     1.0
D    0.761038 -0.977278     1.0
62 eliu Apr 26 2019 at 06:43

Una vista visual complementaria de pd.concat([df0, df1], kwargs). Tenga en cuenta que el significado de kwarg axis=0or axis=1no es tan intuitivo como df.mean()odf.apply(func)


5 GonçaloPeres龚燿禄 Aug 10 2020 at 17:13

En esta respuesta, consideraré un ejemplo práctico de pandas.concat.

Considerando lo siguiente DataFramescon los mismos nombres de columna:

Preco2018 con talla (8784, 5)

Preco 2019 con talla (8760, 5)

Que tengan los mismos nombres de columna.

Puedes combinarlos usando pandas.concat, simplemente

import pandas as pd

frames = [Preco2018, Preco2019]

df_merged = pd.concat(frames)

Lo que da como resultado un DataFrame con el siguiente tamaño (17544, 5)

Si quieres visualizar, acaba funcionando así

( Fuente )