Python para Ciencias de la Tierra

Capítulo 4: Paqueterías Avanzadas: Análisis de Datos

Damian
21 min readApr 26, 2022

--

Índice del curso
<<
Capítulo 3: Mejorando tu Programa (Pt. 2)

4.1 Análisis de Datos: La Paquetería Pandas

Nota antes de comenzar: Puedes descargar el cuaderno de esta sesión, los archivos usados en los ejemplos y los ejercicios resueltos suscribiéndote a mi patreon: https://www.patreon.com/ciencias_tierra.

A estas alturas del curso hemos cubierto suficientes conceptos básicos pero importantes de programación, que ya es pertinente adentrarnos en programas más grandes y complicados. Pero no te asustes, ya que si has llegado hasta aquí es por tu perseverancia e inteligencia, así que seguirá siendo accesible.

En este capítulo aprenderemos sobre las otras paqueterías que no pertenecen a la biblioteca interna de Python. Empezamos con Pandas, para seguir con Matplotlib y Numpy, pero en el trayecto también abordaremos otras paqueterías bastante útiles para el desarrollo de muchos proyectos en Ciencias de la Tierra.

Pandas es un poderoso módulo para manipular y analizar conjuntos de datos básicamente de cualquier tamaño. Si Python fuera una paquetería de ofimática, Pandas es Excel, pero con esteroides. Es el aliado perfecto para trabajar con datos tabulares. Está escrito en C, por lo que es veloz y eficiente. Ya está instalado en Anaconda.

Debido a sus capacidades, es la paquetería más utilizada para el Análisis de Datos. Para darte una idea, Pandas puede hacer las siguientes tareas:

  • Obtener estadísticas de un conjunto de datos.
  • Correlacionar variables.
  • Crear visualizaciones de variables.
  • Limpieza y filtrado de datos.
  • Transformación de datos.
  • Importación y exportación a archivos csv, xlsx, json, entre otros.
  • Y muchas otras tareas más.

Es imposible cubrir todas las capacidades de Pandas en un capítulo, pero en esta sección aprenderás lo suficiente para permitirte avanzar más adelante y adaptar este módulo a tus aplicaciones, pues desde este momento no dejaremos de usar Pandas en el resto del curso. Por otro lado, no olvides que siempre está contigo el comando help.

Antes de iniciar con la parte práctica, es importante que te familiarices con algunos conceptos propios de Pandas, y que utilizaremos en el resto del curso:

  • Dataframe: Es la estructura de datos más importante y utilizada en Pandas, pues es equivalente a una hoja de cálculo, o matriz de datos. Se usará indistintamente el término tabla como dataframe.
  • Serie: Estructura de datos unidimensional llamada arreglo. Admite cualquier tipo de datos y equivale a una columna o a un renglón de un dataframe.
  • Eje (Axis): Es una columna o un renglón. Si axis = 0, se refiere a los renglones; si axis = 1, se refiere a las columnas.
  • Registro: Un renglón de datos.
  • dtype: Tipo de dato que contienen los dataframe, o las series de datos.
  • Serie de tiempo (Time Series): Serie que utiliza intervalos de tiempo como una variable.
  • A la columna se le puede llamar variable. En este curso se usará uno u otro término según el contexto.

Trabajando con Dataframes

Pandas siempre se importa usando una abreviación universal, la cual siempre debes respetar:

import pandas as pd

Hay dos formas principales de definir un dataframe, ya sea vacío o con elementos. Los elementos se ingresan mediante un diccionario.

#Creación del dataframe (df) vacío
df_vacio = pd.DataFrame()
#Creación del dataframe con elementos
muestras = pd.DataFrame({'Roca': ['Basalto', 'Esquisto', 'Dolomía'],
'Tipo': ['Ígnea', 'Metamórfica', 'Sedimentaria']})
muestras
Figura 4.1 Tabla resultado de ejecutar el código superior.

Observa la tabla de la Figura 4.1, se crea una columna extra al inicio con los índices de los renglones. Y el orden de los elementos de las listas deben coincidir para su correcta representación en la tabla. Las claves son los nombres de las columnas.

