Python Avanzado v0.1.4
Python Avanzado v0.1.4
Programación Python
(avanzado)
v 0.1.4
Tabla de contenido
Introducción 6
Plataformas de desarrollo 6
Instalación de Python 3 7
Instalación de PyCharm 10
Clases y objetos 23
Clases y objetos 30
Métodos especiales 35
Encapsulación de atributos 38
Herencia 40
Métodos en listas 48
Métodos en conjuntos 50
Métodos en diccionarios 53
Módulos y paquetes 54
Módulos 54
Collections 56
Datetime 58
2
Math 61
Random 64
Paquetes 67
Manejo de ficheros 68
Creación 68
Apertura o lectura 69
Modificación 70
Pandas 74
Instalación de Pandas 74
Importación de Pandas 77
Instalación de Matplotlib 80
NumPy 101
3
Bases de datos 110
MongoDB 110
MacOS 136
GNU/Linux 136
4
Twitter como fuente de datos 150
5
Introducción
Una vez cursado el módulo de fundamentos de Python, el alumno podrá
continuar su aprendizaje en un modo más avanzado. Para ello se podrán
realizar varios ejercicios en cada sección de modo que el aprendizaje sea
gradual y efectivo, pues el alumno comenzará a programar desde el primer
momento. Al final del módulo se introducirán algunos conceptos básicos y
librerías utilizadas en el tratamiento de datos y cálculo numérico como son
Pandas y NumPy.
Plataformas de desarrollo
Para iniciarse por primera vez en Python se suele recomendar utilizar algún
entorno de desarrollo como Anaconda, que incorpora la aplicación web
Jupiter Notebook, utilizado anteriormente en el módulo de fundamentos de
Python. El uso de Jupiter Notebook nos puede venir muy bien para dar
nuestros primeros pasos y realizar pruebas con sencillos fragmentos de código
de una manera muy fácil y sencilla, pero para seguir avanzando en el
conocimiento de este lenguaje y adentrarnos en técnicas más avanzadas es
altamente recomendable usar algunos de los editores de texto avanzados o
IDE, tales como PyCharm, Atom, Sublime o Visual Studio Code.
6
Comprobación del entorno de trabajo adecuado
Para asegurarnos de que el alumno tiene instalado en su ordenador todos los
recursos necesarios para seguir las clases desde el primer momento será
necesario realizar las siguientes comprobaciones.
Instalación de Python 3
7
(recommended)” y “Add Python 3.10 to PATH”, y finalmente seleccionar
la opción “Customize installation”.
8
4. En esta pantalla basta con seleccionar todos los checkbox indicados en
la siguiente imagen y pulsar el botón “Install”.
9
Instalación de PyCharm
10
8. Podemos seleccionar la ruta de instalación que queramos, pero
recomiendo dejar la ruta que viene por defecto, así será más fácil
localizar las carpetas de instalación en caso de duda o problemas.
Pulsamos el botón “Next”.
11
9. Basta con activar los checkbox que se indican en la siguiente imagen y
pulsamos el botón “Next”.
12
10. Pulsamos el botón “Install”.
13
11. La instalación puede demorar unos minutos. Cuando esta finalice
veremos una pantalla similar a la siguiente imagen. Seleccionamos la
opción “Reboot now” y pulsamos el botón “Finish”.
14
12. Una vez reiniciado el PC, si vamos a la barra de búsqueda de Windows
y escribimos “PyCharm Comunity Edition” veremos que nos aparece
como aplicación instalada. Pulsamos sobre ella y pulsamos sobre la
opción “Abrir” tal y como se muestra en la siguiente imagen.
15
Simple programa de ejemplo
16
14. En “Location” escribiremos el nombre de nuestro primer proyecto, por
ejemplo “prueba_entorno”, para crear una simple aplicación de prueba.
Tiene que quedar de forma similar a como se muestra en la imagen, es
decir, tiene que aparecer una ruta como
“C:\Users\tu_usuario\PycharmProjects\prueba_entorno”.
17
15. En esta pantalla debemos seleccionar del menú de la izquierda la
opción “System interpreter” y en el campo “Interpreter” debemos
seleccionar el ejecutable que se encuentra en “C:\Program
Files\Python310\python.exe”. Finalmente pulsamos el botón “OK”.
18
16. Ahora nos aparecerá en el combo desplegable que se muestra en la
siguiente imagen el intérprete “Python 3.10”, nos aseguramos que esté
seleccionado y activamos el checkbox “Create a main.py welcome
script”. Finalmente pulsamos el botón “Create”.
19
Create a main.py welcome script
20
18. También veremos por la parte inferior de la ventana una serie de
indicaciones que nos confirman que estamos usando Python 3.10 y
alguna barra de progreso en la que podemos ver cómo se indexan
algunos archivos del proyecto. Esto no debería preocuparte demasiado,
es mera información. Pero sí es importante que en la esquina inferior
derecha aparezca la versión 3.10 de Python (o superior).
20. En esta ventana, a priori no tenemos que configurar nada, solo la vamos
a inspeccionar para ver qué nos permite configurar. Por ejemplo, en el
21
campo “Script path” se configura la ruta donde se encuentra nuestro
script de Python que usaremos como “lanzador” o ejecutable principal.
en el campo “Python interpreter” aparece la versión de Python que
vamos a utilizar en este proyecto. Aquí debería aparecer Python 3.10,
pues ya lo hemos configurado anteriormente. Se pueden configurar
muchas otras opciones, pero de momento vamos a cerrar esta ventana
pulsando el botón “OK”.
22
22. Si todo ha ido bien, en la consola de la parte inferior veremos el
resultado de la ejecución de este script, y debe mostrar un mensaje que
diga “Hi, PyCharm”.
Clases y objetos
Con todo lo que hemos aprendido en el módulo de “Fundamentos de
programación en Python” ya podemos crear bastantes programas. Sin
embargo, no dejan de ser instrucciones estructuradas. Esto significa que
cuando queremos solucionar un problema tenemos que pensar de arriba a
abajo, y lo único que nos da un poco de juego son las funciones, las listas y
los diccionarios. Así era la programación en el pasado, bastante aburrida, con
mucho código, mucha gestión de recursos y muy difícil de mantener. Hasta
que poco a poco fue tomando forma un paradigma de programación conocido
como Programación Orientada a Objetos (POO).
23
cada vez más y más sectores se estaban informatizando y era necesario crear
una forma más sencilla de poder trasladar los problemas del mundo real a la
programación. La mejora fue muy importante, ya que las tediosas estructuras
no solo se podían replicar fácilmente en clases y objetos mucho mejor
ordenados, si no que estos además permitían manejar sus propios atributos y
funciones internas, llamadas métodos.
El caso de estudio será el siguiente: Nos piden crear un registro para manejar
los clientes de una empresa, con su nombre, sus apellidos y su DNI. El
programa debe permitirnos mostrar los datos de los clientes o eliminarlos a
partir de su DNI. En un primer momento podremos pensar que lo más
razonable es trabajar con ficheros o bases de datos, pero todavía no hemos
llegado a esa parte, de momento trabajaremos con almacenamiento de
información en memoria, es decir durante la ejecución del programa.
clientes = [
{'nombre': 'Richard', 'apellidos': 'Stallman', 'dni': '01234567A'},
{'nombre': 'Aaron', 'apellidos': 'Swartz', 'dni': '98765432Z'}
]
print(clientes)
24
[{'nombre': 'Richard', 'apellidos': 'Stallman', 'dni': '01234567A'},
{'nombre': 'Aaron', 'apellidos': 'Swartz', 'dni': '98765432Z'}]
print('Cliente no encontrado.')
mostrar_cliente(clientes, '01234567A')
Salida:
Richard Stallman
Muestra el nombre y apellidos del cliente que coincide con el DNI 01234567A.
Vamos a modificar el DNI que estamos poniendo a la hora de invocar la
función mostrar_cliente poniendo un DNI que no exista en nuestra
lista clientes, por ejemplo:
mostrar_cliente(clientes, '00000000B')
Salida:
Cliente no encontrado.
El bucle for completó todas las iteraciones buscando algún cliente con el
DNI 00000000B y como no se encontró ningún resultado se muestra por pantalla
el mensaje correspondiente. Se puede decir que ya tenemos una aplicación
con una funcionalidad o método muy rudimentario que se encarga de buscar
clientes dentro de una lista. Hagamos una nueva funcionalidad que se
encargue de borrar un cliente de la lista, para ello haremos una nueva función
llamada borrar_cliente que reciba también dos argumentos, la lista de clientes
y el DNI del cliente que se quiere borrar, por ejemplo:
25
def borrar_cliente(clientes, dni):
for i,c in enumerate(clientes):
if dni == c['dni']:
del clientes[i]
print(f'{c} --> Borrado')
return # Si se encuentra el cliente se sale de la
iteración.
print('Cliente no encontrado.')
print(clientes)
borrar_cliente(clientes, '01234567A')
print(clientes)
26
lado a otro para poder manejarla y ejecutar acciones sobre ella, esto no es
muy práctico.
class Cliente:
def __str__(self):
return f'{self.nombre} {self.apellidos}'
class Empresa:
27
deben llevar el prefijo self.. En el caso de la clase Empresa solo hay un
atributo clientes. Si este no se especifica tendrá como valor por defecto una
lista vacía.
En lugar de trabajar con funciones, como era el caso de la programación
estructurada, aquí cambia la sintaxis, cada clase tendrá sus propios métodos.
Lo primero que tenemos que hacer a continuación del código anterior es crear
un cliente en memoria, esto se realiza de la siguiente manera:
Hemos creado una variable llamada javier que tiene como valor un objeto o
instancia de la clase Cliente, y además se le ha indicado que el
atributo nombre debe tener por valor Javier, el atributo apellidos el
valor Dominguez y el atributo dni el valor 00000000A.
Vamos a crear otro cliente pero esta vez sin especificar el nombre de los
atributos, solo respetando el orden en el que la clase Cliente espera recibir los
argumentos, que son dni, nombre y apellidos:
Con estas dos nuevas líneas habremos creado dos instancias u objetos de la
clase Cliente, cada una con sus atributos personalizados.
Ahora vamos a crear una instancia u objeto de la clase Empresa, esta clase
necesita recibir como argumento una lista, lo haremos de la siguiente manera:
Vamos a añadir una línea más para imprimir el atributo clientes de la instancia
de la clase Empresa que hemos llamado empresa:
print(empresa.clientes)
28
el nombre, apellidos o el dni. La clase Empresa tiene un método
llamado mostrar_cliente que recibe por parámetro el dni de un cliente.
Para hacer uso de un método de una clase debemos poner el nombre del
objeto seguido de un punto (.) y el nombre del método con paréntesis y los
valores que correspondan dentro de los paréntesis, por ejemplo:
empresa.mostrar_cliente(dni='00000000A')
empresa.borrar_cliente(dni='11111111B')
print(empresa.clientes)
Salida:
En este punto puede que no tengamos muy claro que está sucediendo por
detrás durante la ejecución del programa, pero podemos notar una sintaxis
más clara y auto explicativa que nos ayuda a comprender el programa. Tanto la
empresa como los clientes tienen su propia clase con sus atributos y sus
funciones. Podemos rellenar la lista de clientes de la empresa con objetos de
la clase cliente, cada uno con sus propios atributos y podemos hacer que
interaccionen unos objetos con otros entre clases. En resumen podríamos
decir que la programación orientada a objetos se basa en determinar las
29
entidades con nombres propios en lugar de crear estructuras y diccionarios
para representar la información.
Clases y objetos
En cualquier lenguaje de programación si hablamos de objetos es necesario
hablar también de clases. De hecho sin clases no habría objetos, ya que las
clases son los moldes de los objetos, en cierto modo como lo son un molde de
galletas y las propias galletas. Para ver algunos ejemplos vamos a crear un
nuevo archivo llamado clases_y_objetos.py y vamos a crear la siguiente clase
llamada Galleta que no contendrá nada, es una clase vacía, para ello usamos
la instrucción pass:
class Galleta:
pass
A continuación vamos a escribir estas dos líneas para crear dos objetos de
esta clase:
galleta_1 = Galleta()
galleta_2 = Galleta()
Se podría decir que hemos creado dos galletas galleta_1 y galleta_2 a partir
del molde Galleta. Cada vez que creamos un objeto de una clase lo que
estamos haciendo es instanciar un objeto. El concepto de instancia es muy
importante, ya que hace referencia a algo que existe en la memoria del
ordenador, pero solo mientras el programa se está ejecutando. Cuando el
programa finaliza toda esta información se libera de la memoria y desaparece.
Es lo contrario a una base de datos, en cuyo caso la información permanecerá
almacenada en la base de datos e incluso si el programa finaliza, es lo que se
denomina como persistencia de datos. Hablaremos de ello más adelante.
print(type(galleta_1))
Salida:
<class '__main__.Galleta'>
30
método type() con otro tipo de objetos que ya conocemos, y siempre nos
devolverá el tipo de dato u objeto que se trata, veamos varios ejemplos:
print(type(10))
print(type(3.14))
print(type('Hola'))
print(type([]))
print(type({}))
print(type(True))
def hola():
pass
print(type(hola))
Salida:
<class '__main__.Galleta'>
<class 'int'>
<class 'float'>
<class 'str'>
<class 'list'>
<class 'dict'>
<class 'bool'>
<class 'function'>
Para estudiar este punto seguiremos con el ejemplo del molde de galletas y las
galletas que salen de él, no todas serán iguales. Siguiendo con la metáfora,
todas las galletas compartirán la misma forma y tamaño, pero pueden hacerse
de diferentes colores, sabores o ingredientes. He ahí que sus atributos tengan
diferentes valores y que cada galleta sea única.
31
continuación el nombre del atributo. Estos atributos se pueden definir fuera de
la clase y se crearán automáticamente solo para esa instancia. Para poder
verlo vamos a crear un nuevo archivo llamado galletas.py con el siguiente
código:
class Galleta:
pass
g = Galleta()
g.sabor = 'salada'
g.color = 'amarillo'
Salida:
class Galleta:
sabor = 'salada'
color = 'amarillo'
g1 = Galleta()
g2 = Galleta()
Salida:
Como podemos ver, no es necesario asignar atributos cada vez que se crea un
objeto de la clase Galleta, ya se definen en la propia clase. Lo malo de este
método es que todas tendrán los mismos valores por defecto, por lo que sí
saldrían todas las galletas iguales.
Para que cada objeto tenga sus propios valores de atributos lo mejor es
definirlos en el momento que se crea el objeto, para ello es necesario conocer
32
dos conceptos nuevos de las clases, uno es el método especial
llamado __init__(), y el otro es la palabra reservada self. Vamos a desarrollar
de nuevo la clase introduciendo estos dos nuevos conceptos:
class Galleta:
g1 = Galleta('salada', 'amarilla')
g2 = Galleta('dulce', 'verde')
Añadimos dos líneas para imprimir un mensaje por pantalla donde se puedan
ver los atributos de las instancias g1 y g2, para acceder al dato escribiremos a
continuación del nombre del objeto un punto y el nombre del atributo de ese
objeto:
class Galleta:
33
self.chocolate = False
def chocolatear(self):
self.chocolate = True
def tiene_chocolate(self):
if self.chocolate:
print('Si tiene chocolate')
else:
print('No tiene chocolate')
g1 = Galleta('salada', 'amarilla')
g2 = Galleta('dulce', 'verde')
Salida:
34
Como se puede comprobar, ahora tenemos clases, objetos, atributos y
métodos de clase que nos sirven para poder tener un control sobre el estado
de las cosas de una manera mucho más sencilla.
Métodos especiales
class Pelicula:
# Constructor de clase.
def __init__(self, titulo, duracion, lanzamiento):
self.titulo = titulo
self.duracion = duracion
self.lanzamiento = lanzamiento
print('Se ha creado la película {self.titulo}.')
# Destructor de la clase
def __del__(self):
print(f'Se está borrando la película {self.titulo}.')
del(p)
35
Otro método especial es el método llamado __str__() que servirá para aquellas
ocasiones en las que queremos imprimir un objeto en su totalidad, en cuyo
caso ya no se mostrará una cadena con la dirección de memoria en la que está
almacenado el objeto, si no un mensaje personalizado. Por ejemplo:
print(p)
En Python podemos crear objetos que tengan atributos cuyo valor pueden ser
objetos de otras clases. Al principio de esta sección hemos visto un ejemplo
en el que usábamos la clase Cliente y la clase Empresa. En este ejemplo el
objeto de la clase Empresa contenía una lista de objetos de la clase Cliente.
Ahora vamos a hacer un catálogo para poder manejar las películas del ejemplo
anterior. Modificamos ligeramente la clase Pelicula que teníamos definida en el
archivo peliculas.py del punto anterior. Eliminemos el método especial
destructor y cambiemos el mensaje que devuelve el método
especial __str__(), por ejemplo:
36
class Pelicula:
# Constructor de clase.
def __init__(self, titulo, duracion, lanzamiento):
self.titulo = titulo
self.duracion = duracion
self.lanzamiento = lanzamiento
print(f'Se ha creado la película {self.titulo}.')
Hagamos a continuación una nueva clase llamada Catalogo, esta clase tendrá
un atributo llamado peliculas y tendrá por valor una lista vacía. Además tendrá
un método constructor que inicializa la lista de películas vacía si no se le
especifica ninguna lista o con una ya existente si se especificara como
argumento a la hora de instanciar el objeto de la clase Catalogo. También
tendrá dos métodos, el método agregar() que simplemente hace un append a la
lista peliculas de la película que se le pase como argumento, y el
método mostrar(), que simplemente hace un print() del objeto película.
class Catalogo:
peliculas = []
def mostrar(self):
for p in self.peliculas:
print(p)
c = Catalogo([p1])
37
c.agregar(Pelicula('El padrino II', 202, 1974))
c.mostrar()
Salida:
Encapsulación de atributos
Hasta ahora hemos visto cómo en Python se puede acceder a los atributos y
métodos de una clase de una manera muy sencilla. Esto es por que tal y como
los hemos visto tienen un acceso público, pero en algunas ocasiones podría
interesarnos que no fuera así, y que estos no se puedan ejecutar desde fuera,
en cuyo caso tendrían un acceso privado, que permanezcan encapsulados.
class Ejemplo:
__atributo_privado = 'Soy un atributo inalcanzable desde fuera.'
def __metodo_privado(self):
print('Soy un método inalcanzable desde fuera.')
Ahora vamos a crear una instancia de esta clase y vamos a intentar acceder a
su atributo __atributo_privado desde fuera:
e = Ejemplo()
38
print(e.__atributo_privado)
e.__metodo_privado()
Para poder hacer uso de los atributos y métodos privados desde fuera
tendremos que crear un nuevo método público que haga de puente y que sea
él el que tiene acceso a los elementos privados desde dentro de la clase, por
ejemplo:
def mostrar_atributo(self):
return self.__atributo_privado
print(e.mostrar_atributo())
39
Aplicando la misma técnica al método podremos acceder también al método
privado creando una nuevo método público mostrar_metodo() que haga de
puente, por ejemplo:
def mostrar_metodo(self):
return self.__metodo_privado()
e.mostrar_metodo()
Herencia
Para verlo en un ejemplo vamos a crear una aplicación para la gestión de una
tienda en la que se venderán diferentes productos. Nuestro programa estará
compuesto por varios archivos con código fuente Python en el que vamos a ir
añadiendo diferente código. Empecemos por crear un archivo
llamado producto.py, aquí definiremos la clase Producto donde definiremos
todos los campos posibles relativos a los tipos de producto que podamos
crear, tales como alimentos o libros:
class Producto:
def __init__(self, referencia, tipo, nombre, pvp, descripcion,
productor=None, distribuidor=None, autor=None):
self.referencia = referencia
self.tipo = tipo
self.nombre = nombre
self.pvp = pvp
self.descripcion = descripcion
self.productor = productor
self.distribuidor = distribuidor
self.autor = autor
40
Este sería un buen comienzo para crear productos, de momento una clase
llamada Producto que solo tiene un método constructor __init__() en el que se
definirá el valor de unos atributos obligatorios,
como referencia, tipo, nombre, pvp y descripcion, y luego otros atributos
opcionales, como productor, distribuidor y autor.
Los atributos obligatorios son aquellos que tendremos que especificar siempre
que definamos una instancia u objetos de la clase, en este caso porque son
todos los atributos que todos los productos tendrán en común. Sin embargo
los opcionales podremos especificarlos o no, dependerá del tipo de producto
que queremos instanciar. En los casos en los que no especifiquemos estos
atributos opcionales se le asignará un valor por defecto None.
Vamos a crear un producto instanciando un objeto de esta clase, por ejemplo:
print(adorno.tipo)
print(adorno.descripcion)
Salida:
Adorno
Jarrón de porcelana con dibujos
De momento tenemos algo que podría servirnos, pero no tiene mucho sentido
mezclar tantos atributos tan diferentes como isbn y productor. Además, al crear
un producto de cualquier tipo tendremos que recorrer y establecer valor a
todos los atributos. Esto es poco eficiente, por lo que necesitaremos
establecer de alguna manera una jerarquía y poner orden. La herencia de
clases nos puede servir en estos casos, para ello tendremos que dividir el
código en una Superclase y diferentes Subclases. En una Superclase
agrupamos todos los atributos que sean comunes para todos los productos,
por ejemplo en la clase Producto:
class Producto:
def __init__(self, referencia, nombre, pvp, descripcion):
self.referencia = referencia
self.nombre = nombre
self.pvp = pvp
self.descripcion = descripcion
A esta clase Producto podemos añadirle el método especial __str__() para que
devuelva una descripción del producto, por ejemplo:
41
def __str__(self):
return f"""\
REFERENCIA\t{self.referencia}
NOMBRE\t\t{self.nombre}
PVP\t\t{self.pvp}
DESCRIPCIÓN\t{self.descripcion}"""
class Adorno(Producto):
pass
Salida:
REFERENCIA 00000
NOMBRE Jarrón
PVP 15.5
DESCRIPCIÓN Jarrón de porcelana con dibujos
class Alimento(Producto):
productor = ''
distribuidor = ''
42
Añadimos valor a sus dos atributos e imprimimos el objeto:
print(al)
Salida:
REFERENCIA 00001
NOMBRE Aceite de Oliva
PVP 5
DESCRIPCIÓN Botella de aceite de oliva virgen extra
Si nos fijamos bien se imprimen solo los datos que se indican en la función
especial __str__() de la clase madre Producto, y este método especial no
incluye los atributos propios de cada subclase. Para solucionar esto podremos
redefinir el método especial __str__() en cada subclase, por ejemplo en el
caso de la subclase Alimento lo haríamos de la siguiente manera:
def __str__(self):
return f"""\
REFERENCIA\t{self.referencia}
NOMBRE\t\t{self.nombre}
PVP\t\t{self.pvp}
DESCRIPCIÓN\t{self.descripcion}
PRODUCTOR\t{self.productor}
DISTRIBUIDOR\t{self.distribuidor}"""
REFERENCIA 00001
NOMBRE Aceite de Oliva
PVP 5
DESCRIPCIÓN Botella de aceite de oliva virgen extra
PRODUCTOR La aceitera
DISTRIBUIDOR Distribuciones S.A.
class Libro(Producto):
isbn = ''
autor = ''
def __str__(self):
43
return f"""\
REFERENCIA\t{self.referencia}
NOMBRE\t\t{self.nombre}
PVP\t\t{self.pvp}
DESCRIPCIÓN\t{self.descripcion}
PRODUCTOR\t{self.isbn}
AUTOR\t{self.autor}"""
Salida:
REFERENCIA 00002
NOMBRE El enemigo conoce el sistema
PVP 17.9
DESCRIPCIÓN Libro sobre redes de híper vigilancia
PRODUCTOR 8417636390
AUTOR Marta Peirano
Para que el estudio de estos métodos sea más ágil y eficaz trabajaremos
desde la consola de Python en vez de escribir los ejemplos en un archivo y
ejecutar el programa desde PyCharm. De este modo se podrá experimentar en
tiempo real lo que sucede con los datos y al invocar los métodos que vayamos
utilizando.
Para acceder a la consola de Python basta con abrir un terminal (“Símbolo del
sistema” en Windows o “Terminal” en Mac y GNU/Linux) y escribir
simplemente python3, por ejemplo:
python3
Python 3.8.10 (default, Jun 22 2022, 20:18:18)
Type "help", "copyright", "credits" or "license" for more information.
>>>
44
Tras los tres carácteres >>> ya podemos empezar a escribir código Python. Si
quisiéramos salir bastaría con escribir el método exit() y pulsar intro:
>>> exit()
45
>>> 'Hola mundo mundo mundo'.rfind('mundo')
17
>>> c = '100'
>>> c.isdigit()
True
>>> c = 'abcd1234'
>>> c.isalnum()
True
>>> c = 'abcd'
>>> c.isalpha()
True
Aquí podemos ver cómo devuelve un valor False porque el carácter “espacio”
que hay entre la palabra Hola y mundo no es una letra.
46
>>> c = ' '
>>> c.isspace()
True
>>> c.endswith('o')
True
>>> c.endswith('mundo')
True
Separar una cadena en una lista de subcadenas a partir un caracter que haga
de delimitador, por ejemplo el espacio:
>>> c ='aaa;bbb;ccc'
>>> c.split(';')
['aaa', 'bbb', 'ccc']
>>> ','.join(c)
'H,o,l,a, ,m,u,n,d,o'
>>> '_'.join(c)
'H_o_l_a_ _m_u_n_d_o'
47
>>> c.strip('-')
'Hola mundo'
Métodos en listas
Añadir elementos a una lista:
>>> l = [1, 2, 3]
>>> l.append(4)
>>> l
[1, 2, 3, 4]
>>> l = [1, 2, 3]
>>> l.clear()
>>> l
[]
>>> l1 = [1, 2, 3]
>>> l2 = [4, 5, 6]
>>> l1.extend(l2)
>>> l1
[1, 2, 3, 4, 5, 6]
48
Mostrar la posición del índice en la que aparece por primera vez un elemento
en una lista.
>>> l = [1, 2, 3, 4, 5]
>>> l.reverse()
>>> l
[5, 4, 3, 2, 1]
>>> l = ['uno', 'dos', 'tres']
>>> l.reverse()
>>> l
['tres', 'dos', 'uno']
49
Ordenar elementos de una lista:
Métodos en conjuntos
Añadir elementos a un conjunto:
>>> c = set()
>>> c.add(1)
>>> c.add(2)
>>> c.add(3)
>>> c
{1, 2, 3}
>>> c = {1, 2, 3}
>>> c
{1, 2, 3}
>>> c.discard(2)
>>> c
{1, 3}
>>> c = {'uno', 'dos', 'tres'}
>>> c
{'dos', 'uno', 'tres'}
>>> c.discard('dos')
>>> c
{'uno', 'tres'}
>>> c1 = {1, 2, 3}
>>> c2 = c1.copy()
>>> c2.discard(2)
>>> c1
{1, 2, 3}
>>> c2
{1, 3}
50
método copy() del módulo copy que importamos para hacer copias de objetos
de clases.
Vaciar o eliminar por completo todos los elementos de un conjunto:
>>> c = {1, 2, 3}
>>> c {1, 2, 3}
>>> c.clear()
>>> c
set()
>>> c1 = {1, 2, 3}
>>> c2 = {3, 4, 5}
>>> c3 = {-1, 99}
>>> c1.isdisjoint(c2)
False
>>> c1.isdisjoint(c3)
True
>>> c1 = {1, 2, 3}
>>> c2 = {1, 2, 3, 4}
>>> c1.issubset(c2)
True
>>> c1 = {1, 2, 3}
>>> c2 = {1, 2, 3, 4}
>>> c2.issuperset(c1)
True
>>> c1 = {1, 2, 3, 4, 5}
>>> c2 = {3, 4, 5, 6, 7}
>>> c1.union(c2)
{1, 2, 3, 4, 5, 6, 7}
Pero esto no actualiza el valor de ningún conjunto, solo muestra por pantalla el
resultado de la unión. Si vemos lo que contienen los conjuntos c1 y c2 veremos
que no han mutado:
>>> c1
{1, 2, 3, 4, 5}
>>> c2
51
{3, 4, 5, 6, 7}
Para que se actualice el valor del primer conjunto con la unión de ambos
conjuntos como valor se ha de usar el método update() de la siguiente manera:
>>> c1 = {1, 2, 3, 4, 5}
>>> c2 = {3, 4, 5, 6, 7}
>>> c1.update(c2)
>>> c1
{1, 2, 3, 4, 5, 6, 7}
Encontrar elementos que no son comunes o que son distintos entre dos
conjuntos:
>>> c1 = {1, 2, 3}
>>> c2 = {3, 4, 5}
>>> c1.difference(c2)
{1, 2}
>>> c2.difference(c1)
{4, 5}
>>> c1 = {1, 2, 3}
>>> c2 = {3, 4, 5}
>>> c1.difference_update(c2)
>>> c1
{1, 2}
>>> c1 = {1, 2, 3}
>>> c2 = {3, 4, 5}
>>> c1.intersection(c2)
{3}
Al igual que antes con el método difference() este solo devuelve un resultado,
pero no actualiza el valor de ningún conjunto:
>>> c1 {1, 2, 3}
>>> c2 {3, 4, 5}
>>> c1 = {1, 2, 3}
>>> c2 = {3, 4, 5}
>>> c1.intersection_update(c2)
52
>>> c1
{3}
Métodos en diccionarios
Obtener un valor por defecto cuando queremos acceder a una clave que no
existe en un diccionario:
53
Vaciar o eliminar todos los elementos de un diccionario:
Módulos y paquetes
Los módulos son archivos que contienen definiciones y declaraciones en
lenguaje Python. De esta manera es posible importarlos en otros scripts o
programas y reutilizar estas funcionalidades y a la vez conseguiremos crear
una jerarquía mucho más práctica en nuestros proyectos conteniendo los
módulos en paquetes.
Módulos
Vamos a crear un módulo que tendrá la única funcionalidad de saludar
mediante un mensaje por pantalla. Para ello crearemos un archivo
llamado saludos.py con la siguiente función:
def saludar():
print('Hola, te estoy saludando desde la función saludar del módulo
saludos')
import saludos
Una vez que ya tenemos importado el módulo saludos ya podemos hacer uso
de sus funciones, pero no podemos hacerlo del mismo modo que cuando
teníamos funciones definidas en nuestro archivo principal, en estos casos hay
que hacerlo anteponiendo el nombre del módulo y un punto (.), por ejemplo:
saludos.saludar()
54
Si ejecutamos nuestros programa test.py obtendremos la siguiente salida por
pantalla:
Para no tener que anteponer el nombre del módulo cada vez que queramos
invocar a una de sus funciones se puede importar la función o funciones
concretas de un módulo de la siguiente manera:
saludar()
Salida:
class Saludo():
def __init__(self):
print('Hola, te estoy saludando desde el __init__() de la clase
Saludo')
import saludos
saludos.Saludo()
Salida:
También podríamos importar solo la clase Saludo tal y como hemos visto antes:
55
Saludo()
Salida:
Collections
l = [1, 2, 4, 3, 3, 5, 1, 3, 1, 1, 6]
print(Counter(l))
Salida:
Counter({1: 4, 3: 3, 2: 1, 4: 1, 5: 1, 6: 1})
Otro ejemplo en el uso de la colección Counter es contar las veces que aparece
un carácter en una cadena de caracteres o string:
p = 'Hola mundo!'
print(Counter(p))
Salida:
Counter({'o': 2, 'H': 1, 'l': 1, 'a': 1, ' ': 1, 'm': 1, 'u': 1, 'n': 1, 'd':
1, '!': 1})
En este caso el programa nos dice que el carácter 'o' aparece dos veces, el
carácter 'H' una vez, el caracter 'l' una vez, etc.
56
Podría darse el caso en el que tenemos una cadena de caracteres con una
varias palabras separadas por un espacio, por ejemplo:
En este caso queremos saber cuántas veces aparece cada palabra, pero hay
que precisar que esto no es una lista de palabras, sino una cadena de
carácteres. Para resolverlo primero podemos pasar esta cadena de caracteres
compuesta de palabras separadas por espacio a una lista, y para ello
podemos usar la función integrada split(), al que si no le pasamos ningún
argumento tomará el carácter espacio por defecto:
print(s.split())
Salida:
print(Counter(s.split()))
Salida:
n = [10, 20, 30, 40, 10, 20, 30, 10, 20, 10]
c = Counter(n)
print(c.most_common(1))
Salida:
[(10, 4)]
Nos dice que el elemento más común es el número 10, que aparece cuatro
veces. Si a la función integrada most_common() le pasamos como argumento el
número 2 nos devolverá los dos elementos más comunes:
57
print(c.most_common(2))
Salida:
print(OrderedDict(d))
Salida:
print(d1 == d2)
print(OrderedDict(d1) == OrderedDict(d2))
Salida:
True
False
Datetime
Uno de los módulos más interesantes sin duda es datetime, que nos servirá
para manejar y trabajar con información relacionada con las fechas. Para
trabajar sobre este punto vamos a crear un nuevo archivo
llamado test_datetime.py y vamos a comenzar importando este módulo de la
siguiente manera:
import datetime
58
Ahora vamos a crear un objeto de tipo datetime en el que haremos uso del
subpaquete datetime y su método now():
dt = datetime.datetime.now()
print(dt)
Salida:
2022-10-11 14:10:50.879112
print(dt.year)
print(dt.month)
print(dt.day)
print(dt.hour)
print(dt.minute)
print(dt.second)
print(dt.microsecond)
Salida:
2022
10
11
14
25
45
315492
Ahora que ya sabemos cómo podemos acceder a cada uno de los elementos
de los que se compone una fecha y hora podremos darle el formato que se
prefiera, por ejemplo:
print(f'{dt.year}/{dt.month}/{dt.day}')
print(f'{dt.hour}:{dt.minute}:{dt.second}.{dt.microsecond}')
Salida:
dt = datetime.datetime(2000, 1, 1, 0, 0)
59
print(dt)
Salida:
2000-01-01 00:00:00
dt.year = 3000
Salida:
dt = dt.replace(year=3000)
print(dt)
Salida:
3000-01-01 00:00:00
dt = datetime.datetime.now()
print(dt.isoformat())
Salida:
2022-10-11T19:46:08.409881
print(dt.strftime('%A %d %B %Y %I:%M'))
60
Salida:
import locale
locale.setlocale(locale.LC_ALL, 'es_ES')
locale.setlocale(locale.LC_ALL, 'zh_CN')
python3 test_datetime.py
星期一 11 十月 2022 20:01
Math
El módulo math integra una serie de funciones y métodos que nos servirán para
realizar algunas operaciones matemáticas de forma más sencilla. Al igual que
otros módulos será necesario importarlo al inicio de nuestro código, así que
vamos a hacerlo en un nuevo archivo llamado test_math.py:
import math
print(round(1.4))
Salida:
61
1
print(round(1.5))
Salida:
Gracias al método floor() del módulo math podremos forzar que el redondeo
sea siempre a la baja, por ejemplo:
print(math.floor(1.3))
print(math.floor(1.5))
print(math.floor(1.9))
Salida:
1
1
1
print(math.ceil(1.00001))
print(math.ceil(1.3))
print(math.ceil(1.8))
Salida:
2
2
2
numeros = [1, 2, 3, 4, 5]
print(math.fsum(numeros))
Salida:
62
15.0
Si bien es cierto que existe un método integrado de Python llamado sum() que
ya hace un sumatorio de una lista de números, esta no es igual de eficaz, ya
que si se suman números enteros y flotantes tiene un comportamiento extraño,
por ejemplo:
numeros = [0.9999999, 1, 2, 3]
print(sum(numeros))
print(math.fsum(numeros))
Salida:
6.999999900000001
6.9999999
print(math.trunc(3.14159265359))
Salida:
print(math.pow(2, 3))
print(math.pow(5, 4))
python3 test_math.py
8.0
625.0
También tenemos el método sqrt() que nos permitirá realizar raíces cuadradas,
por ejemplo:
print(math.sqrt(9))
63
Salida:
3.0
Además de métodos también tiene algunos atributos como las constantes del
número pi o el número e:
print(math.pi)
print(math.e)
Salida:
3.141592653589793
2.718281828459045
Random
import random
print(random.random())
print(random.random())
print(random.random())
Salida:
0.06823749155608883
0.9070119606268106
0.4445508707984924
64
que pasar estos dos números como argumentos, por ejemplo números random
entre uno y diez:
print(random.uniform(1, 10))
print(random.uniform(1, 10))
print(random.uniform(1, 10))
Salida:
2.382198826548743
4.8697236381240865
3.8781201434396864
print(random.randrange(10))
print(random.randrange(10))
print(random.randrange(10))
Salida:
8
1
4
También podemos pasarle dos números como argumentos para que devuelva
un número aleatorio entre esos números, por ejemplo:
print(random.randrange(0, 100))
print(random.randrange(0, 100))
print(random.randrange(0, 100))
Salida:
95
52
91
Salida:
65
94
46
32
print(random.choice(cadena))
print(random.choice(cadena))
print(random.choice(cadena))
Salida:
n
u
o
El método choice() también nos vale para listas, en este caso se obtendría de
forma aleatoria cualquiera de los elementos de la lista, por ejemplo:
lista = [1, 2, 3, 4, 5]
print(random.choice(lista))
print(random.choice(lista))
print(random.choice(lista))
Salida:
4
5
3
lista = [1, 2, 3, 4, 5]
print(lista)
random.shuffle(lista)
print(lista)
66
Salida:
[1, 2, 3, 4, 5]
[3, 4, 1, 2, 5]
lista = [1, 2, 3, 4, 5]
print(random.sample(lista, 3))
print(random.sample(lista, 3))
print(random.sample(lista, 3))
Salida:
[4, 5, 1]
[4, 2, 5]
[3, 4, 2]
Paquetes
Utilizar paquetes nos ofrece varias ventajas. En primer lugar nos permite
unificar distintos módulos bajo un mismo número de paquetes. Así podemos
utilizar jerarquías de módulos o submódulos y también subpaquetes. Por otra
parte nos permiten distribuir y manejar fácilmente nuestro código como si
fueran librerías instalables de Python. De este modo se pueden utilizar como
módulos standard desde el intérprete sin cargarlos previamente.
Para crear un paquete primero vamos a crear un nuevo directorio que tendrá
por nombre el nombre del paquete, en este ejemplo lo llamaremos
simplemente paquete. Dentro de este nuevo directorio vamos a crear un nuevo
archivo llamado __init__.py sin ningún contenido, el archivo vacío. Por último
vamos a copiar dentro del directorio paquete el archivo saludos.py que hicimos
anteriormente.
67
from paquete.saludos import *
saludar()
Saludo()
Salida:
Manejo de ficheros
Hasta ahora todo lo que hemos visto son pequeños programas o scripts que
funcionan almacenando información como variables, constantes u objetos en
tiempo de ejecución, es decir, que solo existen mientras el programa se está
ejecutando. Pero hemos llegado a un punto en el que probablemente nos
interese almacenar algunos de los datos con los que hemos aprendido a
trabajar en algún fichero, de modo que al cerrar o apagar el programa estos
queden persistentemente en un archivo que luego podría volver a cargarse al
ejecutar el programa de nuevo, de ese modo no se perdería la información.
● Creación
● Apertura o lectura
● Modificación
● Cierre
Creación
68
necesario crear una nuevo archivo llamado test_ficheros.py con el siguiente
código:
fichero.write(texto)
fichero.close()
En este ejemplo hemos creado una variable llamada texto con el las líneas de
texto que vamos a escribir en el fichero, y otra variable llamada fichero a la que
le hemos asignado como valor un objeto de tipo open() al que le hemos
pasado dos argumentos, el primero es el nombre del fichero con el que vamos
a trabajar, y el segundo argumento es la modalidad que vamos a utilizar, que
en este caso es w de escritura en inglés (write). Esta modalidad creará el
archivo si no existe y escribirá el texto dentro. Si el archivo existiera lo
sobrescribirá.
Apertura o lectura
Con esta modalidad 'r' estaríamos abriendo el fichero en modo lectura (read).
Ahora podríamos almacenar en una variable llamada texto el contenido del
fichero, cerrar el fichero e imprimir el contenido de la variable texto de la
siguiente manera:
texto = fichero.read()
fichero.close()
69
print(texto)
Salida:
Una manera de leer un archivo línea a línea es almacenando cada línea en una
lista. Esto se puede hacer con un método llamado readlines() que tienen los
objetos de tipo archivo, por ejemplo:
print(lineas)
fichero.close()
Salida:
Modificación
Esta modalidad no solo sirve para añadir líneas al final del archivo, si no que
también lo crea si este no existe. Si abrimos el fichero fichero.txt veremos que
ha añadido al final de este una nueva línea con un texto.
70
for linea in fichero:
print(linea.rstrip('\n'))
Salida:
fichero.seek(10)
texto = fichero.read()
fichero.close()
print(texto)
Salida:
a línea de texto.
Y esta es otra línea de texto.
Esta es una línea nueva.
El propio método read() que usamos para leer el contenido del fichero desde la
posición del fichero también tiene la posibilidad de recibir un argumento para
indicarle el número de carácteres que queremos leer o desplazar el puntero,
por ejemplo:
fichero.close()
print(texto)
Salida:
71
Esta e
Existe una modalidad que nos permite leer el archivo y además escribir en él,
pero ubicando el puntero en la primera posición, esta modalidad se define
mediante 'r+' de la siguiente manera:
texto = fichero.read()
fichero.close()
print(texto)
fichero.seek(0)
fichero.writelines(lineas)
fichero.seek(0)
texto = fichero.read()
fichero.close()
print(texto)
72
Ficheros y objetos con pickle
Pickle es un módulo de Python que nos permite trabajar con ficheros binarios
en los que podremos guardar objetos y estructuras de datos complejas como
colecciones, y luego poder recuperarlos para trabajar con ellos. Lo primero que
hay que hacer para comenzar a utilizarlo es importar el módulo pickle en un
nuevo archivo llamado test_pickle.py:
import pickle
A continuación crearemos una lista con unos números y al igual que antes
creamos una variable llamada fichero que tendrá por valor el objeto de un
fichero abierto al que llamaremos lista.bin y lo haremos en modalidad de
escritura binaria 'wb', por ejemplo:
lista = [1, 2, 3, 4, 5]
pickle.dump(lista, fichero)
fichero.close()
lista = pickle.load(fichero)
fichero.close()
print(lista)
73
Salida:
[1, 2, 3, 4, 5]
Pandas
Pandas es una librería de Python creada específicamente para el análisis de
datos. Tiene un elemento clave denominada Dataframe, que no es más que
una serie de datos en una tabla donde podremos ver los registros en filas y
columnas ordenados por un índice. Cada una de las columnas puede tener un
tipo de dato diferente, por ejemplo datos de tipo entero, float, strings, objetos,
etc.
Instalación de Pandas
23. Para instalar Pandas desde PyCharm hacemos click sobre “Python
3.10”, que aparece en la esquina inferior derecha de la ventana.
74
listados los paquetes que actualmente tenemos instalados y sus
versiones.
25. Para instalar un paquete nuevo hemos de hacer click sobre el botón “+”
tal y como se muestra en la siguiente imagen:
75
27. Cuando se termine de instalar deberemos ver un mensaje que dice
“Package ‘pandas’ installed successfully” tal y como se muestra en la
siguiente imagen. Podemos cerrar esta ventana:
76
28. Ahora que volvemos a la ventana anterior, podemos ver que se han
instalado con éxito varios paquetes, además del paquete “pandas”. Esto
sucede porque existen dependencias entre paquetes y cuando instalas
uno muy concreto se suelen instalar otros adicionales necesarios para
que todo funcione correctamente. Finalmente pulsamos el botón “OK”.
Importación de Pandas
import pandas as pd
df = pd.read_csv(
77
r'file.csv',
index_col=0,
nrows=5,
encoding='ISO-8859-1',
delimiter=';'
)
df = pd.read_csv(
r'datasets/Info_pais.csv',
encoding='ISO-8859-1',
delimiter=';',
decimal=','
)
df.head()
print(df.head())
78
A este método head() se le puede indicar dentro de los paréntesis el número de
registros que se quieren mostrar, por ejemplo para mostrar solo los 10 primeros
registros se haría de la siguiente manera:
df.head(10)
df_order = df.sort_values(
'Esperanza de vida',
ascending=True
79
)
Instalación de Matplotlib
29. Para instalar Matplotlib desde PyCharm hacemos click sobre “Python
3.10”, que aparece en la esquina inferior derecha de la ventana.
80
listados los paquetes que actualmente tenemos instalados y sus
versiones.
31. Para instalar un paquete nuevo hemos de hacer click sobre el botón “+”
tal y como se muestra en la siguiente imagen:
81
33. La instalación de Matplotlib puede demorar un poco más de tiempo,
pues tiene bastantes dependencias. Cuando se termine de instalar
deberemos ver un mensaje que dice “Package ‘matplotlib’ installed
successfully” tal y como se muestra en la siguiente imagen. Podemos
cerrar esta ventana:
82
34. Ahora que volvemos a la ventana anterior, podemos ver que se han
instalado con éxito varios paquetes, además del paquete “matplotlib”.
Esto sucede porque existen dependencias entre paquetes y cuando
instalas uno muy concreto se suelen instalar otros adicionales
necesarios para que todo funcione correctamente. Finalmente pulsamos
el botón “OK”.
83
Visualización con Matplotlib
A partir de este momento podremos utilizar en nuestro código el alias plt para
acceder a todos los métodos de esta librería. Veamos un ejemplo en el que
cargaremos un array de datos para el eje x, llamado por ejemplo year, y otro
array de datos para el eje y, llamado por ejemplo value:
84
primero el array de datos que queremos utilizar en el eje x y segundo el array
que usaremos para el eje y:
plt.plot(year, value)
plt.show()
Si quisiéramos generar otro tipo de gráfico con los mismos datos podríamos
utilizar por ejemplo el método scatter() al que también hay que pasarle como
argumentos los datos de los ejes x e y:
plt.scatter(year, value)
85
Esta sería una manera de crear gráficos muy sencillos a partir de un par de
listas con datos, pero normalmente se suelen utilizar fuentes de datos más
grandes y complejas como son los dataframes que hemos visto anteriormente.
Para visualizar con la librería matplotlib la información de un dataframe
podemos hacerlo de la siguiente manera. Primero importamos el dataframe, en
este caso uno llamado hum_temp.csv con algunos datos random relativos a
humedad y temperatura:
df = pd.read_csv(
r'../datasets/hum_temp.csv',
encoding='ISO-8859-1',
delimiter=';'
)
df
86
A continuación usamos el método plot() de la instancia plt al que le
pasaremos el nombre del dataframe, en este caso df y entre corchetes el
nombre de la columna que queremos utilizar para representarlo en el eje y, si
no se especifica el eje x en este se utilizarán los valores del índice de los
registros de datos:
plt.plot(df['temperature'])
Veamos una manera mejor de representar los datos de este dataframe, en este
caso usaremos el método plot() con el dataframe df de la siguiente manera:
df['humidity'].plot()
87
Si eliminamos el nombre de la columna entre corchetes y especificamos
únicamente el nombre del dataframe df podremos ver en el mismo gráfico
todos los registros de cada columna en líneas diferentes, cada una con un color
distinto.
df.plot()
88
Ejemplo Standard & Poor's 500
Veamos otro ejemplo en el que vamos a trabajar con otro dataset. En este caso
vamos a ver la evolución de la cotización de un índice bursátil como el
“Standard & Poor's 500”.
df_sp500 = pd.read_csv(
r'../datasets/SP500_data.csv',
encoding='ISO-8859-1',
delimiter=','
)
df_sp500.head()
Ahora vamos a representar la columna del cierre bursátil de cada día, columna
Close:
df_sp500['Close'].plot()
89
En este gráfico podremos ver la evolución del índice bursátil, pero si nos
fijamos en el eje x ha representado el índice de cada registro. Para poder
representar en el eje x la fecha del dato debemos especificar que el índice del
dataframe df_sp500 ha de ser la columna Date, de la siguiente forma:
df_sp500.index = df_sp500['Date']
df_sp500.head()
df_sp500['Close'].plot()
90
Ahora vemos que en el eje x se representan los valores del campo o columna
Date.
En este otro ejemplo vamos a trabajar con un dataset que he obtenido de este
site. Se tratan de los casos detectados de COVID-19 por comunidades
autónomas en España.
df_covid19_ccaas = pd.read_csv(
r'../datasets/datos_ccaas.csv',
encoding='ISO-8859-1',
delimiter=','
)
df_covid19_ccaas.head()
91
Estableceremos tal y como hemos visto en el ejemplo anterior el campo fecha
como índice y los datos de la columna num_casos en el eje y de la siguiente
manera:
df_covid19_ccaas.index = df_covid19_ccaas['fecha']
df_covid19_ccaas['num_casos'].plot()
df = pd.read_csv(
r'datasets/Info_pais.csv',
encoding='ISO-8859-1',
92
delimiter=';',
decimal=','
)
df_order = df.sort_values(
'Poblacion',
ascending=False
)
df_order.head()
93
De momento se aprecia un gráfico que nos da una idea aproximada de cómo
se ven los datos. Podemos añadir un título y etiquetas a los ejes x e y del
gráfico de la siguiente manera:
plt.scatter(
df_order['Renta per capita'],
df_order['Esperanza de vida']
)
plt.title('Renta per cápita vs Esperanza de vida')
plt.xlabel('Renta per cápita')
plt.ylabel('Esperanza de vida');
df_order['Poblacion_normalizada'] =
df_order['Poblacion']/max(df_order['Poblacion'])
Así, el país que tenga la población más alta quedaría escalado a 1 y el resto de
países quedarían normalizados en base a este valor máximo.
94
Para evitar que un país con esta gran cantidad de habitantes inunde el gráfico
es recomendable que en vez de dividir la población de cada país entre el
máximo de población, hacer la división del máximo entre 10000, para no tener
un factor tan elevado.
df_order['Poblacion_normalizada'] =
df_order['Poblacion']/(max(df_order['Poblacion'])/10000)
df_order.head()
Ahora podremos usar esta nueva columna con los datos escalados para crear
una visualización de los datos mucho más potente.
plt.scatter(
df_order['Renta per capita'],
df_order['Esperanza de vida'],
s=df_order['Poblacion_normalizada']
)
plt.title('Renta per cápita vs Esperanza de vida')
plt.xlabel('Renta per capita')
plt.ylabel('Esperanza de vida');
95
El problema que vemos es que la visualización es muy pequeña, pero podemos
mejorar esto añadiendo a nuestro código lo siguiente para aumentar las
pulgadas de nuestro gráfico:
plt.scatter(
df_order['Renta per capita'],
df_order['Esperanza de vida'],
s=df_order['Poblacion_normalizada']
)
plt.title('Renta per cápita vs Esperanza de vida')
plt.xlabel('Renta per cápita')
plt.ylabel('Esperanza de vida')
fig = plt.gcf()
fig.set_size_inches(14.5, 10);
96
De este modo se ve mucho más grande. Si fuera necesario se pueden cambiar
los valores de la función set_size_inches() por otros más adecuados para
ajustar el tamaño.
Ahora vamos a modificar el color. Para ello debemos añadir el atributo c (color),
a continuación del atributo s (size), y como valor vamos a usar de nuevo la
columna Poblacion_normalizada. Quedaría del siguiente modo:
plt.scatter(
df_order['Renta per capita'],
df_order['Esperanza de vida'],
s=df_order['Poblacion_normalizada'],
c=df_order['Poblacion_normalizada']
)
plt.title('Renta per cápita vs Esperanza de vida')
plt.xlabel('Renta per cápita')
plt.ylabel('Esperanza de vida')
fig = plt.gcf()
97
fig.set_size_inches(14.5, 10);
También podremos añadir la etiqueta del nombre del país dentro de cada
burbuja utilizando el método annotate(), por ejemplo añadiendolo solo a los 10
primeros países con mayor población, pero antes es necesario arreglar los
índices utilizando el método reset_index y pasándole los parámetros drop con
valor True y inplace con valor True también. A continuación el código:
plt.scatter(
df_order['Renta per capita'],
df_order['Esperanza de vida'],
s=df_order['Poblacion_normalizada'],
c=df_order['Poblacion_normalizada']
)
plt.title('Renta per cápita vs Esperanza de vida')
plt.xlabel('Renta per cápita')
plt.ylabel('Esperanza de vida')
fig = plt.gcf()
fig.set_size_inches(14.5, 10);
98
df_order.reset_index(drop=True, inplace=True)
Por último, podemos añadir en la generación del scatter una propiedad llamada
alpha con valor 0.5 para añadir transparencia a los círculos, así podremos ver
los datos que se puedan ocultar a sobreponerse unos encima de otros.
plt.scatter(
df_order['Renta per capita'],
df_order['Esperanza de vida'],
s=df_order['Poblacion_normalizada'],
c=df_order['Poblacion_normalizada'],
alpha=0.5
)
plt.title('Renta per cápita vs Esperanza de vida')
99
plt.xlabel('Renta per cápita')
plt.ylabel('Esperanza de vida')
fig = plt.gcf()
fig.set_size_inches(14.5, 10);
df_order.reset_index(drop=True, inplace=True)
De este modo hemos creado una visualización de los datos muy potente y de
una manera muy sencilla. La conclusión que podemos sacar de este gráfico es
que efectivamente existe una correlación entre la renta per cápita y la
esperanza de vida según el país. Podemos ver que conforme la renta per
cápita aumenta la esperanza de vida también aumenta. También podemos
deducir que el número de población no afecta a la esperanza de vida, ya que
en la visualización que hemos creado se pueden ver países con una gran
100
cantidad de población que no están entre los valores más bajos en cuanto a
esperanza de vida se refiere.
NumPy
NumPy es una librería de Python enfocada en el cálculo numérico que nos
permite realizar operaciones de una manera sencilla y rápida. Su objeto base
es un vector de números denominado Array. Es una alternativa a las listas que
hemos visto hasta ahora y nos va a permitir realizar una serie de funciones muy
potentes. A diferencia de las listas, donde se opera de forma independiente en
cada uno de los elementos, en los Arrays las operaciones se van a realizar
sobre todo el Array simultáneamente.
Importación de NumPy
import numpy as np
a = [1, 2, 3]
b = [4, 5, 6]
a + b
Salida:
[1, 2, 3, 4, 5, 6]
a = np.array([1, 2, 3])
101
b = np.array([4, 5, 6])
a + b
Salida:
array([5, 7, 9])
En este caso se han sumado cada uno de los elementos del Array a con los
elementos del array b.
Otra gran diferencia respecto a las listas tradicionales es que en un Array solo
se admite un tipo de dato, normalmente numérico. Además NumPy nos va a
servir como base de cálculo para otras librerías como Pandas o SciKit Learn.
En este ejemplo vamos a calcular el índice de masa corporal sobre los valores
peso y altura de tres personas.
El cálculo que hay que hacer para obtener el IMC es dividir el peso entre el
cuadrado de la altura:
peso / altura**2
Salida:
El cálculo está bien hecho, pero de este modo es más complicado, entre otras
cosas porque el cálculo se va haciendo secuencialmente elemento a elemento
entre las listas, y en este caso no es mucho problema ya que son listas de solo
102
3 elementos, pero podría ser un problema al trabajar con listas de miles de
elementos. Se realizar el mismo cálculo de una manera mucho más eficiente
usando los Arrays de NumPy, veamos el ejemplo:
Salida:
Además este tipo de objetos Array de NumPy son iterables del mismo modo
que lo son algunas colecciones estándar de Python como las listas, tienen
algunas propiedades como los slices que nos permiten navegar dentro del
Array y acceder a determinados elementos ubicados en ciertas posiciones.
Otro uso interesante de los Arrays es que podemos evaluar todos los
elementos del Array con una simple operación, como por ejemplo saber qué
valores son mayores que 21:
imc > 21
Salida:
En este caso el primer resultado es True puesto que se cumple que 23.183391
es mayor que 21, el segundo es False porque 20.2020202 no es mayor que 21 y
el tercero es True puesto que 21.73650525 si es mayor que 21.
Si quisiéramos obtener solo los elementos del array que cumplen la condición
anterior podremos hacerlo de la siguiente manera:
Salida:
array([23.183391 , 21.73650525])
103
Ejemplo cálculo áreas de triángulos
base * altura / 2
Salida:
Como solo nos interesan las áreas que son > 6.5 podremos obtener los valores
que cumplan la condición de la siguiente manera:
Salida:
104
Salida:
array([6.71 , 7.37625])
nombre_array = np.array([[valores_fila_1],
[valores_fila_2],
[valores_fila_m]])
Salida:
array([[ 2, 7, 8],
[ 4, 8, 10]])
105
Si quisiéramos obtener el valor 10 de nuestro array de dos dimensiones
tendríamos que especificar el índice de la fila seguido del índice de la columna,
teniendo en cuenta que los índices siempre empiezan por el número 0. En este
ejemplo el valor 10 se encuentra en la fila con índice 1 y la columna con índice
2.
a[1, 2]
Salida:
10
Ahora supongamos que queremos obtener todas las filas pero solo los valores
de las columnas primera y segunda. En este caso tendríamos que especificar
en primer lugar que queremos todas las filas mediante los dos puntos :, y a
continuación un slice 0:2 para indicar solo las columnas desde el índice 0 hasta
el 1, ya que en un slice el número que se indica al final no se muestra, es
donde se para.
a[:, 0:2]
Salida:
array([[2, 7],
[4, 8]])
Para realizar cálculo estadístico NumPy nos ofrece una gran variedad de
funciones muy útiles y potentes. En esta sección veremos algunas de ellas que
nos pueden servir para solucionar algunos cálculos que hemos visto en puntos
anteriores de una manera mucho más sencilla y rápida.
Por ejemplo, supongamos que tenemos el siguiente Array con varios registros
de temperaturas de una ciudad:
temperaturas = np.array([12, 13.5, 13, 14, 13.2, 14.8, 15, 15.16, 16, 16.2,
15.7, 17, 17.2, 16.8, 14, 14.2, 14.7, 16, 17.5])
106
Podríamos calcular la media o promedio usando la función mean(array) de la
siguiente manera:
np.mean(temperaturas)
Salida:
15.050526315789472
np.median(temperaturas)
Salida:
15.0
np.min(temperaturas)
Salida:
12.0
np.max(temperaturas)
Salida:
17.5
np.var(temperaturas)
107
Salida:
2.2893207756232683
np.std(temperaturas)
Salida:
1.5130501563475245
np.percentile(temperaturas, 90)
Salida:
17.04
Una cualidad de NumPy muy interesante es que nos permite generar datos
random tomando como partida diferentes parámetros estadísticos, como por
ejemplo una media y una desviación estándar, y generar un Array de valores
con dicha distribución estadística. La función es random.normal() necesita que le
pasemos como argumentos una media, la desviación estándar y un número de
muestras. Su sintaxis es la siguiente:
nombre_array = np.random.normal(
media,
desviacion_estandar,
numero_muestras
)
108
Por ejemplo, si quisiéramos
media = np.mean(array_gauss)
media
Salida:
2.00020348250122
desviacion = np.std(array_gauss)
desviacion
Salida:
0.496490256867947
plt.scatter(
array_gauss,
stats.norm.pdf(array_gauss, media, desviacion)
)
109
Bases de datos
En Python también podremos conectarnos a diferentes bases de datos, en las
que podremos realizar consultas y también podremos escribir o modificar
contenido. En este punto veremos cómo conectarnos a algunas de las más
utilizadas en la industria, como son MongoDB y SQL Server.
MongoDB
110
2. Pulsamos el botón “New Project”.
111
5. Ahora pulsamos el botón “Build a Database”.
112
7. Seleccionamos la opción “FREE Shared”.
113
9. Pulsamos el botón “Create Cluster”.
10. Tenemos que pulsar en “Username and Password” para crear los
datos de acceso.
114
12. Para poder establecer comunicación entre nuestro PC y la base de
datos MongoDB que estamos creando en la nube será necesario añadir
la dirección IP pública que estamos utilizando en este momento, así que
pulsamos el botón “Add My Current IP Address”.
115
14. Ahora pulsamos el botón “Connect”.
116
nuestra base de datos MongoDB recién creada en la nube. Podemos
copiar este fragmento de código para usarlo más adelante.
117
3. Para instalar un paquete nuevo hemos de hacer click sobre el botón “+”
tal y como se muestra en la siguiente imagen:
118
5. Cuando se termine de instalar deberemos ver un mensaje que dice
“Package ‘pymongo’ installed successfully” tal y como se muestra en la
siguiente imagen. Podemos cerrar esta ventana:
119
Conexión y creación de una base de datos MongoDB
Podremos conectarnos a MongoDB desde Python mediante el siguiente
fragmento de código.
import certifi
from pymongo import MongoClient
user = 'testuser'
password = 'testpass'
cluster = 'cluster0.h5a1riz.mongodb.net'
params = '?retryWrites=true&w=majority'
ca = certifi.where()
def get_database(database_name):
connection_string = f'mongodb+srv://{user}:{password}@{cluster}/{params}'
client = MongoClient(connection_string, tlsCAFile=ca)
return client[database_name]
if __name__ == '__main__':
database = get_database('user_shopping_list')
Los datos de las variables user, password, cluster y params los obtenemos del
último punto de la sección “Crear un nuevo proyecto Mongo en la nube” de
esta documentación.
120
Crear una colección
Para crear una colección dentro de nuestra nueva base de datos basta con
añadir la variable collection al final del código anterior, de modo que quede
así:
if __name__ == '__main__':
database = get_database('user_shopping_list')
collection = database['user_1_items']
item_1 = {
'_id': 'U1IT00001',
'item_name': 'Blender',
'max_discount': '10%',
'batch_number': 'RR450020FRG',
'price': 340,
'category': 'kitchen appliance'
}
item_2 = {
'_id': 'U1IT00002',
'item_name': 'Egg',
'category': 'food',
'quantity': 12,
'price': 36,
'item_description': 'brown country eggs'
}
collection.insert_many([item_1, item_2])
121
Ahora ya podremos ir al Dashboard de nuestra cuenta de MongoDB en la
nube, y veremos que se ha creado correctamente la base de datos, la
colección y los datos:
122
{'_id': 'U1IT00001', 'item_name': 'Blender', 'max_discount': '10%',
'batch_number': 'RR450020FRG', 'price': 340, 'category': 'kitchen
appliance'}
{'_id': 'U1IT00002', 'item_name': 'Egg', 'category': 'food', 'quantity':
12, 'price': 36, 'item_description': 'brown country eggs'}
collection.update_one(query, new_values)
En este caso hemos buscado una colección que en el campo _id tenga el valor
U1IT00002. Luego hemos establecido un nuevo valor 35 para el campo price de
este documento utilizando el método update_one() de la colección.
query = {
'_id': {'$regex': '^U1IT'}
}
123
A continuación estableceremos un nuevo valor para el campo price en todos
los documentos que devuelva la consulta anterior.
new_values = {
'$set': {
'price': 7
}
}
collection.update_many(query, new_values)
SQL Server
124
2. Tendremos que descargar en nuestro PC un archivo instalador “.exe”.
Una vez descargado lo ejecutamos. En la primera ventana
seleccionaremos la opción “Básica”.
125
5. El proceso de instalación puede demorar unos minutos.
126
6. Cuando la instalación termine pulsaremos el botón “Cerrar”.
7. Ahora debemos activar el protocolo TCP/IP del servicio SQL Server que
acabamos de instalar en nuestro PC local. Para ello, en la barra de
búsqueda de Windows escribimos “Administrador de configuración de
SQL Server” y pulsamos en “Abrir”.
127
8. Una vez abierto el Administrador de configuración de SQL Server
desplegamos el “Configurador de red de SQL Server” y pinchamos
sobre “Protocolos de MSSQLSERVER”. En la pantalla derecha hacemos
click con el botón derecho del ratón sobre “TCP/IP” y seleccionamos la
opción “Habilitar”.
128
2. Ejecutar el instalador .exe descargado. En la primera ventana
aceptamos el acuerdo de licencia.
129
4. En la siguiente ventana dejamos todo por defecto y pulsamos el botón
“Siguiente”.
130
6. Ahora pulsamos el botón “Instalar” para iniciar la instalación.
131
7. Finalmente pulsamos el botón “Finalizar”.
1. Una vez se abra Azure Data Studio crearemos una nueva conexión.
132
2. En los parámetros de conexión escribimos únicamente “localhost” en el
campo “Server” y pulsamos el botón “Connect”.
133
Crear una tabla e insertar datos en ella
Ahora es el momento de crear una tabla donde podamos añadir datos.
134
Todos los nombres y apellidos utilizados en este ejemplo son ficticios, han sido
seleccionados en base a la estadística de los nombres y apellidos más
comunes a día de hoy en España.
135
GRANT SELECT on ucmdb.dbo.alumnos to JavierDominguezGomez;
MacOS
~$ /bin/bash -c "$(curl -fsSL
https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
~$ brew tap microsoft/mssql-release
https://github.com/Microsoft/homebrew-mssql-release
~$ brew update
~$ HOMEBREW_NO_ENV_FILTERING=1 ACCEPT_EULA=Y brew install msodbcsql18
mssql-tools18
GNU/Linux
~$ sudo apt-get install odbcinst
~$ sudo curl https://packages.microsoft.com/keys/microsoft.asc | sudo
apt-key add -
~$ echo "deb [arch=amd64] https://packages.microsoft.com/ubuntu/21.10/prod
impish main" | sudo tee /etc/apt/sources.list.d/mssql-release.list
~$ sudo apt update
136
~$ sudo apt install msodbcsql18
3. Para instalar un paquete nuevo hemos de hacer click sobre el botón “+”
tal y como se muestra en la siguiente imagen:
137
4. En la barra de búsqueda escribimos “pyodbc”, y nos aparecerán varios
paquetes en los que coincide el literal que buscamos. Hemos de
seleccionar el primero, el que se llama solo “pyodbc” y pulsamos el
botón “Install Package”.
138
Conexión con la base de datos
Para conectarnos a una base de datos SQL Server desde Python podremos
hacerlo con el siguiente código de ejemplo
import pyodbc
conn = pyodbc.connect(
'Driver={SQL Server};'
'server=localhost;'
'database=ucmdb;'
'uid=JavierDominguezGomez;'
'pwd=X6jY47bL!;'
'Trusted_connection=yes;'
'autocommit=True'
)
139
localhost si la base de datos la tuviéramos en nuestro propio PC, pero si se
trata de una base de datos que se encuentra en otro servidor en internet
tendremos que poner el host seguido de una coma y el puerto en el que está
levantado el servicio, por ejemplo servidor.com,13627. Luego vendría el
parámetro database, cuyo valor es el nombre de la base de datos a la que nos
queremos conectar, en este ejemplo pondremos ucmdb. Ahora vienen los
parámetros de autenticación, es decir, el parámetro uid, y como valor
pondremos nuestro usuario de conexión, y el parámetro password con la
contraseña de conexión ligada a nuestro usuario. Obviamente las credenciales
en este ejemplo son ficticias, tendrás que utilizar el usuario y contraseña que
tengas asignado (preguntar al profesor). Finalmente añadiremos los parámetros
Trusted_connection con valor yes y autocommit con valor True.
cursor = conn.cursor()
Si ahora quisiéramos iterar o trabajar con cada uno de los registros que nos ha
devuelto la consulta anterior, podremos hacerlo con un bucle for de la
siguiente manera:
for i in cursor:
print(i)
140
('Manuel', 'Fernández')
('Carmen', 'López')
('Jose', 'Martínez')
…
Cada registro (row) es devuelto en forma de tupla, lo que nos permite trabajar
con estos datos desde Python.
Servicio web
Se puede crear un servicio web con Python de varias maneras diferentes, pero
para este ejemplo usaremos un método bastante sencillo. Únicamente
necesitamos instalar dos librerías: Flask y gunicorn.
1. Para instalar Flask desde PyCharm hacemos click sobre “Python 3.10”,
que aparece en la esquina inferior derecha de la ventana.
141
3. Para instalar un paquete nuevo hemos de hacer click sobre el botón “+”
tal y como se muestra en la siguiente imagen:
142
5. Cuando se termine de instalar deberemos ver un mensaje que dice
“Package ‘Flask’ installed successfully” tal y como se muestra en la
siguiente imagen. Podemos cerrar esta ventana:
143
6. Por último, hay que instalar el paquete “gunicorn” siguiendo los mismos
pasos que hemos realizado en la instalación del paquete “Flask”.
import json
app = Flask(__name__)
@app.route('/')
def home():
return '<h3>Hola mundo!</h3>'
144
@app.route('/alumnos')
def get_alumnos():
data = {
'centro': 'Universidad Complutense de Madrid',
'alumnos': [
{'id': '00', 'matricula': '2022QSPM', 'nombre': 'Mari Carmen',
'apellidos': 'García', 'clase': 'A'},
{'id': '01', 'matricula': '2022NDFK', 'nombre': 'Antonio',
'apellidos': 'Rodríguez', 'clase': 'A'},
{'id': '02', 'matricula': '2022KWSH', 'nombre': 'María',
'apellidos': 'González', 'clase': 'B'},
{'id': '03', 'matricula': '2022ZMLD', 'nombre': 'Manuel',
'apellidos': 'Fernández', 'clase': 'A'},
{'id': '04', 'matricula': '2022POWM', 'nombre': 'Carmen',
'apellidos': 'López', 'clase': 'A'},
{'id': '05', 'matricula': '2022LJBF', 'nombre': 'Jose',
'apellidos': 'Martínez', 'clase': 'B'},
{'id': '06', 'matricula': '2022GQKD', 'nombre': 'Ana María',
'apellidos': 'Sánchez', 'clase': 'B'},
{'id': '07', 'matricula': '2022KJEM', 'nombre': 'Francisco',
'apellidos': 'Pérez', 'clase': 'A'},
{'id': '08', 'matricula': '2022TTMK', 'nombre': 'María Pilar',
'apellidos': 'Gómez', 'clase': 'A'},
{'id': '09', 'matricula': '2022EFRW', 'nombre': 'David',
'apellidos': 'Martín', 'clase': 'A'},
{'id': '10', 'matricula': '2022LWJB', 'nombre': 'Laura',
'apellidos': 'Jiménez', 'clase': 'B'},
{'id': '11', 'matricula': '2022GFDV', 'nombre': 'Juan',
'apellidos': 'Hernández', 'clase': 'B'},
{'id': '12', 'matricula': '2022MKWX', 'nombre': 'Josefa',
'apellidos': 'Ruíz', 'clase': 'B'},
{'id': '13', 'matricula': '2022NSHC', 'nombre': 'Javier',
'apellidos': 'Díaz', 'clase': 'A'},
{'id': '14', 'matricula': '2022PCER', 'nombre': 'Isabel',
'apellidos': 'Moreno', 'clase': 'B'},
{'id': '15', 'matricula': '2022AHIV', 'nombre': 'Jose Antonio',
'apellidos': 'Muñoz', 'clase': 'A'},
{'id': '16', 'matricula': '2022MCTM', 'nombre': 'María
Dolores', 'apellidos': 'Álvarez', 'clase': 'B'}
]
}
return Response(
json.dumps(data, ensure_ascii=False),
mimetype='application/json'
)
145
En este caso el decorador es @app.route('/alumnos'), quiere decir que esta
función get_alumnos() se invocará únicamente cuando se haga una petición
desde un navegador a la URL de nuestra aplicación compuesta por un
hostname:puerto/alumnos (por ejemplo http://localhost:9000/alumnos). En el
cuerpo de la función tenemos por un lado una variable llamada data cuyo valor
es una lista de diccionarios, y cada uno de estos diccionarios contiene los
datos de alumnos (ficticios, son datos random), y por otro lado el retorno de
esta colección de datos en formato JSON. El atributo ensure_ascii con valor
False lo usamos para que nos respete los caracteres especiales como las
vocales con acentos, las eñes, etc.
if __name__ == '__main__':
from werkzeug.serving import run_simple
146
Ahora el servicio permanece iniciado y no debemos pararlo. Podemos hacer
una petición web desde un navegador web cualquiera a la URL de nuestro
servicio: http://localhost:9000/.
El navegador web nos mostrará una página web en la que podremos leer el
mensaje “Hola mundo!” que definimos en el código de nuestra aplicación web
en la función home().
Ahora hacemos otra petición web a esta misma URL pero añadiendo el path
/alumnos después del puerto: http://localhost:9000/alumnos
147
Podemos observar que esta parte o endpoint de la API nos devuelve toda la
información de los alumnos en formato JSON. También hemos observado que
nuestra API devuelve la información en una sola línea muy larga, sin identar o
tabular. Esto es bastante habitual, pues las APIs normalmente suelen devolver
gran cantidad de información y no suele ser procesada por un humano, por lo
que no necesita añadir caracteres adicionales como saltos de línea o
tabuladores. Lo normal es que la respuesta se procese con algún programa o
proceso automático. Pero si queremos verlo más legible (beautify) podemos
instalar en nuestro navegador algún plugin como JSONVUE que nos mostrará
la información de este tipo de respuestas JSON de una manera más
presentable, por ejemplo:
Ahora veamos cómo podemos obtener o procesar esta misma petición web al
endpoint “/alumnos” de nuestra API desde Python. Bastaría con emplear el
siguiente código:
148
import json
import requests
url = 'http://localhost:9000/alumnos'
try:
response = requests.get(url)
response_dict = json.loads(response.text)
Si todo ha ido bien veremos una salida como la siguiente por la terminal de
PyCharm:
149
Y si algo fue mal veremos el error por pantalla también mediante la sentencia
except que sucede al método try. Por ejemplo, si la API no estuviera disponible
por que hemos parado el servicio:
Y no están equivocados. A día de hoy (mediados del año 2022) Twitter tiene
345.5 millones de usuarios, y la mayoría escriben a diario mensajes llenos de
información. Gran parte de esta información es pública y la podemos ver todos
desde la propia aplicación web o móvil, pero otra no es accesible tan
fácilmente. Es una base de datos descomunal que los propios usuarios de la
150
aplicación se encargan de alimentar, indicando en todo momento su
orientación política, sus gustos musicales, culinarios, qué ropa llevan, a dónde
les gusta ir de vacaciones, cuándo se van, cuando vuelven, dónde viven,
poder adquisitivo, si tienen hijos, cómo se llaman sus hijos, a qué colegio
van…
Instalación de Tweepy
Para instalar el paquete Tweepy en PyCharm hay que seguir los siguientes
pasos.
151
2. En la ventana que emerge podremos ver en la opción “Python
Interpreter” la versión que estamos utilizando en este proyecto, que en
este caso es “Python 3.10”, y en la ventana de abajo se muestran
listados los paquetes que actualmente tenemos instalados y sus
versiones.
3. Para instalar un paquete nuevo hemos de hacer click sobre el botón “+”
tal y como se muestra en la siguiente imagen:
152
4. En la barra de búsqueda escribimos “tweepy”, y nos aparecerán varios
paquetes en los que coincide el literal que buscamos. Hemos de
seleccionar el primero, el que se llama solo “tweepy” y pulsamos el
botón “Install Package”.
153
5. Cuando termine la instalación deberemos ver un mensaje que dice
“Package ‘tweepy’ installed successfully” tal y como se muestra en la
siguiente imagen. Podemos cerrar esta ventana:
154
Uso de la API
import tweepy
Para poder usar la API de Twitter debemos configurar una cuenta Developer*
previamente. Una vez creada añadimos las credenciales de nuestra cuenta
Developer de Twitter:
TWITTER_CONSUMER_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxx'
TWITTER_CONSUMER_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
TWITTER_TOKEN = 'xxxxxxxxxxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
TWITTER_TOKEN_SECRET = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
155
* Si tienes una cuenta de Twitter la puedes convertir en una cuenta “Dev” o
“Developer”, si no puedes crear una cuenta nueva para probar la API:
https://developer.twitter.com/en
api = get_api()
twitter_user = 'elonmusk'
tweets = api.user_timeline(screen_name=twitter_user, count=5)
En la terminal de PyCharm podremos ver los 5 últimos tweets del usuario que
hubiéramos escogido, por ejemplo:
156
Aplicación de vuelos comerciales
En internet existen numerosas aplicaciones web de seguimiento de vuelos que
nos permiten hacer tracking o seguimiento de qué vuelos hay en qué momento
y en qué área del mapa, como flightradar24, FlightAware, flightview, etc,
además algunas de ellas nos proporcionan algunos datos interesantes como a
qué altitud se encuentra en ese momento un vuelo determinado o a qué
velocidad va.
En esta sección vamos a ver cómo podemos explotar esta fuente de datos
para su estudio o su representación en un mapa.
1. Obtener datos.
2. Importar las bibliotecas necesarias.
157
3. Cargar el mapa base.
4. Trazar la posición de los aviones.
5. Crear una aplicación de seguimiento de vuelos en "tiempo real".
Vamos a analizar cada una de estas fases y, al final, si la API está disponible y
tenemos datos, veremos cómo funciona una aplicación que es capaz de hacer
un seguimiento de vuelos en tiempo real (refresca la información cada pocos
segundos) y que se ejecuta en el navegador.
Para recuperar los datos usando la API REST se puede hacer usando una
solicitud HTTP de tipo GET. Se pueden utilizar dos tipos de solicitudes. La
primera es la solicitud de un avión específico según la hora en la marca de
tiempo UNIX o la dirección ICAO24. Por ejemplo:
https://opensky-network.org/api/states/all?time=1458564121&icao24=3c6444
158
El segundo método, podemos obtener todos los datos del avión dentro de una
extensión de área utilizando el sistema de coordenadas WGS84. Además el
acceso a los datos puede hacerse de forma anónima o como usuario
registrado. La diferencia es que para una solicitud anónima tiene 10 segundos
de respuesta y 5 segundos para un usuario registrado.
● Solicitud anónima
https://opensky-network.org/api/states/all?lamin=35.9425&lomin=-9.95
03&lamax=43.9617&lomax=4.5517
159
● Solicitud de usuario registrado
https://john_doe:abcd1234@opensky-network.org/api/states/all?lamin=
35.9425&lomin=-9.9503&lamax=43.9617&lomax=4.5517
160
La respuesta, como se muestra en la figura 2, tiene una estructura JSON con
dos claves. El primero es time y el segundo es states que contiene datos para
cada avión en una matriz de listas. Cada una de las listas almacena muchos
datos, como: dirección ICAO24, distintivo de llamada del avión, país de origen,
posición horaria, último contacto, longitud, latitud, altitud del barómetro, etc.
Para obtener una explicación completa sobre la respuesta de los datos y
también más información sobre la API de red de OpenSky, consulte la
documentación de la API de OpenSky Network.
import json
import pandas as pd
import requests
161
esta documentación son de ejemplo, debes registrarte en la web de OpenSky
Network y poner tu propio usuario y password). Finalmente creamos la variable
url en el que concatenamos todos los datos anteriormente especificados.
user = 'john_doe'
password = 'abcd1234'
query = f'lamin={lat_min}&lomin={lon_min}&lamax={lat_max}&lomax={lon_max}'
url =
f'https://{user}:{password}@opensky-network.org/api/states/all?{query}'
response = requests.get(url).json()
162
response = json.load(data)
col_name = [
'icao24', 'callsign', 'origin_country', 'time_position', 'last_contact',
'long', 'lat', 'baro_altitude', 'on_ground', 'velocity', 'true_track',
'vertical_rate', 'sensors', 'geo_altitude', 'squawk', 'spi',
'position_source'
]
flight_df = pd.DataFrame(response['states'])
flight_df = flight_df.loc[:, 0:16]
flight_df.columns = col_name
Ahora reemplazamos los datos en puedan llegar blanco o vacíos con el string
'No Data'.
flight_df.head()
163
Deberemos ver algo como la siguiente imagen:
import numpy as np
return x, y
164
meters.
df['x'] = df[lon] * (k * np.pi / 180.0)
df['y'] = np.log(np.tan((90 + df[lat]) * np.pi / 360.0)) * k
return df
# COORDINATE CONVERSION
xy_min = wgs84_to_web_mercator_point(lon_min, lat_min)
xy_max = wgs84_to_web_mercator_point(lon_max, lat_max)
wgs84_to_web_mercator(flight_df)
# FIGURE SETTING
x_range, y_range = ([xy_min[0], xy_max[0]], [xy_min[1], xy_max[1]])
p = figure(
165
x_range=x_range,
y_range=y_range,
x_axis_type='mercator',
y_axis_type='mercator',
sizing_mode='scale_width',
plot_height=300
)
166
y='y',
text='callsign',
level='glyph',
x_offset=5,
y_offset=5,
source=flight_source,
render_mode='canvas',
background_fill_color='white',
text_font_size='8pt'
)
p.add_tools(my_hover)
p.add_layout(labels)
show(p)
Hasta ahora habíamos visto cómo obtener datos de tráfico aéreo y ubicar los
aviones en un mapa. En esta última sección, veremos cómo crear una
aplicación de seguimiento de vuelos que se ejecuta en un navegador web. La
aplicación recuperará automáticamente nuevos datos en un intervalo
específico y trazará los datos en el mapa. Combinaremos el código del punto
167
anterior y lo empaquetamos en una aplicación usando la biblioteca Bokeh. El
código completo se puede encontrar a continuación.
"""
FLIGHT TRACKING WITH PYTHON AND OPEN AIR TRAFFIC DATA
by ideagora geomatics | www.geodose.com | @ideageo
updated by @JavDomGom
"""
import json
import numpy as np
import pandas as pd
import requests
return x,y
168
def wgs84_to_web_mercator(df, lon='long', lat='lat'):
""" Function to get Dataframe. """
return df
# COORDINATE CONVERSION
xy_min = wgs84_to_web_mercator_point(lon_min, lat_min)
xy_max = wgs84_to_web_mercator_point(lon_max, lat_max)
def flight_tracking(doc):
""" Init bokeh column data source. """
flight_source = ColumnDataSource(
{
'icao24': [],
'callsign': [],
'origin_country': [],
'time_position': [],
'last_contact': [],
'long': [],
'lat': [],
'baro_altitude': [],
'on_ground': [],
169
'velocity': [],
'true_track': [],
'vertical_rate': [],
'sensors': [],
'geo_altitude': [],
'squawk': [],
'spi': [],
'position_source': [],
'x': [],
'y':[],
'rot_angle': [],
'url': []
}
)
def update():
""" Updating flight data. """
response = requests.get(url).json()
flight_df = pd.DataFrame(response['states'])
flight_df = flight_df.loc[:, 0:16]
flight_df.columns = col_name
wgs84_to_web_mercator(flight_df)
flight_df = flight_df.fillna('No Data')
flight_df['rot_angle'] = flight_df['true_track'] * -1
icon_url =
'https://www.iconsdb.com/icons/preview/red/airplane-4-xl.png'
flight_df['url'] = icon_url
170
# PLOT AIRCRAFT POSITION
p = figure(
x_range=x_range,
y_range=y_range,
x_axis_type='mercator',
y_axis_type='mercator',
sizing_mode='scale_width',
plot_height=300
)
tile_prov = get_provider(STAMEN_TERRAIN)
p.add_tile(
tile_prov,
level='image'
)
p.image_url(
url='url',
x='x',
y='y',
source=flight_source,
anchor='center',
angle_units='deg',
angle='rot_angle',
h_units='screen',
w_units='screen',
w=40,
h=40
)
p.circle(
'x',
'y',
source=flight_source,
fill_color='red',
hover_color='yellow',
size=10,
fill_alpha=0.8,
line_width=0
)
171
('Altitude(m)', '@baro_altitude')
]
labels = LabelSet(
x='x',
y='y',
text='callsign',
level='glyph',
x_offset=5,
y_offset=5,
source=flight_source,
render_mode='canvas',
background_fill_color='white',
text_font_size='8pt'
)
p.add_tools(my_hover)
p.add_layout(labels)
doc.title='REAL TIME FLIGHT TRACKING'
doc.add_root(p)
# SERVER CODE
apps = {'/': Application(FunctionHandler(flight_tracking))}
server = Server(apps, port=8084) # Define an unused port.
server.start()
172
Figura 5. Aplicación de seguimiento de vuelos en un navegador web
173