Usar el parámetro on, left_on y right_on en merge para especificar qué columnas se deben usar para casar filas al combinar los dos DataFrames¶

Vimos que, por defecto, merge usa las columnas comunes en ambos DataFrames para casar las filas

In [1]:
# Preliminares
import pandas as pd
import numpy as np

Consideramos los dos DataFrames:

In [2]:
clientes= pd.DataFrame(
    {'dni': ['12345678', '23456789', '34567890', '01234567'],
     'nombre': ['José', 'Pedro', 'María', 'Blanca'],
     'apellido1': ['Pérez', 'Martínez', 'Sánchez', 'Ruiz'],
     'apellido2': ['Martínez', 'Moreno', 'Meseguer', 'Torres']
    }
)
clientes
Out[2]:
dni nombre apellido1 apellido2
0 12345678 José Pérez Martínez
1 23456789 Pedro Martínez Moreno
2 34567890 María Sánchez Meseguer
3 01234567 Blanca Ruiz Torres
In [3]:
pedidos= pd.DataFrame(
    {'id': [10, 12, 21, 22, 24, 25, 28], 
     'dni': np.repeat(['23456789','12345678', '34567890', '87654321'], repeats=[2, 3, 1, 1]),
     'id_producto': ['AAA123', 'SOX433', 'QWE000', 'SOX433', 'PII342', 'ZXY099','PII342']})
pedidos
Out[3]:
id dni id_producto
0 10 23456789 AAA123
1 12 23456789 SOX433
2 21 12345678 QWE000
3 22 12345678 SOX433
4 24 12345678 PII342
5 25 34567890 ZXY099
6 28 87654321 PII342

Consideramos ahora un DataFrame adicional

In [4]:
productos = pd.DataFrame({
        'id': ['AAA123', 'SOX433', 'QWE000', 'PII342', 'ZXY099'],
        'nombre': ['Pila', 'Bombilla', 'Interruptor', 'Enchufe', 'Toma']})
productos
Out[4]:
id nombre
0 AAA123 Pila
1 SOX433 Bombilla
2 QWE000 Interruptor
3 PII342 Enchufe
4 ZXY099 Toma

Queremos añadir la información de cada producto al DataFrame de los pedidos de cada cliente.

Por defecto, merge usa las columnas en común¶

Creemos el DataFrame de clientes_pedidos

In [5]:
clientes_pedidos = clientes.merge(pedidos, how='left')
clientes_pedidos
Out[5]:
dni nombre apellido1 apellido2 id id_producto
0 12345678 José Pérez Martínez 21.0 QWE000
1 12345678 José Pérez Martínez 22.0 SOX433
2 12345678 José Pérez Martínez 24.0 PII342
3 23456789 Pedro Martínez Moreno 10.0 AAA123
4 23456789 Pedro Martínez Moreno 12.0 SOX433
5 34567890 María Sánchez Meseguer 25.0 ZXY099
6 01234567 Blanca Ruiz Torres NaN NaN

Intentamos ahora combinar clientes_pedidos con la información de productos¶

En este caso, intentará casar las columnas nombre y id

In [6]:
clientes_pedidos.merge(productos)
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-6-10fa1c934ab0> in <module>
----> 1 clientes_pedidos.merge(productos)

~\Anaconda3\lib\site-packages\pandas\core\frame.py in merge(self, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
   8203             copy=copy,
   8204             indicator=indicator,
-> 8205             validate=validate,
   8206         )
   8207 

~\Anaconda3\lib\site-packages\pandas\core\reshape\merge.py in merge(left, right, how, on, left_on, right_on, left_index, right_index, sort, suffixes, copy, indicator, validate)
     85         copy=copy,
     86         indicator=indicator,
---> 87         validate=validate,
     88     )
     89     return op.get_result()

~\Anaconda3\lib\site-packages\pandas\core\reshape\merge.py in __init__(self, left, right, how, on, left_on, right_on, axis, left_index, right_index, sort, suffixes, copy, indicator, validate)
    670         # validate the merge keys dtypes. We may need to coerce
    671         # to avoid incompatible dtypes