Si deseas tener un índice más claro de acuerdo con tus necesidades, puedes agregar el parámetro index e indicarlo con una lista.

muestras = pd.DataFrame({'Roca': ['Basalto', 'Esquisto', 'Dolomía'],
'Tipo': ['Ígnea', 'Metamórfica', 'Sedimentaria']},
index = ['Roca 1', 'Roca 2', 'Roca 3'])
muestras
Figura 4.2 Tabla resultado con los índices personalizados.

La serie se define de forma similar, y opcionalmente se agrega un índice personalizado que, de no agregarse, se agrega la columna de índices enteros como en el dataframe.

serie = pd.Series(['Basalto', 'Esquisto', 'Dolomía'],
index = ['Roca 1', 'Roca 2', 'Roca 3'])
serie

>> Roca 1 Basalto
>> Roca 2 Esquisto
>> Roca 3 Dolomía
>> dtype: object

Accediendo a los datos
Para acceder a los datos, primero se indica en corchetes la columna en la que está el valor deseado, después se especifica el índice, sea numérico o cadena.

print(muestras['Roca']['Roca 1'])

>> Basalto

De igual forma si sólo se quiere ver lo que hay en una columna, basta con indicarla dentro de los corchetes sin especificar el índice. Sin embargo, la forma más recomendable de acceder a los datos es con el método loc() y su variación iloc(). Ambos métodos trabajan igual, pero se diferencian en que iloc() sólo admite los índices de las columnas y los renglones, y loc() los nombres dados. Así es, las columnas están enlistadas ‘de izquierda a derecha’ iniciando en el cero. Nota: En estas funciones se indica primero el renglón, y después la columna, como coordenadas en una matriz (Figura 4.3).

Figura 4.3 Comparación de las tres formas comunes para acceder a los datos de un dataframe. Se recomienda el uso de los métodos loc()e iloc() en lugar de la ‘forma anidada’.

El dataframe también puede ser ‘rebanado’ al indicarles índices inicial y final tanto en dirección de las columnas como en dirección de los renglones, pero a diferencia de la sintaxis en las listas, los índices extremos sí se incluyen en el dataframe resultado, excepto por iloc() que conserva esta propiedad.

Figura 4.4 Comparación de las formas comunes para obtener subconjuntos de datos de un dataframe.

Las funciones loc() e iloc() también admiten listas de índices específicos y valores negativos dentro de los corchetes.

Consulta de Datos

La consulta de datos es una actividad enfocada en obtener información particular de interés a partir de una base de datos. El lenguaje por excelencia para la generación de consultas es SQL. Si estás familiarizado con SQL, las formas que agrega Pandas para consultar datos te serán familiares.

A partir de unas pocas sentencias podemos responder preguntas inmediatas sobre los datos, y crear nuevas tablas que contengan la petición deseada. Se pueden filtrar los datos a partir de una etiqueta, agrupar por tipos de datos, ordenarlos, y más.

Ejemplo 4.1 La tabla de datos Exportacion_minera_Chile.csv resume los valores en millones de dólares de los embarques de exportación minera hechos por Chile de 2016 a 2018. Inspecciona la tabla y responde a las siguientes preguntas:

  1. ¿Cuáles fueron los tres países a los que Chile exportó más minerales metálicos?
  2. ¿En qué año se exportaron más productos minerales?
  3. Crea una nueva tabla que muestre las exportaciones por continente. Debe tener las columnas: continente, exportación de minerales metálicos, exportación de minerales no metálicos. Expórtala.
  4. Crea una nueva columna que sume toda la exportación de minerales para cada registro. Exporta la tabla actualizada.
  5. ¿Cuánta sal marina se exportó a Estados Unidos de América y a Canadá en cada año? ¿Y cuánta minería metálica a México en 2017?

Recomentación: Por el tamaño de éste y los siguientes ejercicios en el curso, recomiendo que hagas un nuevo cuaderno para cada ejercicio a partir de ahora. En este caso puedes nombrarlo Ejemplo_4.1, y así sucesivamente.

Como son archivos externos en tablas, debes importar pandas

import pandas as pd

