Manual Python DataScience
Manual Python DataScience
A2 CAPACITACIÓN
A 2 C A P A C I T A C I O N . C O M
Python
para Data Science
Índice
15 INRODUCCIÓN E
INSTALACIÓN
› 159 ARCHIVOS ›
29 INTRODUCCIÓN A LA
PROGRAMACIÓN
› 171 PROGRAMACIÓN ORIENTADA
A OBJETOS
›
45 CONTROL Y DESARROLLO
DE PROGRAMAS
› 185 RECURSIONES, ITERACIONES
BÚSQUEDA Y ORDENAMIENTO
›
103 DICCIONARIOS Y
CONJUNTOS
› 229 COMPUTACIÓN COGNITIVA ›
119 PROGRAMACIÓN
CON NUMPY
› 239 INTRODUCCIÓN A
MACHINE LEARNING
›
Introducción
a Python
Manual para el alumno
Introducción a Python
De A2 Capacitación
Tabla de Contenido
Copyright © 2021 A2 Capacitación. Todos los derechos reservados
Guadalajara, Jalisco
Capítulo1. Introducción e instalación de Python.
Ontario Data Science Consultants Limited 1.1 Introducción 15
1.2 Acerca de Python 15
Marzo 2021. Primera Edición 1.3 ¿Por qué Python para ciencia de datos? 16
1.4 Instalación de Python 16
1.5 Primero cálculos con Anaconda Prompt 18
1.6 El ambiente de Jupyter Notebook para escribir y ejecutar código 20
1.7 Creando el primer notebook con Jupyter 20
1.8 Ejercicios 25
Manual Python | 9
Capítulo 4. Funciones. Capítulo 8. Cadenas.
4. 1 Introducción 69 8.1 Introducción 143
4.2 Función def 69 8.2 Dando formato a las cadenas. 143
Notas 70 8.3 Otras opciones para las cadenas 147
4.3 Funciones con Múltiples Parámetros 71 8.4 Expresiones Regulares 152
4.4 Números aleatorios 71 8.5 Pandas y Expresiones Regulares 156
Ejemplo 1 72
4.5 Funciones sin parámetros y múltiples parámetros 75
4.6 Alcance local y global 77 Capítulo 9. Archivos.
4.7 El módulo de matemáticas de Python 78 9.1 Introducción 159
4.8 Medidas de Tendencia Central y de Dispersión 79 9.2 Archivos TXT 159
Notas 160
9.3 Archivos JSON 162
Capítulo 5. Lista y Tuplas. 9.4 Manipulación de Excepciones 164
5.1 Introducción 83 Ejemplo 1 165
5.2 Listas 83 9.5 Archivos CSV 166
5.3 Tuplas 86 9.6 Lectura de archivos CSV con DataFrame de Pandas 167
5.4 Separando secuencias 88
5.5 Listas ordenadas 90
5.6 Comprensión de listas 93 Capítulo 10. Programación orientada a objetos.
5.7 Listas de 2 dimensiones 98 10.1 Introducción 171
5.8 Visualización de datos estáticos 99 10.2 Métodos y Clases 171
10.3 La clase Cuenta 175
10.4 Herencia 176
Capítulo 6. Diccionarios y conjuntos. 10.5 La clase Personal 176
6.1 Introducción 103 10.6 Métodos de clase 179
6.2 Dicccionarios 103 10.7 Polimorfismo 180
Ejemplo 1 107
Ejemplo 2 108
6.3 Comprensión de diccionarios 111 Capítulo 11. Recursiones, iteraciones, búsqueda y ordenamiento.
6.4 Conjuntos (Sets) 111 11.1 Introducción 185
Unión de conjuntos. 113 11.2 Algoritmos Recursivos e Iterativos 185
Intersección de conjuntos 114 Ejemplo 1 186
Diferencia de conjuntos 114 Ejemplo 2 187
Diferencia simétrica de conjuntos 114 Ejemplo 3 188
Conjuntos disjuntos 115 11.3 Búsqueda 190
11.4 Ordenamiento 193
Introducción e Instalación
de Python
1.1 Introducción
En este capítulo es para compartirte algunas de las causas que hacen de Python la mejor herra-
mienta de programación para Ciencia de Datos. Conoce un poco de las bondades que tiene este
software, del mundo de aplicaciones donde lo puedes encontrar y de las grandes oportunidades
que se te pueden abrir al aprender a programar en este lenguaje.
• Es fácil de usar. Con algunos tips sencillos, cualquier persona puede programar ruti-
nas sencillas en Python. Pronto te darás cuenta de ello.
• Legibilidad del código. La estructura del código es bastante natural y promueve una
forma de escribir que facilita su lectura. Esta es una ventaja importante frente a lengua-
jes dirigidos al mismo sector, como Perl.
• Facilidad de uso en dispositivos. Algunas plataformas como Raspberry Pi están basadas
en Python.
Manual Python | 15
• Facilidad de escritura de código asíncrono. Los lenguajes diseñados antes de Regularmente la instalación es rápida y muy fácil. Un par de recomendaciones, cuando salga el
que las plataformas multiprocesador (o multinúcleo) estuvieran tan generalizadas sue- siguiente cuadro de diálogo:
len tener estructuras bastante complicadas para mantener distintos hilos de ejecución;
en Python el código asíncrono es bastante sencillo de gestionar.
• Abundancia de bibliotecas. Hay muchas bibliotecas disponibles para extender la
funcionalidad básica de Python a cualquier campo.
• Gran base de usuarios. Esto hace que exista mucho código disponible en internet
y que los foros de usuarios sean bastante activos, por lo que es fácil encontrar ayuda
cuando se necesita.
Python, naturalmente, tiene también sus desventajas, algunas de las cuales son consecuencia de sus
ventajas. Por ejemplo: la facilidad de uso tiene como contrapartida una menor flexibilidad o rapidez
de ejecución que otros lenguajes como el mismo C, que sigue siendo el líder en programación de
bajo nivel o cuando la rapidez de ejecución es crítica. Y también tiene algunos problemas de seguri-
dad, lo que es crucial en internet. Ningún lenguaje es la panacea para todas las aplicaciones.
Desde <https://es.quora.com/Qu%C3%A9-ventajas-nos-ofrece-Python-respecto-a-otros-len-
guajes-de-programaci%C3%B3n>
Python es un lenguaje de programación creado por Guido van Rossum a principios de los años 90
cuyo nombre está inspirado en el grupo de cómicos ingleses “Monty Python”
Deja la opción que se encuentra ya seleccionada. Cambiar a All Users, puede provocar conflictos pos-
1.3 ¿Por qué Python para ciencia de datos? teriores con los permisos de instalación de algunas librerías. Verás que también aparecerá el cuadro:
Python es un lenguaje que todo el mundo debería conocer. Su sintaxis simple, clara y sencilla; el
tipado dinámico, el gestor de memoria, la gran cantidad de librerías disponibles y la potencia del
lenguaje, entre otros, hacen que desarrollar una aplicación en Python sea sencillo, muy rápido y,
lo que es más importante, divertido.
La sintaxis de Python es tan sencilla y cercana al lenguaje natural que los programas elaborados en
Python parecen pseudocódigo. Por este motivo se trata además de uno de los mejores lenguajes
para comenzar a programar.
Algunos casos de éxito en el uso de Python son Google, Yahoo, la NASA, Industrias Light & Magic,
y todas las distribuciones Linux, en las que Python cada vez representa un tanto por ciento mayor
de los programas disponibles. (González, R. ())
Después de que escribes 89-20 y presionas Enter, IPython lee el snippet, lo evalúa e imprime el resul-
tado en Out[1]. Observa que IPython muestra ahora el prompt In[2] para indicar que está en es-
pera de un segundo snippet. Esto lo realizará recurrentemente para cada snippet nuevo que agregues.
Ejemplos:
In[2]: 3 + 2 * 5
Out[2]: 13
In[3]: (3 + 2) * 5
Out[3]: 25
En el primer ejemplo, observa que hay prioridad en las operaciones. Ya que, en programación, la
multiplicación es una operación que tiene prioridad sobre la suma.
En el segundo ejemplo, observa que el paréntesis tiene mayor prioridad que la multiplicación. Jus-
to como en los cursos de matemáticas.
1.7 Creando el primer notebook con Jupyter Inicia el ambiente Jupyter Notebook. En el navegador predeterminado de tu computadora se abri-
rá una pestaña como la que se muestra.
Para acceder al Jupyter Notebook, en Windows, lo puedes hacer desde el menú de inicio, o escri-
biendo en la búsqueda rápida Anaconda Navigator Crea una carpeta nueva.
En la ventana de JupyterLab aparece un menú con las carpetas que se muestra en el Notebook de
Jupyter. Observa que también aparece la carpeta que creamos.
Una vez que la carpeta está creada, accede a JupyterLab. Accede a ella verás que está vacía.Aquí selecciona un Notebook de Python 3.
Para ejecutar el código de la celda puedes presionar el ícono , o con el teclado Ctrl+Enter.
En los materiales que acompañan a este manual se encuentran los notebooks con todos los ejem-
plos y ejercicios que realizarás. Estos notebooks no tienen ejecutadas las celdas. Si las ejecutas,
pero las quieres regresar al código original, del menú del Kernel selecciona Restart Kernel y luego
Clear All Outputs. El notebook quedará así
Verás que ya aparece otra celda nueva. Si requieres más celdas, presiona cuando las requieras
agregar.
Evalúa las otras expresiones que habías realizado con Anaconda Prompt.
Escribe 3+2*5, y ejecuta la celda. Para finalizar lo ejercicios, escribe (3+2)*5 en una nueva celda y
verifica que JupyterLab devuelve los mismos resultados.
1.8 Ejercicios
1. En la división aritmética, por ejemplo 17/6, el cociente es 2 y el residuo es 5. De tal manera que
6*2+5=17
Si el Notebook tiene cambios que no has guardado, la en el notebook para cerrar JupiterLab
En Phyton, el operador que muestra el cociente (parte entera de la divi-
cambiará a . Para guardar el notebook selecciona el ícono , o bien, en el menú de JL selecciona
sión 17/6) es //. Y el operador que calcula el residuo (resto, o módulo) es %.
File y luego Save Notebook. Escribe el nombre prueba1.
Utiliza el prompt de Anaconda para determinar si los siguientes enunciados son verdaderos o
falsos.
a. 8 // 3 =2
b. 8 % 3= 1
c. 111 // 6=16
d. 194 % 2=0
e. La parte entera de 326 entre 15 es, 22
f. El residuo de dividir 978 entre 125 es, 103
g. 25 módulo 3 es, 1
Guarda el archivo (Save).
a. 25 / 4=
b. 25 // 4=
c. 0 / 4=
d. 0 // 4=
e. 25 / 0=
f. 25 // 0=
3. Utiliza Jupyter Notebook y JupiterLab para realizar los siguientes cálculos. Guarda tus resulta-
dos en un archivo con nombre prueba2. Identifica aquel que genera un error y explica la razón
por la que ocurre.
a. 32 / 8 -3=
b. 32 // 8 -3=
c. 32 / (8 -3)=
d. 32 // (8 -3)=
e. 32 / (8 -8)=
f. 32 / (8 -5)=
Introducción a la programación
con Python
2.1 Introducción
En este capítulo aprenderás algunas características de programación en Python mediante algunos
ejemplos ilustrativos. La filosofía de este manual es aprender programando, así que:
In[1]: 9 + 2
Out[1]: 11
Los siguientes ejemplos también utilizan Anaconda Prompt, abre esta consola y verifica los resul-
tados que se muestran.
In[2]: w = 39
El snippet [2] es una declaración. Cada declaración define una tarea a realizar. En este caso, el sni-
ppet crea la variable w a la que le asigna, a través del signo = el valor de 9.
Manual Python | 29
Es útil realizar estas declaraciones, ya que las declaraciones permiten almacenar valores que pue-
den ser útiles posteriormente. Por ejemplo:
In[1]: 9 + 2
Out[1]: 11
In[3]: z = 7 In[4]: w / z
Continuando con esta forma de declarar las variables, también podemos asignar
In[5]: division = w / z
In[6]: division
Out[6]: 5.571428571428571
In[7]: Division
<ipython-input-5-75d6e457f232> in <module>
----> 1 Division En matemáticas una operación que no está definida es la división entre cero. Observa que al es-
NameError: name ‘Division’ is not defined cribir 3/0 aparece la leyenda
------------------------------------------------------
NameError Traceback (most recent call last) In [10]: 3/0
-------------------------------------------------------
Aparece un error. Esto ocurre porque Python reconoce mayúsculas y minúsculas, de manera que ZeroDivisionError Traceback (most recent call last)
“division” y “Division” se identifican como dos cosas diferentes. La primera que está definida en el <ipython-input-1-f6cc6d14333b> in <module>
snippet [5] y la segunda que no está definida de manera previa. Es por esto que Python indica que ----> 1 3/0
la variable no está definida. ZeroDivisionError: division by zero
Otra observación importante es el tipo de número que se muestra en el prompt de Anaconda, Esta leyenda indica que hay una excepción del tipo división entre cero (ZeroDivisionError).
para hacer más visible este detalle escribe en el prompt type(w), verás que Python reconoce a la
variable w como un entero. Muchas excepciones son reconocidas como errores.
In[8]: type(w) La línea -->1 indica el lugar en el código que provoca la excepción. La última línea indica la excep-
Out[8]: int ción que ocurre
¿De qué tipo es la variable división?. Teclea type(división) A continuación, se presenta una tabla que muestra el orden o prioridad que tienen las operaciones
en Python
In[9]: type(division)
Out[9]: float 1. Paréntesis: ( )
2. Exponente: **
Observa que el Python indica que la variable es de tipo float, esto indica que el número tiene una 3. Multiplicación, División, División entera, Módulo: *, /, //, %
parte decimal. Por default, Python asigna un número tipo float, aunque el resultado en alguna di- 4. Suma, Resta: +, −
visión pueda tener o no, parte decimal.
El siguiente ejemplo muestra como Python aplica la prioridad cuando se realizan diferentes operaciones.
Seguramente notaste en los ejercicios del capítulo anterior que es posible realizar diversas opera-
ciones aritméticas. La tabla siguiente muestra algunos de los operadores aritméticos más comunes. In[11]: 1+2**4%5
Out[11]: 2
2**4≡24 =16 Esto ocurre porque la función print solicita a Python trabajar en un ambiente de editor de texto,
en lugar de realizar cálculos, como antes lo habías hecho.
La triple línea ≡ es para indicar que las expresiones son equivalentes. Luego realiza la operación
módulo entre 16 y 5 Esta diferencia será más obvia cuando trabajemos líneas de texto en el ambiente de JupyterLab.
Otras opciones para insertar texto el prompt de Anaconda son
16%5 ≡ 16 mod5 = 1
In[5]: print(‘Hoy aprenderé’,’a usar’, ‘la función print’)
Recuerda que la operación módulo es el residuo en una división. Hoy aprenderé a usar la función print
Y la operación final que realiza es la suma In[6]: print(‘Hoy aprenderé\n a usar\n la función print’)
Hoy aprenderé
1 + 1 = 2 a usar
la función print
Demaneraque 1+2 4mod5=1+16mod5=1+1=2
In[7]: print(‘También aprenderé a dividir \
…: líneas de texto cuando las expresiones \
2.3 Función print, arreglos con comillas simples y …: sean demasiado largas’)
dobles comillas También aprenderé a dividir líneas de texto cuando las ex-
presiones sean demasiado largas
Utiliza el prompt de Anaconda y ejecuta el siguiente snippet
El símbolo \ al final de la línea permite continuar escribiendo caracteres en otra línea, ignorando el salto
In[1]: print(‘Hoy aprenderé a usar la función print’) de línea, los símbolos ...: se colocan automáticamente después de presionar enter en el prompt.
Hoy aprenderé a usar la función print
Cuando requieras utilizar comillas dobles y sencillas en algún enunciado, por ejemplo
Ahora ejecuta
Aprender ‘Python’, es realmente “sencillo”
In[2]: print(“Hoy aprenderé a usar la función print”)
Hoy aprenderé a usar la función print Es posible hacerlo utilizando triples comillas
Observa que los resultados son exactamente iguales. Es decir, no hay diferencia el resultado de In[8]: print(“““Aprender ‘Python’ es realmente “sencillo” ”””)
ambas instrucciones. Así que muchos programadores prefieren utilizar comillas simples. Sin em- Aprender ‘Python’ es realmente “sencillo”
bargo, esto que parece ser una redundancia de Python en realidad tiene una aplicación práctica.
Por ejemplo, para declarar el arreglo
Con Python, puedes asignar a una variable un arreglo de caracteres,
Hoy aprenderé a usar la función ‘print’
In[9]: arreglo1=‘Hoy aprenderé a usar la función print’
In[3]: print(‘Hoy aprenderé a usar la función ‘print’ ’) In[10]: print(arreglo1)
File "<ipython-input-3-fa3cc41852b0>", line 1 Hoy aprenderé a usar la función print
print('Hoy aprenderé a usar la función 'print'')
SyntaxError: invalid syntax Como en el caso de las variables numéricas, las cadenas de caracteres o arreglos tienen un forma-
to específico, que Python lo interpreta como un string (cadena de caracteres).
Se produce un error de sintaxis. Esto se resuelve utilizando dobles comillas In[11]: type(arreglo1)
Out[11]: str
In[4]: print(“Hoy aprenderé a usar la función ‘print’”)
Hoy aprenderé a usar la función ‘print’
In[22]: type(nombre)
Out[22]: str
Aunque, como verás más adelante, es posible cambiar el arreglo a una variable numérica entera,
o de tipo float.
Ingresa las siguientes instrucciones en el prompt de Anaconda para sumar los números 9 y 2.
• Primera corrida: El primer valor es más grande que el segundo Para hacerlo desde Anaconda Prompt
• Segunda corrida: El primer valor es más pequeño que el segundo
• Tercera corrida: Los dos valores iguales Paso 1. Entra al prompt, aparecerá
Este ejemplo está incluido en la carpeta del capítulo dos. (base) C:\Users\Equipo>
El código que sigue el anterior planteamiento es el siguiente. Paso 2. Como antes accede a ipython
In[1]: 15<3 Para que se puedan realizar las tareas designadas, es importante que las declaraciones conserven
Out[1]: False la identación o sangría. De otra forma realizará otras tareas o marcará un error.
In[2]: 6>1
D. Cuando aplicas un operador de comparación es importante no dejar espacios al momento
Out[2]: True
escribir el código ya que Python lo define como un error
B. La siguiente tabla muestra una lista los diferentes operadores y la prioridad en que se aplican,
In[5]: 10> =-3
siendo los primeros en la lista, los de mayor prioridad. File "<ipython-input-7-6cda1b356d4b>", line 1
10> =9
^
SyntaxError: invalid syntax
Existe una diferencia importante entre los operadores '=' y '=='. El primero se utiliza para realizar
asignaciones, el segundo es para verificar si dos cantidades son iguales.
a. 8.0
b. ‘6.15’
c. 0.001
d. 6.15
e. 31416
Realiza los cambios necesarios al programa para determinar si algún número ingresado por el
usuario es múltiplo de siete.
3.1 Introducción
A lo largo de este capítulo aprenderás algunas de las estrategias generales que utilizan los exper-
tos de programación para elaborar códigos que resuelven problemas altamente complejos.
Cruzaremos ese camino rodeado de ciclos, lazos y operadores booleanos, así que
En el caso de la programación, trazar la ruta es el equivalente de escribir el código. Por lo que hay
algunos pasos previos que no son visibles al momento de utilizar alguna aplicación en el celular.
Iniciaremos este capítulo con un recorrido breve por estas estrategias de planeación.
Manual Python | 45
Calcula los años del usuario, años= 2021 – año de nacimiento
3.3 Algoritmos Si la variable años es mayor o igual a 25,
el programa debe mostrar que es mayor de edad,
Los libros de programación definen a un algoritmo como una secuencia ordenada de pasos, que
si no se cumple la sentencia debe mostrar que es menor de edad.
han de ejecutarse uno después de otro. Si bien esta definición no está mal del todo, existen otras
definiciones más actuales, por ejemplo, Deitel 1 señala que un algoritmo es un procedimiento rea-
lizado para resolver un problema, en términos de
3.5 Sentencias de Control
1. Las acciones a ejecutar, y
2. El orden en el cual se realizan estas acciones Cuando las sentencias en un programa se ejecutan en el orden en que se escriben, se dice que el
programa realiza una ejecución secuencial. Existen algunas sentencias en Python que especifican
Piensa en la forma en que preparas un café instantáneo que tarea se debe ejecutar, ya que no específicamente debe ser la siguiente que está escrita. A esto
se le llama transferencia de control y están establecidas por las sentencias de control de Python.
1. Calientas agua
2. Agregas café Para representar gráficamente lo que hace una sentencia de control se utilizan diagramas de flujo.
3. Lo bebes Algunos de los elementos de estos diagramas que verás en esta sección son los siguientes.
Pero podemos hacer muchas preguntas con respecto a este procedimiento. El agua se puede ser-
vir, ¿de una llave?, ¿de un envase?, ¿del mar?, ¿de lluvia? Será calentada: ¿en un vaso?, ¿en una olla?,
¿en un plato?, ¿en las manos? Para calentar el agua se debe hacer: ¿con el sol?, ¿con leña?, ¿con un
cerillo?, ¿con una frazada?, etc.
Algunas preguntas pueden parecer exageradas. Incluso fuera de lugar, pero cuando trates de dar
instrucciones a la computadora, estas instrucciones deben ser claras y con un orden específico.
No puedes beber el agua caliente y agregar café después. Este ejemplo lejos de estar alejado de la
realidad, representa uno de los errores más comunes en la programación. 3.6 Sentencias de decisión y repetición
Supongamos que se requiere de un programa que verifique si las personas pueden votar en las Para tomar decisiones, Python tiene tres tipos de sentencias que ejecutan el código de acuerdo a
siguientes elecciones, por lo que debe verificar si son mayores de 18 años. una condición que puede ser evaluada como falsa o verdadera.
Para aquellos problemas que requieren algún proceso iterativo, Python con dos sentencias de repetición.
El pseudocódigo es el empleo de un lenguaje cotidiano para plantear la estrategia que debe em-
plearse para resolver un problema. Como el nombre lo dice, es un código falso, pero representa el
• Sentencia while
puente perfecto, para llegar al punto de iniciar a programar
Esta sentencia indica que la acción se repite mientras que la condición se mantenga como verdadera.
• Sentencia for
Un pseudocódigo del problema anterior puede ser:
Esta sentencia permite repetirla acción para cada elemento en un conjunto de elementos. Útil
En el prompt el usuario ingresa su año de nacimiento
para realiza una acción, cuando la condición es verdadera; y realiza la otra acción cuando es falsa.
La cantidad debe leerse como un entero
Supongamos que una tienda de autoservicio tiene el interés de saber si algún consumidor en par-
In[1]: nac=1993
ticular es mayor de 25 años (población en posibilidad de pagar ciertos servicios), para ofrecerle un
In[2]: if 2021-nac >= 25:
seguro de gastos médicos.
...: print(‘Posible cliente’)
...: print(‘Proporcione información del seguro’)
Un pseudocódigo del problema anterior puede ser:
File "<tokenize>", line 3
print((‘Proporcione información del seguro’)
El usuario proporciona su año de nacimiento
^
La cantidad debe leerse como un entero
IndentationError: unindent does not match any outer inden-
Si la variable 2021 – año de nacimiento, es mayor o igual a 25,
tation level
el programa debe mostrar: Posible cliente
Trata de aplicar las condiciones de identación. Un programa que no está uniformemente identado
Observa que, tanto en el pseudocódigo anterior, como en este, después de escribir la condición
resulta difícil de leer.
Si la variable años es mayor o igual a 25
Para el snippet [2], el diagrama de flujo tiene las siguientes características
En la siguiente línea aparece una identación (sangría) para indicar la acción a realizar:
Esto se hace con el propósito de que recuerdes que, en el código, al utilizar las sentencias de con-
trol de Python es necesario que las acciones a realizar tengan esta identación.
Si algún cliente indica que su año de nacimiento es de 1993 años, el código en Python para el pseu-
docódigo anterior es
In[1]: nac=1993
In[2]: if 2021-nac >= 25:
...: print(‘Posible cliente’)
...:
Posible cliente
Observa que las líneas siguen la dirección del flujo cuando la sentencia es evaluada como verdade-
En este caso, la persona que nace en 1993, tendrá una edad, en años, de 2021-1993=28. Por lo que
ra o como falsa. Si es verdadera, la acción se ejecuta. Si es falsa, el programa continua.
la condición 2021-nac se valúa como verdadera y se muestra en pantalla Posible cliente.
Si no se añade la identación.
3.8 Sentencias if…else, if…elif…else
In[1]: nac=1993
In[2]: if 2021-nac >= 25: La sentencia if…else realiza dos diferentes tipos acciones, y el resultado depende si la condición
es evaluada como verdadera o como falsa.
...: print(‘Posible cliente’)
File "<ipython-input-2-57cdab0cbb89>", line 2
Un pseudocódigo al problema de buscar clientes con una edad identificada por el formato 2021-
print('Posible cliente')
años de nacimiento, puede ser:
^
IndentationError: expected an indented block
El usuario proporciona su año de nacimiento
La cantidad debe leerse como un entero
In[3]: nac=1985
In[4]: if 2021-nac >= 25:
...: print(‘Posible cliente’)
...: else:
...: print(‘No es candidato’)
...:
Posible cliente
Cuando la sentencia es evaluada como verdadera la acción print(‘Posible cliente’) se
ejecuta. En otro caso (si es falsa), el programa ejecuta print(‘No es candidato’).
In[5]: nac=1999
In[6]: if 2021-nac >= 25:
Una forma alternativa de ejecutar las instrucciones anteriores, es asignar las acciones a una variable.
...: print(‘Posible cliente’)
...: else:
In[9]: nac=1999
...: print(‘No es candidato’)
In[10]: edad=2021-nac
...:
In[11]: if edad >= 25:
No es candidato
...: cliente=‘Si’
...: else:
...: cliente=‘No’
...:
Nota
In[12]: cliente
Para ejecutar el programa no es necesario volver a escribir todo el código. Puedes utilizar las fle- Out[12]: ‘Si’
chas en el teclado (arriba, abajo). En el prompt aparecen los snippets que ya has utilizado.
En este caso, se asignó a la variable edad, la resta 2021-nac. Y para la sentencia if… else,
1. En el snippet [5] mueve las flechas y selecciona, por ejemplo: nac=1999, que ya había- cuando es verdadera se asigna a la variable cliente, el arreglo ‘Si’. Y cuando la sentencia es falsa,
mos utilizado, pero antes de presionar enter, cambia el valor, digamos 1993. se asigna a cliente, el arreglo ‘No’. Al final, se hace la solicitud del resultado en el snippet[10].
2. Ahora, en el snippet [6], vuelve a utilizar las flechas para seleccionar lo escrito en [4]. Y
listo, automáticamente se escribe el código en el prompt y se ejecuta al presionar enter. Cada condición de la sentencia puede realizar más de una acción.
De acuerdo a este pseudocódigo, solo una acción se ejecutará. El código para clasificar a una per-
sona de 24 años, es el siguiente.
In[17]: edad=24
In[18]: if edad >= 60:
...: print(‘Adulto mayor’)
...: elif edad >= 27:
...: print(‘Adulto’)
...: elif edad >= 18:
...: print(‘Joven’)
...: elif edad >= 12:
...: print(‘Adolescente’)
...: else:
...: print(‘Infante’)
...:
Joven
Para mostrar la forma en que trabaja esta sentencia, resolveremos el siguiente problema, ¿cuál es
la potencia de 4 más grande que 817?
Esto indica que el programa debe seguir calculando potencias de cuatro (sentencia verdadera),
hasta que la potencia deje de ser menor o igual a 817 (sentencia falsa)
3.10 Sentencia for
In[1]: potencia=4
Como en el caso de while, for repite una o varias acciones. La sentencia for realiza la acción
In[2]: while potencia <= 817:
para cada elemento en una sucesión de elementos. Tal sucesión de elementos puede ser una lista
...: potencia = potencia * 4
de valores, que no necesariamente debe estar ordenada o pueden ser caracteres, ya que una pa-
...:
labra es una lista de caracteres.
In[3]: potencia
1024 Analiza el siguiente ejemplo:
Un código sencillo para determinar el valor factorial del número 5 utilizando la sentencia for, es
el siguiente Cuando la sucesión de elementos en una sentencia for es una sucesión ordenada, es posible
utilizar la función range, por ejemplo
In[6]: fact=1
In[7]: for nmro in [1,2,3,4,5]: In[12]: for contador in range(5)
...: fact=fact*nmro ...: print(contador, end=’ ‘)
...: ...:
In[8]: fact 0 1 2 3 4
Out[8]: 120
Observa que la función range(5) genera una lista de valores que inicia en cero y finaliza, un en-
El resultado final es llamado el valor factorial de 5. En matemáticas, se denota y define como tero previo al 5.
5!=1*2*3*4*5 El siguiente código muestra la forma de utilizar la sentencia for aplicado a una situación común en
las tiendas de autoservicio.
Al utilizar instrucciones como fact=fact*nmro, en una sentencia for, se dice que los cálculos se
encuentran en un proceso iterativo, y en cada ocasión que se repite la sentencia, se le llama itera-
ción. Estas formas de programar son comunes en aplicaciones orientadas a la estadística y otros Ejemplo 3.1
métodos numéricos.
A una pequeña tienda de autoservicio entran 8 personas a consumir diversos productos. La si-
Para mejorar estos procesos iterativos, Python tiene incluidos asignadores de aumento para abre- guiente lista describe los consumos (en pesos) realizados por los clientes
viar códigos como
[130,85,210,45,153,78.5,264.5,94]
fact=fact*nmro.
Elabora un programa que calcule el consumo promedio realizada por estos clientes.
Aquí está la muestra
Para resolver este ejercicio es necesario
In[9]: fact=1
In[10]: for nmro in [1,2,3,4,5]:
...: fact *= nmro
...:
In[11]: fact
Out[11]: 120
56 | Capítulo 3: Control y desarrollo de programas con Python Manual Python | 57
Supongamos que ahora en la tienda solicitan el gasto promedio de los clientes que ingresan en
un lapso de 4 horas. Así, ya no es posible dejar fija la lista pues el número de clientes puede ser
grande, pequeño, pero incluso, puede ser cero.
Cuando esto ocurre es posible utilizar un valor especial, al que llamaremos valor centinela. Este valor
tiene el propósito de indicarle al programa que no habrá más datos de ingreso. Cuando se implementa
esta estrategia el programa seguirá solicitando datos hasta que sea introducido el valor centinela.
Un valor centinela no debe tener las mismas características de los datos de ingreso. Para nuestro
ejemplo, una posibilidad es seleccionar el valor -1 o cualquier otro valor negativo.
En la columna de la derecha se anexa la fase en que se realizan las diferentes tareas en el progra-
ma. Aunque esta clasificación no afecta en nada el resultado final, es de gran ayuda al momento
de planificar las tareas que debe realizar el programa.
1 # ejemplo1_c3.py
2 ”””Uso de la sentencia for para calcular el consumo promedio”””
3
4 #Fase inicial
5 suma_tot=0
6 contador_clientes=0
7 consumos=[130,85,210,45,153,78.5,264.5,94]
8
9 #Fase de ejecución
10 for consumo in consumos:
11 suma_tot += consumo
12 contador_clientes += 1
13
14 #Fase final
15 consumo_prom=suma_tot/contador_clientes 1 # ejemplo2_c3.py
16 print(f’El consumo promedio es de {consumo_prom}’) 2 ”””Uso de la sentencia for con centinela para el con-
sumo promedio”””
3
El consumo promedio es de 132.5 4 #Fase inicial
5 suma_tot = 0
6 contador_clientes = 0
Observa que en la línea 16, el programa utiliza el formato de cadena (formatted string o f-string), 7
cuya función es la de cambiar el valor numérico del promedio en una cadena de caracteres. En los 8 #Fase de ejecución
programas siguientes adelante utilizaremos otras características de este formato para la salida de 9 consumo = float(input(‘Ingresa el consumo, -1 para
la información. finalizar: ’))
Ejemplo 2 10
vuelve a aparecer una cadena formateada, pero en este caso el consumo promedio aparece
con la indicación consumo_prom:.2f, cuya finalidad es que el resultado se presente con dos
cifras decimales significativas.
Aunque parecen un tato repetitivos estos últimos tres cuadros tiene el propósito de que observes
Ejemplo 3
Antes de escribir el programa, es necesario hacer algunas reflexiones que perfeccionarán el pseu-
docódigo y facilitarán las tareas y el orden en que deben realizarse.
1 # ejemplo3_c3.py
2 ”””Uso de sentencias anidadas”””
3 Notas
4 #Fase inicial
5 reb = 0 1. Dado que en las condiciones indican un número fijo de personas, el programa utiliza un ciclo
6 noreb = 0 for como en el ejemplo 1, en lugar de un ciclo while.
7
8 #Fase de ejecución 2. En el código del programa 3, aparece la función range. Esta función genera una lista de valores
9 for registro in range(1,9): ordenados, hacia adelante o hacia atrás. Observa los siguientes ejemplos
10 resultado = int(input(‘Ingresa el resultado (1=si
>=200, 2= si <200) ’)) In[13]: for x in range(-5,6):
11 if resultado==1: ...: print(x, end = ’ ’)
12 reb+=1 ...:
13 else: -5 -4 -3 -2 -1 0 1 2 3 4 5
14 noreb+=1
15 Este ciclo genera una lista de valores enteros consecutivos, desde -5 hasta 5. La opción range
16 #Fase final no incluye el extremo el valor máximo en el rango de -5 a 6.
17 print(‘Número de clientes que rebasaron la venta
meta’,reb) In[14]: for x in range(-5,6,2):
18 print(‘Número de clientes que no rebasaron la venta ...: print(x, end = ’ ’)
meta’,noreb) ...:
19 if reb > 4: -5 -3 -1 1 3 5
20 print(‘Premio al promotor’)
Este ciclo genera una lista de valores enteros, desde -5 hasta 5, pero con un tamaño de paso 2.
Ingresa el resultado (1=si >=200, 2= si <200)1 La opción for interpreta perfectamente el recorrido del ciclo con números enteros. Incluso si
Ingresa el resultado (1=si >=200, 2= si <200)1 es hacia atrás.
Ingresa el resultado (1=si >=200, 2= si <200)2
Ingresa el resultado (1=si >=200, 2= si <200)2 In[15]: for x in range(5,-5,-3):
Ingresa el resultado (1=si >=200, 2= si <200)1 ...: print(x, end = ’ ’)
Ingresa el resultado (1=si >=200, 2= si <200)1 ...:
Ingresa el resultado (1=si >=200, 2= si <200)2 5 2 -1 -4
Ingresa el resultado (1=si >=200, 2= si <200)1
Número de clientes que rebasaron la venta meta 5 Algunas ocasiones es necesario expresar los resultados mediante una tabla.
Número de clientes que no rebasaron la venta meta 3
Premio al promotor El siguiente ejemplo como crece un capital de $25,000 invertido en una cuenta bancaria que
genera un interés simple de 6.5% anual. En este ejemplo se asume que no hay retiros de capital
Ingresa el resultado (1=si >=200, 2= si <200)2 en un periodo 12 años.
Ingresa el resultado (1=si >=200, 2= si <200)2
La fórmula para calcular el capital C_n después de invertir un monto inicial de C_0, en n perio-
Ingresa el resultado (1=si >=200, 2= si <200)2
dos, a una tasa de interés de i*100% es
Ingresa el resultado (1=si >=200, 2= si <200)2
Ingresa el resultado (1=si >=200, 2= si <200)2
Ingresa el resultado (1=si >=200, 2= si <200)1
In[16]: Co=13500 Otra declaración complementaria para break es continue, que utilizaremos posteriormente.
In[17]: i=0.063
In[18]: n=12
In[19]: for año in range(1,n+1): 3.11 Operadores Booleanos
...: Capital=Co*(1+año*i)
...: print(f‘{año:>2}{Capital:>10.2f}’) En programación existen operadores booleanos que permiten poner condiciones que mezclan
1 14350.50 operadores como los que ya has utilizado >, <, >=, <=, == y !=.
2 15201.00
3 16051.50 Operador Booleano and
4 16902.00
5 17752.50 Aquí un ejemplo
6 18603.00
7 19453.50 In[1]: registro_email=’Si’
8 20304.00 In[2]: salario_mens=25000
9 21154.50 In[3]: if registro_email==’Si’ and salario_mens>=20000:
10 22005.00 ...: print(‘Posible cliente. Enviar información’)
11 22855.50 ...:
12 23706.00 Posible cliente. Enviar información
La función clave en este código en and. La sentencia if será calificada como verdadera, solo cuan-
En la instrucción do registro_email e ingreso_mens>=20000 sean verdaderas.
print(f‘{año:>2}{Capital:>10.2f}’)
Esta regla está definida por la lógica proposicional. La siguiente tabla muestra la forma en que
esta implementado un f-string (formato de cadena) y tiene dos marcadores de posición que le dan trabaja la lógica de este operador.
el formato a la salida.
El marcador {año:>2} usa el símbolo >2 para indicar que el año debe estar alineado a la dere-
cha, en un campo de ancho 2. El ancho del campo indica el número de posiciones (medidos en
caracteres) que se utilizarán para mostrar el valor.
Python brinda opciones para alterar el flujo de un ciclo, ya sea for o while. Observa el siguiente
ejemplo:
Con estas instrucciones Python genera una sucesión de números enteros de 1 a 10, pero el ciclo
TIP: Si quieres que se muestren los títulos (Raíz y Factorial), puedes escribir la instrucción antes
de ejecutar el ciclo en los cálculos
3. Modifica el script anterior, para que ahora los números están alineados de la siguiente forma
Raíz Factorial
1.0000 1.0
1.4142 2.0
1.7321 6.0
2.0000 24.0
2.2361 120.0
Esto indica que, si alguna proposición es calificada como verdadera, la sentencia if la calificará 6. En el script del problema, la sentencia if se evalúa al verificar si la fila es par. Modifica esta sen-
como verdadera, y en consecuencia será falsa, solo si ambas son falsas. tencia para comparar filas y columnas, para obtener arreglos como los siguientes
1 1 1 1 1 1
3. 12 Ejercicios 1 1 1 1 1 1
1 1 1 1 1 1
1. Modifica el script del ejemplo 3. Con el objetivo de validar los datos ingresados. Añade un 1 1 1 1 1 1
contador que registre los casos en los que no se registró ni 1, ni 2. Al final el programa debe 1 1 1 1 1 1
mostrar también el número de registros erróneos.
7. ¿Cuánto miden tus amigos? Elabora un programa utilizando la sentencia while, que permita
2. Utiliza un f-string para presentar dos columnas como las siguientes. ingresar una cantidad arbitraria de estaturas (todo dependerá de cuantos amigos tengas), para
calcular el promedio de la estatura.
Raíz Factorial
1.0000 1.00 8. Elabora un programa que indique cuántos de tus amigos miden lo mismo que tú, pero que
1.4142 2.00 también indique cuántos son más altos y cuántos tienen una estatura menor a la tuya.
1.7321 6.00
2.0000 24.00
2.2361 120.00
Funciones
4. 1 Introducción
En programación, como en muchas otras áreas, la mejor receta para resolver un problema grande
y complejo, es resolver problemas pequeños, que de manera conjunta puedan dar solución a to-
dos los detalles involucrados en este enorme problema.
En este capítulo aprenderás a pulir muchos de esas pequeñas soluciones que en poco tiempo po-
drán resolver esos grandes retos que rodean al análisis de grades bases de datos.
Manual Python | 69
Aquí está definida una función llamada raiz_cuad, y la tarea que realiza es calcular la raíz cuadrada
de un valor llamado número.
4.3 Funciones con Múltiples Parámetros
El siguiente código define la raíz cuadrada más grande de tres números
La forma general para definir funciones sigue la siguiente sintaxis
Esto comprueba que el valor de la variable global aprox_pi, sigue siendo el mismo.
[1]: log10(1000) Un estudiante ha tenido el siguiente registro de calificaciones (de 0 a 100) y desea conocer como
ha sido su rendimiento calculando algunos estadísticos descriptivos como la media, la mediana, la
--------------------------------------------------------- moda, el rango, la desviación estándar y la varianza. Las calificaciones son:
NameError Traceback (most recent call last)
<ipython-input-15-075cf7343366> in <module> Calificaciones: 68, 90, 80, 100, 80, 75, 85, 95, 70, 70
----> 1 log10(1000) Este ejemplo está incluido en la carpeta del capítulo cuatro.
[2]: import math calificaciones= [68, 90, 80, 100, 80, 75, 85, 95, 70, 70]
Para invocar a la función log10, utiliza la siguiente sintaxis # Medidas de tendencia central
media=estad.mean(calificaciones)
nombre_librería.función(argumento) mediana=estad.median(calificaciones)
moda=estad.mode(calificaciones)
[3]: math.log10(1000)
# Medidas de dispersión
3.0 rango=max(calificaciones)-min(calificaciones)
varianza=estad.pvariance(calificaciones)
Algunas funciones en la librería math de Python son desv_estandar=estad.pstdev(calificaciones)
Como la media y la mediana no son muy diferentes, es posible afirmar que los datos tienen una
buena medida de tendencia central de 80 aproximadamente. La desviación estándar es aproxima-
damente 10 por lo que a 10 unidades de la media se encuentran aproximadamente el 68% de las
calificaciones según el Teorema de Chebyshev. El comportamiento, podemos intuir
80 | Capítulo 4: Funciones
C A P Í T U L O 5
Listas y Tuplas
5.1 Introducción
En esta sección aprenderás a crear y manipular listas.
Así que ponte listo y camina despacio, verás como el paisaje de la programación comienza a pin-
tarse de colores
5.2 Listas
Una lista regularmente está compuesta por datos del mismo tipo o datos homogéneos sin embar-
go esto no es una regla
[1]: A = ['Patricia','México','F',1989]
[2]: A
[2]: ['Patricia','México','M',1989]
La lista anterior contiene 4 elementos, nombre, país, género y año de nacimiento. A diferencia de
listas más comunes cómo:
[3]: a = [9,10,8.5,8,8,7.5,10]
[4]: a
[4]: [9,10,8.5,8,8,7.5,10]
Manual Python | 83
Para llamar a cada elemento puedes utilizar la siguiente sintaxis [13]: ay = 4
[14]: a[ax-ay]
[14]: 8
Es posible añadir elementos a una lista vacía. Python puede realizar esta tarea de forma dinámica.
[22]: mi_secuencia=[]
[23]: for número in range(-2,3):
mi_secuencia += [número]
[24]: mi_ secuencia
[24]: [-2, -1, 0, 1, 2]
Los índices siempre deben ser enteros o expresiones enteras.
[12]: ax=1
Concatenar dos listas, significa dos o más cadenas en una sola. Esta tarea es posible en Python con [6]: print(datos_cliente1[0],'nació en el año de', 2021-int
el operador +. (datos_cliente1[2]))
Paty nació en el año de 1998
[28]: Lista = A + a
[29]: Lista También es posible concatenar tuplas para formar una nueva
[29]: ['Patricia','México','F',1989,9,10,8.5,7.2,8,7.5,10]
[7]: complemento_info = ('Feb','1998')
El operador + regresa una lista nueva con los elementos de lista A seguidos de la lista a. Para visua- [8]: datos_c1 = datos_cliente1 + complemento_info
lizar los índices y sus valores, puedes utilizar el siguiente código. [9]: datos_c1
[9]: ('Paty', 'F', '23', 'Feb', '1998')
[30]: for i in range(len(Lista)):
print(f'{i}:{Lista[i]}') Es posible acceder a cualquier secuencia de elementos, asignando cada elemento de la secuencia
[30]: 0:Patricia con una variable separada por comas. Aquí dos ejemplos de cómo hacerlo.
1:México
2:F [10]: datos_paciente1 = ('Paco',[1.80,69])
3:1989 [11]: nombre,estatura_peso = datos_paciente1
4:9 [12]: nombre
5:10 [12]: 'Paco'
6:8.5 [13]: estatura_peso
7:7.2 [13]: [1.8,69]
8:8
9:7.5 Si en la tupla solo hay caracteres.
10:10
[14]: primera,segunda = 'Va'
Y como antes, puedes acceder a los elementos de la lista a través de sus índices. [15]: print(f'{primera},{segunda}')
V,a
5.3 Tuplas
Si son valores.
Las tuplas son secuencias de datos, pero, inmutables y con mucha frecuencia contienen datos
heterogéneos. La longitud de una tupla es el número de elementos que contiene, y a diferencia de [16]: Estatura,Peso,Temperatura = (1.8,69,37.5)
una lista, este número de elementos no puede cambiar en la ejecución de un programa. [17]: print(f'{Estatura},{Peso},{Temperatura}')
Para crear una tupla vacía, utiliza paréntesis en lugar de corchetes 1.8,69,37.5
[1]: datos_cliente1 = () También se puede acceder a un valor al indexarlo. La función enumerate recibe una lista o una tu-
[2]: datos_cliente1 pla que contiene dos elementos un índice y un valor. Respectivamente, crea una lista o una tupla.
[2]: ()
[3]: len(datos_cliente1) [18]: estudiantes=['Hugo','Paco','Luis']
[3]: 0 [19]: list(enumerate(estudiantes))
Una forma de presentar estos valores. Se puede modificar una lista cambiando los valores de una parte de los elementos y dejar al resto
sin cambiar.
[21]: for index,valor in enumerate(estudiantes):
print(f'{index}:{valor}') [8]: potencias2[0:3] = ['dos','cuatro','ocho']
0: Hugo [9]: potencias2
1: Paco [9]: ['dos', 'cuatro', 'ocho', 16, 32, 64, 128, 264]
2: Luis
Otras variantes para modificar una lista son
[10]: potencias2[0:2] = []
5.4 Separando secuencias [11]: potencias2[:]
[11]: ['ocho', 16, 32, 64, 128, 264]
Es posible seleccionar elementos de una secuencia o sucesión. Es decir, seleccionar subconjuntos
de una sucesión que sea mutable por ejemplo: Observa que se borran los primeros dos elementos. El siguiente código cambia los elementos con
un tamaño de paso específico.
[1]: potencias2 = [2,4,8,16,32,64,128,264]
[2]: potencias2[3:5] [12]: potencias2 = [2,4,8,16,32,64,128,264]
[2]: [16, 32] [13]: potencias2[::3] = [1,1,1]
[14]: potencias2
Observa que la anotación indica que de la lista potencias2, se seleccionan los elementos con índi- [14]: [1, 4, 8, 1, 32, 64, 1, 264]
ces 3 al 5, sin incluir el 5. Esta notación permite extraer elementos de potencias2 de formas varia- [15]: id(potencias2)
das, es decir: [15]: 2374936891776
[3]: potencias2[:5] El snippet [15] pide el identificador de la lista. Este identificador es único y se preserva a pesar de
[3]: [2, 4, 8, 16, 32] realizar diferentes operaciones. Por ejemplo, al dejar la lista vacía.
Selecciona los elementos con índices de 0 a 4, ya que como antes, el elemento 5 no se incluye. [16]: potencias2[:] = []
[17]: potencias2
[4]: potencias2[3:] [17]: []
[4]: [16, 32, 64, 128, 264] [18]: id(potencias2)
[18]: 2374936891776
Observa que esta selección recoge los valores con índices mayores o iguales a 4. Al omitir los índices
Es posible observar que el identificador no cambia a pesar de cambiar los elementos en la lista. Al
[5]: potencias2[:] hacer la asignación
[5]: [2, 4, 8, 16, 32, 64, 128, 264]
[19]: potencias2 = []
se realiza una copia simple de la sucesión original. [20]: potencias2
[20]: []
También es posible seleccionar elementos no consecutivos añadiendo un tamaño de paso. [21]: id(potencias2)
[21]: 2374937250688
[6]: potencias2[::3]
[6]: [2, 16, 128] en el snippet [19], observa que se han borrado los elementos, por lo que se ha creado una nueva lista.
Esta característica marca una diferencia esencial entre dejar una lista vacía y asignar una lista vacía.
O incluso es posible hacerlo con índices negativos.
Otro de los tópicos clásicos en cómputo es la búsqueda. Python realiza una búsqueda a través del
índice de los elementos de una lista o una tupla.
5.5 Listas ordenadas
[18]: edad = [65,12,19,80,36,28,16,18,36,16,45,32,36,59]
Una de las tareas más comunes en cómputo es ordenar los valores o elementos de una lista. La [19]: edad.index(45)
forma de ejecutar esta instrucción en Python, es con la instrucción sort. [19]: 10
[1]: edad = [65,26,28,36,18] La función index, indica el lugar o índice en donde se encuentre el valor que se requiere encon-
[2]: edad.sort() trar. Un error del tipo ValueError ocurre si el valor no está en la lista de búsqueda.
[3]: edad
[3]: [18, 26, 28, 36, 65] [20]: edad.index(43)
Aquí se ordenan los datos en orden ascendente. Si lo quieres hacer en orden descendente [20]: ----------------------------------------------------
ValueError Traceback (most recent call last)
[4]: edad.sort(reverse = True) <ipython-input-21-3d7a28478f51> in <module>
[5]: edad ----> 1 edad.index(43)
[5]: [65, 36, 28, 26, 18] ValueError: 43 is not in list
Otra función de Python para ordenar es sorted. La función sorted regresa una lista nueva con los Una forma de verificar si algún valor está en la lista es con el comando in.
elementos ordenados. Con este comando la sucesión original no cambia.
[21]: 56 in edad
Para ordenar una lista [21]: False
La función remove, borra el primer elemento con un valor específico. Un error del tipo ValueError Esta tarea es equivalente a
ocurre si el elemento no está en la lista
copia_vegetales=vegetales[:]
[31]: vegetales.remove('esparrago')
[32]: vegetales
[32]: ['lechuga', 'espinaca', 'apio', 'esparrago'] 5.6 Comprensión de listas
Para dejar una lista vacía es posible utilizar clear, La comprensión de listas es una funcionalidad de Python que permite generar listas nuevas, este
es un estilo simplista y elegante de Python aquí algunos ejemplos.
[33]: vegetales.clear()
[34]: vegetales Para anexar elementos a una lista, habías utilizado este código:
[34]: []
[1]: lista1 = []
que es equivalente a [2]: for dato in range (1,11):
lista1.append(dato)
vegetales[:]=[] [3]: lista1
[3]: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
La función count determina el número de veces que aparece un elemento en una lista
[35]: edades = [15, 21, 16, 19, 20, 16, 19, 15, 21, 17, 18,
En términos de mapeos, estás mapeado (llevando) una lista [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] a otra lista [1, El “<generator object <genexpr>” indica que cuadrados_pares es un objeto generador y
4, 9, 16, 25, 36, 49, 64, 81, 100]. que fue creado por un generador de expresiones. Observa que no muestra los valores, esto es
una consecuencia de la evaluación débil del generador. Esto contribuye a no utilizar recursos de
Después, es posible seleccionar elementos que tengan alguna característica deseable, a esta ope- memoria y tiempo de la computadora. Si quieres observar los resultados debes solicitarlo, por
ración se le llama filtrar y es posible realizarla utilizando una sentencia if. Aquí se muestra la lista ejemplo:
anterior, pero únicamente con los elementos menores o iguales a 50.
[21]: list(cuadrados_pares)
[10]: cuad = [dato*dato for dato in range(1,11) if dato*dato<=50] [21]: [64, 16, 36 100]
[11]: cuad
[11]: [1, 4, 9, 16, 25, 36, 49] Hasta aquí has visto algunas características funcionales de Python como comprensión de listas, fil-
traje y mapeo. Ahora utilizaremos funciones específicas qué hacen esta tarea como filter y map.
Y si es de interés aquellas potencias de números pares
El siguiente código identifica los números pares de una lista de enteros.
[12]: cuad2 = [dato*dato for dato in range(1,11) if dato % 2 ==0]
[13]: cuad2 [22]: lista=[-3,5,8,4,1,-6,7,10]
[13]: [4, 16, 36, 64, 100] [23]: def pares(x):
"""Regresa el valor de la lista solo si es un número par"""
La sentencia for puede procesar cualquier iterable. El siguiente es un ejemplo de la versatilidad de return x % 2==0
Python para manipular listas. [24]: list(filter(pares,lista))
[24]: [8, 4, -6, 10]
[14]: vegetales = ['apio','brocoli','lechuga']
[15]: vegetales2 = [dato.upper() for dato in vegetales] Aquí la función filter tiene como primer argumento la función pares. La función pares tam-
[16]: vegetales2 bién tiene un argumento y regresa True si su argumento es par. La función filter llama enton-
[16]: ['APIO', 'BROCOLI', 'LECHUGA'] ces a la función pares para cada valor (de la lista) en el segundo argumento.
La función filter regresa un iterador (una lista generada) por lo que los resultados de filter
Observa que la lista inicial tenía a sus elementos escritos con minúsculas y en la comprensión de no se producen hasta que iteras sobre ellos (la función list los manda llamar), este es otro
lista, asigna estos elementos a otra lista, pero escritos con mayúsculas. ejemplo de una evaluación débil.
[25]: [valor for valor in lista if pares(valor)] [31]: [x**3 for x in lista if x % 2 == 0]
[25]: [8, 4, -6, 10] [31]: [512, 64, -216, 1000]
Recuerda que este puede ser un código más corto, pero que puede tener ciertas desventajas en En las secciones anteriores has comparado valores, algunas veces para ordenar o para encontrar
tiempo de cómputo y uso de memoria cuando las listas son muy largas. máximos o mínimos. Sin embargo, estas comparaciones también se pueden llevar a cabo con ob-
jetos más complejos como cadenas de caracteres, por ejemplo:
Algunas veces es necesario utilizar funciones que realizan tareas relativamente sencillas, como en
el ejemplo anterior la función pares. Para estas tareas Python permite utilizar una función a la [32]: 'Pato'<'murciélago'
que llama lambda y que prácticamente sirve para lo que sea. Esta función es como la χ que usas [32]: True
en álgebra. Por ejemplo
Este resultado puede interpretarse como verdadero, debido a que la P está ubicada después de
[26]: list(filter(lambda x:x%2==0,lista)) m en el abecedario, sin embargo, las cadenas son comparadas por los valores numéricos de sus
[26]: [8, 4, -6, 10] caracteres. En este caso las letras minúsculas tienen valores numéricos más altos que las letras
mayúsculas. Para revisar el valor numérico de las letras es posible utilizar la función ord.
Una función lambda es reconocida como una función anónima o sin nombre y es útil para llamar
alguna función. Aquí están las similitudes entre la sintaxis de una función def [33]: ord('P')
[33]: 80
def nombre_función(parámetros [34]: ord('m')
return expresión [34]: 109
[35]: ord('M')
y una función lambda [35]: 77
Esto facilita la tarea de buscar el nombre específico para alguna función, que va a realizar alguna tarea sencilla. [36]: 'Pato'<'Murciélago'
[36]: False
Utilizaremos una lambda para introducir la función map.
Ahora la cadena pato tiene un valor numérico mayor a murciélago.
[27]: lista
[27]: [-3, 5, 8, 4, 1, -6, 7, 10] Considera la siguiente lista de animales.
[28]: list(map(lambda x:x**3,lista))
[28]: [-27, 125, 512, 64, 1, -216, 343, 1000] animales=['Pato','murciélago','Jirafa','gato','Ratón','conejo']
La función map tiene dos argumentos. El primero recibe un valor y la forma en que lo regresará, el Si los quieres ordenar alfabéticamente, entonces el orden debe ser
segundo es una lista de valores iterables. La función map también realiza una evaluación débil, por
lo que al pasarlos por la función list es posible ver los valores. 'conejo', 'gato', 'Jirafa', 'murciélago', 'Pato', 'Ratón'
La misma lista la podemos generar con una comprensión como se muestra a continuación. Observa que, en términos de orden, conejo es el mínimo en la lista, y ratón es el máximo. Para
que Python pueda comprender este orden, es necesario que todas las palabras sean mayúsculas
[29]: [valor**3 for valor in lista] o minúsculas.
[29]: [-27, 125, 512, 64, 1, -216, 343, 1000]
[37]: animales=['Pato','murciélago','Jirafa','gato','Ratón','conejo']
Sí de la lista anterior sólo queremos los números pares es posible combinar las funciones map y filter [38]: min(animales,key=lambda a:a.upper())
[38]: 'conejo'
[30]: list(map(lambda x:x**3,filter(lambda x:x%2==0,lista))) [39]: max(animales,key=lambda a:a.upper())
[30]: [512, 64, -216, 1000] [39]: 'Ratón'
Aquí, el snippet [42] llama a la función zip para empaquetar la información en tuplas. Que luego
se desempacan en pais y pib.
La función zip determina el número de tuplas, de acuerdo al argumento con menor número de
elementos, en este caso las tuplas tienen el mismo número de elementos.
5.7 Listas de 2 dimensiones Cada elemento de la lista tiene una posición específica interpretada por Python. Por ejemplo, el
elemento peso[1][2], corresponde al elemento en la posición [1][2], es decir, fila 1, columna 2.
Supongamos que un nutriólogo lleva a cabo la supervisión de 2 personas que siguen un régimen
de control de peso. Después de 4 visitas bimestrales obtuvo la siguiente tabla de datos con respec-
to al peso de los pacientes en kilogramos.
Las librerías número Pi proporciona un arreglo que es mucho más rápido que una lista en los si-
guientes capítulos haremos una comparación específica entre estas dos estrategias el arreglo que
regresa y unik es asignado a una variable que utilizará la función para graficar SENS.
Con el argumento indica a unique contar el número de ocurrencias para este ejemplo unik regresa
una tupla con dos elementos que contienen los valores ordenados y su y sus correspondientes fre-
cuencias el arreglo es para separado en funciones y frecuencias para comenzar a crear la gráfica
Diccionarios y conjuntos
6.1 Introducción
Anteriormente habías trabajado con cadenas, listas y tuplas, ahora trabajarás con colecciones no
ordenadas de elementos únicos. En términos matemáticos aprenderás a crear conjuntos y a ma-
nipular las operaciones definidas para ellos.
“Acomoda tu silla de trabajo preferida, acerca el teclado a tus manos, ponte atento y comence-
mos a programar”
6.2 Dicccionarios
Un diccionario tiene es una colección no ordenada de parejas, estas parejas contienen llaves y
datos. Los datos pueden ser números (enteros, flotantes), cadenas (strings, booleanos) o arreglos
(listas,tuplas) e incluso otro diccionario.
Es posible modificar los datos de un diccionario, o su longitud. Es decir, los diccionarios son obje-
tos mutables, sin embargo, las llaves asociadas a los datos, no lo son.
Para crear un diccionario puedes utilizar llaves e ingresar sus elementos separados con una coma.
Cada elemento se escribe con la siguiente notación:
Llave : valor
Para conocer la cantidad de parejas contenidas en el diccionario Si buscas en el diccionario una llave que no está incluida, Python te lo hará saber con un mensaje
de error.
[3]: len(usuario_nickname)
[3]: 4 [15]: usuario_edad['Pepe']
El siguiente diccionario mapea, los nombres de los usuarios con su edad. Observa que las mismas [15]: ---------------------------------------------------
llaves ahora tienen diferentes valores. KeyError Traceback (most recent call last)
<ipython-input-28-58b28069d714> in <module>
[4]: usuario_edad={'Laura':28,'Daniel':31,'Alberto':27,'Rogelio':65} ----> 1 usuario_edad['Pepe']
[5]: usuario_edad
[5]: {'Laura': 28, 'Daniel': 31, 'Alberto': 27, 'Rogelio': 65} KeyError: 'Pepe'
Para generar un arreglo con los nombres de los usuarios y su edad podemos utilizar: El método get de los diccionarios permite conocer el valor asociado a alguna llave.
Y también es posible cambiar el valor de alguna de las llaves. Supongamos que la edad de Rogelio [19]: 'Pepe' in usuario_edad
fue mal capturada. Para corregirla. [19]: False
[20]: 'Pepe' not in usuario_edad
[9]: usuario_edad['Rogelio']=35 [20]: True
[10]: usuario_edad [21]: 'Laura' in usuario_edad
[10]: {'Laura': 28, 'Daniel': 31, 'Alberto': 27, 'Rogelio': 35} [21]: True
Tanto keys, como values, solo muestran una vista del diccionario, por ejemplo: [34]: asistentes_dia1={'Ramírez':'Laura','Cortés':
'Daniel','Pérez':'Alberto'}
[25]: usuario_edad={'Laura':28,'Daniel':31,'Alberto':27, [35]: asistentes_dia2={'García':'Rogelio','Ramírez':
'Rogelio':65} 'Laura','Pérez':'Alberto'}
[26]: usuarios=usuario_edad.keys() [36]: asistentes_dia3={'Pérez':'Alberto','Cortés':
[27]: for llave in usuarios: 'Daniel','Ramírez':'Laura'}
print(llave, end=' ') [37]: asistentes_dia1 == asistentes_dia2
[37]: False
Laura Daniel Alberto Rogelio [38]: asistentes_dia2 != asistentes_dia3
[38]: True
Si añadimos otro elemento al diccionario (llave y valor). [39]: asistentes_dia3 == asistentes_dia1
[39]: True
[28]: usuario_edad['Eva']=29
Observa que en los snippets [37], [39], se trata de verificar si los diccionarios son iguales. Como los
Verificaremos que key solo actualiza al diccionario, pero no conserva una copia de la información diccionarios son colecciones no ordenadas de elementos, el orden no representa un factor que
original. indique a Python que los diccionarios son diferentes.
Para contar el número de palabras en un texto, es posible construir un diccionario que realice esta En la línea 10 tokeniza el texto, con el método split, el cual separa las palabras utilizando como
tarea. En este ejemplo las líneas 4, 5 y 6 crean una cadena de texto que es separada en palabras. argumento delimitador una palabra, si no se escribe ningún argumento, split usa por default,
Aunque los espacios en blanco concatenan a la cadena. estos espacios se sustituyen por un dato un espacio en blanco. El método regresa una lista de tokens Para cada palabra, la línea 12 deter-
reconocible por Python que es ignorado en este proceso. A esta tarea se le reconoce en inglés mina si la palabra ya fue contada. Si esto es verdadero incrementa en 1 al contador. Si es falso, es
como tokenizing a string. En la línea 8 se crea un diccionario vacío. la primera vez que se identifica la palabra y le asigna 1 a su contador.
Las llaves del diccionario son las palabras únicas, y sus valores son las veces que esta llave se repite. Las líneas 17 a la 21 se encargan de mostrar los resultados: el número de repeticiones de cada
palabra y el número de palabras únicas.
Este ejemplo está incluido en la carpeta del capítulo seis.
La tarea de contar palabras puede volverse una tarea común, en algunos casos. Por lo que Python
1 # ejemplo2_Cap6 tiene la herramienta Counter, que permite realizar esta tarea. Esta función se encuentra en las
2 """Conteo de palabras""" librerías del módulo collections. El programa anterior se puede simplificar con esta función, como
3 se muestra enseguida.
4 cuento=('cuenta un cuento que una princesa se la pasa '
5 'cuenta que cuenta ese cuento llamado la princesa ' [40]: from collections import Counter
6 'que cuenta') [41]: cuento=('cuenta un cuento que una princesa se la pasa '
7 'cuenta que cuenta ese cuento llamado la princesa '
Si quieres verificar si algún elemento está incluido en el conjunto [17]: {2,4,6,8} < {4,8,6,2}
[17]: False
[5]: 'perro' in animales
[5]: True Otra forma de verificar si un conjunto es subconjunto propio de otro es
[6]: 'gallo' in animales
[6]: False
[7]: 'gallo' not in animales [18]: {2,5,8}.issubset({5,9,8,2})
[7]: True [18]: True
Los conjuntos son iterables, esta característica permite procesar cada elemento en un ciclo for. De manera similar. A es un superconjunto propio de B, y en código lo denotaremos como A>B, si
todos los elementos de B están en A, pero existe al menos un elemento en A que no está en B
[8]: for animal in animales:
print(animal.upper(),end=' ') [19]: {2,4,6,8}>{4,8,6,2}
[19]: False
PERICO GATO GARZA PERRO RATÓN PATO [20]: {5,9,8,2}>{2,5,8}
[20]: True
Los conjuntos son colecciones no ordenadas de elementos, por lo que el orden, en este caso, es irrelevante.
Para verificar si un conjunto es un superconjunto impropio de otro
Es posible crear un conjunto, a partir de otras colecciones de valores utilizando la función set. El
código siguiente genera una lista con elementos pares en diferentes rangos y luego los concatena. [21]: {2,4,6,8}>={4,8,6,2}
[21]: True
[9]: pares=list(range(0,15,2))+list(range(8,29,2)) [22]: {2,4,6,8,10}>{4,8,6,2}
[10]: pares [22]: True
[10]: [0, 2, 4, 6, 8, 10, 12, 14, 8, 10, 12, 14, 16, 18, 20] [23]: {2,8}>{4,8,6,2}
[23]: False
Para hacer un conjunto con esta lista.
Hay 5 operaciones que es posible realizar con conjuntos
[11]: set(pares)
[11]: {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20}
Unión de conjuntos.
Observa que se eliminan los elementos repetidos. Puedes comparar este conjunto con el siguiente,
La unión de dos conjuntos, es un conjunto que tiene los elementos únicos de ambos conjuntos.
[12]: pares2=list(range(0,28,2)) Esta operación es posible con el operador &, o escribiendo el método tipo union.
[13]: pares2
[13]: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26] [24]: {'Laura','Daniel'} | {'Rogelio','Eva','Laura'}
[14]: set(pares) == set(pares2) [24]: {'Daniel', 'Eva', 'Laura', 'Rogelio'}
[14]: False [25]: {2,4,6,8}|{1,4,6,8,9}
[25]: {1, 2, 4, 6, 8, 9}
El operador == verifica si los conjuntos son exactamente iguales. Si lo son, la expresión es evaluada [26]: {2,4,6}.union([1,2,3,4,5])
como verdadera, si no lo son, será falsa. Otras formas de comparar conjuntos. [26]: {1, 2, 3, 4, 5, 6}
[24]: {'Laura','Daniel'} & {'Rogelio','Eva','Laura'} Dos conjuntos son disjuntos si no tienen elementos en común. Puedes verificar si dos conjuntos
[24]: {'Laura'} son disjuntos utilizando el método tipo isdisjoint.
[25]: {2,4,6,8}&{1,4,6,8,9}
[25]: {4, 6, 8} [26]: {1,3}.isdisjoint({2,4,6})
[26]: {1,3}&{2,4,6} [26]: True
[26]: set() [26]: {1,2,3}.isdisjoint({2,4,6})
[26]: False
En este último ejemplo, no hay intersección por lo que Python regresa un conjunto vacío.
Las anteriores operaciones entre conjuntos generan conjuntos nuevos. Sin embargo, es posible
[26]: {2,4,6}.intersection([1,2,3,4,5]) realizar estas operaciones y actualizar el conjunto original, sin la necesidad de crear un conjunto
[26]: {2, 4} nuevo. Esto se logra con el operador seguido de la asignación =. Aquí un ejemplo.
[26]: numeros = {2,4,6}
[26]: impares = {3,5,7}
Diferencia de conjuntos [26]: numeros |= impares #operador unión seguido de =
[26]: numeros
La diferencia entre dos conjuntos A, B, se denota A-B y se define como el conjunto cuyos elemen- [26]: {2, 3, 4, 5, 6, 7}
tos están en A pero no están en B
Observa que el conjunto numeros original se modificó al finalizar la operación.
[24]: {'Laura','Daniel'} - {'Rogelio','Eva','Laura'}
[24]: {'Daniel'} Esto también ocurre con el método tipo update cuando quieres realizar la operación unión con
[25]: {2,4,6,8} - {1,4,6,8,9} el conjunto que está utilizando.
[25]: {2}
[26]: {1,3} - {2,4,6} [26]: numeros.update(range(5,10))
[26]: {1,3} [26]: numeros
[26]: {2,4,6}.difference([1,2,3,4,5]) [26]: {2, 3, 4, 5, 6, 7, 8, 9}
[26]: {6}
El método tipo add permite añadir elementos al conjunto. Si el argumento no está presente en el
conjunto, lo añade. Si está, el conjunto no se modifica.
[24]: {'Laura','Daniel'} ^ {'Rogelio','Eva','Laura'} El método remove, quita el elemento que este en el argumento. Si este elemento no se encuentra
[24]: {'Daniel','Rogelio','Eva'} en el conjunto, se produce un error tipo KeyError.
[25]: {2,4,6,8} - {1,4,6,8,9}
[25]: {1,2,9} [26]: numeros.remove(9)
[26]: {1,3} - {2,4,6} [26]: numeros
[26]: {1,2,3,4,6} [26]: {2, 3, 4, 5, 6, 7, 8, 11}
Por último, una función que puede ser útil es el método tipo clear. Este método deja vacío al
conjunto que se está invocando.
[26]: numeros.clear())
[26]: numeros
[26]: set()
Programación
con Numpy
7.1 Introducción
En este capítulo aprenderás a utilizar algunas cualidades básicas de NumPy (Numerical Python).
NumPy es una de las librerías más populares de Python, ya que puede procesar listas de múltiples
dimensiones que incluyen lazos anidados, o comprensión de listas con diversas sentencias for.
En la parte final, realizarás una introducción a la librería pandas que es útil para el análisis en cien-
cia de datos.
Así es que,…
“Ponte zapatos cómodos, ropa holgada y fresca. Sigamos caminando por este sendero, orienta-
dos por la brújula de la programación”
El módulo numpy proporciona diversas formas de crear arreglos. Por ejemplo, la función array es
útil para este propósito
[3]: type(factoriales) Para conocer el número de elementos en el arreglo puedes utilizar el atributo size. Y el número
[4]: factoriales de bytes necesarios para almacenarlos se puede conocer mediante itemsize.
[4]: array([ 1, 2, 6, 24, 120, 720])
[17]: enteros.size
Observa que, en la salida de factoriales, NumPy separa cada valor del siguiente con una coma y un [17]: 8
espacio con alineación a la derecha. NumPy deja tantos lugares como sean necesarios, para que [18]: enteros.itemsize
cada elemento cuente con el mismo campo, aunque en algunos casos, sean espacios en blanco. El [18]: 4
ancho del campo queda determinado por el número que tenga la mayor cantidad de caracteres. [19]: flotantes.size
[19]: 6
La función array copia automáticamente las dimensiones del argumento. Por ejemplo, el siguien- [20]: flotantes.itemsize
te arreglo (array) está formado por tres filas y dos columnas. [20]: 8
[5]: np.array([[3,4],[6,7],[10,11]]) Para manipular arreglos es posible hacerlo con el estilo funcional de programación, pero también
[5]: array([[ 3, 4], se puede hacer empleando iteraciones externas, como hasta hoy lo has estado haciendo
[ 6, 7],
[10, 11]]) [21]: for fila in flotantes:
for columna in fila:
Un arreglo tiene atributos que poco a poco irás conociendo. En esta sección utilizaremos los siguientes. print(columna, end=' ')
print()
[6]: import numpy as np
[7]: enteros = np.array([[9,10,11,12],[8,7,6,5]]) 3.0 3.1622776601683795 3.33
[8]: enteros 3.3333333333333335 3.4 3.03
[8]: array([[ 9, 10, 11, 12],
[ 8, 7, 6, 5]]) Puedes, por otro lado, convertir un arreglo multidimensional en uno, de una dimensión con el
[9]: flotantes=np.array([[9**(1/2),10**(1/2),3.33,],[10/3,3.4,3.03]]) atributo flat.
[10]: flotantes
[10]: array([[3. , 3.16227766, 3.33 ], [22]: for n in enteros.flat:
[3.33333333, 3.4 , 3.03 ]]) print(n,end=' ')
Puedes verificar el tipo de elemento generado con dtype. 9 10 11 12 8 7 6 5
[11]: enteros.dtype NumPy tiene funciones que permiten rellenar arreglos con valores específicos. Estas funciones
[11]: dtype('int32') # en algunas plataformas puede ser int64 son zeros, ones y full.
[12]: flotantes.dtype
[12]: dtype('float64') [23]: import numpy as np
[24]: np.zeros(5)
El atributo ndim contiene el número de dimensiones del arreglo y el atributo shape contiene una [24]: array([0., 0., 0., 0., 0.])
tupla que especifica las dimensiones del arreglo. [25]: np.ones((3,2),dtype = int)
[25]: array([[1, 1],
[13]: enteros.ndim [1, 1],
[13]: 2 [1, 1]])
[14]: flotantes.ndim [26]: np.full((2,4),10)
[14]: 2 [26]: array([[10, 10, 10, 10],
[15]: enteros.shape [10, 10, 10, 10]])
[15]: (2, 4)
ValueError: cannot reshape array of size 2000 into shape (4,2000) Este último snippet, permite verificar que el arreglo original no cambió. Otras funcionalidades de
NumPy si cambian al arreglo, por ejemplo, +=, o -=.
Si el arreglo tiene 1,000 o más elementos, NumPy no muestra la totalidad de datos. Para no ocupar
espacio la librería divide al arreglo permitiendo ver una parte de la información. [8]: pares -=1
[9]: pares
El siguiente ejemplo genera un arreglo con 10,000 elementos, para generar otro con 5 filas y 2,000 [9]: array([ 1, 3, 5, 7, 9, 11, 13])
columnas.
Puedes realizar operaciones entre arreglos que tengan las mismas dimensiones.
[34]: np.arange(0,10000).reshape(5,2000)
[34]: array([[ 0, 1, 2, ..., 1997, 1998, 1999], [10]: lista1 = np.arange(2,18,3)
[2000, 2001, 2002, ..., 3997, 3998, 3999], [11]: lista1
[4000, 4001, 4002, ..., 5997, 5998, 5999],
Utilizaremos los métodos sum, min, max, mean, std, var. Que calculan respectivamente, Este último resultado es equivalente a la operación entre arreglos
la suma, el valor mínimo, el máximo, el promedio, la desviación estándar y la varianza con todos
los datos. lista1 + lista2
Entonces, la multiplicación de los arreglos lista3 y lista4 es Con esta notación está indicando a NumPy que solo requieres la fila con índice 1. Para solicitar las
filas con índices 0 y 1
[42]: np.multiply(lista3,lista4)
[42]: array([[ 6, -16, 30, -48], [7]: ventas[0:2]
[ 14, -32, 54, -80]]) [7]: array([[ 554, 606, 710, 851],
[1244, 898, 416, 1763]])
Observa que, con esta forma de multiplicar, lista4 se multiplicó con cada fila de lista3.
Recuerda que con los índices, Python ignora el superior en ventas[0:2]. Entonces, para solici-
NumPy tiene una lista grande de funciones universales, la puedes consultar en : tar las filas con índices 1 y 2.
Recuerda que, en el caso de índices, Python enumera al primer índice como 0. Entonces, para ubi- [11]: ventas[:,[0,2]]
car el elemento ventas[2,1], se encuentra en la fila con índice 2, y columna con índice 1. [11]: array([[ 554, 710],
[1244, 416],
[ 841, 1105]])
Los arreglos que regresa NumPy de la forma array([[argumentos]]), son llamados vistas(views) o
copias superficiales (shallow copies). Otros métodos que muestran resultados pueden definirse con
NumPy a través de view.
El método copy para arreglos genera una copia profunda del arreglo original. [40]: ventas = np.array([[ 500, 600, 550, 800],
[1200, 800, 400,1000]])
Para verificar lo anterior, el siguiente código genera un arreglo con números impares y luego aplica [41]: ventas
el método copy. [41]: array([[ 500, 600, 550, 800],
[1200, 800, 400, 1000]])
[25]: import numpy as np [42]: vector_ventas=ventas.flatten()
[26]: impares = np.arange(3,18,2) [42]: array([[ 500, 600, 550, 800,
[27]: impares 1200, 800, 400, 1000]])
[27]: array([ 3, 5, 7, 9, 11, 13, 15, 17]) [43]: ventas
[28]: impares2 = impares.copy() [43]: array([[ 500, 600, 550, 800],
[29]: impares2 [1200, 800, 400, 1000]])
[29]: array([ 3, 5, 7, 9, 11, 13, 15, 17])
Un DataFrame es un arreglo de dos dimensiones. Y cada columna del DataFrame es un arreglo Puedes acceder a una fila a través del atributo loc de DataFrame.
tipo Series, justo como en la sección anterior. Por lo tanto, todos los atributos de Series son apli-
cables al DataFrame. [9]: peso.loc['Mes 1']
[9]: Vanes 68
El siguiente código genera un diccionario y a partir de él, se crea el DataFrame. Los datos represen- Kevin 89
tan el peso en kilos registrados por una nutrióloga, a lo largo de cuatro meses, de cuatro pacientes. Fernanda 59
Patricia 70
[1]: import pandas as pd Name: Mes 1, dtype: int64
[2]: reg_peso = {'Vanesa':[68,67,66,65],'Kevin':[89,89,90,88],
'Fernanda':[59,60,60,62],'Patricia':[70,68,67,65]} También es posible acceder a las filas a través de índices. Para esto necesitas el atributo iloc.
[3]: peso = pd.DataFrame(reg_peso)
[4]: peso [10]: peso.iloc[1]
[4]: Vanesa Kevin Fernanda Patricia [10]: Vanesa 67
0 68 89 59 70 Kevin 89
1 67 89 60 68 Fernanda 60
2 66 90 60 67 Patricia 68
3 65 88 62 65 Name: Mes 2, dtype: int64
Para añadir índices personalizados Si requieres parte del arreglo, por ejemplo, del mes 1 al mes 3.
[5]: peso.index = ['Mes 1','Mes 2','Mes 3','Mes 4'] [11]: peso.loc['Mes 1':'Mes 3']
[6]: peso [11]: Vanesa Kevin Fernanda Patricia
[6]: Vanesa Kevin Fernanda Patricia Mes 1 68 89 59 70
Mes 1 68 89 59 70 Mes 2 67 89 60 68
Si es con índices numéricos. Este último peso corresponde al paciente en la fila con índice 2 (Mes 3) y columna con índice 0 (Vanesa).
[14]: peso.loc[[0, 2]] Estos atributos también permiten modificar algún elemento del DataFrame. Supongamos que el
[14]: Vanesa Kevin Fernanda Patricia peso de Kevin en el mes 4 debe ser de 85kg, y el Fernanda debe ser 59 en el mes 2 (índices [1,2]).
Mes 1 68 89 59 70
Mes 3 66 90 60 67 [21]: peso.at['Mes 4','Kevin']=85
[22]: peso.at['Mes 4','Kevin']
Con meses específicos y pacientes específicos. [22]: 85
[23]: peso.iat[1,2]=59
[15]: peso.loc['Mes 2':'Mes 3',['Vanesa','Patricia']] [24]: peso.iat[1,2]
[15]: Vanesa Patricia [24]: 59
Mes 2 68 68
Mes 3 66 67 El DataFrame queda de la forma
El siguiente código muestra los estadísticos por mes con la función describe.
[35]: peso.sort_values(by='Mes 1', axis=1,ascending=False)
[31]: peso.T.describe() [35] Kevin Patricia Vanesa Fernanda
[31]: Mes 1 Mes 2 Mes 3 Mes 4 Mes 1 89 70 68 59
count 4.0 4.0 4.0 4.0 Mes 2 89 68 67 59
mean 71.5 70.8 70.8 69.2 Mes 3 90 67 66 60
Mes 4 85 65 65 62
138 | Capítulo 7: Programación con Numpy Manual Python | 139
Con las mismas condiciones, pero utilizando la transpuesta
Cadenas
8.1 Introducción
Este capítulo está pensado en hacer un acercamiento a las cadenas (strings) de caracteres. Mucha de
la información disponible, en las grandes bases de datos, está guardadas o definidas en archivos que
contienen cadenas de información. Una de las grandes aplicaciones de Python es la identificación de
patrones en cadenas de texto. En este capítulo revisarás algunos principios para posteriormente y
esta es el área fundamental para lo que conoce como Procesamiento de Lenguaje Natural.
[1]: f'{3.141592:0.3f}'
[1]: '3.141'
Observa que Python atiende la instrucción del formato float, pero termina mostrando el resultado
como una cadena.
Enteros, con el tipo de presentación d. Los números que aparecen después de los dos puntos (:) indican la longitud del campo. Esta lon-
gitud ya incluye la cantidad de caracteres de la cadena. Por ejemplo, en el snippet [7], la cadena
[2]: f'{150:d}' Alineación ocupa 10 caracteres y añade otros 5 en forma de espacios en blanco.
[2]: '150'
Pero además de especificar la longitud del campo y la cantidad de decimales, también puedes ali-
Caracteres, con el tipo de presentación c. near a la cadena con los símbolos > y <.
[4]: f'{"Este curso está de":s} {100}' Y para centrar, tanto el texto como los valores
[4]: 'Este curso está de 100'
[12]: f'[{"Alineación":^12}{3.14:^10f}]'
Recuerda que habías empleado el f-string para dar formato al texto de salida, y hasta podías [12]: '[ Alineación 3.140000 ]'
especificar el número de caracteres para una cadena añadiendo espacios en blanco. Por default, [13]: f'[{"Alineación":^15}]'
Python da una alineación a la derecha, a los valores; y a las cadenas, a la izquierda. Además, para [13]: '[ Alineación ]'
que esto ocurra debes encerrar los resultados entre corchetes. [14]: f'[{3.14:^10.1f}]'
[14]: '[ 3.1 ]'
Aquí hay algunos ejemplos que muestran la forma de asignar un campo en el f-string.
En el caso particular de cadenas de números, si requieres mostrar el signo. Puedes agregarlo en
[5]: f'[{314:10d}]' el f-string.
[5]: '[ 314]'
[6]: f'[{"Alineación":15}{3.14:10f}]' [15]: f'[{150:+10d}]'
[6]: '[Alineación 3.140000]' [15]: '[ +150]'
[7]: f'[{"Alineación":15}]'
[7]: '[Alineación ]' Para agregar ceros en los espacios en blanco.
[8]: f'[{3.14:10f}]'
[8]: '[ 3.140000]' [16]: f'[{150:+010d}]'
[16]: '[+000000150]'
Python asigna a los números tipo float, 6 dígitos de precisión. Debido a esto, en la salida del sni-
ppet [6] y [7] aparece el número 3.140000. Regularmente a los números positivos no se les agrega el signo +. Pero, si requieres dejar el espa-
cio en blanco para este tipo de números, utiliza un código como el siguiente.
La sintaxis que emplea float en el f-string es la siguiente:
[17]: print(f'{27:d}\n{27: d}\n{-27: d}')
[17]: 27
27
-27
Al operar con cantidades grandes, muchas veces es conveniente utilizar comas para indicar miles
o millones. Esto es posible hacerlo con Python.
[22]: '{0} {0} {0} {1} {2}'.format('Vamos','sigue','adelante') Si requieres eliminar todos los espacios en blanco (esto incluye tabulaciones y saltos de línea), al
[22]: 'Vamos Vamos Vamos sigue adelante' inicio y al final del enunciado. El método strip realiza esta tarea
Y también puedes trabajar con variables dentro del argumento de format [3]: enunciado.strip()
[3]: 'me gusta escuchar música alegre'
[23]: '{nombre} {apellido}'.format(nombre='Rogelio',apellido='García')
[23]: 'Rogelio García' Para eliminar los espacios en blanco a la izquierda (inicio) de la cadena.
[24]: '{apellido} {nombre}'.format(nombre='Rogelio',apellido='García')
[24]: 'García Rogelio' [4]: enunciado.lstrip()
[4]: 'me gusta escuchar música alegre \t\t \n'
Anteriormente utilizaste el símbolo + para concatenar cadenas. Además de esta operación puedes
repetir una misma cadena, de manera similar al snippet [22] O los espacios de la derecha (final) de la cadena.
El método capitalize, cambia la primera letra de una cadena por una mayúscula. Si la letra ya Los argumentos 8, 18 indican los índices de los caracteres entre los cuales se debe realizar la bús-
es mayúscula, no se presenta ningún cambio. queda, en el código anterior, Python busca la cadena quizás entre las letras señaladas con verde.
[7]: 'me gusta eschuchar música alegre. bailemos'.title() 'quizás si quizás no quizás es una posibilidad'
[7]: 'Me Gusta Eschuchar Música Alegre. Bailemos'
El método index busca una subcadena dentro de una cadena, e indica el primer índice en donde
El método title, cambia la primera letra de cada palabra de una cadena por una mayúscula. Si la aparece. Si la subcadena no está incluida, ocurre un error del tipo ValueError.
letra ya es mayúscula, en alguna de las palabras, en éstas, no se presenta ningún cambio. Además
de dar formato a las cadenas, Python permite compararlas. Esto se realiza con los valores numéri- [18]: enunciado.index('quizás')
cos que tiene cada carácter. Aquí algunos ejemplos. [18]: 0
[8]: 'Python' == 'python' El resultado indica que la cadena 'quizás' aparece en la primera palabra de la cadena.
[8]: False
[9]: 'Python' != 'python' [19]: enunciado.rindex('quizás')
[9]: True
[19]: 20
[10]: 'Python' > 'python'
[10]: False
[11]: 'Python' < 'python' El método rindex realiza la misma tarea que index, pero inicia la búsqueda desde la parte final
[11]: True de la cadena. En el caso de la cadena
[12]: 'Python' >= 'python'
[12]: False 'quizás si quizás no quizás es una posibilidad'
[13]: 'Python' <= 'python'
[13]: True El caracter s, de la tercera palabra quizás, ocupa el índice 20 iniciando desde la parte final.
Si solo necesitas conocer si en la cadena se encuentra una subcadena, es posible utilizar los ope-
Para contar el número de veces que aparece un trozo de cadena (substring) en una cadena más radores in o not in.
grande, Python cuenta con el método count. Por ejemplo.
[20]: 'Si' in enunciado
[14]: enunciado='quizás si quizás no quizás es una posibilidad' [20]: False
[15]: enunciado.count('quizás') [21]: 'Si' in enunciado
[15]: 3 [21]: True
[22]: 'Si' not in enunciado
Si añades un segundo argumento, éste indica el índice de inicio de la búsqueda (recuerda que los [22]: True
índices inician en 0).
Los métodos startswith y endswith regresan True si la cadena inicia o termina, respectiva-
[16]: enunciado.count('quizás',8) mente, con alguna subcadena específica.
[16]: 2
[23]: enunciado.startswith('quizás')
El argumento 8, es el índice del caracter a partir del cual inicia la búsqueda, en el caso de la cadena [23]: True
[24]: enunciado.startswith('si')
'quizás si quizás no quizás es una posibilidad' [24]: False
[25]: enunciado.endswith('posibilidad')
El caracter con índice 8 es la i, antes del espacio en blanco del segundo quizás.
[25]: True
[26]: enunciado.endswith('una')
Si añades un segundo y tercer argumento al método count, estarás indicando el campo en donde
Python debe realizar la búsqueda. [26]: False
[30]: unir_palb=['p','a','l','a','b','r','a'] Esta misma estrategia puede emplearse para identificar caracteres alfanuméricos
[31]: ','.join(unir_palb)
[31]: 'p,a,l,a,b,r,a' [40]: 'Code84'.isalnum()
[40]: True
El siguiente snippet une los elementos de una comprensión de lista. [41]: '3.1416'.isalnum()
[41]: False
[32]: ','.join([str(n) for n in range(1,11)]) [42]: 'Calle 5 No 314'.isalnum()
[32]: '1,2,3,4,5,6,7,8,9,10' [42]: False
Si hay una gran cantidad de texto en una cadena, puede ser deseable separar la cadena en una El snippet [40] ha sido calificado como verdadero porque contiene caracteres alfabéticos y nu-
lista de líneas. El método splitlines regresa una lista de cadenas que representan líneas de méricos, los otros dos han sido calificados como falsos, ya que contienen caracteres que no son
texto. Como en el siguiente código. alfanuméricos como el punto decimal del snippet [41] y los espacios del snippet [42].
[33]: verso="""Ayer pensé en tí, Dentro de los caracteres que no son alfanuméricos, uno de ellos que es de bastante utilidad y al
creí que aquí estabas, que está dedicado este espacio es la diagonal invertida o backslash. Este carácter es utilizado, por
y cuando mi rostro volví, un lado, para definir secuencias de escape como los saltos de línea (\n) o las tabulaciones (\t).
note que me mirabas""" Por otro lado, Microsoft Windows lo emplea para separar nombres de carpetas y las ubicaciones
[34]: verso de los archivos.
[34]: 'Ayer pensé en tí,\ncreí que aquí estabas,\ny cuando
mi rostro volví,\nnote que me mirabas' Para indicar alguna ubicación en Windows es aceptable escribir
[35]: verso.splitlines()
[35]: ['Ayer pensé en tí,', [43]: ubicación='C\\usuario\\documentos\\praticas\\mi_archivo.txt'
'creí que aquí estabas,', [44]: ubicación
'y cuando mi rostro volví,', [44]: 'C\\usuario\\documentos\\praticas\\mi_archivo.txt'
'note que me mirabas']
Una expresión regular es un patrón de coincidencia de texto, que tiene una sintaxis muy específi- Los snippets [5] y [6] validan si la cadena definida por el número telefónico, contiene 10 dígitos.
ca. Un ejemplo de una expresión regular son los números de un teléfono. Contienen 10 dígitos y
los dos primeros indican la región del país. Así que al leer un número telefónico es posible recono- También es posible verificar si, por ejemplo, el nombre de las personas está bien escrito (letra ma-
cer la región a la que pertenece y si está bien escrito (dígitos completos) yúscula al inicio del nombre).
Otros casos de expresiones regulares son: el código postal, el número de seguro social, el registro [7]: 'Escritura válida' if re.fullmatch('[A-Z][a-z]*','rogelio')
federal de contribuyente (RFC), la clave única de registro de población (CURP), las direcciones de else 'Escritura no válida'
correo electrónico, etc. Al verificar que todos estos objetos cumplen con el patrón adecuado, esta- [7]: 'Escritura no válida'
rás dando una validación de los datos ingresados.
[8]: 'Escritura válida' if re.fullmatch('[A-Z][a-z]*','Laura')
else 'Escritura no válida'
[8]: 'Escritura válida'
Además de validar información, las expresiones regulares también son aplicables para: [9]: 'Escritura válida' if re.fullmatch('[A-Z][a-z]*','Rogelio')
else 'Escritura no válida'
• La extracción de datos de texto. [9]: 'Escritura válida'
• Limpiar datos.
• Transformar datos en otros formatos. Aquí, [A-Z] verifica que la primera letra esté escrita con mayúsculas, de manera similar, [a-z]*
verifica si las letras, después de la primera, están escritas con minúsculas. El operador *, en [a-
Para utilizar expresiones regulares es necesario importar el módulo re.
z]*, verifica si hay cero o más ocurrencias de [a-z].
[1]: import re Al escribir [^a-z], estarás verificando si algún caracter no coincide con las letras minúsculas.
La función más simple para expresiones regulares es fullmatch. A continuación, se muestran [10]: 'Correcto' if re.fullmatch('[^a-z]','O') else 'Incorrecto'
algunos ejemplos de la forma en que se puede utilizar. [10]: 'Correcto
[11]: 'Correcto' if re.fullmatch('[^a-z]','w') else 'Incorrecto'
[2]: código = '9400354' [11]: 'Incorrecto'
[3]: 'Código correcto' if re.fullmatch(código,'9400355') else [12]: 'Correcto' if re.fullmatch('[^a-z]','o') else 'Incorrecto'
'Código incorrecto' [12]: 'Incorrecto'
[3]: 'Código incorrecto'
[4]: 'Código correcto' if re.fullmatch(código,'9400354') else Si requieres verificar si al menos una letra minúscula aparece en el nombre, puedes utilizar [a-z]+
'Código incorrecto'
[4]: 'Código correcto' [13]: 'Correcto' if re.fullmatch('[A-Z][a-z]+','Eva') else 'Incorrecto'
[13]: 'Correcto'
Esta parece ser una tarea muy obvia, pero en realidad la utilizas con bastante frecuencia, por ejem- [14]: 'Correcto' if re.fullmatch('[A-Z][a-z]+','E') else 'Incorrecto'
plo: al escribir tu nip en un cajero automático, o tu contraseña al encender tu computadora, o la [14]: 'Incorrecto'
clave para activar tu celular.
Otras dos funcionalidades del módulo re, son sub y split. Observa estos ejemplos Los módulos re tienen características opcionales para realizar búsquedas más robustas. En el
siguiente caso, al módulo re se le agrega una bandera que ignora si la coincidencia en la cadena
[21]: import re está escrita con mayúsculas o minúsculas.
[22]: re.sub(r'\n',', ','Salto 1\nSalto 2\nSalto 3')
[22]: 'Salto 1, Salto 2, Salto 3' [31]: busca3=re.search('GUIDO','Guido Van Rossum',flags=re.
IGNORECASE)
La función sub requiere de tres argumentos [32]: busca3.group() if busca3 else 'no se encontró'
[32]: 'Guido'
• El modelo de coincidencia, en este ejemplo el salto de línea ('\n')
• El texto de reemplazo, en este ejemplo, la coma (', ') El meta caracter ^ al principio de una cadena regular, es un ancla que indica a Python buscar la
• La cadena donde será buscado el modelo ('Salto 1\nSalto 2\nSalto 3') expresión que coincide solo con el inicio de la cadena. Si la encuentra, la muestra
Al final, obtienes una cadena nueva. También puedes declarar un número máximo de reemplazos. [33]: buscador=re.search('^Guido','Guido Van Rossum es el
creador de Python',flags=re.IGNORECASE)
[23]: re.sub(r'\n',', ','Salto 1\nSalto 2\nSalto 3', count=1) [34]: buscador.group() if buscador else 'no se encontró'
[23]: 'Salto 1, Salto 2\nSalto 3' [34]: 'Guido'
[35]: buscador=re.search('^Rossum','Guido Van Rossum es el
La función split puede tokenizar una cadena utilizando una expresión regular al especificar un creador de Python',flags=re.IGNORECASE)
delimitador y regresar una cadena. Haremos una separación utilizando como delimitador, una [36]: buscador.group() if buscador else 'no se encontró'
coma, o una coma seguida por espacios en blanco. [36]: 'no se encontró'
[24]: re.split(r',\s*','s, e,p,a, r, a, d,o') De manera similar, el meta caracter $ al final de una cadena regular, es un ancla que indica a
[24]: ['s', 'e', 'p', 'a', 'r', 'a', 'd', 'o'] Python buscar la expresión que coincide solo al final de la cadena. Si la encuentra, la muestra.
[41]: usuario='Francisco García, Tel_casa:52-1234-1234, El método match aplica la expresión regular \w{4}\d{6} a cada elemento de Series, validando
Celular:52-4321-4321' si los elementos tienen exactamente 4 letras y 6 dígitos. Observa que no es necesario escribir un
[42]: re.findall(r'\d{2}-\d{4}-\d{4}',usuario) ciclo para revisar cada uno de los elementos, match lo realiza de manera automática.
[42]: ['52-1234-1234', '52-4321-4321']
Ahora crearemos una cadena que contiene los nombres de tres países, su código ISO 3 y el prefijo
Con finditer. telefónico.
[43]: for telefono in re.finditer(r'\d{2}-\d{4}-\d{4}', usuario): [5]: códigost=pd.Series(['México, MEX 52','Colombia, COL
print(telefono.group()) 57','Chile, CHL 56'])
[43]: 52-1234-1234 [6]: códigost
52-4321-4321 [6]: 0 México, MEX 52
1 Colombia, COL 57
Naturalmente, cuando hay una gran cantidad de coincidencias, la lectura es más sencilla con fin- 2 Chile, CHL 56
diter y con la bondad de no ocupar tanto espacio en la memoria de la computadora. dtype: object
[7]: códigost.str.contains(r' [A-Z]{3}')
[7]: 0 True
8.5 Pandas y Expresiones Regulares 1 True
2 True
En esta sección utilizaremos las expresiones regulares para validar la escritura del RFC. dtype: bool
[8]: códigost.str.match(r' [A-Z]{3}')
En México, el RFC es el Registro Federal de Contribuyentes, que es una clave única alfanumérica [8]: 0 False
con la que el gobierno de México, identifica a personas físicas (personas que reciben un salario) y 1 False
personas morales (empresas) que lleven a cabo una actividad económica en el país. 2 False
dtype: bool
Para una persona física, el RFC sin homoclave (sin registro oficial), consta de 4 letras y 6 dígitos. Las
letras están vinculadas al nombre de la persona y los dígitos con la fecha de nacimiento. El snippet [7] utiliza la función contains para mostrar que los tres elementos de Series contienen
subcadenas que coinciden con [A-Z]{3}. Es decir, la cadena tiene 3 letras mayúsculas. El snippet
El siguiente código crea una Series de Pandas con los RFC de dos usuarios. Intencionalmente [8] emplea match para mostrar si alguno de los elementos en Series coincide completamente con
uno de ellos tiene un error. El objetivo es ver la forma en que Python lo identifica este error. [A-Z]{3}. Aunque las letras mayúsculas si aparecen, también aparecen espacios en blanco y
números, por lo que no hay, en ningún caso una coincidencia completa.
[1]: import pandas as pd
[2]: rfc=pd.Series({'Usuario1': 'COG891201','Usuario2':
'GUHA911020'})
[3]: rfc
Archivos
9.1 Introducción
Hasta hoy, los programas o códigos que elaboraste conservan solo temporalmente los datos que
haz utilizado. Sin embargo, puede resultar necesario conservar esta información en archivos con
el fin de realizar consultas o hacer informes posteriores. En este capítulo aprenderás a guardar
tus resultados en diferentes formatos como: TXT (texto plano), JSON (JavaScript Object Notation), y
CSV (coma-separated values). Además de aprender a lidiar con algunos tipos de errores que ocu-
rren con frecuencia al momento de programar.
Mensaje
Cada sistema operativo tiene su propio instrumento para indicar cuando termina el archivo. A este
elemento se le llama end-on-file marker.
Por cada archivo que se abre, Python genera un archivo tipo objeto que le permite interactuar con
el archivo original.
Fuente: https://marketing4ecommerce.mx/top-los-influencers-mas-seguidos-en-redes-sociales- Para cambiar alguno de los registros, no es recomendable modificar directamente el archivo de
en-el-mundo/. Última revisión 26/02/2021. texto, pues se corre el riesgo de cambiar las características del archivo, como la cantidad de carac-
teres o el tamaño de los campos que Python lee a través de sus rutinas.
Notas Hacerlo a través de Python puede resultar un tanto complejo. La siguiente rutina muestra todos
los pasos que se realizan.
La sentencia with de Python
[3]: seguidores=open('seguidores.txt','r')
• Gestiona un recurso (un archivo tipo objeto para seguidores.txt) y asigna este objeto a [4]: temporal=open('temporal.txt','w')
una variable (seguidores). [5]: with seguidores,temporal:
• Otorga permisos a la aplicación para manipular el recurso a través de la variable. for record in seguidores:
• Llama al instrumento end-on file marker, para liberar el recurso cuando el programa handle,nombre,num_seg = record.split()
finaliza. if handle!='@charlidamelio':
temporal.write(record)
La función open abre el archivo seguidores.txt asociado con el archivo tipo objeto. La función else:
open tiene dos argumentos: el primero es el nombre del archivo, el segundo es el modo, que pue- nuevo_nombre=' '.join([handle, 'Charlie', num_seg])
de ser de lectura o escritura. En este caso w. Este modo indica que el archivo se abre para escribir temporal.write(nuevo_nombre +'\n')
(write). El archivo se guarda por default, en la misma carpeta en donde se escribe el código con
extensión TXT. Observa que cambiar un solo registro requiere:
La sentencia with asigna el objeto generado por open a la variable seguidores, por medio de as. • Copiar el registro que se quiere modificar en un archivo temporal
Dentro de la sentencia with, la variable interactúa con el archivo con el método write, que se • Escribir la modificación que ha de realizarse
presenta 4 veces en el código para anexar los datos de los usuarios. • Copiar la actualización en el archivo temporal
• Renombrar al archivo temporal con el nombre original
El archivo seguidores.txt, contiene la siguiente información
La desventaja de esto, es que se genera un archivo nuevo que ocupa espacio en la memoria. La
@charlidamelio D’Amelio 108.1 ventaja es que la información original no se modifica. Aunque esta rutina puede resultar incómo-
@addisonre Addison 76.4 da, tiene un mejor rendimiento cuando el archivo tiene una gran cantidad de registros y se requie-
@zachking Zach 56.6 ren hacer múltiples modificaciones.
@bellapoarch Bella 56.3
Los datos del archivo temporal de seguidores son:
La tarea de revisar los contenidos a través de Python se puede realizar con el siguiente código.
@charlidamelio Charlie 108.1
[2]: with open('seguidores.txt', mode = 'r') as seguidores: @addisonre Addison 76.4
print(f'{"Handle" :<20}{"Nombre" :<10}{"num_seg" :>10}') @zachking Zach 56.6
for record in seguidores: @bellapoarch Bella 56.3
handle,nombre,num_seg = record.split()
Los objetos tipo JSON son similares a los diccionarios de Python. Cada objeto JSON contiene un Como en los archivos TXT, la función open ahora tiene en el segundo argumento la opción 'r' de
lista con elementos agrupados con llaves, { }. Los elementos son nombres clave y sus valores se- lectura.
parados por comas.
Justo como esperabas, ya puedes acceder a los contenidos del diccionario. Para obtener la lista del
Por ejemplo: {'handle':@charlidamelio, 'name':'Charlie', 'puntos': 108.1} diccionario asociada a la llave 'seguidores':
Aunque también, JSON soporta arreglos con elementos separados por comas agrupados entre [6]: seguidores_json['seguidores']
corchetes. [6]: [{'handle': '@charlidamelio', 'name': 'Charlie', 'num_seg': 108.1},
{'handle': '@addisonre', 'name': 'Addison', 'num_seg': 76.4},
Por ejemplo: [108.1, 76.4, 56.6 56.3] {'handle': '@zachking', 'name': 'Zach', 'num_seg': 56.6},
{'handle': '@bellapoarch', 'name': 'Bella', 'num_seg': 56.3}]}
Pyhon tiene en sus librerías el módulo json que permite interactuar objetos JSON con archivos
de texto. Y para obtener los registros individuales
Consideremos el siguiente diccionario referente al número de seguidores que tienen los usuarios [7]: seguidores_json['seguidores'][0]
de la aplicación TikTok. [7]: {'handle': '@charlidamelio', 'name': 'Charlie', 'num_seg': 108.1}
[8]: seguidores_json['seguidores'][3]
[1]: seguidores_dicc={'seguidores\n':[ [8]: {'handle': '@bellapoarch', 'name': 'Bella', 'num_seg': 56.3}
{'handle':'@charlidamelio', 'name':'Charlie', 'num_seg':108.1},
{'handle':'@addisonre', 'name':'Addison', 'num_seg':76.4},
{'handle':'@zachking', 'name':'Zach', 'num_seg':56.6}, Nota PREVENTIVA.
{'handle':'@bellapoarch', 'name':'Bella', 'num_seg':56.3}]}
Otra forma de serializar y deserializar es con el módulo pickle de Python. Sin embargo, la docu-
Para escribir este objeto con el formato JSON. mentación de Python hace algunas advertencias acerca del módulo pickle:
[2]: import json • Los archivos pickle pueden ser hackeados fácilmente, por lo que no es nada confiable
[3]: with open('seguidores.json','w') as seguidores: abrir archivos con este formato.
json.dump(seguidores_dicc,seguidores) • El protocolo de pickle puede llevar a una serialización profundamente compleja de ob-
jetos de Python que pueden derivar en la interacción no autorizada con otras aplica-
ciones, particularmente si los datos fueron creados con objetivos fraudulentos de un
El snippet [6] abre archivo seguidores.json y utiliza la función dump del módulo json para
experto.
serializar al diccionario seguidores_dicc dentro del archivo. El archivo seguidores.json con-
tiene a los elementos. Como en los archivos TXT, la función open tiene en el segundo argumento
Cuando abres un archivo, además de los modos de lectura (r) y de escritura (w), Python cuenta con
la opción 'w' para escribir.
otros modos de trabajar archivos.
Para recuperar los datos del archivo JSON es posible utilizar la función load. La función load del
módulo json realiza una lectura de todos los elementos del archivo JSON y convierte a este ele-
mento en un objeto de Python, a esto se le llama deserializar los datos.
ValueError: invalid literal for int() with base 10: 'hola mundo'
En ambos casos la ejecución del programa se detiene para mostrar el mensaje de error. Para dar
continuidad a la ejecución del programa, si es que hay más tareas por realizar. La estrategia es
reconocer cuando ocurre la excepción y manipularla para que el programa siga con la totalidad de
las tareas. Aquí está un ejemplo que evita la excepción ZeroDivisionError.
Ejemplo 1
# programa1_C9.py
"""Manipulación de la excepción ZeroDivisionError"""
En el ejemplo anterior, Python utiliza la sentencia try. La condición try es seguida de una o más [3]: with open('seguidores.csv','r', newline='') as seguidores:
excepciones, cada except especifica un tipo de excepción a manipular. Después del último ex- print(f'{"Handle":<20}{"Nombre":<10}{"Seguidores":>10}')
cept, una condición opcional else, se ejecuta, si ninguna excepción ocurre. lectura=csv.reader(seguidores)
for record in lectura:
El programa del ejemplo 1, trata de dividir dos números enteros, por lo que pide al usuario intro- handle, nombre, num_seg=record
ducir dos números: numerador y denominador. Si alguno de los dos números no es entero, se print(f'{handle:<20}{nombre:<10}{num_seg:>10}')
comete una excepción tipo ValueError, y solicita al usuario ingresar nuevamente los valores. Si
se asigna al denominador el valor de cero, ocurre una excepción del tipo ZeroDivisionError, Handle Nombre Seguidores
por lo que vuelve a solicitar al usuario introducir nuevos valores. Cuando se introducen los dos va- @charlidamelio Charlie 108.1
lores son enteros y el denominador no es cero, el programa muestra la división de los dos valores. @addisonre Addison 76.4
@zachking Zach 56.6
@bellapoarch Bella 56.3
9.5 Archivos CSV
La función reader del módulo csv regresa un objeto que lee los datos del formato CSV del
Este es uno de los tópicos más populares en Python, pues representa una herramienta poderosa archivo objeto.
que se utiliza en Ciencia de Datos. En esta sección procesarás archivos CSV con pandas de Python.
Si algún campo dentro del archivo necesita alguna coma, es posible hacer una modificación senci-
Para iniciar, crearemos un archivo de seguidores con los registros de los usuarios de TikTok que lla, por ejemplo:
ya haz utilizado.
writer.writerow(['@charlidamelio', "D’Amelio, Charlie", 108.1])
[1]: import csv
[2]: with open('seguidores.csv', mode='w',newline='w') as seguidores: Con esta modificación Python interpreta a "D’Amelio", "Charlie" como un solo elemento,
writer=csv.writer(seguidores) además de que permite anexar el apostrofe en D’Amelio.
writer.writerow(['@charlidamelio', 'Charlie', 108.1])
writer.writerow(['@addisonre', 'Addison', 76.4]) El detalle de la coma es importante, pues si escribes "D’Amelio", "Charlie", estás indicando
writer.writerow(['@zachking', 'Zach', 56.6]) a Python que el registro tiene 2 elementos y no uno solo. Esto provocará un error, ya que en el
writer.writerow(['@bellapoarch', 'Bella', 56.3]) ciclo for para leer el archivo, la lista solo tiene tres elementos para cada registro: handle, nombre
y número de seguidores.
La extensión en el archivo .csv, indica que al archivo tendrá un formato de archivo CSV. La función
writer del módulo csv regresa un objeto que escribe datos CSV en el archivo objeto especifi-
cado. Cada llamada del método writerow recibe un iterable que almacena en el archivo. Este 9.6 Lectura de archivos CSV con DataFrame de Pandas
método utiliza listas para cada registro. Por default writerow delimita los valores con comas, peo
puedes utilizar un delimitador personalizado. A las personas que se inscriben en un gimnasio se les toman ciertos datos, como el género, el peso
(en kg), el diámetro de la cintura (en cm), el número de pulsaciones por minuto. Y se les pide que
Los elementos en el archivo son: realicen una prueba de acondicionamiento físico en la que realizan lagartijas, medias sentadillas y
saltos, hasta que el usuario decide detenerse.
Los datos del archivo temporal de seguidores son
El archivo tiene nombre datos_gimnasio.csv, y está guardado en la carpeta donde se escri-
@charlidamelio,Charlie,108.1 ben los códigos de Python, con el objetivo de facilitar su llamado.
@addisonre Addison,76.4
@zachking,Zach,56.6 Para que Python lea el archivo csv.
@bellapoarch,Bella,56.3
[1]: import pandas as pd
Los archivos CSV no contienen espacios en blanco después de las comas, aunque algunas veces [2]: datosgym=pd.read_csv('datos_gimnasio.csv')
este detalle mejora la lectura de los archivos.
Este conjunto de datos contiene los registros de 20 usuarios con 7 variables.
Y con la función describe de Pandas, es posible obtener un resumen de las estadísticas descrip-
tivas del conjunto de datos.
[8]: datosgym.describe()
[8]: Peso Cintura Pulso Lagartijas Sentadillas Saltos
count 20.0 20.0 20.0 20.0 20.0 20.0
mean 81.0 89.9 56.1 9.4 145.6 70.3
std 11.2 8.1 7.2 5.3 62.6 51.3
min 62.6 78.7 46.0 1.0 50.0 25.0
25% 72.9 83.8 51.5 4.8 101.0 39.5
50% 79.8 88.9 55.0 11.5 122.5 54.0
75% 86.9 94.0 60.5 13.2 210.0 85.2
max 112.0 116.8 74.0 17.0 251.0 250.0
Programación orientada
a objetos
10.1 Introducción
La programación orientada a objetos la puedes entender como una estrategia o como un modelo
que permite el diseño y el desarrollo de programas (software).
Con este capítulo inicia una serie de tópicos especializados en programación. La continuidad en
los contenidos busca, con ejemplos sencillos, adentrarte en la programación orientada a objetos,
esperando que este postre, que saborean quienes programan, tenga un sabor dulce y profundo,
sin llegar a fastidiar al paladar.
Toma asiento, acerca tus instrumentos y prueba con calma este pequeño postre de programación.
Por ejemplo, si te gustan las mascotas, un perro puede ser un objeto. Pero el perro que tienes en
casa tiene cierta raza: un pug, un schnauzer o un pitbull. Y estos perros pueden cumplir tareas
como la de ser un animal de compañía o de seguridad en casa. A la imagen común de mascota,
le llamaremos plantilla o molde. Y partiendo de esta plantilla es posible visualizar otras versiones
de una mascota, como: perro, gato, pájaro, etc, que tienen características diferentes. A éstas les
llamaremos atributos.
El trabajo inicia diseñando algunas herramientas que pondrás en tu anaquel personal. Luego la Como en el caso de las sentencias for e if, los atributos se definen dentro de una identación (san-
tarea será, utilizar tres herramientas del vasto almacén de Python. gría) al escribirlo fuera, no reconocerá este atributo.
El siguiente código crea tu primera clase personalizada. Supongamos que requieres hacer el registro, con información básica de tres aspirantes Eva, Laura y
Luis a un puesto de diseñador web. Esta información básica es: edad, experiencia laboral y estado civil.
[1]:class Mascota:
#atributos En este caso tiene varios objetos, los cuales son Eva, Laura y Luis. La clase la podemos nombrar,
tipo='pequeño' por ejemplo, registro. Los atributos son entonces
raza='chihuahua'
tarea='guardián' • Edad
[2]: perro=Mascota() #Objeto • Experiencia laboral
[3]: """ Atributos de objeto.""" • Estado civil
[4]: print(perro.raza)
[4]: chihuahua Una forma alternativa de definir objetos y atributos, es la siguiente
[5]: print(perro.tarea)
[5]: guardián class Registro:
pass
Una convención en Python al definir los nombres de las clases, es que el nombre de la clase debe
empezar con una letra mayúscula. Hasta aquí se crea la clase Registro, ahora definiremos los atributos para cada objeto. La línea an-
terior, pass hace que Python salga del ambiente clase para ser llamada posteriormente. Ahora se
Dentro de la clase están definidos los atributos, en este caso, tipo, raza y tarea. crean objetos en la clase Registro.
El objeto, en este ejemplo puede ser un gato, o un ave. Aquí se definió como un perro. eva=Registro()
laura=Registro()
Las últimas líneas, son para mostrar un par de atributos del objeto perro. Para que la clase quede luis=Registro()
bien definida, no son necesarias. Sin embargo, se añaden de prueba para entender la forma de eva.edad = 30
invocar a los atributos. eva.experiencia = 6
eva.edo_civ = 'soltera'
Si es necesario cambiar alguno de los atributos, puedes realizarlo con la función setattr, de la si- laura.edad = 32
guiente manera. laura.experiencia = 5
laura.edo_civ = 'casada'
setattr(perro, 'tarea', 'amigo') luis.edad = 28
print(perro.raza) luis.experiencia = 1
print(perro.tarea) luis.edo_civ = 'soltero'
chihuahua
amigo Hasta aquí está definida la clase, y los objetos con sus atributos. Las líneas siguientes permiten ver
los atributos
Para borrar alguno de los atributos que estás utilizando, la función delattr permite realizar esta tarea
print(luis.experiencia)
delattr(perro,'tarea') print(eva.edo_civ)
print(perro.tarea) print(laura.edad)
En este caso, la clase se llama Oferta, y el método descuento. Este programa tiene la tarea de
calcular la cantidad que será descontada del costo. self es un parámetro de todos los métodos. Como antes, hasta aquí se ha creado la clase, y dos métodos, pero no se ha definido ningún objeto.
Este parámetro es un acuerdo para usuarios de Python y se utiliza para acceder a los atributos del Si ejecutas estas líneas observarás que, aunque no muestra error, no retorna nada, porque la clase
objeto. Es importante aclarar que existen métodos que tienen otros parámetros, además de self. no se ha aplicado a ningún objeto.
Hasta aquí se ha creado la clase y el método. Ahora construiremos un objeto llamado rebaja.
El método __init__ cambia la forma de inicializar el método. Cuando la clase se aplica a un objeto,
rebaja=Oferta() es lo que primero se ejecuta.
rebaja.descuento()
El primer método permite generar un objeto, una cuenta de ahorro designado a nombre y con un
Esta línea indica que el objeto está invocando al método. El único que hay en este caso es descuento. capital inicial ahorro. Esta rutina permite validar la cantidad que se asigna al ahorro, verificando
que la cantidad sea mayor o igual a 0. Si ingresas un valor negativo, muestra una excepción del
Las dos líneas anteriores indican que el objeto esta en la clase Oferta y va a utilizar el método tipo ValueError.
descuento. Hasta aquí ya tienes la clase, el método y el objeto. Sin embargo, en el código no se ha
calculado la rebaja. Para mostrar la rebaja puedes usar nuevamente la función print. El segundo método permite realizar un depósito con un valor definido por cantidad. Este valor se
acumula en el capital inicial. Aquí también se valida cantidad. Si cantidad es un valor negativo ocu-
print(rebaja.costo*rebaja.desc) rre un error del tipo ValueError.
180
Aplicaremos esta clase a un caso particular con el fin de observar el comportamiento de la rutina.
Esta forma de definir al método tiene la sintaxis.
cuenta1=Cuenta('Juan',2000)
class Nombre_clase:
def nombre_metodo(self): En este caso se define el objeto cuenta1 en la clase Account, con parámetros Juan y 2000. Juan es
self.nombre_variable=valor_o_tarea quien abre la cuenta de ahorro con un capital inicial de $2000. Para verificar:
Tal parece que es demasiado código solo para realizar la multiplicación, pero tiene grandes bene- print(cuenta1.nombre)
ficios en problemas más complejos. Juan
print(cuenta1.ahorro)
Otra forma alternativa de construir métodos es a través de la función __init__. 2000
Si Juan hace un depósito de $2000, entonces, el programa debe acumular esta cantidad en el ahorro
<ipython-input-10-ec27d46eea27> in deposito(self, cantidad) Ahora utilizaremos el constructor para diseñar un objeto de la clase pers_nvo que tiene los atribu-
8 def deposito(self,cantidad): tos de Personal y el método detalle.
9 if cantidad<Decimal('0.00'):
---> 10 raise ValueError('La cantidad debe ser positiva') ingeniero=pers_nuevo('Paco','Ingeniero en Sistemas',"Supervisión")
11 self.ahorro+=cantidad print(ingeniero.detalle())
Paco es un Ingeniero en Sistemas y tiene el cargo de Supervisión
ValueError: La cantidad debe ser positiva
También puedes solicitar del objeto ingeniero, con los atributos de las otras clases
Esta clase define la clase ahorro. Para prevenir errores, tiene una excepción cuando deposito es Para terminar la parte de la herencia, es posible verificar si las clases Gasto y Ahorro son clases hijo
un valor negativo. Si deposito no cumple la excepción, el valor deposito se suma al valor de capital. o subclases de Cuenta
Observa que el argumento de la clase ahorro es la clase padre Cuenta.
print(issubclass(Ahorro,Cuenta))
class Gasto(Cuenta): True
def cantidad(self,retiro): print(issubclass(Gasto,Cuenta))
if retiro<Decimal('0.00'): True
raise ValueError('La cantidad a retirar debe print(issubclass(Gasto,Ahorro))
ser positiva') False
#if retiro>capital:
# raise ValueError('No tiene fondos suficientes') En este último caso, naturalmente, Cuenta y Ahorro funcionan de manera independiente, aunque
self.capital-=retiro tengan una misma clase origen.
return '{} tiene ahora en su cuenta {}'.format(self.
nombre, self.capital) Hasta ahora, los métodos empleados utilizan la palabra reservada self, pero hay métodos que
hacen uso de otras palabras reservadas. El uso de otras palabras reservadas implica que estás
Esta clase define la clase Gasto. Para prevenir errores, tiene una excepción cuando retiro es un va- utilizando un método diferente al que ya haz utilizado. Python define tres tipos de métodos
lor negativo. Cuando retiro no cumple la excepción, el valor retiro se resta al valor de capital. Como
el argumento de la clase Gasto es Cuenta. Gasto es también una clase hijo de Cuenta. • Métodos de clase
• Métodos estáticos
Hasta aquí están definidas las clases. Si ejecutas el programa observarás que no regresa nada. • Método
Esto se debe a que no está aún definido ningún objeto. En las dos clases se llamó al método can-
tidad, esto es posible ya que la tarea que realizará el método depende del lugar donde se defina
el objeto. 10.6 Métodos de clase
Ahora se definen dos objetos cuenta1 en Ahorro y cuenta2 en Gasto. Al utilizar este método se antepone el método @classmethod. Una característica importante es
que, al invocarlo, no es necesario crear el objeto. El siguiente ejemplo muestra los números telefó-
cuenta1=Ahorro('Juan',2000) nicos de emergencia de tres países además del tipo de emergencia que atienden.
print(cuenta1.informacion())
Juan tiene en su cuenta $2000 print(cuenta1.capital) class Emergencia:
2000 def __init__(self,tipo):
cuenta1.cantidad(1500) self.tipo=tipo def __repr__(self):
'Juan tiene ahora en su cuenta 3500' return f'Emergencia({self.tipo !r})'
cuenta2=Gasto('Paco',5000) @classmethod
print(cuenta2.informacion()) def Colombia(cls):
Paco tiene en su cuenta $5000 return cls(['Accidente','Policía','Marque 123'])
cuenta2.cantidad(50) @classmethod
'Paco tiene ahora en su cuenta 4950' def Salvador(cls):
print(cuenta2.capital) return cls(['Accidente','Policía','Marque 911'])
4950 @classmethod
def Paraguay(cls):
Ahora el usuario retira 5000 return cls (['Bomberos', 'Policía', 'Marque 131'])
print(Emergencia.Paraguay())
cuenta2.cantidad(5000) Emergencia(['Bomberos', 'Policía', 'Marque 131'])
'Paco tiene ahora en su cuenta -50'
En las líneas ¿? El código es muy parecido al habitual que ya haz utilizado. En esta parte, el ejemplo divisa=Pais()
muestra el tipo de emergencia que puede atenderse cuando se llama al número 911. En la segun- divisa.moneda()
da parte se utiliza un método estático que trabaja de manera independiente a la primera parte.
Cuando se invoca, aparecen algunos países que emplean al número 911 como número de emer- Cada país tiene una moneda propia
gencia. Este número, aunque es el mismo que en el método de instancia, refieren a dos tareas
diferentes. De aquí que se haya empleado el método estático. divisa_nicaragua=nicaragua()
divisa_nicaragua.moneda()
El polimorfismo se define como la capacidad que tienen los objetos, en diferentes clases, para Observa que hay tres subclases o clases hijo, y en cada una de ellas los métodos tienen el mismo nombre.
usar un comportamiento o un atributo con el mismo nombre, pero con diferente valor. Este es un
ejemplo sencillo. Dentro de las librerías definidas en Python se encuentra commissionemployee, esta librería resul-
ta útil para administrar listas de empleados y resulta un ejemplo común, por sus características,
class Matematicas: num_creditos = 8 def creditos(self): en diversos libros y páginas web dedicadas a la programación en Python.
print('Matemáticas tiene 8 créditos')
class Idioma: num_creditos = 5 def creditos(self): Enseguida se muestra un ejemplo sencillo de la forma en que se emplea. Las clases, variables y
print('Idioma tiene 5 créditos') atributos están escritos en inglés, más aún, los comentarios están escritos en español. En este
#Hay un objeto con diferentes valores ejemplo se muestra el caso de dos tipos de empleados, uno que recibe un pago por comisión
#Hay dos clases con el mismo atributo (commission_rate) en ventas (gross_sales) de y otro que también recibe la comisión, pero que tam-
bién cuenta con un salario base (base_salary)
Para probar el código, se crea un objeto, en este caso asignatura
"""Pago a empleado por comisión."""
asignatura=Matematicas() from commissionemployee import CommissionEmployee
asignatura.creditos() from decimal import Decimal
class SalariedCommissionEmployee(CommissionEmployee): A continuación, se muestra un ejemplo de la manera en que funciona este programa
def __init__(self, first_name, last_name, gross_sa-
les, commission_rate, base_salary): s = SalariedCommissionEmployee('Eva', 'García', Decimal
"""Atributos para un empleado que gana comisión.""" ('5000.00'), Decimal ('0.1'), Decimal('3000.00'))
super ().__init__ (first_name, last_name, gross_sa- print(s.first_name,s.last_name,s.ssn,s.gross_sales,s.com-
les, commission_rate) self.base_salary= base_salary mission_rate,s.base_salar y)
# validate via property print(f'{s.earnings():0.2f}')
Eva García ABCD800808 5000.00 0.1 3000.00
Aquí se define la clase SalariedCommissionEmployee y los atributos de los objetos. El método su- 3500.00
per(), se utiliza para llamar métodos definidos y en la herencia múltiple. Este método se utiliza solo
en subclases y se caracteriza por brindar más atención a tales subclases.
@property
def base_salary(self): return self._base_salary
@base_salary.setter
def base_salary(self, salary):
"""Escribe el salario base o un ValueError si es inváli-
do.""" if salary < Decimal ('0.00'):
raise ValueError ('El salario base debe ser >= to 0')
self._base_salary = salary
En estas líneas puedes observar dos clases con el mismo nombre (polimorfismo). La primera está
precedida de @property. Esto indica que la clase base_salary definida es de solo lectura cuan-
do clase base_salary ya tiene asignado un valor. Si se va a ingresar un nuevo valor para clase
base_salary, se debe utilizar la segunda clase. La segunda está precedida por @base_salary.
setter. Python define dos tipos de métodos uno llamado de adquisición u obtención (getter) y otro
llamado de colocación (setter). Esto significa que la clase base_salary debe proporcionar (colo-
car) un valor a la variable. Observa que este método valida el salario base, si no es válido muestra
una excepción del tipo ValueError.
def earnings(self):
"""Calculate earnings."""
return super ().earnings() + self.base_salary
Aquí se definen la clase earnings, esta es la ganancia del empleado debida al tanto por ciento de la
comisión. Este método regresa el salario más la comisión ganada.
def __repr__(self):
"""Muestra la cadena para repr()."""
return ('Salaried' + super ().__repr__ () +
f'\nsalario base : {self.base_salary:.2f}')
Esta clase utiliza el método __repr__. A diferencia de __str__, el método __repr__.es una represen-
tación formal de un string (cadena) para Python. __str__ está más orientado a ser entendido por
los usuarios, mientras que __repr__ está más orientado a ser interpretado por Python. Esta última
Recursiones, iteraciones,
búsqueda y ordenamiento
11.1 Introducción
En este capítulo se tratan tres temas clásicos de programación recursión-iteración, búsqueda y
ordenamiento. A pesar del tiempo que ha pasado desde que se empezaron a utilizar las compu-
tadoras, estos temas siguen siendo actuales y permiten al programador en formación, conocer la
forma en que se realizan estos procedimientos.
Así que... trae tu bata y tu cubrebocas. Python ya tienen preparado el microscopio. Ponte atento
que iniciaremos un análisis minucioso de la forma en que trabajan algunos algoritmos.
k3 = k2 + k1 = 1 + 0 = 1.
k5 = k4 + k3 = 2+1=2.
Ejemplo 2
Si seguimos esta regla, entonces
Series geométricas.
k100 = k99 + k98.
Las series geométricas finitas, son una suma de potencias de un número r, que pueden estar mul-
Sea cual sea el valor de k99 y k98. Más aún, para cualquier número natural n que sea mayor a 2, se cumple tiplicadas por otro número a. Estas series (sumas) tienen la forma
Por ejemplo, si k = 100, entonces k − 1 = 99 y k − 2 = 98. Como estaba escrito antes. La Esta serie se puede ver de una forma recursiva. Utilizaremos la variable s en lugar de k (por aque-
fórmula de kn, es una fórmula de recursión y a diferencia de las fórmulas que aprendemos en las llo de las sumas). Los elementos de la sucesión se describen de la siguiente manera
matemáticas del nivel básico, como
s1 = a
A = πr2, o F=ma s2 = a + ar = s1 + ar
s3 = a + ar + ar2 = s2 + ar2
Donde las cantidades representaban valores físicos o geométricos, en una fórmula recursiva apa- s4 = a+ar+ar2 +ar3 =s3 +ar3
recen elementos del mismo tipo, es decir, nk, nk-1, nk−2 son todos números y tienen una variable
ordenada de números naturales, por ejemplo, los subíndices k, k−1, k−2, de este ejemplo.
Entonces, para cualquier número natural n,
La sucesión de Fibonacci. El siguiente ejemplo es la construcción de una serie geométrica con a=3, r=1/2 y n=20
"""ejemplo1_C11.py"""
def Fibonacci(n): """ejemplo2_C11.py"""
if n in (0,1): a=3
return n r=1/2
else: def serie_geom(n):
return Fibonacci(n-1)+Fibonacci(n-2) if n == 0: return n
for n in range (31): else:
print(f'k({n})={Fibonacci(n)}') return serie_geom (n - 1) + a * r ** (n - 1)
k(0)=0 for n in range (1, 10):
k(1)=1 print (f'k({n})={serie_geom (n)}')
k(2)=1
k(3)=2 Los resultados son
k(4)=3
k(5)=5 s(1)=3.0
k(6)=8 s(2)=4.5
k(7)=13 s(3)=5.25
k(8)=21
186 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 187
s(4)=5.625 return n*factorial(n-1)
s(5)=5.8125 s(6)=5.90625 for i in range(1,21): print(f'{i}!={factorial(i)}')
┆
s(15)=5.99981689453125 Los resultados de los primeros 20 números naturales son
s(16)=5.999908447265625
s(17)=5.9999542236328125 1!=1
s(18)=5.999977111816406 2!=2
s(19)=5.999988555908203 3!=6
s(20)=5.999994277954102 4!=24
5!=120
Con los valores asignados, la suma es 6!=720
┆
3(1+½+(½)2+(½)3+┄+(½)19)=5.999994277954102 17!=355687428096000
18!=6402373705728000
De acuerdo al comportamiento de esta sucesión de valores, mientras más aumentas el número de 19!=121645100408832000
términos, la suma se acerca cada vez más al valor de 6. 20!=2432902008176640000
Los dos ejemplos anteriores se han escrito de forma recursiva. Pero también es posible hacer esto
Ejemplo 3 de manera iteriativa. Por ejemplo, la sucesión de Fibonacci
De manera recursiva, se puede escribir como Cuando j = 0, aux = 1, suma = 0, suma + aux = 1
Cuando j = 1, aux = 0, suma = 1, suma + aux = 1
1! = 1 Cuando j = 2, aux = 1, suma = 1, suma + aux = 2
2! = (2)1! = 2 Cuando j = 3, aux = 1, suma = 2, suma + aux = 3
3! = (3)2! = 6
4! = (4)3! = 24...etc Y para calcular los números factoriales
188 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 189
la forma de escribir el código obedece casi de forma directa a las fórmulas de recurrencia, hacién- • Si no es el valor central y el valor buscado es menor, descarta el conjunto de valores
dolo fácil de programar. Sin embargo, para efectos de mantener una programación más depurada que están a la derecha, incluyendo el punto medio.
y eficiente con el uso de memoria y almacenamiento de datos, los métodos iterativos suelen ser • Si no es el valor central y el valor buscado es mayor, descarta el conjunto de valores que
mejores. están a la izquierda, incluyendo el punto medio.
• Después de descartar los segmentos que no son de interés, revisa el segmento restan-
Otro par de tópicos clásicos de programación son la búsqueda y el ordenamiento. A continuación, te, con los mismos criterios.
se trata cada uno de estos tópicos. • Si resulta que algún segmento ya no tiene elementos, significa que el valor que buscas
no está presente en la lista.
11.3 Búsqueda A continuación, se muestra un código más elaborado que realiza la búsqueda binaria.
En esta sección se presentan dos métodos de búsqueda. Uno que es muy sencillo de programar y """Implementación de la búsqueda binaria."""
otro que es mucho más rápido, pero también, más complejo de programar. import numpy as np
def busqueda_binaria(datos, dato_buscar): bajo = 0
El primero de ellos es el algoritmo de búsqueda lineal. Este método busca un elemento dentro de alto = len (datos) - 1
un arreglo, por lo prueba con cada elemento del arreglo si existe alguna coincidencia. Si esto ocu- medio = (bajo + alto + 1) // 2 # índice del elemento medio
rre o no, informa al usuario el resultado de la búsqueda. localizacion = -1
Para probar este método considera el siguiente conjunto de valores En esta parte el programa divide al conjunto en dos segmentos, cuando ya no sea posible mostra-
rá -1 para indicar que el elemento no está en la lista
1.70, 1.65, 1.58, 1.81, 1.84, 1.78, 1.68, 1.72
while bajo <= alto and localizacion == -1:
Este método es llamado de búsqueda lineal, y se presenta a continuación. print (elementos_restantes (datos, bajo, alto))
print (' ' * medio, end='')
def busqueda_lineal(datos, dato_buscar): print (' * ')
for indice, valor in enumerate (datos):
if valor == dato_buscar: return indice En esta parte, el programa muestra los elementos que quedan y coloca un asterisco en la posición medio.
return -1
datos = [1.70, 1.65, 1.58, 1.81, 1.84, 1.78, 1.68, 1.72] if dato_buscar == datos[medio]:
print('El número que buscas tiene índice:',busqueda_li- localizacion = medio
neal(datos, 1.81)) elif dato_buscar < datos[medio]:
El número que buscas tiene índice: 3 alto = medio - 1
else:
Observa la rutina. Este programa revisa cada valor de la lista, si lo encuentra, regresa el índice de bajo = medio + 1
la lista donde se encuentra el valor. Si no lo encuentra regresa -1.
Cuando el elemento está en posición medio, asigna la localización al índice medio. Si no está y su
Cuando el valor de búsqueda se ubica en la posición n de la lista, se hacen n comparaciones. Pero valor es menor, elimina la mitad superior. Si no está, y su valor es mayor elimina la mitad inferior.
si el valor no está, se realizan tantas comparaciones como elementos tenga la lista. Este último
detalle es llamado el peor de los casos para determinar la eficiencia del algoritmo. El algoritmo de medio = (bajo + alto + 1) // 2
búsqueda lineal es poco eficiente, aunque fácil de programar. El algoritmo es rápido, cuando la return localizacion
lista no es muy grande, pero puede ser tardado cuando la cantidad de elementos es considerable-
mente grande. El programa recalcula la posición medio, si encontró al valor de búsqueda regresa la localización
del dato.
El otro método es llamado búsqueda binaria. Aquí se muestra una descripción del método.
def elementos_restantes(datos, bajo, alto):
• Considera de manera inicial a toda la lista ordenada, en orden ascendente, por ejemplo. return ' ' * bajo + ' '.join (str (s) for s in datos[ba-
• Revisa el valor que se encuentra en la mitad de la lista (el valor central), si es el valor que jo:alto + 1])
buscas,regresa el índice de este valor.
190 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 191
En esta parte, muestra los elementos restantes para la búsqueda. Este programa está lleno de detalles que permiten ver como trabaja el método, por lo que buena
cantidad de código se utiliza para mostrar tales detalles en la rutina. Cada segmentación en dos
def main(): partes del conjunto de datos equivale a una comparación. Por lo tanto, un arreglo con 1,048,575
datos = np.random.randint (10, 91, 15) datos.sort () elementos (220 − 1), en el peor de los casos, requiere de un máximo de 20 comparaciones para
print (datos, '\n') encontrar el valor de búsqueda. Esta es la gran diferencia entre la eficiencia del algoritmo de bús-
buscar_key = int (input ('Ingresa un valor entero (-1 para queda lineal y el de búsqueda binaria.
salir): '))
El programa crea un arreglo de prueba, de 15 números aleatorios enteros, en el intervalo [10, 90] 11.4 Ordenamiento
y solicita al usuario el número que requiere buscar.
El ordenamiento de datos es una de las aplicaciones más importantes en la programación. En esta
while buscar_key != -1:
sección se discuten tres métodos, dos de ellos sencillos, pero poco eficientes para una gran canti-
localizacion = busqueda_binaria (datos, buscar_key)
dad de datos. El tercero es más eficiente pero también más complicado de programar.
if localizacion == -1:
print (f'{buscar_key} no se encuentra\n')
else: Para iniciar, observa esta lista que se requiere ordenar en orden ascendente
print (f'{buscar_key} está en la posición {lo-
calizacion}\n') 15 13 9 10
buscar_key = int (input ('Ingresa un valor entero (-1 para
salir): ')) Una posible forma de ordenarla, es buscar el elemento más pequeño, y ponerlo al inicio, pero
intercambiando las posiciones entre el elemento que estaba en la primera posición y el elemento
Repite el ciclo de búsqueda hasta ingresar -1. más pequeño. Entonces la lista toma la forma
if __name__ == '__main__': 9 13 15 10
main ()
Ahora se repite el procedimiento descartando la primera posición. Es decir, se intercambian las
Esta parte del programa hace que el programa se ejecute y muestre los resultados. Algunas prue- posiciones de 13 y 10, entonces el resultado es
bas son las siguientes.
9 10 15 13
[10 14 21 22 35 45 50 60 61 64 68 82 83 83 88]
Ahora se repite el procedimiento descartando las primeras dos posiciones. El orden final es
Ingresa un valor entero (-1 para salir): 14
10 14 21 22 35 45 50 60 61 64 68 82 83 83 88 9 10 13 15
*
10 14 21 22 35 45 50
A este proceso se le conoce como ordenamiento por selección. Un programa que realiza
*
esta tarea es el siguiente.
10 14 21
*
14 está en la posición 1 def ordenamiento_sel(datos):
for indice1 in range(len(datos) - 1):
Ingresa un valor entero (-1 para salir): 90 peque = indice1
10 14 21 22 35 45 50 60 61 64 68 82 83 83 88
* En este ciclo, se reduce la cantidad de elementos, una vez que se ha encontrado el elemento más
61 64 68 82 83 83 88 pequeño y se ubica en la primera posición.
*
83 83 88 for indice2 in range(indice1 + 1, len(datos)):
*
if datos[indice2] < datos[peque]:
88
* peque = indice2
90 no se encuentra datos[peque], datos[indice1] = datos[indice1], datos[peque]
Ingresa un valor entero (-1 para salir): -1
192 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 193
En esta parte se identifica el elemento más pequeño, entre los elementos que quedan, y se inter- • Que el tercer elemento sea mayor que el primero y menor que el segundo, entonces el
cambia de posición con el elemento que tiene el índice más bajo. Con la última línea se arman los elemento se inserta en la segunda posición.
segmentos de la nueva lista ordenada. • Que el tercer elemento se mayor que los dos primeros, entonces el elemento se queda
en la tercera posición, y se repite la rutina con el siguiente elemento.
Aplicaremos este algoritmo con una lista que contiene la estatura de 9 personas.
Para finalizar, se compara el último elemento con los tres primeros, que ya están ordenados. El
1.85, 1.70, 1.58, 1.83, 1.80, 1.75, 1.70, 1.90, 1.65 arreglo final es
[1.85 1.7 1.58 1.83 1.8 1.75 1.7 1.9 1.65] while mover_dato > 0 and datos[mover_dato - 1] > insertar:
paso 1: 1.58 1.7 1.85 1.83 1.8 1.75 1.7 1.9 1.65 datos[mover_dato] = datos[mover_dato - 1]
paso 2: 1.58 1.65 1.85 1.83 1.8 1.75 1.7 1.9 1.7 mover_dato -= 1
paso 3: 1.58 1.65 1.7 1.83 1.8 1.75 1.85 1.9 1.7 datos[mover_dato] = insertar
paso 4: 1.58 1.65 1.7 1.7 1.8 1.75 1.85 1.9 1.83
paso 5: 1.58 1.65 1.7 1.7 1.75 1.8 1.85 1.9 1.83 Este ciclo busca el lugar adecuado para colocar el elemento actual. Recuerda que en el ejemplo
paso 6: 1.58 1.65 1.7 1.7 1.75 1.8 1.85 1.9 1.83 había tres posibilidades. Con la última línea, se arma el nuevo arreglo y se continua con el siguiente
paso 7: 1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.9 1.85 valor en la lista, cuando el ciclo for no ha terminado.
paso 8: 1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9
Arreglo ordenado: Aplicaremos este algoritmo a la lista de estaturas.
[1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9 ]
1.85, 1.70, 1.58, 1.83, 1.80, 1.75, 1.70, 1.90, 1.65
Supongamos nuevamente que se requiere ordenar en orden ascendente
datos = np.array ([1.85, 1.70, 1.58, 1.83, 1.80, 1.75, 1.70,
15 13 9 10 1.90, 1.65]) print (f'Arreglo sin orden: {datos}\n')
Arreglo sin orden: [1.85 1.7 1.58 1.83 1.8 1.75 1.7 1.9 1.65]
Otra forma de ordenarla, es comparar los primeros dos elementos si el segundo es menor que el ordenamiento_inser (datos)
primero, se intercambian de lugar. Entonces la lista toma la forma print (f'\nArreglo ordenado: {datos}\n')
Arreglo ordenado: [1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9 ]
13 15 9 10
Las etapas de esta tarea realizada manualmente son:
Ahora se compara el tercer elemento con los dos primeros. Pueden ocurrir tres casos diferentes:
Arreglo sin orden:
• Que el tercer elemento se menor que los dos primeros, entonces el elemento se inserta
en la primera posición (como en este ejemplo). [1.85 1.7 1.58 1.83 1.8 1.75 1.7 1.9 1.65]
Paso 1: 1.7 1.85 1.58 1.83 1.8 1.75 1.7 1.9 1.65
9 13 15 10 Paso 2: 1.58 1.7 1.85 1.83 1.8 1.75 1.7 1.9 1.65
Paso 3: 1.58 1.7 1.83 1.85 1.8 1.75 1.7 1.9 1.65
194 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 195
Paso 4: 1.58 1.7 1.8 1.83 1.85 1.75 1.7 1.9 1.65 def arreglo_ordenado(datos, bajo, alto):
Paso 5: 1.58 1.7 1.75 1.8 1.83 1.85 1.7 1.9 1.65 """Split datos, sort subarrays and mezcla them into sorted array."""
Paso 6: 1.58 1.7 1.7 1.75 1.8 1.83 1.85 1.9 1.65 if (alto - bajo) >= 1:
Paso 7: 1.58 1.7 1.7 1.75 1.8 1.83 1.85 1.9 1.65 medio1 = (bajo + alto) // 2 medio2 = medio1 + 1
Paso 8: 1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9
En esta parte el algoritmo se calculan los elementos que tendrá cada lista
Arreglo ordenado:
# output split step
[1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9 ] print (f'split:
print (f'
Otra vez se requiere ordenar en orden ascendente print (f'
{subarreglo (datos, bajo, alto)}')
15 13 9 10 {subarreglo (datos, bajo, medio1)}')
{subarreglo (datos, medio2, alto)}\n')
Una forma alternativa de ordenarla, es dividir la lista en dos arreglo_ordenado (datos, bajo, medio1)
arreglo_ordenado (datos, medio2, alto)
15 13 9 10
Ahora el algoritmo secciona a la lista en dos partes. Si la lista tiene una cantidad par de elementos,
Para entonces ordenar cada una de manera individual ambas listas tienen el mismo tamaño. Si tiene una cantidad impar, a la segunda lista se le asigna
un elemento más.
15 13 9 10
mezcla (datos, bajo, medio1, medio2, alto)
Y luego comparar ambas listas para hacer una lista única más larga.
Con esta parte, el algoritmo mezcla dos listas que ya están ordenadas
En este paso se comparan los elementos más pequeños de cada lista, y se comienzan a mezclar las
dos listas los primeros dos elementos ordenados son def mezcla(datos, izq, medio1, medio2, der): izq_indice = izq
der_indice = medio2
9 13 indice_combinado = izq
mezclado = [0] * len (datos)
Luego compara el segundo elemento de la primera lista (15), con los dos primeros y vuelve a mez-
clar los elementos La tarea del método mezcla, es ordenar dos subarreglos ordenados en uno solo también ordenado
9 13 15
print (f'mezcla: {subarreglo (datos, izq, medio1)}')
Y para finalizar compara el segundo elemento de la segunda lista, para obtener print (f' {subarreglo (datos, medio2, der)}')
A este proceso se le conoce como ordenamiento por mezcla. Este procedimiento es más while izq_indice <= medio1 and der_indice <= der: if da-
complejo, ya que, si la lista tiene más elementos, cada subarreglo se dividiría otros arreglos más tos[izq_indice] <= datos[der_indice]:
pequeños hasta llegar a subarreglos de tamaño 2, para luego comenzar a mezclarse con los otros mezclado[indice_combinado] = datos[izq_indice] indice_com-
subarreglos. Un programa que realiza esta tarea es el siguiente. binado += 1
izq_indice += 1
import numpy as np else:
def ordenamiento_mezcla(datos): mezclado[indice_combinado] = datos[der_indice] indice_com-
arreglo_ordenado (datos, 0, len (datos) - 1) binado += 1
der_indice += 1
Aquí se define el método ordenamiento_mezcla para utilizar el algoritmo de ordenamiento por mezcla
196 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 197
En este ciclo, el programa compara a los elementos por parejas y ubica a cada elemento en el lugar 1.85
adecuado 1.7
198 | Capítulo 11: Recursiones, iteraciones, búsqueda y ordenamiento Manual Python | 199
mezcla: 1.58 1.7 1.8 1.83 1.85
1.65 1.7 1.75 1.9
1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9
Arreglo ordenado: [1.58 1.65 1.7 1.7 1.75 1.8 1.83 1.85 1.9 ]
Procesamiento de
Lenguaje Natural
12.1 Introducción
Todas las formas de comunicación que conoces como texto, audio, video, señales, etc; así como el
tipo de lenguaje que utilizas, español, inglés, chino entre muchos otros son objetos de estudio del
Procesamiento de Lenguaje Natural (Natural Languaje Processing, NLP).
Dialoguemos, esperando compartir los significados del procesamiento del lenguaje natural.
12.3 TextBlob El etiquetado de partes en una oración (Parts-of-speech) es la tarea de evaluar palabras, basados
en un contexto con el fin de identificar cada palabra como parte de una oración. En inglés hay 8
TextBlob es la clase fundamental para NLP con el módulo textblob. El siguiente código crea tu partes principales en una oración:
primer TextBlob.
Para obtener una lista de oraciones del texto puedes utilizar la propiedad sentence para obtener La propiedad tag regresa una lista que contiene una palabra y una cadena que indica la parte a la
una lista de objetos Sentence. que pertenece.
blob.sentences blob.tags
[Sentence("Y cuando despertó."), Sentence("Todo a su alre- [('I', 'PRP'),
dedor era luminoso")] ('have', 'VBP'),
('good', 'JJ'),
O también puedes obtener una lista de palabras. ('discipline', 'NN'),
('to', 'TO'),
blob.words ('study', 'VB'),
WordList(['Y', 'cuando', 'despertó', 'Todo', 'a', 'su', ('In', 'IN'),
'alrededor', 'era', 'luminoso']) ('the', 'DT'),
('future', 'NN'),
Hasta aquí no hay problemas con el lenguaje, sin embargo, las librerías de Python para modelar ('I', 'PRP'),
y reconocer emociones están diseñadas para trabajar con el idioma inglés. Así que utilizaremos ('will', 'MD'),
frases y texto principalmente en este idioma. ('be', 'VB'),
('a', 'DT'),
texto = 'I have good discipline to study. In the future I ('great', 'JJ'),
will be a great engineer' ('engineer', 'NN')]
blob = TextBlob(texto)
blob
TextBlob("I have good discipline to study. In the future I
will be a great engine er")
blob.sentences
[Sentence("I have good discipline to study."),
Naive Bayes es un algoritmo bastante popular dentro de los algoritmos de aprendizaje de machine
learning. Observa los detalles que ofrece, al aplicar esta librería
La evaluación de Naive-Bayes indica que en total el sentimiento es clasificado como positivo (clas-
La propiedad noun_phrases de TextBlob regresa una lista de objetos que contiene una lista de
sification='pos'). El objeto p_pos de Sentiment indica que TextBlob es 91.1% positivo y el objeto
objetos Word, cada uno con una frase del enunciado.
p_neg es 8.8% negativo
blob.noun_phrases
Para revisar cada oración debes aplicar la propiedad sentiment. Esto lo realizaste anteriormente
WordList(['good discipline', 'great engineer'])
for sentence in blob2.sentences:
Uno de los grandes aportes al análisis de lenguaje, es la interpretación que Python hace de las
print(sentence.sentiment)
emociones a través de propiedad sentiment de un objeto Sentiment.
Sentiment(classification='neg',p_pos=0.36600302868341356,
blob.sentiment p_neg=0.6339969713165864)
Sentiment(polarity=0.5, subjectivity=0.4916666666666667) Sentiment(classification='pos', p_pos=0.9466836548265999,
p_neg=0.05331634517339978)
La polaridad indica el tipo de sentimiento, negativo si es cercano a -1.0, positivo si es cercano a 1.0
y neutro cuando es 0.0. La subjetividad es un valor de 0.0, cuando es objetivo, hasta 1.0 cuando se
clasifica como totalmente subjetivo. Otro ejemplo Observa como la evaluación de Naive-Bayes clasifica a la primera oración como negativa y la se-
gunda como positiva.
from textblob import TextBlob
texto2= 'I am a bad student. I will not be able to finish
my studies' blob2 = TextBlob(texto2) 12.4 Detección de lenguaje y traducción
blob2.sentiment
Un reto enorme en programación ha sido la traducción entre diferentes idiomas, sin embargo, la solu-
Sentiment(polarity= -0.09999999999999992,
ción se ha dado a través del procesamiento de lenguaje natural y de inteligencia artificial. Esto ha he-
subjectivity= 0.6458333333333333 )
cho posible los servicios de traducción de Google (más de 100 idiomas) y de Bing (más de 66 idiomas).
Es posible determinar el valor de polarity y subjetivity de cada oración individual. La estrategia es
Si requieres determinar el lenguaje que tiene un segmento de texto puedes utilizar el método
obtener una lista de objetos Sentence y entonces mostrar la propiedad sentiment.
detect_language.
for sentence in blob2.sentences: print(sentence.sentiment)
texto3='Bonjour'
Sentiment( polarity= -0.6999999999999998,
blob3=TextBlob(texto3)
subjectivity= 0.6666666666666666)
blob3.detect_language()
Sentiment( polarity= 0.5,
'fr'
subjectivity= 0.625)
Observa que palabra con el más alto índice de ocurrencia no necesariamente es la palabra correc- Si el archivo de texto ya está tokenizado, puedes contar frases específicas en la lista a través del
ta para un contexto dado. método count.
Por ejemplo, si requieres buscar alguna definición: Por ejemplo, para cargar la lista de palabras stop words del idioma inglés
Primero debes cargar las librerías necesarias y el libro que nos ha permitido realizar las tareas de
análisis de texto.
Luego cargar las palabras de paro de NLKT. Para obtener las primeras 15 palabras más repetidas.
items=libro_drac.word_counts.items()
El método ítems permite generar una tupla con una lista de palabras y las veces que se repite.
Una vez que se han obtenido las palabras más repetidas, es posible seleccionar únicamente las
primeras 15 de interés
primeros15=items_ordenados[1:16]
En algunos casos será necesario instalarlo desde Anaconda Powershell Prompt, para utilizar los
privilegios de administrador. Esta opción es necesaria, más aún si tu equipo de cómputo tiene
varios usuarios.
texto=open('dracula.txt',encoding='utf-8').read()
stopwords=set(STOPWORDS)
Carga una imagen de máscara para la nube mediante la función imread. En este caso se ha selec-
cionado un óvalo.
import imageio
mascara=imageio.imread('mask_oval.png')
drac_nubpal=WordCloud(colormap='prism', background_color='whi-
te', max_words=1000, stopwords=stopwords, mask=mascara)
Luego se aplica el método generate de WordCloud. Este método tiene como argumento una cadena.
drac_nubpal.generate(texto) <wordcloud.wordcloud.WordCloud at
0x18291c7cd90>
Ya puedes obtener la nube
plt.imshow(drac_nubpal,interpolation='bilinear') plt.axis('off')
plt.show
drac_nubpal=drac_nubpal.to_file('dracula.png')
Minería de datos
13.1 Introducción
Pío Baroja (1872-1956)
Fue un escritor español, que, aunque estudio medicina terminó por dedicarse a la literatura. Escribió
novelas, cuentos cortos, poemas y obras teatrales. Su forma de escribir lo ubica en el terreno de la
narrativa. Su estilo de vida apartado, abonó para clasificarlo como una persona solitaria y pesimista.
• El árbol de la ciencia
• Zalacaín el aventurero
• Aventuras, inventos y mixtificaciones de Silvestre Paradox
• Camino de perfección
• Las inquietudes de Shanti Andía
• César o nada
• El aprendiz de conspirador
• Con la pluma y con el sable
Esta breve introducción a la vida y obra de Pío Baroja es una especie de carta de presentación, es
un vistazo fugas del escenario que ya se vislumbra y que se concreta, en el análisis de algunas de
sus obras.
Toma tu taza de café, algunas hojas y un buen bolígrafo. Escribamos en el idioma de Python
https://www.gutenberg.org/browse/authors/b#a2669
• scipy, es una paquetería con varios toolbox orientados a atender problemas en cómputo
científico. Los submódulos contienen aplicaciones como interpolación, integración, optimiza-
Las obras seleccionadas fueron:
ción, procesamiento de imágenes, estadística, funciones especiales, etc.
• nltk, es un conjunto de herramientas para el procesamiento de lenguaje natural.
• mpl, es un alias de la librería pyplot de matplotlib.
• sklearn, es una librería empleada para realizar análisis y minería de datos. Sus módulos
atienden problemas de clasificación, regresión, cluster, reducción de dimensiones, selección
de modelos y preprocesamiento de datos.
• matplotlib,esunabibliotecaauxiliarenlageneracióndegráficosdedatoscontenidosenlistasy
arreglos.
• numpy, es una librería de Python especializada en el cálculo numérico y análisis de grandes
bases de datos.
• os, este módulo permite realizar operaciones dependientes del sistema operativo como crear
carpetas, listar contenidos de una carpeta, etc.
• math, es un módulo que permite utilizar funciones matemáticas.
Ahora se extraen los archivos de texto. Python brinda la posibilidad de descargar bases de datos
de manera automática. En este caso, la información ya está descargada y tiene una ruta en el sis-
tema operativo
/Users/marti/textos
Esta son todas las palabras de paro. Aquí termina la parte de preprocesamiento de la información. Ángulo de separación de los documentos (grados)
11.200136945764994
Impresión de similitud de documentos por método de coseno
array([[-0. , 0.02, 0.02, 0.02, 0.02, 0.02, 0.02, 0.04, 0.02],
13.5 Parte 3. Análisis y visualización de los datos [ 0.02, 0. , 0.03, 0.02, 0.03, 0.03, 0.03, 0.04, 0.03],
[ 0.02, 0.03, -0. , 0.02, 0.02, 0.03, 0.03, 0.05, 0.03],
En esta parte se verifican las dimensiones de las matrices [ 0.02, 0.02, 0.02, 0. , 0.03, 0.04, 0.03, 0.04, 0.04],
[ 0.02, 0.03, 0.02, 0.03, -0. , 0.02, 0.03, 0.04, 0.02],
44 #Parte 3. Análisis y visualización de los datos [ 0.02, 0.03, 0.03, 0.04, 0.02, -0. , 0.03, 0.05, 0.02],
45 print('Corroborar tamaño de la matriz Documentos vs Términos') [ 0.02, 0.03, 0.03, 0.03, 0.03, 0.03, 0. , 0.04, 0.03],
46 print(tfidfmatrix.shape) [ 0.04, 0.04, 0.05, 0.04, 0.04, 0.05, 0.04, -0. , 0.04],
[ 0.02, 0.03, 0.03, 0.04, 0.02, 0.02, 0.03, 0.04, -0. ]])
Corroborar tamaño de la matriz Documentos vs Términos
(9, 34320) El array resultante es una matriz de similaridades entre los diferentes documentos. La matriz que
observas es una matriz cuadrada de dimensiones 9x9.
El 9, es la cantidad de libros y 34320 fue el ajuste que hizo Python para que todas las obras tengan
las mismas dimensiones. Aquí inicia la parte de visualización de los resultados. A continuación, se presenta un método visual
para identificar la similaridad de dos obras de Pío.
En esta parte se calcula el coeficiente se similitud coseno. Python tiene varios coeficientes, sin em-
bargo, cosine_similarity es el que cuenta con más popularidad. 64 r = 1
65 d = 2 * r * (1 - cosine)
47 print('Obteniendo similitud de coseno entre 2 documentos 66 circle1 = plt.Circle((0, 0), r, alpha=.5)
48 (si son iguales el valor es 1)') 67 circle2 = plt.Circle((d, 0), r, alpha=.5)
49 cosine = cosine_similarity(tfidf_matrix[0:1], tfidf_matrix[2:3])
68 ## set axis limits
50 print(cosine)
51 print('Cálculo de distancia') 69 plt.ylim([-1.1, 1.1])
52 dist = 1 - cosine 70 plt.xlim([-1.1, 1.1 + d])
53 print(dist) 71 fig = plt.gcf()
54 72 fig.gca().add_artist(circle1)
73 fig.gca().add_artist(circle2)
Obteniendo similitud de coseno entre 2 documentos (si son 74
iguales el valor es 1) [[0.98095469]]
Cálculo de distancia <matplotlib.patches.Circle at 0x225aa142850>
[[0.01904531]]
El coeficiente de similitud es cercano a 1, lo cual implica que las obras con índices 0 y 2 son muy
parecidas.
La siguiente parte del código calcula el ángulo de separación entre los documentos. Para que se
muestre mejor la relación entre los documentos, se realiza una conversión en grados.
Observa que la obra pg60464 es la más alejada de las demás obras y que además, pg49470 y
pg48783 son las más cercanas (más parecidas).
Hasta aquí:
En resumen, ya iniciaste el análisis de información realizando minería de datos por lo que cada vez
estás más cerca de la ciencia de datos.
Computación Cognitiva
14.1 Introducción
De acuerdo a Wikipedia, no existe una definición ampliamente aceptada de computación cognitiva.
Sin embargo, el término computación cognitiva (CC) hace referencia a nuevo hardware y/o softwa-
re que imita el funcionamiento del cerebro humano y ayuda a mejorar la toma de decisiones. En
este sentido, CC es un nuevo tipo de computación que tiene como objetivo elaborar modelos más
precisos de la forma en que el cerebro/mente humana percibe, razona y responde a los estímulos.
• Aprender a medida que cambia la información y a medida que evolucionan las metas
y los requisitos.
• Interactuar fácilmente con los usuarios para que esos usuarios puedan definir sus ne-
cesidades cómodamente.
• Ayudar a definir un problema haciendo preguntas o encontrando fuentes de entrada
adicionales si el enunciado del problema es ambiguo o incompleto.
• Comprender, identificar y extraer elementos contextuales como el significado, la sinta-
xis, la hora, la ubicación, el dominio apropiado, las regulaciones, el perfil del usuario, el
proceso, la tarea y el objetivo.
Casos de uso:
• Reconocimiento de voz
• Análisis de los sentimientos
• Detección de rostro
• Evaluación de riesgos
• Detección de fraudes
• Recomendaciones de comportamiento
14.3 Ejemplo de un traductor básico 2. La aplicación interactúa con el servicio Voz a Texto de Watson para transcribir el archivo
de audio a texto. Al hacerlo, muestra
Supongamos que viajas a los Estados Unidos, pero no eres exactamente un experto en hablar
inglés. Es más, tienes alguna especie de pánico escénico para hacerlo. Por lo que necesitas de una Pregunta en español: dónde puedo encontrar el banco más
aplicación que pueda auxiliarte a solicitar servicios básicos, como preguntar donde puedes encon- cercano
trar un baño, una gasolinera, un banco o comida. Esta aplicación debe ser capaz de trasladar voz
en español y traducir en voz a inglés. El otro interlocutor debe escuchar el audio en inglés, respon- 21 # Step 2: Transcribe la voz en español a texto en español
derte en el mismo idioma, pero la aplicación lo llevará al español 22 texto_espannol = voz_a_texto(file_name = 'preg_espannol.wav',
23 model_id = 'es-ES_SofiaVoice')
1 #Traductor_ejemplo.py 24 print('Pregunta en español:', texto_espannol)
2 25
3 """TraductorbásicoconlosserviciosdeWatson."""
4 3. Ahora, la aplicación utiliza el servicio de traducción, para traducir del idioma español al
5 fromwatson_developer_cloudimportSpeechToTextV1 idioma inglés. El resultado es el texto traducido
6 fromwatson_developer_cloudimportLanguageTranslatorV3
7 fromwatson_developer_cloudimportTextToSpeechV1 English: where is the closest bank
8 import keys # contiene las API keys de Watson 26 # Step 3: Traducción de texto en español a texto en inglés
9 import pyaudio # permite acceder a los controles del mi 27 texto_ingles = translate(text_to_translate = texto_es-
crófono 10 import pydub # para cagar archivos WAV pannol, model='es-en')
11 import pydub.playback # para reproducir archivos WAV 28 print('Pregunta en inglés:', texto_ingles)
12 import wave # para guardar archivos WAV 29
Las primeras 3 líneas de código son los módulos para el procesamiento de audio de los servicios 4. Paso 4. El texto es llevado al servicio Texto a Voz para convertir el texto en un archivo
de Watson. En la línea 8 está incluido el archivo donde se encuentran tus credenciales, y los si- de audio.
guientes 4 son los módulos de Python que permiten cargar, leer, reproducir y grabar archivos de
audio con extensión WAV. Este tipo de archivos fue desarrollado por Microsoft e IBM para almace- 30 # Paso 4: Sintetiza el texto en inglés, en voz en inglés
nar sonido en archivos. 31
Esta aplicación realiza 10 pasos básicos. 32 text_to_speech(text_to_speak = texto_ingles, voice_to_
use='es-US_ BroadbandModel',
1. Solicita el registro, en español, de un archivo de audio. Inicialmente la aplicación muestra: 33 file_name = 'preg_ingles.wav')
Introducción a
Machine Learning
15. 1 Introducción
Machine Learning es un tema grande y complejo que puede emplearse en muchos problemas
pero que se caracteriza por plantear soluciones sutiles, es decir, en lugar de utilizar la experiencia
del programador para resolver alguna situación específica para tales problemas, la programación
está orientada a aprender de los datos.
En este capítulo se presentan diversos ejemplos para construir modelos de Machine learning que
puedes utilizar para realizar predicciones con gran precisión.
Este tipo de aprendizaje lo pueden utilizar los reclutas que buscan candidatos para
postularlos en algún puesto específico. El algoritmo debe realizar sugerencias de
aquellas personas cuyo currículum se adapta más a un perfil específico. En térmi-
nos académicos, el algoritmo podría ser útil para identificar estudiantes con ca-
racterísticas comunes que puedan tener problemas de reprobación o deserción.
• Los cuatro vecinos más cercanos a la muestra A son todos círculos verdes. Así, se esti-
15.3 Machine Learning Supervisado. ma que A pertenece a la clase círculos verdes.
Clasificación y Pronóstico • Los cuatro vecinos más cercanos a la muestra B son todos triángulos azules. Así, se
estima que B pertenece a la clase triángulos azules.
Para ejemplificar el problema de la clasificación, puedes utilizar la base de datos Digits incluido en • En el caso de la muestra C, no es evidente la clase a la cual hay que asignarla. Pero si-
Scikit-Learn. guiendo el algoritmo k-NN, de los 4 vecinos más cercanos, 3 son triángulos azules. Por
lo que la muestra C debe asignarse a la clase triángulos azules.
Scikit-Learn (o sklearn) es una librería de Python para Machine Learning. Las técnicas que emplea
están encapsuladas, por lo que no es fácil acceder a la intrincada complejidad de los algoritmos Iniciaremos la tarea de clasificar números dígitos con la base de datos de Scikit-Learn.
que utiliza. Con sklearn es posible entrenar y probar el modelo.
Inicialmente incluiremos las librerías necesarias, en este caso
La base de datos Digits contiene 1797 imágenes de los números dígitos escritos a mano. El obje-
tivo es predecir el dígito de una imagen específica. Como hay 10 dígitos, este es un problema de [1]: %matplotlib inline
clasificación múltiple. import matplotlib.pyplot as plt
[2]: from sklearn import datasets, svm, metrics
En este caso es posible utilizar aprendizaje supervisado, ya que cada imagen tiene una etiqueta. [3]: from sklearn.model_selection import train_test_split
Para identificar los diferentes números, el algoritmo de clasificación más utilizado es el del vecino
más cercano, (k- nearest neighbors, k-NN) En la primera línea, el comando %matplotlib inline es necesario para que los resultados aparezcan
en el área de trabajo de Jupyter, si no se incluye, las gráficas aparecerán en otras ventanas. Como
Una forma gráfica de explicar cómo funciona el algoritmo k-NN es la siguiente: en otras ocasiones, pyplot, proporciona una caja de opciones para generar gráficos personaliza-
dos. Las siguientes dos líneas invocan librerías de sklearn.
• El módulo datasets contiene una gran cantidad de bases de datos, los de nuestro inte-
rés son los números dígitos escritos a mano.
Para cargar la base de datos para trabajar Para mostrar a la imagen con índice 14
La base de datos contiene 1797 muestras (imágenes de los dígitos), cada una con 64 valores en un Este número parece un 9, para verificar si lo es:
rango de 0 a 16 y que representan la intensidad de un pixel. Con Matplotlib, es posible visualizar
las intensidades en escalas de grises, desde le blanco (0) hasta el negro (16).
El arreglo objetivo (target) contiene las etiquetas de las imágenes. El arreglo es llamado target,
debido a que compararás un método de identificación con las etiquetas de las imágenes que su-
miremos correctas. Esto es, si el método dice que la imagen es 8 y coincide con la etiqueta 8, la
clasificación será correcta, pero, puede ocurrir que no lo sea.
De dimensiones 1x64. Los títulos en cada imagen se definen a través de ax.set_title, con título Etiqueta y un entero
que indica el label de la imagen.
15.6 Exploración básica de datos La tarea de plt.tight_layout() es la de remover el espacio en blanco, en los extremos su-
periores, inferiores y a la derecha e izquierda del gráfico.
Esto consiste en familiarizarte con el tipo de datos que estás trabajando y esto se realiza explo-
rando un poco la información. En este caso, puedes visualizar la información de la base de datos Por último, plt.savefig guarda el gráfico con el nombre de out, en formato png, en la misma
carpeta donde se ejecuta el programa.
[14]: _, axes = plt.subplots(nrows=3, ncols=5, figsize=(10,12))
for ax, image, label in zip(axes.ravel(), digits.images, digits.
target): 15.7 Separación de datos para Entrenamiento y Prueba
ax.set_axis_off()
ax.imshow(image, cmap=plt.cm.gray_r, interpolation='nearest') De un solo conjunto de datos, haremos dos partes: una parte que servirá de entrenamiento y otro
ax.set_title('Etiqueta: %i' % label) que será parte de las pruebas del método de reconocimiento.
plt.tight_layout()
plt.savefig("out.png",bbox_inches='tight',pad_inches=0) La función train_test_split del módulo sklearn.model_selection realiza una especie de divi-
sión en dos muestras y aleatorización. Esto permite quitar el sesgo al momento de seleccionar las
muestras y les da características similares.
La función train_test_split regresa una tupla de 4 elementos. Los primeros 2 son las mues-
tras divididas en conjuntos de entrenamiento y prueba. Los otros corresponden a los valores ob-
jetivo (targets), también de entrenamiento y de prueba.
Por convención, utilizaremos la X mayúscula para representar a las muestras y la y minúscula para
representar a los valores objetivo.
Con el objetivo de verificar la reproductibilidad de los resultados, la semilla para generar números
pseudoaleatorios la dejaremos fija. Esto es con random_state=1 podrás comprobar que se obtie-
nen los mismos resultados.
Por default, train_test_split asigna el 75% de los datos para el entrenamiento y 25% para
las pruebas
[28]: from sklearn.metrics import confusion_matrix [31]: from sklearn.metrics import classification_report
[29]: mat_confusion=confusion_matrix(y_true=esperado,y_pred=pronostico) [32]: names=[str(digit) for digit in digits.target_names]
[30]: mat_confusion [33]: print(classification_report(esperado,pronostico,-
[30]:array([[52, 0, 0, 0, 0, 0, 0, 0, 0, 0], target_names=names))
[ 0, 48, 0, 0, 0, 0, 0, 0, 0, 0], [33]: precision recall f1-score support
[ 0, 0, 48, 0, 0, 0, 0, 0, 0, 0], 0 1.00 1.00 1.00 52
[ 0, 0, 0, 41, 0, 0, 0, 1, 0, 1], 1 0.94 1.00 0.97 48
[ 0, 0, 0, 0, 47, 0, 0, 0, 0, 0], 2 1.00 1.00 1.00 48
[ 0, 0, 0, 0, 0, 38, 0, 0, 0, 0], 3 0.91 0.95 0.93 43
[ 0, 0, 0, 0, 0, 0, 38, 0, 0, 0], 4 1.00 1.00 1.00 47
[ 0, 0, 0, 0, 0, 0, 0, 41, 0, 0], 5 0.97 1.00 0.99 38
[ 0, 2, 0, 2, 0, 0, 0, 0, 46, 0], 7 0.98 1.00 0.99 41
[ 0, 1, 0, 2, 0, 1, 0, 0, 0, 41]], dtype=int64) 8 1.00 0.92 0.96 50
9 0.98 0.91 0.94 45
Los valores en la diagonal principal representan los pronósticos correctos, los valores no-cero fue- accuracy 0.98 450
ra de la diagonal indican pronósticos erróneos. macro avg 0.98 0.98 0.98 450
weighted avg 0.98 0.98 0.98 450
Cada fila representa una clase distinta (dígitos de 0 a 9). Las columnas dentro de una fila, indica
cuántas pruebas fueron clasificadas en cada una de las distintas clases.
• precision, es el número total de pronósticos correctos para cada clase, dividido entre el núme-
Por ejemplo, la fila 0: ro total de pronósticos para tal dígito. Por ejemplo, en la columna con índice 3, hay 2’s en la fila 8 y 9
indicando que dos 8’s y dos 9’s fueron clasificados como 3. Y el 41 de la misma columna, indica que
[52, 0, 0, 0, 0, 0, 0, 0, 0, 0] 41 imágenes fueron correctamente clasificadas. La precisión para el número 3 es de 41/45 o 0.91.
Representa la clase del dígito 0. Las columnas representan los 10 posibles objetivos (targets) de 0 a 9. • recall, es el número total de pronósticos correctos para cada clase, dividida entre el total del
De acuerdo a la fila 0, 52 muestras fueron clasificadas en la clase 0 y ninguna muestra fue asignada número de muestras que han sido pronosticadas en tal clase. Por ejemplo, la fila 3, hay un 7 y
a otra clase de manera incorrecta. Por lo que el 100% de los 0’s fueron correctamente clasificados. un 9 indicando que dos 3’s fueron clasificados en otras clases. El número 41, indica que 41 imá-
genes fueron correctamente clasificadas, por lo que el recall, para el dígito 3 es 41/43 o 0.95.
Otro ejemplo, la fila 9:
• f1-score, es el promedio entre precision y recall.
[ 0, 1, 0, 2, 0, 1, 0, 0, 0, 41]
• support, es el número de muestras con un valor esperado dado. Por ejemplo, en la fila 3, se
Representa la clase del dígito 9. De acuerdo a la fila 9, 41 muestras fueron clasificadas en la clase 9, pero: esperaban 43 clasificaciones correctas.
• El 1 de la columna con índice 1, indica que un 9 fue incorrectamente clasificado como 1. Un mapa de calor muestra con colores aquellos valores de mayor magnitud. Las funciones para
• El 2 de la columna con índice 3, indica que dos 9’s fueron incorrectamente clasificados como 3. graficar de seaborn pueden realizarlo automáticamente con datos de dos dimensiones. Converti-
• El 1 de la columna con índice 5, indica que un 9 fue incorrectamente clasificado como 5. remos la matriz de confusión en un DataFrame para graficarlo.
Por lo que el algoritmo hizo un pronóstico correcto de 91.11% (41 de 45) de 9’s. [34]: import pandas as pd
[35]: confusion_df = pd.DataFrame(mat_confusion,index =
De acuerdo a la matriz de confusión, del método de estimación, y con los parámetros selecciona- range(10),columns=range(10))
dos en el estimador y en las semillas de valores pseudoaleatorios, los números 8 y 9 son los que [36]: import seaborn as sns
presentan una aparente mayor dificultad para ser reconocidos. [37]: axes=sns.heatmap(confusion_df,annot=True,cmap=
'nipy_spectral_r')
[42]: evaluaciones
El argumento annot=True de la función heatmap muestra una barra de colores a la derecha. El
[43]: array([0.95555556, 0.99444444, 0.99444444, 0.98888889, 1. ,
cmap='nipy_spectral_r' el argumento que especifica el mapa de colores a utilizar, en este
0.97222222, 0.98888889, 0.97765363, 0.98882682, 0.98882682])
caso 'nipy_spectral_r'.
Una vez que se tiene la matriz de precisión de los 10 grupos, es posible evaluar la precisión de todo
el modelo, mediante la evaluación promedio de la precisión y la respectiva desviación estándar.
15.12 Validación Cruzada K-Fold
[44]: print(f'Precisión promedio:{evaluaciones.mean():0.2%}')
La validación cruzada habilita el uso de todos los datos para entrenar y probar, en el sentido de
[45]: Precisión promedio:98.50%
que tan bueno puede ser el modelo para realizar pronósticos, en nuevos datos, mediante la repe-
[46]: print(f'DesviaciónestándardelaPrecisión:
tición y prueba con diferentes proporciones de conjuntos de datos. La validación cruzada K-fold
divide al conjunto de datos en k grupos (folds) de igual tamaño. El algoritmo trabaja así: considera
{evaluaciones.std():0.2%}')
el uso de k=10 grupos, numerados del 1 al 10. Con 10 grupos, realizaremos 10 ciclos de entrena- [47]: Desviación estándar de la Precisión:1.24%
mientos y pruebas, es decir
En promedio, el modelo tuvo una precisión del 98.5%, que resulta ligeramente mejor del 98% que
• Primero, entrenamos con los conjuntos 1 al 9, y probamos con el grupo 10. se había logrado, cuando se realizó un ciclo con 75% de datos de entrenamiento y con 25% de
• Ahora, entrenamos con los conjuntos 1 al 8, y probamos con el grupo 9. datos de prueba.
• Ahora, entrenamos con los conjuntos 1 al 7, y probamos con el grupo 8.
Además de todas las bondades que ha mostrado Scikit-learn también permite comparar la preci-
Este ciclo de entrenamiento y prueba continua hasta que cada grupo ha sido utilizado para probar sión con diferentes modelos y determinar a la mejor máquina de aprendizaje.
el modelo.
A continuación, se presenta los estimadores KNeighborsClassifier, SVC y GaussianNB (pero hay
Scikit-learn tiene la clase KFold y la función cross_val_score (ambas en el módulo sklearn.model_ más). Los últimos dos no los habíamos utilizado, pero resultan fáciles de implementar.
selection) para realizar los ciclos de entrenamiento y prueba. Primero crearemos un objeto KFold.
Para importar las librerías necesarias:
[38]: from sklearn.model_selection import KFold
[39]: kfold=KFold(n_splits=10,random_state=7,shuffle=True) [48]: from sklearn.svm import SVC
[49]: from sklearn.naive_bayes import GaussianNB
Los argumentos son:
Ahora crearemos los estimadores, justo como lo realizamos con el método KNeighborsClassifier
• n_splits=10, éste es el número de grupos (folds).
• random_state=11, es la misma semilla que habíamos utilizado anteriormente. [50]: estimadores={'KNeighborsClassifier':knn,
• shuffle=True, que tiene la tarea de aleatorizar los datos antes de separarlos en 'SVC': SVC(gamma='scale'),
grupos. 'GaussianNB': GaussianNB()}
Basados en los resultados el estimador SVC es ligeramente mejor que los demás. Aunque todos pue- [3]: print(boston.DESCR)
den mejorar las precisiones, si se atienden mejor los parámetros del estimador. SVC y KNeighbors- .. _boston_dataset:
Classifier presentan resultados casi idénticos, por lo que son candidatos a revisar los parámetros. Boston house prices dataset
---------------------------
**Data Set Characteristics:**
15.13 Regresión Lineal Múltiple
:Number of Instances: 506
En esta sección trabajarás el tópico de análisis de regresión múltiple. Un modelo de regresión lineal :Number of Attributes: 13 numeric/categorical predictive. Median
múltiple tiene la forma: Value (attribute 14) is usually the target.
This dataset was taken from the StatLib library which is [7]: import pandas as pd
maintained at Carnegie Mellon University. [8]: pd.set_option('precision', 4)
[9]: pd.set_option('max_columns', 8)
The Boston house-price data of Harrison, D. and Rubinfeld, [10]: pd.set_option('display.width', None)
D.L. 'Hedonic prices and the demand for clean air', J. En-
viron. Economics & Management, vol.5, 81-102, 1978. Used in En este caso,
Belsley, Kuh & Welsch, 'Regression diagnostics ...', Wiley,
1980. N.B. Various transformations are used in the table on • 'precision', es el número máximo de decimales que se mostrarán en los cálculos.
pages 244-261 of the latter. • 'max_columns', es el número máximo de columnas que se mostrarán en el DataFrame.
• 'display.width', especifica el ancho de caracteres en el Prompt, en este caso no
The Boston house-price data has been used in many machine hay ningún límite.
learning papers that address regression problems.
Ahora, construiremos un DataFrame con los datos,
.. topic:: References
[11]: boston_df = pd.DataFrame(boston.data, columns=bos-
- Belsley, Kuh & Welsch, 'Regression diagnostics: Identif- ton.feature_names)
ying Influential Data and Sources of Collinearity', Wiley, [12]: boston_df['MEDV'] = pd.Series(boston.target)
1980. 244-261.
Observa que en el snippet [11] se definen las variables independientes ('CRIM', 'ZN', 'IN-
- Quinlan,R. (1993). Combining Instance-Based and Model-Ba-
DUS', 'CHAS', 'NOX', 'RM', 'AGE', 'DIS', 'RAD', 'TAX', 'PTRATIO', 'B',
sed Learning. In Proceedings on the Tenth International
'LSTAT') y en el siguiente snippet la variable objetivo (target) o que también hemos llamado
Conference of Machine Learning, 236-243, University of Mas-
variable dependiente.
sachusetts, Amherst. Morgan Kaufmann.
Para ver la información del DataFrame
De acuerdo con la información en la descripción, esta base de datos contiene la información de
[13]: boston_df.head()
506 individuos (viviendas) con 13 variables diferentes, de las cuales una sirve como variable de
respuesta y es la última. Esta variable está definida como Y, y representa el valor medio de las vi-
[13]: CRIM ZN INDUS ... B LSTAT MEDV
viendas ocupadas por sus propietarios, medida en miles de dólares. 0 0.0063 18.0 2.31... 396.90 4.98 24.0
1 0.0273 0.0 7.07... 396.90 9.14 21.6
2 0.0273 0.0 7.07... 392.83 4.03 34.7
3 0.0324 0.0 2.18... 394.63 2.94 33.4
Para hacer la visualización más clara graficaremos a las variables por pares, y utilizaremos el méto-
do sample de DataFrame, seleccionando aleatoriamente solo el 30% de las 506 muestras, solo con
el propósito de mostrar las gráficas y analizar el comportamiento de las variables.
Nuevamente, con el objetivo de hacer este análisis reproducible, queda fija la semilla para realizar
la misma selección de datos.
Ahora construiremos los diagramas de dispersión de cada una de las variables independientes
CRIM, ZN, INDUS, CHAS, NOX, RM, AGE, DIS, RAD, TAX, PTRATIO, B, LS-
TAT, contra MEDV
Sin embargo, algunas pistas, son evidentes al momento de interpretar los diagramas.
• En el primer diagrama, CRIM vs MEDV, tal parece que mientras más pequeño sea el
índice de criminalidad el valor promedio de la vivienda será mayor.
• En el diagrama, CHAS vs MEDV, se puede leer que una buena proporción de viviendas
colindan con el río y que esta característica no incide en el precio de la vivienda.
• El diagrama, RM vs MEDV, indica que mientras mayor sea el número de habitaciones en
las viviendas mayor será el precio de éstas.
• En el diagrama, LSTAT vs MEDV, se puede leer que mientras mayor sea el porcentaje de
personas con status bajo, el precio de la vivienda tenderá a disminuir.
Recuerda que al dejar las opciones por default en import train_test_split, se deja el 75% de los da-
tos para realizar entrenamiento y 25% para realizar pruebas.
Tanto, X_entrena, X_prueba tienen 13 columnas que representan a las variables independientes.
Como se había planeado, en cada etapa del ciclo for: Para crear un estimador de regresión lineal invocamos el método fit para entrenar al estimador,
utilizando x_entrena, y_entrena.
• Pyplot genera un gráfico con tamaño de 16x9 in
• Seaborn genera un diagrama de dispersión con la variable (feature) actual en el eje x, y [25]: from sklearn.linear_model import LinearRegression
la variable objetivo (boston.target) en el eje vertical. [26]: regresion_lineal = LinearRegression()
• Los colores de los puntos están definidos por la variable objetivo (boston.target) a tra- [27]: regresion_lineal.fit(X=X_train, y=y_train)
vés de hue. [27]: LinearRegression()
̂ +β
MEDV=β ̂ CRIM+β
̂ ZN+…+β
̂ B+β
̂ LSTAT
0 1 2 12 n
Para valores específicos de las variables independientes CRIM, ZN, INDUS, etc. Es posible determi-
nar el precio aproximado de una vivienda.
Cuando los coeficientes son de signo positivo, al incrementarse el valor de la variable indepen-
diente, el costo de la vivienda también se incrementa, justo como lo habíamos señalado con RM y
MEDV. Si el coeficiente es negativo, al incrementarse el valor de la variable independiente, el costo
de la vivienda disminuye, como es el caso de LSTAT y MEDV.
Otro indicador que muestra que tan bueno es el modelo es el error cuadrático medio. El módulo 15.20 Machine Learning No Supervisado.
sklearn.metrics lo puede calcular mediante la función mean_squared_error. Reducción de Dimensiones
[41]: metrics.mean_squared_error(esperado, pronostico) La reducción de dimensiones en un problema puede resultar en un gran ahorro de recursos, ya sea
[41]: 29.5151377901978 en el tiempo de recursos computacionales o en el tiempo invertido en realizar un análisis de datos.
Siendo este indicador una medida del error, es deseable que sea cercano al cero. En este caso, no En esta sección aprenderás a utilizar una estrategia sencilla pero poderosa que permite reducir la
lo es, pero tampoco representa un valor grande. dimensión de las variables que explican un fenómeno.
Utilizaremos nuevamente la base de datos Digits de sklearn. En este caso no es necesario manipular
15.20 Comparando diferentes modelos las etiquetas de las imágenes por lo estarás empleando una máquina de aprendizaje no supervisado.
Existen varios métodos que permiten calcular los coeficientes de un modelo de regresión, para Primero cargaremos la base de datos:
realizar una comparación de ellos, podemos utilizar la misma base de datos y verificar el coeficien-
te de determinación y establecer cuál método proporciona el mejor ajuste. [1]: %matplotlib inline
from sklearn.datasets import load_digits
En este ejemplo utilizaremos los estimadores: linear_regression, ElasticNet, Lasso y Ridge. Para [2]: digits = load_digits()
mayor información acerca de estos métodos puedes ingresar a:
Ahora, emplearemos un estimador TSNE, este estimador utiliza el algoritmo t-SNE (del inglés, t-dis-
https://scikit-learn.org/stable/modules/linear_model.html
tributed Stochastic Neighbor Embedding) para analizar un conjunto de datos y reducirlos a un
número de dimensiones específica.
El código para esta comparación es el siguiente.
[42]: from sklearn.linear_model import ElasticNet, Lasso, Ridge Crearemos un objeto TSNE para reducir las características de un conjunto de datos a dos dimen-
[43]: estimadores = { siones con el argumento n_components. Como con los otros estimadores dejaremos una semilla
'LinearRegression': regresion_lineal, generadora fija, con el fin de verificar que ocurren los mismos resultados.
'ElasticNet': ElasticNet(),
'Lasso': Lasso(), [3]: from sklearn.manifold import TSNE
'Ridge': Ridge() [4]: tsne = TSNE(n_components=2, random_state=7)
}
Cuando el método se ejecuta, regresa el mismo número de filas, pero sólo dos columnas.
[6]: reduced_data.shape
[6]: (1797, 2)
Los primeros dos argumentos de plt.scatter son las columnas 0 y 1 con los datos reducidos.
El argumento c='blue' especifica el color de los puntos. Las nuevas características de los datos
reducidos pueden ser muy diferentes a los datos originales.
Para realizar una mejor visualización, es posible asignar un color a los puntos más cercanos.
Aprendizaje Profundo
(Deep Learning)
16.1 Introducción
Una de las áreas que ha tenido mayor desarrollo es el llamado Deep learning. Esta es una rama
poderosa de machine learning, que ha generado resultados impactantes en diversas y nuevas
áreas de las ciencias, como consecuencia del novedoso desarrollo de software y hardware de los
últimos años.
• Reconocimiento facial
• Chatbots
• Visión por computadora
• Conducción automática de vehículos, etc.
16.2 Keras
Los modelos de Deep Learning requieren configuraciones más sofisticadas y regularmente están
conectadas a múltiples objetos, llamados capas (layers). En este capítulo construirás modelos con
Keras, el cual ofrece una interfaz amigable con TensorFlow de Google.
• Fácil de extender. Keras permite escribir bloques de construcción personalizados, para Paso 2. Actualiza la librería Scikit-learn. En el Prompt de Anaconda escribe:
expresar nuevas ideas para la investigación. Crea nuevas capas, métricas, funciones de
perdida y desarrolla modelos de estado del arte. conda update scikit-learn
•
Keras es a Deep learning, como Scikit-learn es a machine learning. Como Scikit-learn, Keras man- Paso 3. Instala las librerías para Deep Learning En este paso se instalarán las imprescindibles ke-
tiene las funciones y los atributos encapsulados, lo cual permite proteger a las funciones originales ras y Tensorflow de Google. En el Prompt de Anaconda escribe:
de modificaciones accidentales.
conda install -c conda-forge tensorflow
Los modelos de Deep learning trabajan muy bien para grandes bases de datos, aunque también,
puede proporcionar buenos resultados con bases de datos no tan grandes. Estos modelos regu- Luego,
larmente realizan una gran cantidad de operaciones, por lo que es recomendable tener un equipo
de cómputo con una significativa potencia de procesamiento. pip install keras
No te preocupes, con un procesador de regular potencia puedes ejecutar los modelos, puede ocu- Ten paciencia, la actualización de Anaconda y de las librerías de Keras y TensorFlow puede resultar
rrir que tarden más en ejecutarse, pero en algún instante llegarás al resultado. un tanto lentas. Todo depende de la capacidad de tu procesador y de tu red WIFI.
Como Scikit-Learn, Keras tiene sus propios conjuntos de datos que resultan útiles para probar Para dar un vistazo breve a los ejemplos que realizarás, necesitas primero tener algunos antece-
modelos. En este capítulo utilizaremos los dos primeros. dentes básicos de Redes Neuronales y de Tensores.
• MNIST, esta es una base de datos con dígitos escritos a mano. Esta colección es útil
para clasificar imágenes. La base de datos contiene 60,000 imágenes de 28x28 pixeles 16.4 Redes Neuronales
de los números dígitos, para entrenar y 10,000 para probar.
Una red neuronal artificial o simplemente red neuronal, es un software construido para operar
• IMDb, esta es una base de críticas de cine. Está base de datos permite realizar análisis justo como lo hace el cerebro humano. Es decir, las redes neuronales artificiales tratan de imitar
de sentimientos. Las críticas están etiquetadas como positivas (1) o negativas y cuenta la forma en que la gente toma decisiones. O de manera más básica, la forma en que las neuronas
con más de 25,000 críticas para entrenar y 25,000 más para probar. biológicas toman decisiones y se comunican con las demás con el fin de aprender.
• Fashion-MNIST, esta es una base de datos de artículos de moda. Es utilizada para cla- El siguiente diagrama muestra una red neuronal de 3 capas.
sificar imágenes de 28x28 pixeles de ropa, etiquetadas en 10 categorías con 60,000
muestras para entrenar y 10,000 para probar. • Cada círculo representa una neurona
• Las líneas entre ellos representan las sinapsis (comunicación).
• CIFAR100, es una base de datos para clasificar imágenes pequeñas, contiene 50,000 • La información de salida de una neurona representa la información de entrada de otra
imágenes a color de 32x32 pixeles etiquetadas en 100 categorías para entrenar y 10,000
imágenes de prueba. Este diagrama está completamente interconectado, es decir, cada neurona está conectada con
otra de la siguiente capa.
En resumen, una red neuronal (o modelo) es una secuencia de capas que contienen neuronas
utilizadas para aprender de las muestras. En Keras, así es como trabaja una red neuronal básica:
• Cada neurona en la capa, recibe una entrada, las procesa (a través de la función de
activación) y produce una salida.
• Los datos se introducen en las redes a través de una capa de entrada, esto define las
dimensiones de los datos de muestra.
• Esto es seguido por capas ocultas de neuronas que implementan el aprendizaje y una
capa de salida realiza predicciones
• Cuantas más capas se implementen, más profunda será la red. De aquí el término de
aprendizaje profundo
Como el aprendizaje en esta red artificial simula el aprendizaje humano, como en los humanos, la
red necesita entrenarse para aprender. Es justo como aprender a programar
¿Cuándo serás un experto?, cuando hayas entrenado lo suficiente y para diferentes personas el
tiempo para aprender fluidamente a programar puede ser diferente. No hay una regla o fórmula
que indique el tiempo específico para ser un experto. Esto mismo ocurre con las redes neuronales
conforme evolucionan con el tiempo, a cada iteración se le llamaremos epoch (época). De manera
que, en cada epoch, la red procesa una muestra del conjunto de datos de entrenamiento a la vez.
Cuando la red se está entrenando calcula algunos coeficientes (como en el caso de regresión), 16.5 Capas convolucionales
llamados pesos (weigths) para cada conexión entre las neuronas de una capa y las de la siguiente.
Una capa convolucional utiliza las relaciones entre pixeles vecinos para aprender características útiles (o
Cuando existe una entrada (input), esta es multiplicada por su respectivo coeficiente y comunicada a patrones) en áreas pequeñas de cada muestra. Estas características son entradas de capas subsecuentes.
la función de activación. Esta función tiene la tarea de activar la neurona o neuronas específicas y de-
penderá de la entrada que tenga la función. El diagrama siguiente esquematiza este procedimiento. Las áreas pequeñas, de las que aprende la convolución se llaman kernels o parches. Para enten-
der como funciona la convolución revisemos el siguiente ejemplo. Supongamos que tenemos una
imagen de 6x6 y un cuadrado de 3x3 sombreado que representa al kernel. Los números, tanto de
la imagen con en el kernel son simplemente para ejemplificar.
Se puede entender que un kernel es una especie de ventana deslizante y que la convolución mue-
ve la capa convolución un pixel a la vez, primero del extremo superior izquierdo hasta al extremo
superior derecho. Y luego baja un pixel y vuelve a realizar el ciclo. Típicamente los kernels son
matrices de 3x3, aunque hay versiones de 5x5 y hasta de 7x7 para las imágenes grandes de alta
Los valores w1, w2 son llamados pesos o cargas. En un modelo que se entrena desde cero, inicial- resolución. Después de realizar la convolución por toda la imagen original, queda una matriz de
mente estos valores son seleccionados de manera aleatoria. Cuando la red se entrena, trata de dimensiones más pequeñas que contiene las características de la imagen original.
minimizar la tasa de error entre las etiquetas de los pronósticos y las de las muestras. A la tase
16.6 Tensores
En términos computacionales, un tensor es un arreglo. En términos matemáticos es un vector fila
o vector columna de cualquier dimensión. Esta última característica es la que distingue a los ten-
sores, de los vectores habituales de álgebra lineal.
Por ejemplo, supongamos que requieres identificar y rastrear objetos in videos de alta resolución
que tienen 30 tramas por segundo. Cada trama en un video 4K de alta resolución tiene 3840x2160
pixeles. Supongamos que los pixeles están representados en un formato RGB (Red, Green, Blue)
de color. Así, cada trama tiene un tensor de 3D que contiene 24,883,200 elementos (3840x2160x3)
y cada video puede tener un tensor de 4D que contiene una sucesión de tramas. Si el vídeo es de
un minuto de duración, entonces hay 44,789,760,000 elementos por tensor.
En Google se cargan aproximadamente 600hrs de video por minuto. Así que Google contiene ten-
sores de 1,612,431,360,000,000 elementos, los cuales requieren un rápido procesamiento cuando
se entrenan modelos de aprendizaje profundo.
[3]: X_entrena.shape
[3]: (60000, 28, 28)
[4]: y_entrena.shape
[4]: (60000, )
Parte de los inconvenientes a los que tendrá que enfrentarse nuestro estimador son:
[5]: X_prueba.shape
[5]: (10000, 28, 28) • Como en la fila 3, el 5 que aparece puede ser confundido con un 6.
[6]: y_prueba.shape • El número 7 de la tercera fila, puede ser confundido con un 1 o un 9.
[6]: (10000, ) • Los números 4, algunas veces aparecerán abiertos, como en las imágenes o cerrados.
• Los números 1, aparecen como una línea simple, pero a veces aparecen con un guión
Con esta parte de código puedes visualizar una parte del conjunto de datos bajo. Este es el caso de los unos de la última fila
[7]:%matplotlib inline Como las imágenes son de 28x28 pixeles, puedes observar que tienen mejor resolución.
import matplotlib.pyplot as plt
[0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0] [30]: cnn.add(Conv2D(filters=128, kernel_size=(3, 3),
activation='relu'))
Para transformar y_entrena y y_prueba, de arreglos con una dimensión que contienen valores de [31]: cnn.add(MaxPooling2D(pool_size=(2, 2)))
0 a 9, en arreglos de dos dimensiones de datos categóricos.
Hasta este punto la salida de la última capa regresa un arreglo de tres dimensiones (5x5x128),
[19]: from tensorflow.keras.utils import to_categorical pero la salida final debe un arreglo de una dimensión de 10 probabilidades para clasificar a los
[20]: y_entrena = to_categorical(y_entrena) números dígitos. Para preparar el pronóstico final utilizaremos la capa Flatten de Keras.
[21]: y_entrena.shape
[32]: cnn.add(Flatten())
De acuerdo a la información anterior, el modelo convnet es 99.13% preciso cuando se utiliza para [46]: len(pronostico_incorrecto)
reconocer imágenes nuevas. Lo cual es bastante bueno, a pesar haber utilizado algunos valores de [46]: 87
los argumentos que se encuentran por default en las funciones.
El método predict del modelo pronostica las clases de las imágenes en el arreglo X_test
[42]: y_prueba[0]
[42]: array([0., 0., 0., 0., 0., 0., 0., 1., 0., 0.], dtype=float32)
De acuerdo a esta salida, el número al que pertenece es al 7. Para revisar las probabilidades calcu-
ladas por el método predict para la primera muestra.
Esta información indica que, en el pronóstico, el número observado debe ser el 7 con casi 100%
de certeza.
Este número se esperaba que fuera identificado con el 9, sin embargo, el modelo estima que es 4 El módulo imdb de la función load_data regresa los conjuntos para entrenamiento y prueba. En el
con una probabilidad de 69.76%, contra 23.15% de que sea 9. Observa que también hay probabi- conjunto de datos hay alrededor de 88,000 palabras únicas. La función load_data permite establecer
lidades de que sea considerado 6 con 3.12%, 0 con 1.93% y 8 con 1.61%. un número fijo de palabras únicas de interés. En este ejemplo cargaremos las 10,000 palabras más fre-
cuentes que ocurren, esto se hace por las limitaciones computacionales que nos podamos encontrar.
[45]: display_probabilities(predictions[1326])
[46]: 0: 0.0079155841% [2]: number_of_words = 10000
1: 0.2348761540% [3]: (X_entrena, y_etrena), (X_prueba, y_prueba) =
2: 0.0108659347% imdb.load_data(num_words=number_of_words)
Downloading data from https://storage.goo-
16.14 Exploración de Datos Aunque el diccionario de valores de Keras el 1 es para la palabra más frecuente, los valores 0,1 y 2
tienen los siguientes propósitos:
Revisemos las dimensiones del conjunto de muestras de entrenamiento y de prueba.
• El valor 0 en una crítica representa el padding (relleno). Los algoritmos de Keras necesi-
[4]: X_entrena.shape tan que las muestras tengan las mismas dimensiones, por lo que algunas críticas pue-
[4]: (25000, ) den necesitar expandirse a una longitud específica. Esta expansión es llamada relleno,
[5]: y_entrena.shape y se rellena con ceros.
[5]: (25000, )) • El valor 1 representa el token, este es utilizado internamente para indicar el inicio de
[6]: X_prueba.shape una secuencia de texto.
• El valor 2 representa una palabra desconocida. Esto puede ocurrir al limitar el número
[6]: (25000, )
de datos cargados.
[7]: y_ prueba.shape
[7]: (25000, ))
Como ejemplo, decodificaremos una crítica
Los arreglos y_entrena y y_prueba son arreglos unidimensionales que contienen ceros y unos,
[10]: word_to_index = imdb.get_word_index()
indicando cuando la crítica fue positiva o negativa. Sin embargo X_entrena y X_prueba también
aparecen como arreglos unidimensionales, peor sus elementos son una lista de enteros cada uno
Downloading data from https://storage.googleapis.com/ten-
representando los contenidos de una crítica. Aquí una muestra. sorflow/tf- keras-datasets/imdb_word_index.json
1646592/1641221 [==============================] - 0s 0us/
[8]: %print step
Pretty printing has been turned OFF
[9]: X_train[123] La palabra 'amazing' puede aparecer en una crítica positiva, por lo que es interesante saber si
aparece en el diccionario
[9]: array([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
[11]: word_to_index['amazing']
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
[11]: 447
0, 0, 0, 0, 0, 0, 0, 0, 1, 5, 14,
9, 6, 55, 1193, 22, 13, 203, 30, 355, 21, 14,
De acuerdo a este valor. La palabra 'amazing' en el conjunto de datos es la 477 palabra más frecuente
9, 4, 236, 22, 121, 13, 1192, 2967, 3622, 5, 779,
284, 37, 5844, 4, 217, 5, 2132, 6, 749, 10, 10,
Para transformar el rating numérico en palabras, primero invertiremos el orden del word_to_index
2636, 4252, 5, 2931, 4517, 26, 82, 321, 36, 26, 2,
en el diccionario, y luego una entrada en el nuevo diccionario con la expresión index:word
5, 4960, 2, 1786, 8, 358, 4, 704, 117, 122, 36,
124, 51, 62, 593, 375, 10, 10, 4, 1381, 5, 732, La siguiente compresión de lista muestra las primeras 50 palabras del nuevo diccionario. En este
26, 821, 5, 1249, 14, 16, 159, 4, 504, 7, 3728, caso el índice 1 es la que más veces se repite.
4913, 10, 10, 51, 9, 91, 1193, 44, 14, 22, 9,
4, 192, 15, 1370, 40, 14, 131, 1778, 11, 938, 704, [12]: index_to_word = \
3834, 131, 2, 543, 84, 12, 9, 220, 6, 1117, 5, {index: word for (word, index) in word_to_index.items()}
6, 320, 237, 4, 3286, 325, 10, 10, 25, 80, 358, [13]: [index_to_word[i] for i in range(1, 51)]
14, 22, 12, 16, 814, 11, 4, 3968, 8084, 7, 1226, [13]: ['the', 'and', 'a', 'of', 'to', 'is', 'br', 'in',
7111, 63, 131, 1778, 43, 92, 1278, 501, 15, 8, 6353, 'it', 'i', 'this', 'that', 'was', 'as', 'for', 'with',
2, 15, 1609, 131, 47, 24, 77, 2, 237, 2, 2, 'movie', 'but', 'film', 'on', 'not', 'you', 'are', 'his',
158, 158]) 'have', 'he', 'be', 'one', 'all', 'at', 'by', 'an', 'they',
'who', 'so', 'from', 'like', 'her', 'or', 'just', 'about',
Los modelos de aprendizaje profundo de Keras requieren datos numéricos, sin embargo, las crí- "it's", 'out', 'has', 'if', 'some', 'there', 'what', 'good',
ticas se encuentran codificadas. Para ver el texto original es necesario conocer la palabra a la cual
'more']
Para verificar de que tipo es la crítica Ahora, es necesario importar las capas que utilizaremos en el modelo.
Por lo tanto, es positiva. Para reducir la dimensionalidad, la RNN inicia con una capa embebida, que codifica cada palabra
en una más compacta llamada representación denso-vector. Los vectores producidos por la capa
embebida guardan el contexto de la palabra, es decir, como una palabra se relaciona con otras a
16.15 Preparación de los datos su alrededor. De esta manera la capa embebida habilita a la RNN para aprender relaciones entre
palabras durante el entrenamiento.
Keras requiere que todas las muestras tengan el mismo tamaño, por lo que restringiremos el nú-
mero de palabras de las críticas. Aunque, puede haber críticas que necesiten rellenarse. La función Para crear una capa embebida
pad_sequences del módulo tensorflow.keras.preprocessing.sequence puede realizar esta tarea.
[28]: rnn.add(Embedding(input_dim=number_of_words, output_dim=128,
[16]: words_per_review = 200 input_length=words_per_review))