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
# Preliminares
import pandas as pd
import numpy as np
Consideramos los dos DataFrames:
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
| 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 |
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
| 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
productos = pd.DataFrame({
'id': ['AAA123', 'SOX433', 'QWE000', 'PII342', 'ZXY099'],
'nombre': ['Pila', 'Bombilla', 'Interruptor', 'Enchufe', 'Toma']})
productos
| 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
DataFramede los pedidos de cada cliente.
merge usa las columnas en común¶Creemos el DataFrame de clientes_pedidos
clientes_pedidos = clientes.merge(pedidos, how='left')
clientes_pedidos
| 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 |
clientes_pedidos con la información de productos¶En este caso, intentará casar las columnas
nombreyid
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.
# Comprobamos tipos
clientes_pedidos.dtypes
dni object nombre object apellido1 object apellido2 object id float64 id_producto object dtype: object
# Comprobamos tipos
productos.dtypes
id object nombre object dtype: object
ides de tipofloat64enclientes_pedidosy de tipostr(string) enproductos.
Cambiamos el tipo de id en clientes_pedidos:
clientes_pedidos['id'] = clientes_pedidos['id'].astype(str)
Volvemos a intentar el merge
clientes_pedidos.merge(productos)
| dni | nombre | apellido1 | apellido2 | id | id_producto |
|---|
Como era esperado, obtenemos ahora un
DataFramevacío porque las columnas comunesidynombreno contienen información sobre los mismos elementos y no tienen valores en común.
Para empezar, vamos a cambiar los nombres de las columnas conflictivas de productos
productos.rename(columns={'nombre': 'nombre_producto'}, inplace=True)
productos
| 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_onyright_onpara especificar sobre qué columna delDataFramede la izquierda y qué columna delDataFramede la derecha nos vamos a basar para casar filas
clientes_pedidos.merge(productos, left_on='id_producto', right_on='id')
| 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
clientes_pedidos.merge(productos, left_on='id_producto', right_on='id', suffixes=['_pedido','_producto'])
| 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 |