El archivo está en formato csv. Para importarlo con Pandas se utiliza la función read_csv(). Es recomendable que el archivo csv esté codificado como UTF-8 para la adecuada lectura automática de los caracteres. De sintaxis similar existen read_json(), read_excel(), entre otros. La tabla se guarda en una variable.

exportaciones = pd.read_csv('Exportacion_minera_Chile.csv', 
index_col = 0)

Si la tabla ya cuenta con una columna de índices, se puede agregar el parámetro opcional index_col = n, donde n es el índice de la columna. En este caso el archivo ya tiene columna de índices, y es la cero. De no tenerlo, se omite el parámetro y Pandas genera los índices. En automático considera al primer renglón como el encabezado de las columnas.

Se imprime la tabla.

exportaciones
Figura 4.5 Impresión de un dataframe. Sólo muestra las filas iniciales y finales. De haber más columnas, haría lo mismo mostrando las primeras y las últimas. En la parte inferior muestra el tamaño completo de la tabla.

Podemos hacer algunas anotaciones sobre lo que vemos. En la parte inferior se lee el tamaño de la tabla, la cual también puedes saber con el atributo shape. El nombre de los índices (id) aparentemente aparece ocupando otro renglón, pero sólo es para su distinción visual. De estar sin nombre los índices, los nombres de las columnas estarían inmediatamente sobre la tabla. Los ‘NaN’ significan ‘Not a Number’, y son celdas vacías. Es común que se haga un tratamiento de limpieza a estas celdas.

Exploración
En el mejor de los casos las tablas vienen con un archivo aparte llamado diccionario de datos. También se le puede llamar metadatos, pues describe cada columna, tipo de dato, qué es cada inicial, valores que puede tomar, entre otros. Si no hay un archivo extra que describa a la tabla, como en este caso, debes tomarte unos minutos para entender lo que son las columnas.

En la tabla exportaciones se observa que las columnas se separan en dos grupos: minería metálica y no metálica. La metálica se concentra en una sola columna, pero la no metálica está desglosada en varias columnas, incluyendo la columna ‘Otros’. Además, la columna ‘Minería no metálica’ resume todas las exportaciones de las columnas de minerales no metálicos. En cierta forma, esta columna repite datos, por lo que debemos tenerlo en cuenta para hacer futuras operaciones. Se observa por los datos numéricos que también la columna ‘Otros’ es parte de la minería no metálica.

Podemos usar algunos métodos comunes para explorar la tabla y ver si hay algo más que convertir además de los nan.

Los métodos head() y tail() muestran los primeros y últimos cinco registros de la tabla, respectivamente. Como parámetro se puede agregar un número entero para especificar cuántos primeros o últimos elementos deseas imprimir.

El método keys() muestra los nombres de las columnas, las cuales pueden ser convertidas de forma sencilla en una lista.

El método sort_values() requiere el nombre de una columna como parámetro para ordenar los registros en orden ascendente de los elementos de esa columna. De querer ordenarlos en forma desendente, se indica el parámetro ascending = False.

El método describe() muestra un resumen estadístico de las columnas numéricas, omitiendo los NaN. Explícitamente muestra el conteo de elementos, la media, los valores mínimo y máximo, la desviación estándar y los percentiles 25, 50 y 75. Implícitamente da más información, como la cantidad de valores nulos, pues el conteo de elementos debe coincidir en todos los elementos con el número de filas.

Figura 4.6 Tabla resultado de utilizar el método describe(). Sólo considera columnas numéricas y valores no nulos.

Y algo extraño sucede con la impresión de esta tabla. En principio los datos de la mayoría de las columnas son numéricos, por lo que deberían haberse impreso todas las asociadas a los minerales. Visualmente son números para nosotros, ¿pero en verdad son numéricos? Para comprobarlo podemos utilizar el atributo dtypes, el cual da una lista del tipo de dato que contiene cada columna. De haber cadenas en la columna, indicará que es un object, caso contrario, el valor entero o flotante (Figura 4.7).

Pero no es suficiente, pues símbolos numéricos como alfabéticos pueden ser cadenas, por ello es recomendable inspeccionar qué valores hay en al menos una columna. El método unique() muestra los elementos únicos sin repetir que hay en una columna, evitando una inspección individual de todos los elementos. Es un método propio de una Serie, por lo que siempre se debe indicar la columna (Figura 4.7).

Figura 4.7 Uso del atributo dtypes para conocer los tipos de datos de cada columna, y uso del método unique() para saber qué valores tiene una columna.

En la figura 4.7 se muestra que en efecto sólo las columnas ‘Mineria no metalica’ y ‘Año’ son numéricas. E inspeccionando los elementos que tiene por ejemplo la columna ‘Yodo’, se aprecian números en tipo cadena más el elemento ‘(a)’, cuyo significado desconocemos, y para nuestros fines la podemos ignorar. Las cadenas no pueden operarse matemáticamente, por lo que hay que cambiarlas a tipo numérico.

Limpieza
Esto sólo es en una columna, pero puede que en otras haya más cadenas diferentes a las numéricas y a los nan. Por ello haremos lo siguiente: 1) convertir las cadenas de números a números flotantes, y 2) convertir los elementos nan y otras cadenas a cero.

En pocas palabras, si un número es tipo cadena, convertirlo a flotante, si no, se le asigna un cero. Para ello se harán dos conversiones, primero los nan y luego las cadenas numéricas. El nan es un valor de tipo flotante, por lo que se puede convertir a cadena. Si la cadena resultado de la conversión es ‘nan’, cambiarlo por un cero. Esta conversión de hace en una función.

En otra función se hace la conversión de las cadenas a números cuando sea posible, caso contrario, se asigna un cero. Las funciones quedan de la siguiente forma:

#Primera función
anular_nan = lambda nan : 0 if str(nan) == 'nan' else nan
#Segunda función
def conversion_f(n):
try:
numero = float(n)
except:
numero = 0

return numero

Estas funciones iterarán sobre cada elemento de cada columna. Es decir, pasamos columna por columna, en cada columna pasamos renglón por renglón ambas funciones. Parecen requerirse dos ciclos for anidados, pero hay un método muy especial para evitarnos esto: método apply(). Es un método del objeto Serie, y permite ejecutar una función a cada uno de los elementos de una serie. Si se usa en un dataframe, se debe especificar la columna. Esto nos deja con un sólo for que iterará en cada columna. Para ello se crea una lista con los nombres de las columnas. Se usa keys().

No todas las columnas deben transformarse con estas funciones, por lo que se especifica cuáles debe saltar nuestro ciclo. El código queda como sigue:

#Creación de la lista de los encabezados.
columnas = list(exportaciones.keys())
for col in columnas:
exportaciones[col] = exportaciones[col].apply(anular_nan)
for col in columnas:
if col == 'Continente' or col == 'Pais' or col == 'Año':
continue
else:
exportaciones[col]=exportaciones[col].apply(conversion_f)
exportaciones
Figura 4.8 Dataframe limpio.

Nota: Nuestra función anular_nan equivale al método fillna(n), donde n es el número por el que se sustituyen los nan. Puedes implementarlo para obtener el mismo resultado.

Si ejecutamos otra vez el describe(), veremos una tabla estadística más completa.

exportaciones.describe()
Figura 4.9 Dataframe resultado con información estadística de las columnas numéricas. Observa que ahora todas las columnas tienen el mismo número de elementos numéricos.

Es adecuado también revisar si las demás columnas no numéricas y ‘Año’ tienen elementos extraños. Con unique() es suficiente para ello, pero si son varios valores, es conveniente guardarlo en una lista para inspeccionarlos de forma más fácil. Si revisas esas columnas, notarás que no hay nada extraño en sus valores. Claro que hay formas más sofisticadas de buscar anomalías en cadenas. Y de hecho tú ya puedes hacer filtros para limpiar cadenas.

Opcionalmente se pueden cambiar los elementos de la columna ‘Continentes’, pues están todas en mayúsculas. Pero los países están bien escritos con letra mayúscula inicial. Se entiende que quien capturó estos datos lo hizo con la intensión de distinguir continentes de países categóricamente. Podemos dejarlo así.

