Cómo fusionar DataFrames en Pandas: merge (), join (), append (), concat () y update ()

    Introducción

    Pandas proporciona una amplia gama de métodos y funciones para manipular datos, incluida la fusión de DataFrames. Fusionar DataFrames le permite crear un nuevo DataFrame sin modificar la fuente de datos original o alterar la fuente de datos original.

    Si está familiarizado con SQL o un tipo similar de datos tabulares, probablemente esté familiarizado con el término join, lo que significa combinar DataFrames para formar un nuevo DataFrame. Si eres un principiante, puede ser difícil comprender completamente los tipos de unión (interna, externa, izquierda, derecha). En este tutorial repasaremos los tipos de combinación con ejemplos.

    Nuestro enfoque principal sería el uso de merge() y concat() funciones. Sin embargo, discutiremos otros métodos de fusión para brindarle tantas alternativas prácticas como sea posible.

    Para este tutorial, usamos Pandas versión 1.1.4 y NumPy versión 1.19.4.

    Para su comodidad, aquí está la tabla de contenido:

    • Fusionar DataFrames usando merge ()
    • Fusionar DataFrames usando join ()
    • Combinar DataFrames usando append ()
    • Fusionar DataFrames usando concat ()
    • Fusionar DataFrames usando combine_first () y update ()

    Fusionar DataFrames usando merge ()

    Comencemos por configurar nuestros DataFrames, que usaremos para el resto del tutorial.

    df1 incluirá nuestra lista de usuarios imaginaria con nombres, correos electrónicos e ID.

    import pandas as pd
    
    df1 = pd.DataFrame({'user_id': ['id001', 'id002', 'id003', 'id004', 'id005', 'id006', 'id007'],
                        'first_name': ['Rivi', 'Wynnie', 'Kristos', 'Madalyn', 'Tobe', 'Regan', 'Kristin'],
                        'last_name': ['Valti', 'McMurty', 'Ivanets', 'Max', 'Riddich', 'Huyghe', 'Illis'],
                        'email': ['[email protected]', '[email protected]', '[email protected]',
                                  '[email protected]', '[email protected]', '[email protected]', '[email protected]']
                        })
    

    Al diseñar bases de datos, se considera una buena práctica mantener la configuración del perfil (como el color de fondo, el enlace de la imagen del avatar, el tamaño de fuente, etc.) en una tabla separada de los datos del usuario (correo electrónico, fecha de adición, etc.) Estas tablas pueden tener una relación de uno a uno.

    Para simular este escenario haremos lo mismo creando df2 con URL de imagen e ID de usuario:

    
    df2 = pd.DataFrame({'user_id': ['id001', 'id002', 'id003', 'id004', 'id005'],
                        'image_url': ['http://example.com/img/id001.png', 'http://example.com/img/id002.jpg',
                                      'http://example.com/img/id003.bmp', 'http://example.com/img/id004.jpg',
                                      'http://example.com/img/id005.png']
                        })
    

    Así es como se ven nuestros DataFrames:

    # df1
      user_id first_name last_name                  email
    0   id001       Rivi     Valti    [email protected]
    1   id002     Wynnie   McMurty  [email protected]
    2   id003    Kristos   Ivanets  [email protected]
    3   id004    Madalyn       Max      [email protected]
    4   id005       Tobe   Riddich  [email protected]
    5   id006      Regan    Huyghe    [email protected]
    6   id007    Kristin     Illis    [email protected]
    
    #df2
      user_id                         image_url
    0   id001  http://example.com/img/id001.png
    1   id002  http://example.com/img/id002.jpg
    2   id003  http://example.com/img/id003.bmp
    3   id004  http://example.com/img/id004.jpg
    4   id005  http://example.com/img/id005.png
    

    Combinemos estos DataFrames con el merge() función. Primero, eche un vistazo a todas las opciones que esta función puede aceptar de un vistazo:

    pd.merge(left, right, how='inner', on=None, left_on=None, right_on=None,
             left_index=False, right_index=False, sort=True,
             suffixes=('_x', '_y'), copy=True, indicator=False,
             validate=None)
    

    La mayoría de estas opciones tienen un valor predeterminado, excepto el izquierda y derecho. Estos dos parámetros son los nombres de los DataFrames que fusionaremos. La función en sí devolverá un nuevo DataFrame, que almacenaremos en df3_merged variable.

    Ingresa el siguiente código en tu shell de Python:

    df3_merged = pd.merge(df1, df2)
    

    Dado que nuestros dos DataFrames tienen la columna user_id con el mismo nombre, el merge() La función une automáticamente dos tablas que coinciden con esa clave. Si tuviéramos dos columnas con diferentes nombres, podríamos usar left_on='left_column_name' y right_on='right_column_name' para especificar claves en ambos DataFrames explícitamente.

    Vamos a imprimir el df3_merged variable para ver su contenido:

      user_id first_name last_name                  email                         image_url
    0   id001       Rivi     Valti    [email protected]  http://example.com/img/id001.png
    1   id002     Wynnie   McMurty  [email protected]  http://example.com/img/id002.jpg
    2   id003    Kristos   Ivanets  [email protected]  http://example.com/img/id003.bmp
    3   id004    Madalyn       Max      [email protected]  http://example.com/img/id004.jpg
    4   id005       Tobe   Riddich  [email protected]  http://example.com/img/id005.png
    

    Notarás que df3_merged tiene solo 5 filas, mientras que el df1 original tenía 7. ¿Por qué?

    Cuando el valor predeterminado de la how el parámetro está establecido en inner, se genera un nuevo DataFrame a partir de la intersección de los DataFrames izquierdo y derecho. Por lo tanto, si un user_id falta en una de las tablas, no estaría en el DataFrame combinado.

    Esto seguiría siendo cierto incluso si se intercambiaran los lugares de las filas izquierda y derecha:

    df3_merged = pd.merge(df2, df1)
    

    Los resultados siguen siendo:

      user_id                         image_url first_name last_name                  email
    0   id001  http://example.com/img/id001.png       Rivi     Valti    [email protected]
    1   id002  http://example.com/img/id002.jpg     Wynnie   McMurty  [email protected]
    2   id003  http://example.com/img/id003.bmp    Kristos   Ivanets  [email protected]
    3   id004  http://example.com/img/id004.jpg    Madalyn       Max      [email protected]
    4   id005  http://example.com/img/id005.png       Tobe   Riddich  [email protected]
    

    Usuarios con ID 'id006' y 'id007' no forman parte de los DataFrames fusionados ya que no se cruzan en ambas tablas.

    Sin embargo, hay ocasiones en las que queremos usar uno de los DataFrame como el DataFrame principal e incluir todas las filas incluso si no todas se cruzan entre sí. Es decir, tener todos nuestros usuarios, mientras que el image_url es opcional.

    ¿Cómo? Mediante el uso merge(), podemos pasar el 'left' argumento a la how parámetro:

    df_left_merge = pd.merge(df1, df2, how='left')
    
    print(df_left_merge)
    

    Con una combinación izquierda, hemos incluido todos los elementos del DataFrame izquierdo (df1) y todos los elementos del DataFrame correcto (df2). Ejecutar el código anterior mostraría esto:

      user_id first_name last_name                  email                         image_url
    0   id001       Rivi     Valti    [email protected]  http://example.com/img/id001.png
    1   id002     Wynnie   McMurty  [email protected]  http://example.com/img/id002.jpg
    2   id003    Kristos   Ivanets  [email protected]  http://example.com/img/id003.bmp
    3   id004    Madalyn       Max      [email protected]  http://example.com/img/id004.jpg
    4   id005       Tobe   Riddich  [email protected]  http://example.com/img/id005.png
    5   id006      Regan    Huyghe    [email protected]                               NaN
    6   id007    Kristin     Illis    [email protected]                               NaN
    

    Las celdas que no tienen ningún valor coincidente con el DataFrame izquierdo se rellenan con NaN.

    ¿Por qué no intentamos una combinación correcta? Cree el siguiente DataFrame combinado:

    df_right_merge = pd.merge(df1, df2, how='right')
    
    print(df_right_merge)
    

    Como era de esperar, la combinación derecha devolvería todos los valores del DataFrame izquierdo que coincida con el DataFrame derecho:

      user_id first_name last_name                  email                         image_url
    0   id001       Rivi     Valti    [email protected]  http://example.com/img/id001.png
    1   id002     Wynnie   McMurty  [email protected]  http://example.com/img/id002.jpg
    2   id003    Kristos   Ivanets  [email protected]  http://example.com/img/id003.bmp
    3   id004    Madalyn       Max      [email protected]  http://example.com/img/id004.jpg
    4   id005       Tobe   Riddich  [email protected]  http://example.com/img/id005.png
    

    Como cada fila en df2 tiene un valor en df1, esta right unirse es similar a la inner unirse, en este caso.

    Echemos un vistazo a outer Uniones. Para ilustrar mejor cómo funcionan, intercambiemos lugares de nuestros DataFrames y creemos 2 nuevas variables para las uniones izquierdas y externas:

    df_left = pd.merge(df2, df1, how='left', indicator=True)
    df_outer = pd.merge(df2, df1, how='outer', indicator=True)
    
    print(df_left)
    print(df_outer)
    

    Tenga en cuenta que nuestro DataFrame izquierdo es df2 y el DataFrame correcto es df1. Utilizando how='outer' fusiona DataFrames que coinciden con la clave, pero también incluye los valores que faltan o no coinciden.

    También agregamos el indicator bandera y ponerlo en True para que Pandas agregue una columna adicional _merge hasta el final de nuestro DataFrame. Esta columna nos dice si se encontró una fila en el DataFrames izquierdo, derecho o en ambos.

    los df_left variable se ve así:

      user_id                         image_url first_name last_name                  email _merge
    0   id001  http://example.com/img/id001.png       Rivi     Valti    [email protected]   both
    1   id002  http://example.com/img/id002.jpg     Wynnie   McMurty  [email protected]   both
    2   id003  http://example.com/img/id003.bmp    Kristos   Ivanets  [email protected]   both
    3   id004  http://example.com/img/id004.jpg    Madalyn       Max      [email protected]   both
    4   id005  http://example.com/img/id005.png       Tobe   Riddich  [email protected]   both
    

    Sin embargo, df_outer tiene estos datos:

      user_id                         image_url first_name last_name                  email      _merge
    0   id001  http://example.com/img/id001.png       Rivi     Valti    [email protected]        both
    1   id002  http://example.com/img/id002.jpg     Wynnie   McMurty  [email protected]        both
    2   id003  http://example.com/img/id003.bmp    Kristos   Ivanets  [email protected]        both
    3   id004  http://example.com/img/id004.jpg    Madalyn       Max      [email protected]        both
    4   id005  http://example.com/img/id005.png       Tobe   Riddich  [email protected]        both
    5   id006                               NaN      Regan    Huyghe    [email protected]  right_only
    6   id007                               NaN    Kristin     Illis    [email protected]  right_only
    

    Note que en el df_outer Marco de datos id006 y id007 solo existe en el DataFrame derecho (en este caso es df1). Si intentáramos comparar las uniones izquierdas y externas sin intercambiar los lugares, obtendríamos los mismos resultados para ambas.

    Fusionar DataFrames usando join ()

    diferente a merge() que es un método de la instancia de Pandas, join() es un método del propio DataFrame. Esto significa que podemos usarlo como un método estático en el DataFrame: DataFrame.join(other, on=None, how='left', lsuffix='', rsuffix='', sort=False).

    El DataFrame que llamamos join() de será nuestro DataFrame izquierdo. El DataFrame en el other El argumento sería nuestro DataFrame correcto.

    los on El parámetro puede tomar uno o más (['key1', 'key2' ...]) argumentos para definir la clave coincidente, mientras que how El parámetro toma uno de los argumentos del identificador (izquierdo, derecho, externo, interno) y se establece en left por defecto.

    Intentemos unirnos df2 a df1:

    df_join = df1.join(df2, rsuffix='_right')
    
    print(df_join)
    

    Como el merge() función, la join() La función intenta automáticamente hacer coincidir las claves (columnas) con el mismo nombre. En nuestro caso, es el user_id llave.

    El código anterior imprime esto:

      user_id first_name last_name                  email user_id_right                         image_url
    0   id001       Rivi     Valti    [email protected]         id001  http://example.com/img/id001.png
    1   id002     Wynnie   McMurty  [email protected]         id002  http://example.com/img/id002.jpg
    2   id003    Kristos   Ivanets  [email protected]         id003  http://example.com/img/id003.bmp
    3   id004    Madalyn       Max      [email protected]         id004  http://example.com/img/id004.jpg
    4   id005       Tobe   Riddich  [email protected]         id005  http://example.com/img/id005.png
    5   id006      Regan    Huyghe    [email protected]           NaN                               NaN
    6   id007    Kristin     Illis    [email protected]           NaN                               NaN
    

    Probablemente hayas notado una “columna duplicada” llamada user_id_right. Si no desea mostrar esa columna, puede configurar el user_id columnas como un índice en ambas columnas para que se unan sin un sufijo:

    df_join_no_duplicates = df1.set_index('user_id').join(df2.set_index('user_id'))
    
    print(df_join_no_duplicates)
    

    Al hacerlo, nos estamos deshaciendo de la user_id columna y configurándola como la columna de índice. Esto nos proporciona un DataFrame resultante más limpio:

            first_name last_name                  email                         image_url
    user_id                                                                              
    id001         Rivi     Valti    [email protected]  http://example.com/img/id001.png
    id002       Wynnie   McMurty  [email protected]  http://example.com/img/id002.jpg
    id003      Kristos   Ivanets  [email protected]  http://example.com/img/id003.bmp
    id004      Madalyn       Max      [email protected]  http://example.com/img/id004.jpg
    id005         Tobe   Riddich  [email protected]  http://example.com/img/id005.png
    id006        Regan    Huyghe    [email protected]                               NaN
    id007      Kristin     Illis    [email protected]                               NaN
    

    Combinar DataFrames usando append ()

    Como apunta la documentación oficial de Pandas, desde concat() y append() Los métodos devuelven nuevas copias de DataFrames, el uso excesivo de estos métodos puede afectar el rendimiento de su programa.

    Agregar es muy útil cuando desea fusionar dos DataFrames en el eje de fila únicamente. Esto significa que en lugar de hacer coincidir los datos en sus columnas, queremos un nuevo DataFrame que contenga todas las filas de 2 DataFrames.

    Vamos a añadir df2 a df1 e imprime los resultados:

    df_append = df1.append(df2, ignore_index=True)
    
    print(df_append)
    

    Utilizando append() no coincidirá con DataFrames en ninguna clave. Simplemente agregará el otro DataFrame al primero y devolverá una copia del mismo. Si las formas de DataFrames no coinciden, Pandas reemplazará cualquier celda no coincidente con un NaN.

    El resultado para agregar los dos DataFrames se ve así:

       user_id first_name last_name                  email                         image_url
    0    id001       Rivi     Valti    [email protected]                               NaN
    1    id002     Wynnie   McMurty  [email protected]                               NaN
    2    id003    Kristos   Ivanets  [email protected]                               NaN
    3    id004    Madalyn       Max      [email protected]                               NaN
    4    id005       Tobe   Riddich  [email protected]                               NaN
    5    id006      Regan    Huyghe    [email protected]                               NaN
    6    id007    Kristin     Illis    [email protected]                               NaN
    7    id001        NaN       NaN                    NaN  http://example.com/img/id001.png
    8    id002        NaN       NaN                    NaN  http://example.com/img/id002.jpg
    9    id003        NaN       NaN                    NaN  http://example.com/img/id003.bmp
    10   id004        NaN       NaN                    NaN  http://example.com/img/id004.jpg
    11   id005        NaN       NaN                    NaN  http://example.com/img/id005.png
    

    La mayoría de los usuarios eligen concat() sobre el append() ya que también proporciona la opción de eje y coincidencia de claves.

    Fusionar DataFrames usando concat ()

    La concatenación es un poco más flexible en comparación con merge() y join() ya que nos permite combinar DataFrames verticalmente (en filas) u horizontalmente (en columnas).

    La compensación es que se descartarán los datos que no coincidan. Aquí está la función completa con los parámetros:

    pandas.concat(objs, axis=0, join='outer', ignore_index=False, keys=None,
                  levels=None, names=None, verify_integrity=False, sort=False, copy=True)
    

    A continuación, se muestran los parámetros más utilizados para concat() función:

    • objs es la lista de objetos DataFrame ([df1, df2, …]) para ser concatenados
    • axis define la dirección de la concatenación, 0 para filas y 1 para columna
    • join puede ser inner (intersección) o outer (Unión)
    • ignore_index por defecto establecido en False que permite que los valores de índice permanezcan como estaban en los DataFrames originales, puede causar valores de índice duplicados. Si se establece en True, ignorará los valores originales y reasignará valores de índice en orden secuencial
    • keys nos permite construir un índice jerárquico. Piense en ello como otro nivel del índice que se adjunta en la parte exterior izquierda del DataFrame que nos ayuda a distinguir los índices cuando los valores no son únicos.

    Creemos un nuevo DataFrame con los mismos tipos de columna que el df2, pero este incluye el image_url para id006 y id007:

    df2_addition = pd.DataFrame({'user_id': ['id006', 'id007'],
                                 'image_url': ['http://example.com/img/id006.png',
                                               'http://example.com/img/id007.jpg']
                                 })
    

    Para unirse df2 y df2_addition por filas, podemos pasarlos en una lista como el objs y asigne el DataFrame resultante a una nueva variable:

    df_row_concat = pd.concat([df2, df2_addition])
    
    print(df_row_concat)
    

    Completamos con éxito los valores faltantes:

      user_id                         image_url
    0   id001  http://example.com/img/id001.png
    1   id002  http://example.com/img/id002.jpg
    2   id003  http://example.com/img/id003.bmp
    3   id004  http://example.com/img/id004.jpg
    4   id005  http://example.com/img/id005.png
    0   id006  http://example.com/img/id006.png
    1   id007  http://example.com/img/id007.jpg
    

    Sin embargo, eche un vistazo a los índices de la columna más a la izquierda. Los índices 0 y 1 están repitiendo. Para obtener valores de índice completamente nuevos y únicos, pasamos True al ignore_index parámetro:

    df_row_concat = pd.concat([df2, df2_addition], ignore_index=True)
    

    Ahora nuestro df_row_concat tiene valores de índice únicos:

      user_id                         image_url
    0   id001  http://example.com/img/id001.png
    1   id002  http://example.com/img/id002.jpg
    2   id003  http://example.com/img/id003.bmp
    3   id004  http://example.com/img/id004.jpg
    4   id005  http://example.com/img/id005.png
    5   id006  http://example.com/img/id006.png
    6   id007  http://example.com/img/id007.jpg
    

    Como mencionamos anteriormente, la concatenación puede funcionar tanto horizontal como verticalmente. Para unir dos DataFrames juntos por columnas, necesitaremos cambiar el axis valor del predeterminado 0 a 1:

    df_column_concat = pd.concat([df1, df_row_concat], axis=1)
    
    print(df_column_concat)
    

    Notará que no funciona como una combinación, haciendo coincidir dos tablas en una clave:

      user_id first_name last_name                  email user_id                         image_url
    0   id001       Rivi     Valti    [email protected]   id001  http://example.com/img/id001.png
    1   id002     Wynnie   McMurty  [email protected]   id002  http://example.com/img/id002.jpg
    2   id003    Kristos   Ivanets  [email protected]   id003  http://example.com/img/id003.bmp
    3   id004    Madalyn       Max      [email protected]   id004  http://example.com/img/id004.jpg
    4   id005       Tobe   Riddich  [email protected]   id005  http://example.com/img/id005.png
    5   id006      Regan    Huyghe    [email protected]   id006  http://example.com/img/id006.png
    6   id007    Kristin     Illis    [email protected]   id007  http://example.com/img/id007.jpg
    

    Si nuestro DataFrame correcto ni siquiera tuviera un user_id columna, esta concatenación todavía devolvería el mismo resultado. los concat() La función pega dos DataFrames juntos, teniendo en cuenta los valores de los índices de DataFrames y la forma de la tabla.

    No hace coincidir claves como merge() de join(). Pruebe diferentes combinaciones de concatenación cambiando el join parámetro para ver las diferencias!

    Fusionar DataFrames usando combine_first () y update ()

    En algunos casos, es posible que desee completar los datos que faltan en su DataFrame combinándolos con otro DataFrame. Al hacerlo, mantendrá todos los valores que no faltan en el primer DataFrame mientras reemplaza todos NaN valores con valores disponibles no perdidos del segundo DataFrame (si hay alguno).

    Para este ejemplo, importaremos NumPy para usar NaN valores. Si instaló Pandas con pip, NumPy ya debería estar instalado.

    Escriba el siguiente código en su shell de Python o archivo de secuencia de comandos:

    import numpy as np
    
    df_first = pd.DataFrame({'COL 1': ['X', 'X', np.nan],
                             'COL 2': ['X', np.nan, 'X'],
                             'COL 3': [np.nan, 'X', 'X']},
                            index=range(0, 3))
    
    df_second = pd.DataFrame({'COL 1': [np.nan, 'O', 'O'],
                              'COL 2': ['O', 'O', 'O']},
                             index=range(0, 3))
    
    print(df_first)
    print(df_second)
    

    los df_first DataFrame tiene 3 columnas y 3 valores faltantes en cada una de ellas:

      COL 1 COL 2 COL 3
    0     X     X   NaN
    1     X   NaN     X
    2   NaN     X     X
    

    Mientras df_second tiene solo 2 columnas y un valor faltante en la primera columna:

      COL 1 COL 2
    0   NaN     O
    1     O     O
    2     O     O
    

    Nosotros podemos usar df_second para parchear los valores faltantes en df_first con todos los valores correspondientes:

    df_tictactoe = df_first.combine_first(df_second)
    
    print(df_tictactoe)
    

    Como se mencionó anteriormente, el uso de combine_first() el método solo reemplazará NaN valores en orden de índice, y dejará todos los valores no perdidos en el primer DataFrame como están:

      COL 1 COL 2 COL 3
    0     X     X   NaN
    1     X     O     X
    2     O     X     X
    

    Por otro lado, si quisiéramos sobrescribir los valores en df_first con los valores correspondientes de df_second (independientemente de que sean NaN o no), usaríamos el update() método.

    Primero agreguemos otro DataFrame a nuestro código:

    df_third = pd.DataFrame({'COL 1': ['O'], 'COL 2': ['O'], 'COL 3': ['O']})
    
    print(df_third)
    

    La forma es (1, 3) – 1 fila y tres columnas, excluyendo el índice:

      COL 1 COL 2 COL 3
    0     O     O     O
    

    Ahora actualice el df_first con los valores de df_third:

    df_first.update(df_third)
    
    print(df_first)
    

    Tenga en cuenta que a diferencia combine_first(), update() no devuelve un nuevo DataFrame. Modifica el df_first in situ, alterando los valores correspondientes:

      COL 1 COL 2 COL 3
    0     O     O     O
    1     X   NaN     X
    2   NaN     X     X
    

    los overwrite parámetro de la update() la función está configurada en True por defecto. Es por eso que cambia todos los valores correspondientes, en lugar de solo NaN valores. Podemos cambiarlo a False para reemplazar solo NaN valores:

    df_tictactoe.update(df_first, overwrite=False)
    
    print(df_tictactoe)
    

    Aquí está el estado final de nuestro df_tictactoe Marco de datos:

      COL 1 COL 2 COL 3
    0     X     X     O
    1     X     O     X
    2     O     X     X
    

    ¡No solo actualizamos con éxito los valores, sino que también ganamos el juego Tic-Tac-Toe!

    Conclusión

    Pandas proporciona herramientas poderosas para fusionar DataFrames. Pero puede ser difícil decidir cuándo usar qué. Mientras que la mayoría de las veces merge() la función es suficiente, en algunos casos es posible que desee utilizar concat() para fusionar filas o usar join() con sufijos, o deshacerse de los valores perdidos con combine_first() y update(). Incluso puede agregar filas de datos con append().

    Utilice la función con la que se sienta más cómodo y que sea mejor para la tarea en cuestión. ¿Cómo te ayudarían estas funciones a manipular datos en Pandas?

     

    Etiquetas:

    Deja una respuesta

    Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *