Python para Ciencias de la Tierra

Capítulo 2: Conceptos Básicos de Programación en Python (Pt. 5)

Damian
14 min readMar 17, 2022

--

Índice del curso
<<
Capítulo 2: Conceptos Básicos de Programación (Pt. 4)

2.5 Una Introducción a las Paqueterías

Como consecuencia de la gran comunidad que mejora y agrega constantemente funcionalidades a python, actualmente cuenta con una enorme variedad de paqueterías o paquetes, también llamadas módulos o librerías, las cuales agregan más funciones al lenguaje de programación. En general cada paquetería está diseñada para cierto tipo de usos.

Hay una infinidad de paqueterías, las cuales ningún curso sensato sería capaz de explicar todas. Pero de todas las paqueterías, nosotros veremos las que más se utilizan, y por tanto, las más respaldadas en los temas que nos competen. Podemos definir dos tipos de paqueterías: las que están integradas de forma predeterminada a python y forman, por decirlo de algún modo, una biblioteca interna, de las cuales veremos en esta sesión. Y las que han sido diseñadas para incorporarse a python, y siguen creciendo de forma independiente a éste. En este último tipo existen tres ‘monstruos’: Numpy, Pandas y Matplotlib, de los cuales hablaremos detalladamente más adelante.

Sintaxis para utilizar una paquetería
Para usar una paquetería se debe importar al código. La sintaxis básica es:

import nombre_de_la_paqueteria

Las paqueterías, como se mencionó arriba, tienen funciones propias, como las ya vistas print, type, str, etcétera. Una vez importada, se puede utilizar una función con la sintaxis:

nombre_de_la_paqueteria.funcion(parametro)

Esto se hace para cada función del módulo que se desee utilizar. Hay paqueterías con nombres relativamente extensos, que conviene importarlas con un nombre clave, o alias, comúnmente más pequeño:

import nombre_de_la_paqueteria as alias

Con este sobrenombre, las funciones pueden utilizarse con la sintaxis:

alias.funcion(parametro)

También hay paqueterías que por consenso ya tienen un alias definido, y hay que respetar.

Hay paquetes tan grandes que puede ser mejor idea importar sólo las funciones o módulos que se vayan a utilizar. También se pueden importar módulos, los cuales contienen funciones, propios de la paquetería. Todo esto con el fin de no cargar demasiado a la memoria temporal. La sintaxis es la siguiente:

from nombre_de_la_paqueteria import funcion_a_utilizar

o

from nombre_de_la_paqueteria import modulo_a_utilizar

o

from nombre_de_la_paqueteria import funcion1, funcion2, funcion3

Una forma de evitar utilizar el nombre o el alias de una paquetería cada que se llame a una de sus funciones, pero es menos recomendable cuando se utilizan dos o más paqueterías en el mismo código, o una paquetería muy extensa; es con la sintaxis:

From nombre_de_la_paqueteria import *

Con esto las funciones de la paquetería se podrán llamar sin invocar a la paquetería en sí, como si se tratara de funciones propias de python.

Puedes abrir tu nuevo cuaderno llamado Sesion_6 en jupyter.

Recuerda que puedes descargar el cuaderno de esta sesión, los archivos y los ejercicios resueltos, así como apoyarme a hacer más contenido como este suscribiéndote a mi patreon: https://www.patreon.com/ciencias_tierra.

La primera librería que usaremos es math, la cual como su nombre lo indica, es matemática y contiene diversas funciones. Por si te habías preguntado cómo obtener un resultado trigonométrico, logarítmico o exponencial, pues esta paquetería tiene éstas y otras funciones.

import math

Si ejecutas, no hay mensaje de confirmación, pero el hecho que no haya un solo error indica que se ha importado adecuadamente.

Figura 2.23 Vista de cómo se ve la importación de una paquetería. Al ejecutar no hay notificación satisfactoria, pero tampoco error. En automático se abre otra celda.

Empecemos con las funciones trigonométricas, las cuales es importante indicar que trabajan con radianes de forma predeterminada. ¿Quieres grados? Tienes que hacer la conversión, pero descuida, que el paquete tiene la función degrees() para hacer la conversión de radianes a grados, y radians() para convertir grados a radianes. Math también tiene constantes como e y pi.