Consulta de Datos
Con la tabla adecuada para operaciones numéricas y filtrado de información, podemos realizar las consultas pedidas en el ejercicio. Sí, apenas vamos a resolver el ejercicio.

1. ¿Cuáles fueron los tres países a los que Chile exportó más minerales metálicos?
Para responder esta pregunta debemos saber cuánto se exportó por país. Siendo que cada país puede repetirse hasta tres veces, pues es el número de años que abarca la base de datos, es necesario agruparlos. Para ello existe el método groupby(). Como parámetro debe tener el nombre de la columna que agrupará. El groupby() pertenece a un conjunto de métodos denominados de agregación, pues requieren forzosamente una operación matemática que permita obtener un valor para cada elemento agrupado.

Si sólo ejecutas exportaciones.groupby(‘Pais’) no obtendrás el resultado deseado. Debes agregar una operación, por ejemplo count().

exportaciones.groupby('Pais).count()

Se muestra todo un dataframe donde el índice es el nombre del país, y se cuenta las veces que se repite en cada una de las columnas.

Como queremos saber el total de exportaciones, hay que utilizar el método sum(). Lo guardamos en otro dataframe ¡qué ocupa memoria!, pero ya sabes cómo borrar objetos de la memoria temporal cuando ya no los ocupas, así que no hay problema.

A este nuevo dataframe se ordenan para que se muestren primero los de mayor cantidad de exportaciones de minerales metálicos. Y como sólo queremos ver los primeros tres, lo especificamos en un head().

df_paises = exportaciones.groupby('Pais').sum()
df_paises.sort_values('Mineria metalica', ascending = False).head(3)
Figura 4.10 Dataframe resultado de la consulta.

Con esa vista podemos responder a la pregunta planteada.

print('Los países a los que Chile más minerales metálicos exportó
de 2016 a 2018 son:'
'\n1. Taiwán con 2,424.5 millones de dólares en exportación.'
'\n2. Canadá con 1,947.8 millones de dólares en exportación.'
'\n3. Francia con 1,862.6 millones de dólares en
exportación.')

>> Los países a los que Chile más minerales metálicos exportó de 2016 a
>> 2018 son:
>> 1. Taiwán con 2,424.5 millones de dólares en exportación.
>> 2. Canadá con 1,947.8 millones de dólares en exportación.
>> 3. Francia con 1,862.6 millones de dólares en exportación.

Nota: La columna ‘Año’ también se sumó. En este caso no afecta, pero en otros casos puede afectar, por ello puede ser buena idea convertir la columna en cadena.

2. ¿En qué año se exportaron más productos minerales?
Mismo principio: sumar por año, ordenar y observar la respuesta. Pero hay un detalle adicional, debemos primero obtener toda la minería exportada, por lo que hay que sumar la cantidad de registros por año luego de agruparlo.

df_anio = exportaciones.groupby('Año').sum()

Ya hemos agrupado, ahora debemos sumar los registros columna por columna, es decir, especificar un axis = 1. Pero si hacemos esto ¡estaremos mal! Porque se hizo una exploración de las columnas al iniciar, y no debemos olvidar lo descubierto en ese paso. La columna ‘Mineria no metalica’ ya suma varias columnas. Sólo hay que sumar dos columnas para obtener el resultado de la siguiente imagen:

Figura 4.11 Vista de la serie de datos resultado.

Con esto ya podemos ver que en 2017 hubo más exportaciones, e imprimirlo como parte de nuestros resultados.

Por cierto, tal cual lo estás viendo en la imagen, se pueden sumar (+), restar (-), multiplicar (*) y dividir (/) dos o más columnas de un dataframe. Incluso se pueden concatenar cadenas. Estas operaciones se hacen elemento a elemento.

3. Crea una nueva tabla que muestre las exportaciones por continente. Debe tener las columnas: continente, exportación de minerales metálicos, exportación de minerales no metálicos. Expórtala.

De nuevo, agrupamos por continentes y sumamos.

df_continente = exportaciones.groupby('Continente').sum()
df_continente
Figura 4.12 Vista de la tabla con los datos resumidos por continente.

¡Y ya tenemos lo que nos pide el ejercicio! De hecho, sobra información, o mejor dicho, sobran columnas. Para eliminarlas está el método drop(), en el cual hay que indicar nombre de columna y eje en el que se ejecuta. Opcionalmente se agrega el parámetro inplace =True para indicar que se sobreescriba en el dataframe actual. De forma preliminar espera ser guardado en un nuevo dataframe.

Hacemos un ciclo para eliminar cada una de esas columnas, cuidando que las que nos interesan no se borren.

columnas = df_continente.keys()for col in columnas:
if col == 'Mineria metalica' or col == 'Mineria no metalica':
continue
else:
df_continente.drop(col, axis = 1, inplace = True)
df_continente
Figura 4.13 Tabla que muestra la exportación en millones de dólares a cada uno de los continentes.

Ahora, vamos a exportarla con el método to_csv() el cual tiene sus similares como to_excel() o to_json().

df_continente.to_csv('exportacion_minera_continente_Chile.csv')

Y en la carpeta donde está nuestro cuaderno debe aparecer ese nuevo archivo. Si lo abres en un lector de texto plano verás la tabla, pero si lo abres en Excel notarás que los acentos no están bien codificados. Para solucionar esto, agrega el parámetro encoding = ‘latin1’ al momento de exportar.

4. Crea una nueva columna que sume toda la exportación de minerales para cada registro. Exporta la tabla actualizada.

Como lo vimos en la pregunta anterior, basta con escribir
exportaciones[‘Total’] = exportaciones[‘Mineria metalica’] + exportaciones[‘Mineria no metalica’]

Pero esto enviaría a nuestra nueva columna al final de todas, situación que no es la más adecuada, porque todas las columnas relacionadas a las exportaciones están juntas. Ninguna está más a la derecha que ‘Año’. Por ello mejor se crea una nueva serie llamada total, la cual será la suma de las columnas ‘Mineria metalica’ y ‘Mineria no metalica’.

total = exportaciones['Mineria metalica'] + exportaciones['Mineria no metalica']

Esta serie se inserta en el dataframe con el método insert(), el cual nos permite definir el índice donde queremos que esté, en este caso el 13 para estar al final de todas las columnas de minerales. Los tres parámetros mínimos requeridos son el índice, el nombre de la nueva columna, y la serie, lista o tupla a agregar. Debe tener el mismo tamaño.

exportaciones.insert(13, 'Total', total)
exportaciones
Figura 4.14 Tabla actualizada con una columna nueva.

Y ya, podemos exportar.

exportaciones.to_csv('exportaciontotal_minera_Chile.csv')

Nota: Si por alguna razón no deseamos que el índice se agregue al archivo exportado, lo podemos omitir escribiendo el parámetro index = False.

5. ¿Cuánta sal marina se exportó a Estados Unidos de América y a Canadá en cada año? ¿Y cuánta minería metálica a México en 2017?

Primero se verifica la forma en que están escritos los países. Estados Unidos de América está escrito como ‘Estados Unidos’. Canadá sigue siendo ‘Canadá’, lo mismo para México.

La forma de filtrar información en un dataframe es mediante la sintaxis:

dataframe[ filtro basado en condición para una o varias columnas]

donde el filtro es un dataframe anidado.

Así, para buscar todos los registros de Estados Unidos hay que escribir:

exportaciones[exportaciones['Pais'] == 'Estados Unidos']
Figura 4.15 Tabla de registros coincidentes de Estados Unidos en la columna ‘Pais’.

Y nos muestra todas las coincidencias. En el caso de mostrar más elementos, hay que usar un operador lógico: | equivale a or; y & equivale a and.

Figura 4.16 Resultado de utilizar un operador lógico para filtrar una tabla. Se usa el | en vez de & porque no hay un registro que tenga ambos países al mismo tiempo. Nota el uso de paréntesis.

El resultado de filtrar las exportaciones a Canadá y Estados Unidos lo guardamos en un nuevo dataframe. Por último, con el método loc() delimitamos las columnas que queremos ver.

Figura 4.17 Tabla resultado que resume lo solicitado en la primera pregunta.

Nota en la figura 4.17 que el orden de las columnas en la lista agregada a loc() es el orden en que se imprimen.

Por último, para la segunda pregunta se hace un mismo procedimiento. Se filtra a los valores de ‘México’ para la columna ‘Pais’ y 2017 para la columna ‘Año’.

Figura 4.18 Tabla resultado de la consulta sobre México.

Fin del ejemplo 4.1

¡Y hemos terminado el ejemplo! ¡Por fin! A esto me refería con que serían ejercicios más largos. En general así serán los que tendrás que afrontar. Si hiciste este ejemplo sin pestañear, ¡felicidades, vas por buen camino! Y si lo hiciste en más de una sesión. ¡Pues también vas por buen camino!

Además de los métodos que tiene un objeto, también puede tener atributos, otro concepto de la POO. Línea arriba utilizaste el atributo dtypes. Decimos que los atributos los medios para acceder a variables internas que tiene un objeto. La sintaxis para hacer uso de estas variables es objeto.atributo. Nota la diferencia con el método; el atributo no requiere parámetros.

Joins

Cuando los datos que estás trabajando se encuentran en dos o más tablas, es necesario unirlas para poder generar consultas u otros procesos de análisis como gráficas. Justo un join permite unir dos o más tablas por medio de una columna que tengan en común.

El término join se refiere a una familia de comandos muy importantes y populares en SQL. En Pandas esta familia de comandos se resumen en un método llamado merge(). También hay un método llamado join(), el cual básicamente funciona igual que merge(). ¿Entonces cuál es la diferencia? join() sólo une tablas por columnas que tengan índices enteros, mientras que merge() une tablas con columnas que tengan el mismo tipo de dato entre ellas, sin importar si son cadenas o numéricos.

Imagina dos tablas, una izquierda (primera) y una derecha (segunda). Con esto en mente, las uniones se pueden describir como sigue:

  • Left join: Devuelve todas las filas de la tabla izquierda junto con las filas coincidentes de la derecha. También se llama left outer join.
  • Right join: Devuelve todas las filas de la tabla derecha junto con las filas coincidentes de la izquierda. También se llama right outer join.
  • Outer join: También llamado full outer join, devuelve todas las columnas y filas de las dos tablas en una sola.
  • Inner join: Devuelve las filas que tengan en común las tablas que se están uniendo, es decir, la intersección de ambas.

Nota importante: Todas las columnas se agregan en la tabla resultado, es decir, se suman las columnas de ambas tablas, sólo las filas interactúan según la coincidencia que se presente en el tipo de join.

Estas formas de unir tablas se indican como parámetro dentro del método merge(), dando lugar a una sintaxis similar como la siguiente:

dataframe1.merge(dataframe2, how = ‘tipo de join’, on = ‘columna en común’)

Donde el tipo de join puede ser ‘left’, ‘right’, ‘outer’ o ‘inner’.

Como científico de datos es poco común que te encuentres con muchas tablas a unir, y cuando eso suceda, es seguro que se solucione con un outer join. Pero hago este apartado para que tengas conceptos básicos en caso que te encuentres con problemas que involucren más de una tabla.

Visualización de Datos

A pesar de que Pandas no es una paquetería pensada en la visualización de datos, tiene algunas funciones que permiten darnos una idea inmediata del comportamiento de los datos. Aquí te mencionaré dos visualizaciones basándome en los datos de exportación minera del ejemplo 4.1.

Dataframe colorido
Se pueden colorear los datos de un dataframe según el valor que tengan. Esto es gracias a un módulo interno de Pandas llamado style, el cual permite implementar comandos html y CSS en el estilo de nuestros datos; y la función applymap().

Para ejemplificar su función, hacemos una tabla que sólo tenga valores numéricos a partir del dataframe exportaciones. La función applymap() también requiere de una función como parámetro, por lo que se hace una función que sólo dé formato CSS al texto. La función tiene una condición para resaltar visualmente números que superen un valor dado dentro del grupo de los minerales no metálicos.

def realce_color(df,color, umbral = 50):
if df > umbral:
color = 'color:{}'.format(color)
return color
else:
None
df = exportaciones.iloc[20:35, 3:13]df.style.applymap(realce_color, color = 'red')

Y se muestra la tabla con los valores remarcados en color rojo.

Figura 4.19 Tabla con realce de valores.

De forma similar se pueden hacer una función que permita obtener un ‘semáforo’ de nuestros valores: rojo para valores críticos, verde para valores intermedios, y azul para valores adecuados; según el contexto del proyecto. Observa la siguiente imagen. Te invito a intentar hacer la función que muestre estos colores en una tabla.

Figura 4.20 Ejemplo de una tabla con tres colores diferentes.

Gráfica de línea
Por último, una gráfica cotidiana útil para visualizar series de datos donde el eje X es la serie de índices del objeto, sea serie o dataframe, y el eje Y son los valores.

import mathx = [x for x in range(-20,20)]
y = [math.cos(x/3) for x in range(-20,20)]
coseno = pd.Series(y, index = x)coseno.plot()
Figura 4.21 Gráfica de la función coseno

El método plot() también puede aplicarse a una tabla, pero debes especificar la columna. El eje X siempre es la serie de índices.

Pandas tiene más visualizaciones, no muchas en realidad. Pero basta con las que acabas de ver pues permiten obtener información relevante inmediata sin aportar mucho estilo. Por ello resulta inútil tratar de exportar esas gráficas o abordarlas con más detalle.

En la siguiente sesión veremos una paquetería poderosa para la realización de objetos visuales, los cuales incrementarán tus habilidades de análisis y mejorarán tu entrega de resultados.

Puedes descargar el cuaderno de esta sesión, los archivos usados en los ejemplos y los ejercicios resueltos suscribiéndote a mi patreon: https://www.patreon.com/ciencias_tierra.

Ejercicios

4.1 - Crea las siguientes dos tablas y únelas con un outer join.*

4.2 - Del archivo usado en el ejemplo 4.1 (Exportacion_minera_Chile.csv) realizar y responder lo siguiente:**

a) ¿Cuáles fueron los dos países a los que Chile exportó más minerales en cada continente? ¿Y cuáles fueron los dos países a los que exportó menos minerales en cada continente?

b) ¿A qué países se exportó Carbonato de Litio y Yodo en el mismo año? Agrupa tus resultados por año.