--> 672         self._maybe_coerce_merge_keys()
    673 
    674         # If argument passed to validate,

~\Anaconda3\lib\site-packages\pandas\core\reshape\merge.py in _maybe_coerce_merge_keys(self)
   1191                     inferred_right in string_types and inferred_left not in string_types
   1192                 ):
-> 1193                     raise ValueError(msg)
   1194 
   1195             # datetimelikes must match exactly

ValueError: You are trying to merge on float64 and object columns. If you wish to proceed you should use pd.concat

El error que devuelve es porque la columna id en los dos DataFrames son de diferentes tipos. No se pueden unir usando dos columnas que no sean del mismo tipo.

In [7]:
# Comprobamos tipos
clientes_pedidos.dtypes
Out[7]:
dni             object
nombre          object
apellido1       object
apellido2       object
id             float64
id_producto     object
dtype: object
In [8]:
# Comprobamos tipos
productos.dtypes
Out[8]:
id        object
nombre    object
dtype: object

id es de tipo float64 en clientes_pedidos y de tipo str (string) en productos.

Cambiamos el tipo de id en clientes_pedidos:

In [9]:
clientes_pedidos['id'] = clientes_pedidos['id'].astype(str)

Volvemos a intentar el merge

In [10]:
clientes_pedidos.merge(productos)
Out[10]:
dni nombre apellido1 apellido2 id id_producto

Como era esperado, obtenemos ahora un DataFrame vacío porque las columnas comunes id y nombre no contienen información sobre los mismos elementos y no tienen valores en común.

Para arreglar este problema:¶

Para empezar, vamos a cambiar los nombres de las columnas conflictivas de productos

In [11]:
productos.rename(columns={'nombre': 'nombre_producto'}, inplace=True)
productos
Out[11]:
id nombre_producto
0 AAA123 Pila
1 SOX433 Bombilla
2 QWE000 Interruptor
3 PII342 Enchufe
4 ZXY099 Toma

Ahora vamos a usar los argumentos left_on y right_on para especificar sobre qué columna del DataFrame de la izquierda y qué columna del DataFrame de la derecha nos vamos a basar para casar filas

In [12]:
clientes_pedidos.merge(productos, left_on='id_producto', right_on='id')
Out[12]:
dni nombre apellido1 apellido2 id_x id_producto id_y nombre_producto
0 12345678 José Pérez Martínez 21.0 QWE000 QWE000 Interruptor
1 12345678 José Pérez Martínez 22.0 SOX433 SOX433 Bombilla
2 23456789 Pedro Martínez Moreno 12.0 SOX433 SOX433 Bombilla
3 12345678 José Pérez Martínez 24.0 PII342 PII342 Enchufe
4 23456789 Pedro Martínez Moreno 10.0 AAA123 AAA123 Pila
5 34567890 María Sánchez Meseguer 25.0 ZXY099 ZXY099 Toma

merge ha añadido sufijos a los nombres de las columnas comunes para diferenciarlas, podríamos haber especificado nuestros propios sufijos con el parámetro suffixes

In [14]:
clientes_pedidos.merge(productos, left_on='id_producto', right_on='id', suffixes=['_pedido','_producto'])
Out[14]:
dni nombre apellido1 apellido2 id_pedido id_producto id_producto nombre_producto
0 12345678 José Pérez Martínez 21.0 QWE000 QWE000 Interruptor
1 12345678 José Pérez Martínez 22.0 SOX433 SOX433 Bombilla
2 23456789 Pedro Martínez Moreno 12.0 SOX433 SOX433 Bombilla
3 12345678 José Pérez Martínez 24.0 PII342 PII342 Enchufe
4 23456789 Pedro Martínez Moreno 10.0 AAA123 AAA123 Pila
5 34567890 María Sánchez Meseguer 25.0 ZXY099 ZXY099 Toma