pi = math.pi    #Definición de pi con base en la función de math
math.sen(pi/2)

>> 1.0

Puedes obtener el ángulo correspondiente a una razón trigonométrica.

math.atan(1)

>> 0.7853981633974483

Pero está en radianes, por lo que conviene hacer la conversión a grados.

x = math.atan(1)
math.degrees(x)

>> 45.0

Y hemos obtenido un resultado bastante familiar.

La lista de funciones que contiene math abarca la obtención del factorial, combinación, valor absoluto, logaritmos, exponenciales, funciones hiperbólicas, entre otras. Una liga a la documentación de este paquete la puedes encontrar al final de esta sesión, donde se explica cada una de ellas.

Pero ahora, hagamos un ejemplo práctico para que te familiarices más con la importación de paqueterías.

Ejemplo 2.4 Estás caminando sobre un terreno plano en el campo, y te encuentras con un cuerpo intrusivo con forma tabular. Deseas obtener su espesor, por lo que sacas tu brújula Brunton y tu flexómetro para medir su echado y su espesor aparente sobre el suelo (Figura 2.24).

Figura 2.24 Tú tomando las mediciones pertinentes. La imagen no está a escala.

Para obtener el espesor del cuerpo, marcado en línea punteada, se forma un triángulo rectángulo junto con la base del cuerpo y el horizonte. La relación que hay entre el echado, el espesor aparente y el espesor real están dados por la función trigonométrica seno. Sea x el espesor real, A el espesor aparente y a el echado, la siguiente ecuación es suficiente para obtener el resultado.

Es decir:

rad = math.radians(43)
x = 11.13*math.sin(rad)
print('El espesor real del cuerpo intrusivo es de', x,'metros.')

>> El espesor real del cuerpo intrusivo es de 7.590641747495608 metros.

Y hemos terminado. Como puedes ver, son demasiadas cifras decimales. Podemos acotar este resultado a dos cifras significativas, tal que parezca que se mide hasta centímetros. Basta con cambiar el tercer renglón por lo siguiente. Advertencia: esta forma de edición sólo es para la impresión, mas no cambia el valor de la variable.

print('El espesor real del cuerpo intrusivo es de {:.3f} metros.'.format(x))

>> El espesor real del cuerpo intrusivo es de 7.59 metros.

No te preocupes si no sabes bien qué pasó, más adelante veremos con detenimiento el formato de impresión que se le puede dar a las variables.

Fin del ejemplo 2.4

A pesar de ver la utilidad del paquete math con este ejemplo, puede que digas ‘Eso se puede hacer con una calculadora.’ Cosa cierta si además de llevar tu brújula Brunton, llevas tu calculadora Casio. Pero qué sucede si son varios los echados medidos, y no tienes el tiempo de calcular sus espesores en ese mismo recorrido. Habrá que ir a gabinete a capturar y calcular los datos. Veamos otro ejemplo.

Ejemplo 2.5 En el campo recolectas una serie de echados y espesores aparentes de una secuencia de once estratos tabulares. Defines dos puntos extremos A y B que contienen a todos los estratos, enumerados como se muestra en la Figura 2.25. Obtener el espesor de cada estrato, y el espesor de toda la secuencia, es decir, del punto A al punto B.

Figura 2.25 Tú luego de medir varios echados y espesores, pero sin el tiempo para calcular sus espesores reales. La imagen no está a escala.

Al costado derecho del dibujo están los echados E y espesores aparentes d que mediste. Lo primero que debes hacer es capturarlos en una hoja de cálculo. Luego guarda esa tabla en un archivo delimitado por comas (.csv)., indicando la unidad y el número de renglón en la primera columna. Puedes nombrarlo como gustes. En este ejemplo se guardó como Ejemplo_2–5.

Como es un archivo externo, debemos utilizar los comandos aprendidos en la sesión anterior. Pero además, al estar en formato csv puede ser de gran ayuda el uso de una paquetería hecha para leer estos archivos.

Si has tenido problemas con el archivo csv, o deseas tener los mismos resultados aquí expuestos, puedes descargar el archivo dando clic aquí.

import csv

Éste es un paquete diseñado para leer este tipo de archivos. Su función que usaremos es reader(). Como el texto se mantiene en memoria por muy poco tiempo, es necesario guardarlo en una estructura que podamos usar en las operaciones siguientes. Es útil hacerlo en una lista, la cual sabemos tiene orden y es mutable.

