Antes de nada, el contexto, para esta serie de entradas se va a usar lo siguiente:
Versión de Python: 3.3.1 (default, Apr 10 2013, 19:05:32) [GCC 4.6.3] Versión de Pandas: 0.13.1 Versión de Numpy: 1.8.1 Versión de Matplotlib: 1.3.1
Y sin más preámbulos seguimos con esta quinta parte de la serie.
Unir (merge/join)
Pandas dispone de la función merge
(documentación oficial) que permite ‘unir’ datos al estilo de como se hace con bases de datos relacionales (usando SQL). También se puede acceder al método merge
disponible en las instancias a un Dataframe.
Por su parte, join
es un método disponible en un DataFrame y sirve para hacer uniones de índices sobre índices o de índices sobre columnas. Las uniones que hace join
las hace sobre los índices, en lugar de hacerlo sobre columnas comunes como se hace con merge
. A ver si viendo los ejemplos queda un poco mejor este último párrafo y las diferencias entre join
y merge
.
Las uniones pueden ser uno-a-uno, muchos-a-uno o muchos-a-muchos.
Una unión uno-a-uno sería cuando unimos dos tablas (DataFrames) con índices únicos como hemos hecho en la entrega anterior con las concatenaciones.
datos1 = pd.DataFrame(np.random.randn(10), columns = ['columna1'])
datos2 = pd.DataFrame(np.random.randn(14), columns = ['columna2'], index = np.arange(1,15))
datos1j = datos1.join(datos2)
datos2j = datos2.join(datos1)
print('datos1j n{}n'.format(datos1j))
print('datos2j n{}'.format(datos2j))
datos1j columna1 columna2 0 -0.209303 NaN 1 -0.430892 1.052453 2 0.766200 -0.346896 3 1.773694 -0.249700 4 -2.259187 -0.588739 5 -0.930647 0.160590 6 0.029990 0.421446 7 0.812770 -0.315913 8 0.681786 0.256745 9 -0.115109 0.524278 [10 rows x 2 columns] datos2j columna2 columna1 1 1.052453 -0.430892 2 -0.346896 0.766200 3 -0.249700 1.773694 4 -0.588739 -2.259187 5 0.160590 -0.930647 6 0.421446 0.029990 7 -0.315913 0.812770 8 0.256745 0.681786 9 0.524278 -0.115109 10 -1.707269 NaN 11 -1.140342 NaN 12 -1.751337 NaN 13 -0.481319 NaN 14 1.604800 NaN [14 rows x 2 columns]
En los anteriores ejemplos, datos1j
es el resultado de unir los datos datos2
a los datos datos1
en todos los índices comunes que tienen ambos teniendo solo en cuenta el rango de índices definido en datos1
. Si algún dato en datos2
no tiene un índice presente en datos1
se rellenará con un NaN
. Con datos2j
sucede lo mismo que con datos1j
lo que el índice que tiene relevancia ahora es el perteneciente a datos2j
. No sé si habrá quedado más o menos claro.
Ahora vamos a unir pero usando la palabra clave how
que nos permite decir como se van a tener en cuenta los índices. Normalmente le pasaremos el parámetro outer
o inner
. El primero, outer
, indica que los índices de los DataFrames se unen como en una unión de conjuntos, el segundo, inner
, une los índices como si hiciéramos una intersección de conjuntos. Veamos un par de ejemplos para que se vea de forma práctica, el primero usando outer
y el segundo usando inner
:
datos3j1 = datos1.join(datos2, how = 'outer')
datos3j2 = datos2.join(datos1, how = 'outer')
print('datos3j1 n{}n'.format(datos3j1))
print('datos3j2 recolocadosn{}n'.format(datos3j2.ix[:, ['columna1','columna2']]))
print('datos3j2 n{}'.format(datos3j2))
datos3j1 columna1 columna2 0 -0.209303 NaN 1 -0.430892 1.052453 2 0.766200 -0.346896 3 1.773694 -0.249700 4 -2.259187 -0.588739 5 -0.930647 0.160590 6 0.029990 0.421446 7 0.812770 -0.315913 8 0.681786 0.256745 9 -0.115109 0.524278 10 NaN -1.707269 11 NaN -1.140342 12 NaN -1.751337 13 NaN -0.481319 14 NaN 1.604800 [15 rows x 2 columns] datos3j2 recolocados columna1 columna2 0 -0.209303 NaN 1 -0.430892 1.052453 2 0.766200 -0.346896 3 1.773694 -0.249700 4 -2.259187 -0.588739 5 -0.930647 0.160590 6 0.029990 0.421446 7 0.812770 -0.315913 8 0.681786 0.256745 9 -0.115109 0.524278 10 NaN -1.707269 11 NaN -1.140342 12 NaN -1.751337 13 NaN -0.481319 14 NaN 1.604800 [15 rows x 2 columns] datos3j2 columna2 columna1 0 NaN -0.209303 1 1.052453 -0.430892 2 -0.346896 0.766200 3 -0.249700 1.773694 4 -0.588739 -2.259187 5 0.160590 -0.930647 6 0.421446 0.029990 7 -0.315913 0.812770 8 0.256745 0.681786 9 0.524278 -0.115109 10 -1.707269 NaN 11 -1.140342 NaN 12 -1.751337 NaN 13 -0.481319 NaN 14 1.604800 NaN [15 rows x 2 columns]
datos4j1 = datos1.join(datos2, how = 'inner') datos4j2 = datos2.join(datos1, how = 'inner') print('datos4j1 n{}n'.format(datos4j1)) print('datos4j2 recolocadosn{}n'.format(datos4j2.ix[:, ['columna1','columna2']])) print('datos4j2 n{}'.format(datos4j2))
datos4j1 columna1 columna2 1 -0.430892 1.052453 2 0.766200 -0.346896 3 1.773694 -0.249700 4 -2.259187 -0.588739 5 -0.930647 0.160590 6 0.029990 0.421446 7 0.812770 -0.315913 8 0.681786 0.256745 9 -0.115109 0.524278 [9 rows x 2 columns] datos4j2 recolocados columna1 columna2 1 -0.430892 1.052453 2 0.766200 -0.346896 3 1.773694 -0.249700 4 -2.259187 -0.588739 5 -0.930647 0.160590 6 0.029990 0.421446 7 0.812770 -0.315913 8 0.681786 0.256745 9 -0.115109 0.524278 [9 rows x 2 columns] datos4j2 columna2 columna1 1 1.052453 -0.430892 2 -0.346896 0.766200 3 -0.249700 1.773694 4 -0.588739 -2.259187 5 0.160590 -0.930647 6 0.421446 0.029990 7 -0.315913 0.812770 8 0.256745 0.681786 9 0.524278 -0.115109 [9 rows x 2 columns]
Todo lo anterior se puede hacer también usando la función o método merge
pero encuentro que es una forma un poco más rebuscada por lo que no la vamos a mostrar aquí ya que añade complejidad. Veremos usos de merge
más adelante.
Ahora vamos a mostrar una unión muchos-a-uno. Estas uniones se hacen sobre una o más columnas como referencia, no a partir de índices, por lo que los valores contenidos pueden no ser únicos. Como siempre, vamos a ver un poco de código para ver si clarifica un poco más la teoría:
datos1 = pd.DataFrame(np.random.randn(10), columns = ['columna1'])
datos1['otra_columna'] = ['hola', 'mundo'] * 5
datos2 = pd.DataFrame(np.random.randn(2,2), columns = ['col1', 'col2'], index = ['hola', 'mundo'])
print('datos1 n {} n'.format(datos1))
print('datos2 n {} n'.format(datos2))
print(u'Unión de datos n {} n'.format(datos1.join(datos2, on = 'otra_columna')))
datos1 columna1 otra_columna 0 -2.086230 hola 1 -1.015736 mundo 2 -0.919460 hola 3 0.923531 mundo 4 -0.445977 hola 5 0.719787 mundo 6 1.064480 hola 7 -0.235803 mundo 8 1.395844 hola 9 1.492875 mundo [10 rows x 2 columns] datos2 col1 col2 hola 0.400267 -0.678126 mundo 0.855735 0.619193 [2 rows x 2 columns] Unión de datos columna1 otra_columna col1 col2 0 -2.086230 hola 0.400267 -0.678126 1 -1.015736 mundo 0.855735 0.619193 2 -0.919460 hola 0.400267 -0.678126 3 0.923531 mundo 0.855735 0.619193 4 -0.445977 hola 0.400267 -0.678126 5 0.719787 mundo 0.855735 0.619193 6 1.064480 hola 0.400267 -0.678126 7 -0.235803 mundo 0.855735 0.619193 8 1.395844 hola 0.400267 -0.678126 9 1.492875 mundo 0.855735 0.619193 [10 rows x 4 columns]
Estamos uniendo sobre los valores de la columna del DataFrame datos1
que presenta valores presentes en los índices del DataFrame datos2
. En el anterior ejemplo hemos unido teniendo en cuenta una única columna, si queremos unir teniendo en cuenta varias columnas, el DataFrame que se le pase deberá presentar un MultiÍndice con tantos índices como columnas usemos (ver documentación sobre MultiÍndices y sobre unión con ellos).
Para hacer uniones de muchos-a-muchos usaremos merge
que ofrece mayor libertad para poder hacer uniones de cualquier tipo (también las que hemos visto hasta ahora de uno-a-uno y de muchos-a-uno).
En el siguiente ejemplo vamos a hacer una unión de dos DataFrames usando merge
y luego iremos explicando lo que hemos estado haciendo poco a poco para ver si se entiende un poco mejor.
datos_dcha = pd.DataFrame({'clave': ['foo'] * 3, 'valor_dcha': np.arange(3)})
datos_izda = pd.DataFrame({'clave': ['foo'] * 3, 'valor_izda': np.arange(5, 8)})
datos_unidos = pd.merge(datos_izda, datos_dcha, on = 'clave')
print('datos_dcha n {} n'.format(datos_dcha))
print('datos_izda n {} n'.format(datos_izda))
print('datos_unidos n {}'.format(datos_unidos))
datos_dcha clave valor_dcha 0 foo 0 1 foo 1 2 foo 2 [3 rows x 2 columns] datos_izda clave valor_izda 0 foo 5 1 foo 6 2 foo 7 [3 rows x 2 columns] datos_unidos clave valor_izda valor_dcha 0 foo 5 0 1 foo 5 1 2 foo 5 2 3 foo 6 0 4 foo 6 1 5 foo 6 2 6 foo 7 0 7 foo 7 1 8 foo 7 2 [9 rows x 3 columns]
Vemos que si hacemos una unión de la anterior forma, a cada valor de datos_dcha
le ‘asocia’ cada uno de los valores de datos_izda
que tengan la misma clave. En la siquiente celda de código vemos otro ejemplo de lo anterior un poco más completo teniendo en cuenta dos columnas de claves y usando el método outer
de ‘unión’:
datos_dcha = pd.DataFrame({'clave1': ['foo', 'foo', 'bar', 'bar'],
'clave2': ['one', 'one', 'one', 'two'],
'val_dcha': [4, 5, 6, 7]})
datos_izda = pd.DataFrame({'clave1': ['foo', 'foo', 'bar'],
'clave2': ['one', 'two', 'one'],
'val_izda': [1, 2, 3]})
datos_unidos = pd.merge(datos_izda, datos_dcha, how='outer')
print('datos_dcha n {} n'.format(datos_dcha))
print('datos_izda n {} n'.format(datos_izda))
print('datos_unidos n {}'.format(datos_unidos))
datos_dcha clave1 clave2 val_dcha 0 foo one 4 1 foo one 5 2 bar one 6 3 bar two 7 [4 rows x 3 columns] datos_izda clave1 clave2 val_izda 0 foo one 1 1 foo two 2 2 bar one 3 [3 rows x 3 columns] datos_unidos clave1 clave2 val_izda val_dcha 0 foo one 1 4 1 foo one 1 5 2 foo two 2 NaN 3 bar one 3 6 4 bar two NaN 7 [5 rows x 4 columns]
Otra vez hemos llegado al final. ¡¡Estad atentos a la última entrega!!