c) Crea dos nuevas columnas: una que indique el porcentaje de minería metálica exportada respecto al total de la minería, y otra que indique la tasa de minería metálica respecto a la minería no metálica. Una columna tendrá valores entre 0 y 100, la otra, valores flotantes. Insértalas antes de la columna ‘Año’. Expórtala como archivo csv bajo el nombre relacion_mineriametalica_Chile.csv

4.3 - El archivo HistoricoPreciosDieselMX_2017–2021 tiene los precios promedios diarios de diésel en México desde el 1 de febrero de 2017 al 31 de diciembre de 2021. La primera columna muestra las fechas en formato dd/mm/aaaa, la segunda columna muestra el precio. Responder las siguientes preguntas:***

a) ¿En qué mes, y de ser posible en qué día, se ha registrado el mayor precio en todo este período? Si dos o más meses reportan el mismo precio, muéstralos.

b) ¿Cuál fue el precio promedio en cada año? Crea una tabla que lo muestre.

c) Haz una tabla que muestre el precio promedio, los máximos y mínimos registrados de cada mes del año para todo el período. Es decir, una tabla con 12 filas, una por mes, y una columna para cada estadístico más el mes. Se deben considerar todos los años del período.

d) Crea una nueva tabla con el precio mensual durante esos años. Agrega una columna que muestre la tasa de cambio de un mes respecto a otro. ¿En qué mes se han presentado el mayor y la menor tasa?

e) Haz una gráfica de línea que muestre los valores promedios mensuales para todo ese período de tiempo.

Siguiente sesión
>> Capítulo 4: Paqueterías avanzadas: Visualización de Datos

Índice del curso

--

--

Damian

Anything I want and is related to data. Learning to become a Data Professional.