archivo = open('Ejemplo_2-5.csv', 'r')
tabla = csv.reader(archivo, delimiter = ',')
estratos = list() #Lista para guardar la tabla

for renglon in tabla:
print(renglon)
estratos.append(renglon)

archivo.close()
Figura 2.26 Lectura de una tabla en formato csv. Observa que se indica el tipo de delimitador que tiene el archivo. Nota muy importante: Los datos son importados como cadenas.

Se crea una lista de listas, las cuales ya puedes trabajar muy bien. La primera lista es el encabezado, por lo que se debe saltar en la lectura de datos. Nota que los valores de nuestro interés son los que están en los índices 1 y 2 de cada lista anidada.

Para acceder a cada uno de los renglones, usamos un ciclo for. Los índices 1 tienen el echado en grados, los cuales deben convertirse a radianes. Los índices 2 tienen el espesor aparente. Hay que crear dos variables, una para cada valor numérico, que cambien en cada iteración para ser introducidos en la función seno.

for renglon in estratos[1:]:   #Omisión del renglón de encabezado
echado = float(renglon[1]) #Conversión de cadena a flotante
rad = math.radians(echado) #Conversión de grados a radianes
d = float(renglon[2])

#Obtención del espesor real
espesor_r = d*math.sin(rad)

print('Espesor real:', espesor_r)

>> Espesor real: 1.5282101245739859
>> Espesor real: 1.4128406895905414
>> Espesor real: 3.3772391647663227
>> Espesor real: 1.300345123403404
>> Espesor real: 2.521115007771773
>> Espesor real: 2.4384105240495177
>> Espesor real: 1.463261445906704
>> Espesor real: 2.2102926095533353
>> Espesor real: 2.1282240262905687
>> Espesor real: 3.5694549320688003
>> Espesor real: 3.0917106915104458

¡Y se imprimen los espesores reales!

Pero no podemos dejarlos ahí con la certeza que se borrarán al cerrar jupyter. Debemos exportarlos, y mejor aún, agregarlos al archivo csv de echados que ya hemos hecho, como columna nueva.

Se crea una nueva lista llamada tabla. Ya existe esa variable, pero como ya no la utilizamos podemos sobrescribir en ella. Esta lista contendrá varias listas, una por renglón.

Se hace un ciclo for sobre la lista estratos, la cual contiene la tabla del archivo csv. El primer renglón es el encabezado, y ahora no lo debemos saltar porque necesitamos agregar la nueva columna también. Al ser de tipo cadena nos dará error si hacemos operaciones sobre esos valores, por lo que condicionamos que de contener una de las palabras clave que sabemos tiene el encabezado se agregue el nombre de la nueva columna al renglón, seguido de agregarlo a la tabla. Para cualquier otro caso, se hacen las operaciones echas arriba, y a cada renglón se agrega el nuevo resultado.

Ahora usamos la función interna round() de python. Redondea el valor flotante del primer parámetro al número de decimales indicado en el segundo parámetro. Observa cómo se puede escribir una función dentro de un método.

Se apila el renglón con la nueva columna a la tabla. Si la imprimes en otra celda sin usar print (porque visualmente es más entendible), verás algo muy parecido a una tabla, como en la Figura 2.27.

tabla = list()

for renglon in estratos:

if renglon[0] == 'estrato':
renglon.append('espesor real (m)')
tabla.append(renglon)
else:
echado = float(renglon[1])
rad = math.radians(echado)
d = float(renglon[2])

espesor_r = d*math.sin(rad)
renglon.append(round(espesor_r,2))
tabla.append(renglon)
Figura 2.27 Impresión de la tabla. Si se usara el comando print, la vista no sería clara. Inténtalo.

Ya tenemos la tabla que deseamos exportar. Así que es tiempo de abrir un nuevo archivo, pero ahora con la modalidad de escribir. Se agrega un nuevo parámetro: newline = ‘’, el cual indica que al escribir no se agregue un renglón vacío entre cada renglón escrito, que es la configuración predeterminada.

La función writer() del paquete csv permite indicar a qué archivo previamente abierto se le va a escribir, y definir el delimitador que se usará, en este caso la coma. El objeto escribir es el objeto ligado a archivo donde se escribirán las líneas.

Se usa un ciclo for para escribir renglón por renglón. La función writerow() permite hacer esta tarea. Se cierra el archivo.

archivo = open('tabla_estratos.csv', 'w', newline = '')

escribir = csv.writer(archivo, delimiter = ',')

for renglon in tabla:
escribir.writerow(renglon)

archivo.close()

Si abres tu explorador de archivos, ya debió crearse un nuevo archivo llamado tabla_estratos.csv. Ábrelo para ver que nuestra tabla original tiene una nueva columna.

Ahora debemos calcular el espesor total de todos los estratos. Como se ha visto, basta con hacer una suma de cada uno de los elementos que están en la columna con índice 3.

suma = 0
for renglon in tabla[1:]:
suma = suma + renglon[3]

esp_total = suma
print('El espesor total de la secuencia es de', esp_total,'metros.')

>> El espesor total de la secuencia es de 25.04 metros.

Como los espesores se guardaron con una precisión de centésimos, la suma también tiene esa precisión.

Fin del ejemplo 2.5

La paquetería math tiene su contraparte compleja cmath, la cual contiene funciones útiles para obtener la fase de un número complejo, transformar y representar números a sus formas exponenciales y polares. Sus funciones trigonométricas, hiperbólicas, logarítmicas y exponenciales admiten valores complejos.

Hasta ahora hemos trabajado con procesos deterministas, lo cual es bueno si lo que queremos es que dado un valor de entrada, siempre obtengamos el mismo valor de salida. Pero habrá varias ocasiones en las que deseemos en el algoritmo o incluso sea necesario tener que utilizar valores aleatorios. Las computadoras no pueden generar valores aleatorios, dado que los algoritmos para su generación son deterministas. Sin embargo son generados con suficiente impredecibilidad que se pueden denominar pseudoaleatorios, los cuales llamaremos aleatorios, por simplicidad.

Una paquetería que permite generar números pseudoaleatorio es random. La función más básica para generar un número aleatorio es random, la cual genera números aleatorios en el rango 0 ≤ x < 1.

Vamos a importar esta paquetería de tal forma que no requiramos llamar a la paquetería cada que usemos alguna de sus funciones.

from random import *

for i in range(5):
x = random() #Sin el *, tendríamos que escribir random.random()
print(x)

>> 0.8738480046832207
>> 0.4342375109783312
>> 0.7989334978449537
>> 0.813740194939889
>> 0.6870427513749767

También permite generar números aleatorios enteros con la función randint(a,b), donde a y b son los límites del rango de valores enteros de donde generarlos. Estos son parámetros obligatorios e incluye a ambos extremos.

for i in range(5):
x = randint(2, 50)
print(x)

>> 2
>> 26
>> 4
>> 24
>> 18

Hasta este punto seguro ya notaste que tu cuaderno está generando diferentes números a los que aquí muestro. Esto sucede con los valores aleatorios. De hecho, si ejecutas una y otra vez cualquiera de las dos celdas escritas hasta ahora con random, notarás que se generan nuevos valores en cada ejecución.

Es muy útil escribir código que pueda ser replicado por otras personas, y además obtengan los mismos resultados. Por ello existe una función que permite generar los mismos valores aleatorios sin importar en qué máquina se ejecute el código. La función que necesitamos es seed, con sintaxis seed(a = valor_inicial).

¿Qué hace seed? Como se explicó arriba, los valores aparentemente aleatorios son deterministas, y por decirlo de algún modo, si al algoritmo generador se le da un valor inicial de entrada, generarán el mismo valor de salida. La función seed justo hace eso: define un valor inicial para generar los números aleatorios. Con ese valor inicial se obtienen los mismos números en donde se ejecute el código. ¿Y en qué valor se apoya para generar los valores si no se agrega uno inicial? De la hora de tu computadora. Es muy importante esta función y su concepto ya que aparece en varias paqueterías que manejan algoritmos probabilísticos, por lo que la verás de nuevo.

Retomando, ahora hagamos un código con esta función. Es importante que la función seed esté en la misma celda de ejecución.

seed(a = 42)

for i in range(5):
x = randint(2, 50)
print(x)

>> 42
>> 9
>> 3
>> 49
>> 19

Y ahora sí tienes los mismos resultados que se muestran aquí.

Otra función de especial relevancia es choice, la cual permite elegir aleatoriamente un elemento de una lista o una tupla.

numeros = [5,7,8,2,4,6,8,2,1,5,3,6,9,7]
x = choice(numeros)
print(x)

>> 2

Observa que las funciones random, randint, seed y choice son funciones propias de la paquetería random, pero no fue explícitamente escrita por la forma en que se importó dicho paquete.

Ejemplo 2.6 Generar una serie de calificaciones entre 5 y 10 puntos de 20 estudiantes de Geología General, donde 5 es un valor reprobatorio, y una calificación ≥ 6 es aprobatorio. Obtener la media, mediana, moda y desviación estándar de las calificaciones.

Lo primero a realizar es importar el paquete random para generar las calificaciones en el rango indicado.

import random

Se define una semilla, para que tengamos las mismas calificaciones registradas; y una lista donde guardarlas. Con randint generamos las calificaciones.

random.seed(a = 23)
calificaciones = list()

for c in range(20):
calificacion = random.randint(5,10)
calificaciones.append(calificacion)

print(calificaciones)

>> [7, 5, 5, 9, 7, 8, 8, 9, 7, 6, 10, 6, 7, 8, 5, 6, 9, 8, 5, 5]

Ahora que tenemos las calificaciones, debemos obtener los estadísticos indicados. Para ello utilizaremos la paquetería básica pero útil, statistics, la cual contiene las funciones más utilizadas en la estadística descriptiva. Como su nombre es extenso, podemos importarla bajo el alias stat.

import statistics as stat

Primero calculamos y guardamos los estadísticos de tendencia central.

media = stat.mean(calificaciones)
mediana = stat.median(calificaciones)
moda = stat.mode(calificaciones)

Ahora obtenemos y guardamos la desviación estándar poblacional. Nota que la p de la función es de población. La función muestral no tiene la p.

desviacion = stat.pstdev(calificaciones)

Ahora sólo queda imprimir los resultados.

print('La calificación media es,', media,'.'
'\nPor otro lado, la mediana y la calificación que más se
repite son', mediana,'y',moda,', respectivamente.'
'\nLas calificaciones presentan una desviación de más menos
{:.2f} puntos.'.format(desviacion))

>> La calificación media es, 7 .
>> Por otro lado, la mediana y la calificación que más se repite son 7.0 y 5 ,
>> respectivamente.
>> Las calificaciones presentan una desviación de más menos 1.55 puntos.

Fin del ejemplo 2.6

La siguiente sesión terminamos con este recorrido de temas básicos con uno de los temas más importantes que hay pues mejora notablemente la forma de hacer código: Funciones.

Recuerda visitar y apoyarme a hacer más contenido como este en mi patreon: https://www.patreon.com/ciencias_tierra.

Ejercicios

2.19 - En campo recolectas los rumbos y echados de diversas secuencias estratigráficas. Las escribes en tu libreta en una tabla como la que se muestra a continuación.***

Debes realizar lo siguiente:

  • Transcribir esta tabla en un archivo csv, puedes llamarlo ejercicio_2–19_estratos, o similar, para importarlo en python.
  • Calcular los espesores reales de cada estrato dado el espesor aparente y el echado.
  • Generar tres archivos de salida, uno por secuencia. Cada uno debe tener cuatro columnas: Estrato, Echado, Espesor medido, Espesor real, como en el archivo resultado del ejemplo 2.5.

Tómate unos minutos en pensar cómo capturar los datos en tu archivo csv, ya que de esto dependerá en gran medida la cantidad de trabajo que harás en el código para manipular esa data.

2.20 - En el ejercicio 2.16 de la sesión anterior obtuviste tres listas de rocas: ígneas, sedimentarias y metamórficas. Con base en estas listas harás lo siguiente. Elegir una roca aleatoriamente de la lista que contiene las rocas escritas abajo; y clasificarla como ígnea, sedimentaria o metamórfica. *

arenisca, kimberlita, dolomía, limolita, gabro, cuarcita, granodiorita, pizarra, dacita, pumita, andesita, arcilla, gneis, basalto, caliza, migmatita, brecha, andesita, diorita, anfibolita, basalto, limolita, grauvaca, granito, conglomerado, mármol, arcilla

--

--

Damian

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