Está en la página 1de 222

1

Elogio a las matemáticas esenciales para la ciencia de datos


En la cacofonía que es el panorama actual de la educación en ciencia de datos, este libro se
destaca como un recurso con muchos ejemplos claros y prácticos de los fundamentos de lo que se
necesita para comprender y construir con datos. Al explicar los conceptos básicos, este libro
permite al lector navegar por cualquier trabajo de ciencia de datos con un marco mental sólido de
sus componentes básicos.
Vicki Boykis, ingeniera sénior de aprendizaje automático en Tumblr
La ciencia de datos se basa en el álgebra lineal, la teoría de la probabilidad y el cálculo. Thomas
Nield nos guía de manera experta a través de todos esos temas, y más, para construir una base
sólida para comprender las matemáticas de la ciencia de datos.
Mike X Cohen, sincXpress
Como científicos de datos, usamos modelos y algoritmos sofisticados a diario. Este libro desmitifica
rápidamente las matemáticas detrás de ellos, por lo que son más fáciles de comprender e
implementar.
Siddharth Yadav, científico de datos independiente
¡Ojalá hubiera tenido acceso a este libro antes! Thomas Nield hace un trabajo increíble al
desglosar temas matemáticos complejos de una manera digerible y atractiva. Un enfoque
refrescante tanto para las matemáticas como para la ciencia de datos, que explica a la perfección
los conceptos matemáticos fundamentales y sus aplicaciones inmediatas en el aprendizaje
automático. Este libro es una lectura obligada para todos los aspirantes a científicos de datos.
Tatiana Ediger, científica de datos independiente y desarrolladora e instructora de cursos

Essential Math for Data Science


Matemáticas esenciales para la ciencia de datos
Tome el control de sus datos con álgebra lineal fundamental, probabilidad y estadística

Thomas Nield
Matemáticas esenciales para la ciencia de datos
por Thomas Nield
Copyright © 2022 Thomas Nield. Reservados todos los derechos.
Impreso en los Estados Unidos de América.
Publicado por O'Reilly Media, Inc., 1005 Gravenstein Highway North, Sebastopol, CA 95472.
Los libros de O'Reilly se pueden comprar con fines educativos, comerciales o de promoción de
ventas. Las ediciones en línea también están disponibles para la mayoría de los títulos (
http://oreilly.com ). Para obtener más información, comuníquese con nuestro departamento de
ventas corporativo/institucional: 800-998-9938 o corporate@oreilly.com.
Editora de adquisiciones: Jessica Haberman
Editora de desarrollo: Jill Leonard
Editora de producción: Kristen Brown
Editor de estilo: Piper Editorial Consulting, LLC
Correctora: Shannon Turlington
Indexador: Potomac Indexing, LLC
Interior Designer: David Futato
Diseño de portada: Karen Montgomery
Ilustrador: Kate Dullea
Junio 2022: Primera Edición

Historial de revisiones de la primera edición


 2022-05-26: Primer lanzamiento
Consulte http://oreilly.com/catalog/errata.csp?isbn=9781098102937 para conocer los detalles de la
versión.
El logotipo de O'Reilly es una marca comercial registrada de O'Reilly Media, Inc. Essential Math for
Data Science, la imagen de portada y la imagen comercial relacionada son marcas comerciales de
O'Reilly Media, Inc.
Las opiniones expresadas en este trabajo son las del autor y no representan las opiniones del
editor. Si bien el editor y el autor se han esforzado de buena fe para garantizar que la información y
las instrucciones contenidas en este trabajo sean precisas, el editor y el autor renuncian a toda

2
responsabilidad por errores u omisiones, incluida, entre otras, la responsabilidad por daños
resultantes del uso o confianza en este trabajo. El uso de la información e instrucciones contenidas
en este trabajo es bajo su propio riesgo. Si alguna muestra de código u otra tecnología que este
trabajo contiene o describe está sujeta a licencias de código abierto o a los derechos de propiedad
intelectual de otros, es su responsabilidad asegurarse de que su uso cumpla con dichas licencias
y/o derechos.
978-1-098-10293-7
[LSI]

Prefacio
En los últimos 10 años más o menos, ha habido un interés creciente en aplicar las matemáticas y la
estadística a nuestro trabajo y vida cotidianos. ¿Porqué es eso? ¿Tiene que ver con el interés
acelerado en la "ciencia de datos", que Harvard Business Review llamó "el trabajo más sexy del
siglo XXI" ? ¿O es la promesa del aprendizaje automático y la "inteligencia artificial" cambiando
nuestras vidas? ¿Es porque los titulares de las noticias están inundados de estudios, encuestas y
hallazgos de investigación, pero no están seguros de cómo analizar tales afirmaciones? ¿O es la
promesa de autos y robots "autónomos" que automatizan trabajos en un futuro cercano?
Argumentaré que las disciplinas de las matemáticas y las estadísticas han captado el interés
general debido a la creciente disponibilidad de datos, y necesitamos las matemáticas, las
estadísticas y el aprendizaje automático para darles sentido. Sí, tenemos herramientas científicas,
aprendizaje automático y otras automatizaciones que nos llaman como sirenas. Confiamos
ciegamente en estas "cajas negras", dispositivos y softwares; no los entendemos, pero los usamos
de todos modos.
Si bien es fácil creer que las computadoras son más inteligentes que nosotros (y esta idea se
comercializa con frecuencia), la realidad no puede ser más opuesta. Esta desconexión puede ser
precaria en muchos niveles. ¿Realmente desea que un algoritmo o una IA ejecuten sentencias
penales o conduzcan un vehículo, pero nadie, incluido el desarrollador, puede explicar por qué se
tomó una decisión específica? La explicabilidad es la próxima frontera de la computación
estadística y la IA. Esto puede comenzar solo cuando abrimos la caja negra y descubrimos las
matemáticas.
También puede preguntar cómo puede un desarrollador no saber cómo funciona su propio
algoritmo. Hablaremos de eso en la segunda mitad del libro cuando discutamos las técnicas de
aprendizaje automático y enfaticemos por qué necesitamos entender las matemáticas detrás de las
cajas negras que construimos.
En otro punto, la razón por la que se recopilan datos a gran escala se debe en gran medida a los
dispositivos conectados y su presencia en nuestra vida cotidiana. Ya no usamos Internet
únicamente en una computadora de escritorio o portátil. Ahora lo llevamos con nosotros en
nuestros teléfonos inteligentes, automóviles y dispositivos domésticos. Esto ha permitido sutilmente
una transición en las últimas dos décadas. Los datos ahora han evolucionado de una herramienta
operativa a algo que se recopila y analiza para objetivos menos definidos. Un reloj inteligente
recopila constantemente datos sobre nuestra frecuencia cardíaca, respiración, distancia recorrida y
otros marcadores. Luego carga esos datos en una nube para analizarlos junto con otros usuarios.
Nuestros hábitos de conducción están siendo recopilados por automóviles computarizados y los
fabricantes los utilizan para recopilar datos y habilitar vehículos autónomos. Incluso los "cepillos de
dientes inteligentes" están llegando a las farmacias, que rastrean los hábitos de cepillado y
almacenan esos datos en una nube. Si los datos del cepillo de dientes inteligente son útiles y
esenciales es otra discusión.
Toda esta recopilación de datos está impregnando todos los rincones de nuestras vidas. Puede ser
abrumador, y se puede escribir un libro completo sobre cuestiones de privacidad y ética. Pero esta
disponibilidad de datos también crea oportunidades para aprovechar las matemáticas y las
estadísticas de nuevas maneras y crear una mayor exposición fuera de los entornos académicos.
Podemos aprender más sobre la experiencia humana, mejorar el diseño y la aplicación de
productos y optimizar las estrategias comerciales. Si comprende las ideas presentadas en este
libro, podrá desbloquear el valor contenido en nuestra infraestructura de almacenamiento de datos.
Esto no implica que los datos y las herramientas estadísticas sean una bala de plata para resolver
todos los problemas del mundo, pero nos han dado nuevas herramientas que podemos usar. A
veces, es igual de valioso reconocer ciertos proyectos de datos como madrigueras de conejo y
darse cuenta de que es mejor gastar los esfuerzos en otra parte.

3
Esta creciente disponibilidad de datos ha abierto el camino para que la ciencia de datos y el
aprendizaje automático se conviertan en profesiones en demanda. Definimos las matemáticas
esenciales como una exposición a la probabilidad, el álgebra lineal, las estadísticas y el aprendizaje
automático. Si está buscando una carrera en ciencia de datos, aprendizaje automático o ingeniería,
estos temas son necesarios. Agregaré las matemáticas, el cálculo y las estadísticas universitarias
necesarias para comprender mejor lo que ocurre en las bibliotecas de caja negra que encontrará.
Con este libro, pretendo exponer a los lectores a diferentes áreas matemáticas, estadísticas y de
aprendizaje automático que serán aplicables a problemas del mundo real. Los primeros cuatro
capítulos cubren conceptos matemáticos fundamentales, incluidos cálculo práctico, probabilidad,
álgebra lineal y estadística. Los últimos tres capítulos darán paso al aprendizaje automático. El
propósito final de enseñar el aprendizaje automático es integrar todo lo que aprendemos y
demostrar conocimientos prácticos en el uso del aprendizaje automático y las bibliotecas
estadísticas más allá de la comprensión de la caja negra.
La única herramienta necesaria para seguir los ejemplos es una computadora con
Windows/Mac/Linux y un entorno Python 3 de su elección. Las bibliotecas principales de Python
que necesitaremos son numpy, scipy, sympy y sklearn. Si no está familiarizado con Python, es un
lenguaje de programación amigable y fácil de usar con recursos de aprendizaje masivos detrás.
Aquí hay algunos que recomiendo:
Ciencia de datos desde cero, 2.ª edición de Joel Grus (O'Reilly)
El segundo capítulo de este libro tiene el mejor curso intensivo de Python que he encontrado.
Incluso si nunca antes ha escrito código, Joel hace un trabajo fantástico al ponerlo en
funcionamiento con Python de manera efectiva en el menor tiempo posible. ¡También es un gran
libro para tener en su estantería y aplicar sus conocimientos matemáticos!
Python para el desarrollador de Java ocupado por Deepak Sarda (Apress)
Si usted es un ingeniero de software que viene de un fondo de programación orientada a objetos y
tipado estáticamente, este es el libro para agarrar. Como alguien que comenzó a programar con
Java, aprecio mucho la forma en que Deepak comparte las características de Python y las
relaciona con los desarrolladores de Java. Si ha trabajado con.NET, C++ u otros lenguajes
similares a C, probablemente también aprenderá Python de manera efectiva con este libro.
Este libro no lo convertirá en un experto ni le dará conocimientos de doctorado. Hago lo mejor que
puedo para evitar expresiones matemáticas llenas de símbolos griegos y en su lugar me esfuerzo
por usar un inglés sencillo en su lugar. Pero lo que hará este libro es que se sienta más cómodo
hablando de matemáticas y estadísticas, brindándole el conocimiento esencial para navegar estas
áreas con éxito. Creo que el camino más amplio hacia el éxito no es tener un conocimiento
profundo y especializado en un tema, sino tener exposición y conocimiento práctico en varios
temas. Ese es el objetivo de este libro, y aprenderá lo suficiente como para ser peligroso y hacer
esas preguntas críticas que alguna vez fueron esquivas.
¡Entonces empecemos!

Las convenciones usadas en este libro


En este libro se utilizan las siguientes convenciones tipográficas:
Itálico
Indica nuevos términos, URL, direcciones de correo electrónico, nombres de archivo y extensiones
de archivo.
Ancho constante
Se utiliza para listas de programas, así como dentro de párrafos para hacer referencia a elementos
de programas como nombres de variables o funciones, bases de datos, tipos de datos, variables de
entorno, declaraciones y palabras clave.

Negrita de ancho constante


Muestra comandos u otro texto que el usuario debe escribir literalmente.
Cursiva de ancho constante
Muestra texto que debe reemplazarse con valores proporcionados por el usuario o por valores
determinados por el contexto.

CONSEJO
Este elemento significa un consejo o sugerencia.

4
NOTA
Este elemento significa una nota general.
ADVERTENCIA
Este elemento indica una advertencia o precaución.

Uso de ejemplos de código


El material complementario (ejemplos de código, ejercicios, etc.) está disponible para descargar en
https://github.com/thomasnield/machine-learning-demo-data.
Si tiene una pregunta técnica o un problema al usar los ejemplos de código, envíe un correo
electrónico a bookquestions@oreilly.com.
Este libro está aquí para ayudarle a hacer su trabajo. En general, si se ofrece un código de ejemplo
con este libro, puede usarlo en sus programas y documentación. No es necesario que se
comunique con nosotros para obtener permiso a menos que esté reproduciendo una parte
importante del código. Por ejemplo, escribir un programa que use varios fragmentos de código de
este libro no requiere permiso. Vender o distribuir ejemplos de libros de O'Reilly requiere permiso.
Responder una pregunta citando este libro y citando código de ejemplo no requiere permiso. La
incorporación de una cantidad significativa de código de ejemplo de este libro en la documentación
de su producto requiere permiso.
Apreciamos, pero generalmente no requerimos, atribución. Una atribución suele incluir el título, el
autor, el editor y el ISBN. Por ejemplo: “ Matemáticas esenciales para la ciencia de datos de
Thomas Nield (O'Reilly). Derechos de autor 2022 Thomas Nield, 978-1-098-10293-7.”
Si cree que su uso de los ejemplos de código está fuera del uso justo o del permiso otorgado
anteriormente, no dude en contactarnos en permisos@oreilly.com.

Aprendizaje en línea de O'Reilly


NOTA
Durante más de 40 años, O'Reilly Media ha brindado capacitación, conocimientos y perspectivas en
tecnología y negocios para ayudar a las empresas a tener éxito.
Nuestra red única de expertos e innovadores comparte su conocimiento y experiencia a través de
libros, artículos y nuestra plataforma de aprendizaje en línea. La plataforma de aprendizaje en línea
de O'Reilly le brinda acceso a pedido a cursos de capacitación en vivo, rutas de aprendizaje en
profundidad, entornos de codificación interactivos y una amplia colección de texto y video de
O'Reilly y más de 200 editores más. Para obtener más información, visite https://oreilly.com.

Cómo contactarnos
Dirija sus comentarios y preguntas sobre este libro a la editorial:
O'Reilly Media, Inc.
1005 Carretera Gravenstein Norte
Sebastopol, CA 95472
800-998-9938 (en los Estados Unidos o Canadá)
707-829-0515 (internacional o local)
707-829-0104 (fax)
Tenemos una página web para este libro, donde enumeramos las erratas, ejemplos y cualquier
información adicional. Puede acceder a esta página en https://oreil.ly/essentialMathDataSci.
Envíe un correo electrónico a bookquestions@oreilly.com para comentar o hacer preguntas
técnicas sobre este libro.
Para noticias e información sobre nuestros libros y cursos, visite https://oreilly.com.
EncuénTrain os en LinkedIn: https://linkedin.com/company/oreilly-media
Síguenos en Twitter: https://twitter.com/oreillymedia
Míranos en YouTube: https://youtube.com/oreillymedia

Expresiones de gratitud
Este libro fue el valor de más de un año de esfuerzos de muchas personas. Primero, quiero
agradecer a mi esposa Kimberly por su apoyo mientras escribía este libro, especialmente cuando
criamos a nuestro hijo, Wyatt, hasta su primer cumpleaños. Kimberly es una esposa y madre
increíble, y todo lo que hago ahora es por el futuro mejor de mi hijo y de nuestra familia.

5
Quiero agradecer a mis padres por enseñarme a luchar más allá de mis límites y nunca tirar la
toalla. Dado el tema de este libro, me alegro de que me animaran a tomarme el cálculo en serio en
la escuela secundaria y la universidad, y nadie puede escribir un libro sin salir regularmente de su
zona de confort.
Quiero agradecer al increíble equipo de editores y al personal de O'Reilly que han seguido
abriéndome puertas desde que escribí mi primer libro sobre SQL en 2015. Ha sido maravilloso
trabajar con Jill y Jess para escribir y publicar este libro, y Estoy agradecido de que Jess pensara
en mí cuando surgió este tema.
Quiero agradecer a mis colegas de la Universidad del Sur de California en el programa de
Seguridad y Protección de la Aviación. Haber tenido la oportunidad de ser pionero en conceptos de
seguridad de sistemas de inteligencia artificial me ha enseñado conocimientos que pocas personas
tienen, y espero ver lo que continuaremos logrando en los años venideros. Arch, sigues
sorprendiéndome y me preocupa que el mundo deje de funcionar el día que te jubiles.
Por último, quiero agradecer a mi hermano Dwight Nield y a mi amigo Jon Ostrower, quienes son
socios en mi empresa, Yawman Flight. Arrancar una startup es difícil, y su ayuda ha permitido un
valioso ancho de banda para escribir este libro. Jon me trajo a bordo en la USC y sus incansables
logros en el mundo del periodismo de aviación son nada menos que notables (¡búsquenlo!). Es un
honor que estén tan apasionados como yo por un invento que comencé en mi garaje, y no creo que
pudiera traerlo al mundo sin ellos.
A cualquiera que haya extrañado, gracias por las cosas grandes y pequeñas que ha hecho. La
mayoría de las veces, he sido recompensado por ser curioso y hacer preguntas. No doy eso por
sentado. Como dijo Ted Lasso: “Sé curioso, no crítico”.

Contenido
Las convenciones usadas en este libro...........................................................................................4
Uso de ejemplos de código................................................................................................................5
Aprendizaje en línea de O'Reilly.......................................................................................................5
Cómo contactarnos.............................................................................................................................5
Expresiones de gratitud......................................................................................................................5
Capítulo 1. Repaso de cálculo y matemáticas básicas.........................................................10
Teoría de los números......................................................................................................................10
Orden de operaciones......................................................................................................................11
Variables.............................................................................................................................................12
Funciones...........................................................................................................................................12
sumatorias..........................................................................................................................................15
Exponentes.........................................................................................................................................16
logaritmos...........................................................................................................................................18
Número de Euler y logaritmos naturales.......................................................................................19
Número de Euler............................................................................................................................20
Logaritmos naturales.....................................................................................................................22
Límites..............................................................................................................................................22
Derivados............................................................................................................................................24
Derivadas parciales.......................................................................................................................26
La regla de la cadena....................................................................................................................28
Integrales.......................................................................................................................................29
Conclusión..........................................................................................................................................33
Ejercicios.............................................................................................................................................33
Capítulo 2. Probabilidad................................................................................................................34
comprensión de la probabilidad......................................................................................................34
Probabilidad Versus Estadística..................................................................................................35
matemáticas de probabilidad...........................................................................................................35
Probabilidades conjuntas.............................................................................................................35

6
Unión de probabilidades...............................................................................................................36
Probabilidad Condicional y Teorema de Bayes........................................................................38
Probabilidades Condicionales Conjuntas y Uniones...............................................................39
Distribución binomial.........................................................................................................................40
Distribución beta................................................................................................................................42
Conclusión..........................................................................................................................................47
Ejercicios.............................................................................................................................................47
Capítulo 3. Estadística descriptiva e inferencial....................................................................48
¿Qué son los datos?.........................................................................................................................48
Estadística descriptiva versus estadística inferencial..................................................................49
Poblaciones, muestras y sesgo(bias)............................................................................................49
Estadísticas descriptivas..................................................................................................................52
Media y media ponderada............................................................................................................52
Mediana...........................................................................................................................................53
Moda................................................................................................................................................54
Varianza y desviación estándar...................................................................................................54
La distribución normal...................................................................................................................57
La CDF inversa..............................................................................................................................62
Puntuaciones Z..............................................................................................................................63
Estadística inferencial.......................................................................................................................64
El teorema del límite central.........................................................................................................64
Intervalos de confianza.................................................................................................................66
Comprender los valores P............................................................................................................68
Prueba de hipótesis.......................................................................................................................69
La distribución T: tratar con muestras pequeñas..........................................................................74
Consideraciones sobre Big Data y la falacia del francotirador de Texas.................................75
Conclusión..........................................................................................................................................76
Ejercicios.............................................................................................................................................77
Capítulo 4. Álgebra lineal..............................................................................................................78
¿Qué es un vector?...........................................................................................................................78
Adición y combinación de vectores.............................................................................................81
Vectores de escala........................................................................................................................82
Intervalo y dependencia lineal.....................................................................................................84
Transformaciones lineales...............................................................................................................86
Vectores base.................................................................................................................................86
Multiplicación de vectores de matrices.......................................................................................88
Multiplicación de matrices................................................................................................................92
Determinantes.............................................................................................................................93
Tipos especiales de matrices..........................................................................................................96
Matriz cuadrada.............................................................................................................................96
Matriz de identidad........................................................................................................................96
Matriz inversa.................................................................................................................................96
Matriz diagonal...............................................................................................................................97
matriz triangular.............................................................................................................................97
Matriz dispersa...............................................................................................................................97
Sistemas de Ecuaciones y Matrices Inversas............................................................97
Vectores propios y valores propios...............................................................................................100
Conclusión........................................................................................................................................102
Ejercicios...........................................................................................................................................102

7
Capítulo 5. Regresión lineal.......................................................................................................103
Una regresión lineal básica............................................................................................................103
Residuos y errores cuadráticos.....................................................................................................106
Encontrar la mejor línea de ajuste................................................................................................109
Ecuación de forma cerrada........................................................................................................109
Técnicas de matriz inversa.........................................................................................................110
Descenso de gradiente...............................................................................................................111
Sobreajuste y varianza...................................................................................................................116
Descenso de gradiente estocástico..............................................................................................117
El coeficiente de correlación..........................................................................................................118
Significancia estadística.................................................................................................................120
Coeficiente de determinación........................................................................................................124
Error estándar de la estimación....................................................................................................124
Intervalos de predicción..................................................................................................................125
Train /Divisiones de prueba...........................................................................................................127
Regresión lineal múltiple................................................................................................................131
Conclusión........................................................................................................................................132
Ejercicios...........................................................................................................................................132
Capítulo 6. Regresión logística y clasificación.....................................................................133
Comprender la regresión logística................................................................................................133
Realización de una regresión logística........................................................................................135
Función Logística.........................................................................................................................135
Ajuste de la curva logística.........................................................................................................136
Regresión logística multivariable..................................................................................................140
Comprender las probabilidades de registro................................................................................142
R-cuadrado.......................................................................................................................................145
Valores P...........................................................................................................................................148
Train /Divisiones de prueba...........................................................................................................149
Matrices de confusión.....................................................................................................................150
Teorema y clasificación de Bayes.................................................................................................152
Características del operador del receptor/área bajo la curva..................................................153
Desequilibrio de clases...................................................................................................................154
Conclusión........................................................................................................................................154
Ejercicios...........................................................................................................................................155
Capítulo 7. Redes neuronales....................................................................................................156
Cuándo usar redes neuronales y aprendizaje profundo...........................................................156
Una red neuronal simple................................................................................................................157
Funciones de activación.............................................................................................................159
Propagación hacia adelante.......................................................................................................162
retropropagación..............................................................................................................................166
Cálculo de las derivadas de peso y sesgo..............................................................................166
Descenso de gradiente estocástico..........................................................................................169
Usando scikit-learn..........................................................................................................................171
Limitaciones de las redes neuronales y el aprendizaje profundo............................................172
Conclusión........................................................................................................................................174
Ejercicio.............................................................................................................................................174
Capítulo 8. Asesoramiento profesional y el camino a seguir...........................................175
Redefiniendo la ciencia de datos..................................................................................................175
Una breve historia de la ciencia de datos....................................................................................177
Encontrar su borde..........................................................................................................................178

8
Dominio de SQL...........................................................................................................................179
Competencia en programación.................................................................................................180
Visualización de datos................................................................................................................182
Conociendo su industria.............................................................................................................183
Aprendizaje Productivo...............................................................................................................184
Practicante versus asesor..........................................................................................................184
Qué tener en cuenta en los trabajos de ciencia de datos.........................................................186
Definición de roles.......................................................................................................................186
Enfoque organizacional y compromiso....................................................................................186
Recursos adecuados...................................................................................................................187
Objetivos razonables...................................................................................................................188
Competir con los sistemas existentes......................................................................................189
Un papel no es lo que esperabas.............................................................................................190
¿El trabajo de tus sueños no existe?...........................................................................................191
¿Adónde voy ahora?.......................................................................................................................191
Conclusión........................................................................................................................................192
Uso de renderizado LaTeX con SymPy.......................................................................................193
Distribución binomial desde cero..................................................................................................194
Distribución beta desde cero.........................................................................................................194
Derivación del teorema de Bayes.................................................................................................196
CDF y CDF inversa desde cero....................................................................................................197
Use e para predecir la probabilidad de eventos a lo largo del tiempo....................................198
Escalada de colinas y regresión lineal.........................................................................................198
Escalada de colinas y regresión logística....................................................................................200
Una breve introducción a la programación lineal.......................................................................201
Clasificador MNIST usando scikit-learn.......................................................................................205
Capítulo 1..........................................................................................................................................205
Capitulo 2..........................................................................................................................................206
Capítulo 3..........................................................................................................................................207
Capítulo 4..........................................................................................................................................208
Capítulo 5..........................................................................................................................................209
Capítulo 6..........................................................................................................................................211
Capítulo 7..........................................................................................................................................213

9
Capítulo 1. Repaso de cálculo y matemáticas básicas
Basic Math and Calculus Review Comenzaremos el primer capítulo que cubre qué son los números y
cómo funcionan las variables y funciones en un sistema cartesiano. Luego cubriremos exponentes
y logaritmos. Después de eso, aprenderemos las dos operaciones básicas del cálculo: derivadas e
integrales.
Antes de sumergirnos en las áreas aplicadas de las matemáticas esenciales, como la probabilidad,
el álgebra lineal, las estadísticas y el aprendizaje automático, probablemente deberíamos revisar
algunos conceptos básicos de matemáticas y cálculo. Antes de que dejes caer este libro y corras
gritando, ¡no te preocupes! Presentaré cómo calcular derivadas e integrales para una función de
una manera que probablemente no te enseñaron en la universidad. Tenemos a Python de nuestro
lado, no a lápiz y papel. Incluso si no está familiarizado con las derivadas y las integrales, no
necesita preocuparse.
Haré que estos temas sean lo más precisos y prácticos posible, centrándome solo en lo que nos
ayudará en capítulos posteriores y lo que cae bajo el paraguas de las "matemáticas esenciales".

¡ESTE NO ES UN CURSO ACELERADO COMPLETO DE MATEMÁTICAS!


Esto no es de ninguna manera una revisión exhaustiva de las matemáticas de la escuela secundaria
y la universidad. Si quieres eso, un gran libro para leer es No Bullshit Guide to Math and Physics de
Ivan Savov (perdón por mi francés). Los primeros capítulos contienen el mejor curso intensivo de
matemáticas de la escuela secundaria y la universidad que he visto. El libro Matemáticas 1001 del
Dr. Richard Elwes también tiene un gran contenido y explicaciones breves.

Teoría de los números


¿Qué son los números? Prometo no ser demasiado filosófico en este libro, pero ¿no son los
números una construcción que hemos definido? ¿Por qué tenemos los dígitos del 0 al 9 y no
tenemos más dígitos que esos? ¿Por qué tenemos fracciones y decimales y no solo números
enteros? Esta área de las matemáticas en la que reflexionamos sobre los números y por qué los
diseñamos de cierta manera se conoce como teoría de números.
La teoría de los números se remonta a la antigüedad, cuando los matemáticos estudiaban
diferentes sistemas numéricos, y explica por qué los hemos aceptado de la forma en que lo
hacemos hoy. Aquí hay diferentes sistemas numéricos que puede reconocer:
Números naturales
Estos son los números 1, 2, 3, 4, 5… y así sucesivamente. Aquí solo se incluyen números
positivos, y son el sistema más antiguo conocido. Los números naturales son tan antiguos que los
hombres de las cavernas marcaban los huesos y las paredes de las cuevas para llevar registros.
Números enteros
Sumado a los números naturales, posteriormente se aceptó el concepto de “0”; los llamamos
"números enteros". Los babilonios también desarrollaron la útil idea de la notación de reserva de
lugar para "columnas" vacías en números mayores que 9, como "10", "1000" o "1090". Esos ceros
indican que ningún valor ocupa esa columna.
enteros
Los números enteros incluyen números naturales positivos y negativos, así como el 0. Podemos
darlos por sentado, pero los antiguos matemáticos desconfiaban profundamente de la idea de los
números negativos. Pero cuando restas 5 de 3, obtienes -2. Esto es útil especialmente cuando se
trata de finanzas donde medimos ganancias y pérdidas. En 628 d. C., un matemático indio llamado
Brahmagupta demostró por qué los números negativos eran necesarios para que la aritmética
progresara con la fórmula cuadrática y, por lo tanto, se aceptaron los números enteros.
Numeros racionales
Cualquier número que puedas expresar como una fracción, como 2/3, es un número racional. Esto
incluye todos los decimales y enteros finitos, ya que también se pueden expresar como fracciones,
como 687/100 = 6,87 y 2/1 = 2, respectivamente. Se llaman racionales porque son razones. Los
números racionales se consideraron necesarios rápidamente porque el tiempo, los recursos y otras
cantidades no siempre se podían medir en unidades discretas. La leche no siempre viene en
galones. Es posible que tengamos que medirlo como partes de un galón. Si corro durante 12
minutos, no se me puede obligar a medir en millas enteras cuando en realidad corrí 9/10 de milla.
Numeros irracionales

10
Los números irracionales no se pueden expresar como una fracción. Esto incluye el famoso π, las
raíces cuadradas de ciertos números como 2 y el número e de Euler , del que aprenderemos más
adelante. Estos números tienen un número infinito de dígitos decimales, como
3.141592653589793238462…
Hay una historia interesante detrás de los números irracionales. El matemático griego Pitágoras
creía que todos los números son racionales. Creía esto tan fervientemente que hizo una religión
que rezaba al número 10. “¡Bendícenos, número divino, tú que engendraste dioses y hombres!” él y
sus seguidores rezaban (por qué el “10” era tan especial, no lo sé). Existe la leyenda de que uno de
sus seguidores, Hippasus, demostró que no todos los números son racionales simplemente
demostrando la raíz cuadrada de 2. Esto alteró gravemente el sistema de creencias de Pitágoras, y
respondió ahogando a Hippassus en el mar.
Independientemente, ahora sabemos que no todos los números son racionales.
Numeros reales
Los números reales incluyen tanto números racionales como irracionales. En la práctica, cuando
realiza cualquier trabajo de ciencia de datos, puede tratar cualquier decimal con el que trabaje
como números reales.
Números complejos e imaginarios
Te encuentras con este tipo de número cuando sacas la raíz cuadrada de un número negativo. Si
bien los números imaginarios y complejos tienen relevancia en ciertos tipos de problemas, en su
mayoría nos mantendremos alejados de ellos.
En ciencia de datos, encontrará que la mayoría (si no todo) de su trabajo utilizará números enteros,
números naturales, enteros y números reales. Los números imaginarios se pueden encontrar en
casos de uso más avanzados, como la descomposición de matrices, que abordaremos en el
Capítulo 4.

NÚMEROS COMPLEJOS E IMAGINARIOS


Si desea aprender sobre los números imaginarios, hay una gran lista de reproducción Los números
imaginarios son reales en YouTube (Imaginary Numbers Are Real [Part 1: Introduction] - YouTube ).

Orden de operaciones
Con suerte, está familiarizado con el orden de las operaciones, que es el orden en que resuelve
cada parte de una expresión matemática. Como un breve repaso, recuerda que evalúas los
componentes entre paréntesis, seguidos de los exponentes, luego la multiplicación, la división, la
suma y la resta. Puede recordar el orden de las operaciones mediante el recurso mnemotécnico
PEMDAS (Por favor, disculpe a mi querida tía Sally), que corresponde al orden de paréntesis,
exponentes, multiplicación, división, suma y resta.
Tomemos por ejemplo esta expresión:

Primero evaluamos los paréntesis (3 + 2), que es igual a 5:

A continuación resolvemos el exponente, que podemos ver está elevando al cuadrado ese 5 que
acabamos de sumar. Eso es 25:

A continuación tenemos la multiplicación y la división. El orden de estos dos es intercambiable ya


que la división también es multiplicación (usando fracciones). Prosigamos y multipliquemos el 2 con

el , dando :

A continuación realizaremos la división, dividiendo 50 entre 5, lo que nos dará 10:


10 - 4
Y por último, realizamos cualquier suma y resta. Por supuesto, 10 - 4 nos dará 6:
10 - 4 = 6

11
Efectivamente, si tuviéramos que expresar esto en Python imprimiríamos un valor de 6.0 como se
muestra en el Ejemplo 1-1.
Ejemplo 1-1. Resolver una expresión en Python
my_value = 2 * (3 + 2)**2 / 5 - 4

print(my_value) # prints 6.0


Esto puede ser elemental, pero sigue siendo crítico. En el código, incluso si obtiene el resultado
correcto sin ellos, es una buena práctica usar paréntesis generosamente en expresiones complejas
para establecer el control del orden de evaluación.
Aquí agrupo la parte fraccionaria de mi expresión entre paréntesis, lo que ayuda a diferenciarla del
resto de la expresión en el ejemplo 1-2.
Ejemplo 1-2. Haciendo uso de paréntesis para mayor claridad en Python
my_value = 2 * ((3 + 2)**2 / 5) – 4
print(my_value) # prints 6.0

Si bien ambos ejemplos son técnicamente correctos, el último es más claro para nosotros, los
humanos que se confunden fácilmente. Si usted u otra persona realiza cambios en su código, los
paréntesis brindan una referencia fácil del orden de operación a medida que realiza los cambios.
Esto proporciona una línea de defensa contra los cambios de código para evitar errores también.

Variables
Si ha realizado algunos scripts con Python u otro lenguaje de programación, tiene una idea de lo
que es una variable. En matemáticas, una variable es un marcador de posición con nombre para un
número no especificado o desconocido.
Puede tener una variable x que represente cualquier número real y puede multiplicar esa variable
sin declarar cuál es. En el Ejemplo 1-3, tomamos una entrada variable x de un usuario y la
multiplicamos por 3.
Ejemplo 1-3. Una variable en Python que luego se multiplica
x = int(input("Please input a number\n"))
product = 3 * x
print(product)
Hay algunos nombres de variables estándar para ciertos tipos de variables. Si estos nombres de
variables y conceptos no le son familiares, ¡no se preocupe! Pero algunos lectores pueden
reconocer que usamos theta θ para denotar ángulos y beta β para un parámetro en una regresión
lineal. Los símbolos griegos crean nombres de variables incómodos en Python, por lo que
probablemente nombraríamos a estas variables theta y beta en Python como se muestra en el
Ejemplo 1-4.
Ejemplo 1-4. Nombres de variables griegas en Python
beta = 1.75
theta = 30.0
Tenga en cuenta también que los nombres de las variables se pueden subíndice para que se
puedan usar varias instancias de un nombre de variable. Para propósitos prácticos, simplemente
trátelos como variables separadas. Si encuentra variables x 1, x2 y x3, simplemente trátelas como
tres variables separadas como se muestra en el Ejemplo 1-5.
Ejemplo 1-5. Expresando variables con subíndice en Python
x1 = 3 # or x_1 = 3
x2 = 10 # or x_2 = 10
x3 = 44 # or x_3 = 44

Funciones
Las funciones son expresiones que definen relaciones entre dos o más variables. Más
específicamente, una función toma variables de entrada (también llamadas variables de dominio o
variables independientes ), las inserta en una expresión y luego da como resultado una variable de
salida (también llamada variable dependiente ).
Tome esta función lineal simple:
y=2x+1

12
Para cualquier valor de x dado, resolvemos la expresión con esa x para encontrar y. Cuando x = 1,
entonces y = 3. Cuando x = 2, y = 5. Cuando x = 3, y = 7 y así sucesivamente, como se muestra en
la Tabla 1-1.
Diferentes valores para y = 2x +
1
X 2x + 1 y
0 2(0) + 1 1
1 2(1) + 1 3
2 2(2) + 1 5
3 2(3) + 1 7
Las funciones son útiles porque modelan una relación predecible entre variables, como cuántos
incendios podemos esperar a una temperatura x. Usaremos funciones lineales para realizar
regresiones lineales en el Capítulo 5.
Otra convención que puede ver para la variable dependiente y es etiquetarla explícitamente como
una función de x, como f(x). Entonces, en lugar de expresar una función como y = 2 x + 1, también
podemos expresarla como:
f(x)=2x+1
El ejemplo 1-6 muestra cómo podemos declarar una función matemática e iterarla en Python.
Ejemplo 1-6. Declarar una función lineal en Python
def f(x):
return 2 * x + 1
x_values = [0, 1, 2, 3]
for x in x_values:
y = f(x)
print(y)
Cuando se trata de números reales, una característica sutil pero importante de las funciones es que
a menudo tienen un número infinito de valores de x y valores de y resultantes. Pregúntese esto:
¿cuántos valores de x podemos poner a través de la función y = 2 x + 1 ? En lugar de solo 0, 1,
2, 3.. ¿por qué no 0, 0,5, 1, 1,5, 2, 2,5, 3 como se muestra en la Tabla 1-2 ?
Tabla 1-2. Diferentes valores para y = 2x + 1
X 2x + 1 y
0.0 2(0) + 1 1

0.5 2(.5) + 1 2

1.0 2(1) + 1 3

1.5 2(1.5) + 1 4

2.0 2(2) + 1 5

2.5 2(2.5) + 1 6

3.0 2(3) + 1 7

¿O por qué no hacer cuartos de paso para x ? ¿O 1/10 de un paso? Podemos hacer que estos
pasos sean infinitamente pequeños, demostrando efectivamente que y = 2 x + 1 es una función
continua, donde para cada valor posible de x hay un valor para y. Esto nos lleva muy bien a
visualizar nuestra función como una línea, como se muestra en la Figura 1-1.

13
Figura 1-1. Gráfico para la función y = 2x + 1

Cuando graficamos en un plano bidimensional con dos rectas numéricas (una para cada variable)
se conoce como plano cartesiano, plano xy o plano de coordenadas. Trazamos un valor x dado y
luego buscamos el valor y correspondiente, y trazamos las intersecciones como una línea. Tenga
en cuenta que debido a la naturaleza de los números reales (o decimales, si lo prefiere), hay una
cantidad infinita de valores de x. Es por eso que cuando trazamos la función f ( x ) obtenemos una
línea continua sin interrupciones. Hay un número infinito de puntos en esa línea, o cualquier parte
de esa línea.
Si desea trazar esto usando Python, hay varias bibliotecas de gráficos desde Plotly hasta
matplotlib. A lo largo de este libro usaremos SymPy para realizar muchas tareas, y la primera que
usaremos es trazar una función. SymPy usa matplotlib, así que asegúrese de tener ese paquete
instalado. De lo contrario, imprimirá un gráfico feo basado en texto en su consola. Después de eso,
simplemente declare la variable x en SymPy usando símbolos(), declare su función y luego trácela
como se muestra en el Ejemplo 1-7 y la Figura 1-2.
Ejemplo 1-7. Trazar una función lineal en Python usando SymPy
from sympy import *
x = symbols('x')
f = 2*x + 1
plot(f)

Figura 1-2. Usando SymPy para graficar una función lineal

14
El ejemplo 1-8 y la figura 1-3 son otro ejemplo que muestra la función f (x) = x2 + 1.
Ejemplo 1-8. Graficar una función exponencial
from sympy import *
x = symbols('x')
f = x**2 + 1
plot(f)
Tenga en cuenta que en la figura 1-3 no obtenemos una línea recta, sino una curva suave y
simétrica conocida como parábola. Es continuo pero no lineal, ya que no produce valores en línea
recta. Funciones con curvas como esta son matemáticamente más difíciles de trabajar, pero
aprenderemos algunos trucos para que no sea tan malo.

FUNCIONES CURVILÍNEAS
Cuando una función es continua pero con curvas, en lugar de lineal y recta, la llamamos función
curvilínea.

Figura 1-3. Usando SymPy para graficar una función exponencial

Tenga en cuenta que las funciones utilizan múltiples variables de entrada, no solo una. Por
ejemplo, podemos tener una función con variables independientes x e y. Tenga en cuenta que y no
es dependiente como en los ejemplos anteriores.
f( x, y ) = 2x + 3y
Como tenemos dos variables independientes ( x e y ) y una variable dependiente (la salida de f ( x,
y )), necesitamos trazar este gráfico en tres dimensiones para producir un plano de valores en lugar
de una línea, como se muestra en Ejemplo 1-9 y Figura 1-4.
Ejemplo 1-9. Declarar una función con dos variables independientes en Python
from sympy import *
from sympy.plotting import plot3d
x, y = symbols('x y')
f = 2*x + 3*y
plot3d(f)

15
Figura 1-4. Usando SymPy para graficar una función tridimensional

No importa cuántas variables independientes tenga, su función generalmente generará solo una
variable dependiente. Cuando resuelva múltiples variables dependientes, probablemente usará
funciones separadas para cada una.

sumatorias
Prometí no usar ecuaciones llenas de símbolos griegos en este libro. Sin embargo, hay uno que es
tan común y útil que sería negligente no cubrirlo. Una suma se expresa como sigma Σ y suma
elementos.
Por ejemplo, si quiero iterar los números del 1 al 5, multiplicar cada uno por 2 y sumarlos, así es
como lo expresaría usando una suma. El ejemplo 1-10 muestra cómo ejecutar esto en Python.

Ejemplo 1-10. Realizando una suma en Python


summation = sum(2*i for i in range(1,6))
print(summation)

Tenga en cuenta que i es una variable de marcador de posición que representa cada valor de
índice consecutivo que estamos iterando en el bucle, que multiplicamos por 2 y luego sumamos
todos juntos. Cuando está iterando datos, puede ver variables como x i que indican un elemento
en una colección en el índice i.

LA FUNCIÓN RANGE()
Recuerde que la función range() en Python es exclusiva al final, lo que significa que si invoca
range(1,4) iterará los números 1, 2 y 3. Excluye el 4 como límite superior.
También es común ver que n representa la cantidad de elementos en una colección, como la
cantidad de registros en un conjunto de datos. Aquí hay uno de esos ejemplos donde iteramos una
colección de números de tamaño n, multiplicamos cada uno por 10 y los sumamos:

En el Ejemplo 1-11 usamos Python para ejecutar esta expresión en una colección de cuatro
números. Tenga en cuenta que en Python (y la mayoría de los lenguajes de programación en
general) normalmente hacemos referencia a elementos que comienzan en el índice 0, mientras que
en matemáticas comenzamos en el índice 1. Por lo tanto, cambiamos en consecuencia en nuestra
iteración comenzando en 0 en nuestro RANGE().
Ejemplo 1-11. Suma de elementos en Python
x = [1, 4, 6, 2]
n = len(x)
summation = sum(10*x[i] for i in range(0,n))
print(summation)

Esa es la esencia de la suma. En pocas palabras, una suma Σ dice, "suma un montón de cosas
juntas", y usa un índice i y un valor máximo n para expresar cada iteración que alimenta la suma.
Los veremos a lo largo de este libro.

SUMAS EN SYMPY
Siéntase libre de volver a esta barra lateral más tarde cuando aprenda más sobre SymPy. SymPy,
que usamos para graficar funciones, es en realidad una biblioteca matemática simbólica;
hablaremos de lo que esto significa más adelante en este capítulo. Pero tenga en cuenta para
referencia futura que una operación de suma en SymPy se realiza utilizando el operador Sum(). En
el siguiente código, iteramos i de 1 a n, multiplicamos cada i y los sumamos. Pero luego usamos la

16
función subs() para especificar n como 5, que luego iterará y sumará todos los elementos i del 1 al
n:
from sympy import *
i,n = symbols('i n')
# iterate each element i from 1 to n,
# then multiply and sum
summation = Sum(2*i,(i,1,n))
# specify n as 5,
# iterating the numbers 1 through 5
up_to_5 = summation.subs(n, 5)
print(up_to_5.doit()) # 30
Tenga en cuenta que las sumas en SymPy son perezosas, lo que significa que no se calculan
automáticamente ni se simplifican. Así que usa la función doit() para ejecutar la expresión.

Exponentes
Los exponentes multiplican un número por sí mismo un número específico de veces. Cuando
elevas 2 a la tercera potencia (expresado como 2 3 usando 3 como superíndice), eso es multiplicar
tres 2 juntos:
23 = 2 * 2 * 2 = 8
La base es la variable o valor que estamos exponenciando, y el exponente es el número de veces
que multiplicamos el valor de la base. Para la expresión 2 3 , 2 es la base y 3 es el exponente.
Los exponentes tienen algunas propiedades interesantes. Digamos que multiplicamos x 2 y x 3
juntos. Observe lo que sucede a continuación cuando amplío los exponentes con una simple
multiplicación y luego los consolido en un solo exponente:
x2x3 = (x*x)*(x*x*x) = x2+3 = x5
Cuando multiplicamos exponentes con la misma base, simplemente sumamos los exponentes, lo
que se conoce como la regla del producto. Permítanme enfatizar que la base de todos los
exponentes multiplicados debe ser la misma para que se aplique la regla del producto.
Exploremos la división a continuación. ¿Qué sucede cuando dividimos x 2 por x 5 ?

Como puedes ver, cuando dividimos x2 por x5 podemos cancelar dos x en el numerador y el
denominador, dejándonos con . Cuando existe un factor tanto en el numerador como en el
denominador, podemos cancelar ese factor.
¿Qué pasa con el x-3, te preguntas? Este es un buen punto para introducir exponentes negativos,
que es otra forma de expresar una operación exponencial en el denominador de una fracción. Para

demostrar, es lo mismo que x -3 :

Al vincular la regla del producto, podemos ver que también se aplica a los exponentes negativos.
Para obtener intuición detrás de esto, abordemos este problema de una manera diferente.
Podemos expresar esta división de dos exponentes haciendo negativo el exponente “5” de x 5 y
luego multiplicándolo por x 2. Cuando agrega un número negativo, está realizando efectivamente

17
una resta. Por lo tanto, la regla del producto de exponentes que suma los exponentes multiplicados
aún se mantiene como se muestra a continuación. :

Por último, pero no menos importante, ¿puedes averiguar por qué cualquier base con un exponente
de 0 es 1?
x0 = 1
La mejor manera de obtener esta intuición es razonar que cualquier número dividido por sí mismo
es 1. Si tienes x 3 x 3 es algebraicamente obvio que se reduce a 1. Pero esa expresión
también se evalúa como x 0 :
1 = x 3 x 3 = x 3 x -3 = x 3+-3 = x 0
Por la propiedad transitiva, que establece que si a = b y b = c, entonces a = c, sabemos que x 0
= 1.

SIMPLIFICAR EXPRESIONES CON SYMPY


Si no se siente cómodo con la simplificación de expresiones algebraicas, puede usar la biblioteca
SymPy para que haga el trabajo por usted. He aquí cómo simplificar nuestro ejemplo anterior.:
from sympy import *
x = symbols('x')
expr = x**2 / x**5
print(expr) # x**(-3)
Ahora, ¿qué pasa con los exponentes fraccionarios? Son una forma alternativa de representar
raíces, como la raíz cuadrada. Como un breve repaso, un pregunta "¿Qué número
multiplicado por sí mismo me da 4?" que por supuesto es 2. Note aquí que 4 1/2 es lo mismo
que :

Las raíces cúbicas son similares a las raíces cuadradas, pero buscan un número multiplicado por sí
mismo tres veces para dar un resultado. Una raíz cúbica de 8 se expresa como y pregunta
"¿Qué número multiplicado por sí mismo tres veces me da 8?" Este número sería 2 porque 2 * 2 *
2 = 8. En exponentes, una raíz cúbica se expresa como un exponente fraccionario, y se puede
reexpresar como 8 1/3 :

Para volver a cerrar el círculo, ¿qué sucede cuando multiplicas la raíz cúbica de 8 tres veces? Esto
deshará la raíz cúbica y producirá 8. Alternativamente, si expresamos la raíz cúbica como
exponentes fraccionarios , queda claro que sumamos los exponentes para obtener un
exponente de 1. Eso también deshace la raíz cúbica:

Y una última propiedad: un exponente de un exponente multiplicará los exponentes. Esto se

conoce como la regla de la potencia. Entonces se simplificaría a 86:

Si no está seguro de por qué esto es así, intente expandirlo y verá que la regla de la suma lo
aclara:

18
Por último, ¿qué significa cuando tenemos un exponente fraccionario con un numerador distinto de
1, como ? Bueno, eso es sacar la raíz cúbica de 8 y luego elevarla al cuadrado. Echar un
vistazo:

Y sí, los números irracionales pueden servir como exponentes como 8 π, que es 687,2913. Esto
puede parecer poco intuitivo, ¡y es comprensible! En aras del tiempo, no profundizaremos en esto,
ya que requiere algunos cálculos. Pero esencialmente, podemos calcular exponentes irracionales
aproximando con un número racional. Esto es efectivamente lo que hacen las computadoras, ya
que de todos modos solo pueden calcular hasta tantos lugares decimales.
Por ejemplo, π tiene un número infinito de decimales. Pero si tomamos los primeros 11 dígitos,
3.1415926535, podemos aproximar π como un número racional 31415926535 / 10000000000.
Efectivamente, esto nos da aproximadamente 687.2913, que debería coincidir aproximadamente
con cualquier calculadora.:

logaritmos
Un logaritmo es una función matemática que encuentra una potencia para un número y una base
específicos. Puede que no suene interesante al principio, pero en realidad tiene muchas
aplicaciones. Desde la medición de terremotos hasta la gestión del volumen de su estéreo, el
logaritmo se encuentra en todas partes. También encuentra su camino en el aprendizaje
automático y la ciencia de datos. De hecho, los logaritmos serán una parte clave de las regresiones
logísticas en el Capítulo 6.
Comience su pensamiento preguntando "¿2 elevado a qué potencia me da 8?" Una forma de
expresar esto matemáticamente es usar una x para el exponente:
2x = 8
Intuitivamente sabemos la respuesta, x = 3 , pero necesitamos una forma más elegante de
expresar esta operación matemática común. Para esto es la función log().

Como puede ver en la expresión logarítmica anterior, tenemos una base 2 y estamos encontrando
una potencia que nos dé 8. De manera más general, podemos reexpresar un exponente variable
como un logaritmo:
ax =b

Hablando algebraicamente, esta es una forma de aislar x, lo cual es importante para resolver para
x. El ejemplo 1-12 muestra cómo calculamos este logaritmo en Python.
Ejemplo 1-12. Usando la función de registro en Python
from math import log
# 2 raised to what power gives me 8?
x = log(8, 2)
print(x) # prints 3.0
Cuando no proporciona un argumento base a una función log() en una plataforma como Python,
normalmente tendrá una base predeterminada. En algunos campos, como las mediciones de
terremotos, la base predeterminada para el registro es 10. Pero en la ciencia de datos, la base
predeterminada para el registro es el número e de Euler. Python usa este último, y hablaremos de
e en breve.
Al igual que los exponentes, los logaritmos tienen varias propiedades cuando se trata de
multiplicaciones, divisiones, exponenciaciones, etc. En aras del tiempo y el enfoque, solo
presentaré esto en la Tabla 1-3. La idea clave en la que centrarse es que un logaritmo encuentra
un exponente para una base dada para dar como resultado un número determinado.
Si necesita sumergirse en las propiedades logarítmicas, la Tabla 1-3 muestra los comportamientos
de exponentes y logaritmos uno al lado del otro que puede usar como referencia.

19
Tabla 1-3. Propiedades para exponentes y logaritmos

Número de Euler y logaritmos naturales


Hay un número especial que aparece bastante en matemáticas llamado número e de Euler. Es un
número especial muy parecido a Pi π y es aproximadamente 2.71828. e se usa mucho porque
matemáticamente simplifica muchos problemas. Cubriremos e en el contexto de exponentes y
logaritmos.
Número de Euler
En la escuela secundaria, mi profesor de cálculo demostró el número de Euler en varios problemas
exponenciales. Finalmente le pregunté: “Sr. Ahora, ¿qué es e de todos modos? ¿De dónde viene?"
Recuerdo que nunca estuve completamente satisfecho con las explicaciones que involucraban a las
poblaciones de conejos y otros fenómenos naturales. Espero dar una explicación más satisfactoria aquí.

¿POR QUÉ SE USA TANTO EL NÚMERO DE EULER?


Una propiedad del número de Euler es que su función exponencial es una derivada de sí mismo, lo
cual es conveniente para funciones exponenciales y logarítmicas. Aprenderemos acerca de las
derivadas más adelante en este capítulo. En muchas aplicaciones donde la base realmente no
importa, elegimos la que resulta en la derivada más simple, y ese es el número de Euler. Por eso
también es la base predeterminada en muchas funciones de ciencia de datos.
Así es como me gusta descubrir el número de Euler. Digamos que le prestas $100 a alguien con un
20% de interés anual. Por lo general, el interés se capitalizará mensualmente, por lo que el interés
de cada mes sería . 20 / 12 =. 01666. ¿A cuánto ascenderá el saldo del préstamo después de dos
años? Para simplificar, supongamos que el préstamo no requiere pagos (y no se realizan pagos)
hasta el final de esos dos años.

Reuniendo los conceptos de exponentes que aprendimos hasta ahora (o tal vez sacando un libro
de texto de finanzas), podemos encontrar una fórmula para calcular el interés. Consiste en un saldo
A para una inversión inicial P, tasa de interés r, lapso de tiempo t (número de años) y períodos n
(número de meses en cada año). Aquí está la fórmula:

Entonces, si fuéramos a capitalizar el interés cada mes, el préstamo crecería a $148.69 como se
calcula aquí:

20
Si quiere hacer esto en Python, pruébelo con el código del Ejemplo 1-13.
Ejemplo 1-13. Cálculo de interés compuesto en Python
from math import exp
p = 100
r = .20
t = 2.0
n = 12
a = p * (1 + (r/n))**(n * t)
print(a) # prints 148.69146179463576
Pero, ¿y si capitalizáramos el interés diariamente? ¿Qué pasa entonces? Cambie n a 365:

¡Eh! Si capitalizamos nuestro interés diariamente en lugar de mensualmente, ganaríamos 47.4666


centavos más al final de dos años. Si nos volvimos codiciosos, ¿por qué no componer cada hora
como se muestra a continuación? ¿Eso nos dará aún más? Hay 8.760 horas en un año, así que
establezca n en ese valor:

¡Ah, exprimimos aproximadamente 2 centavos más en intereses! Pero, ¿estamos experimentando


un rendimiento decreciente? ¡Intentemos capitalizar cada minuto! Tenga en cuenta que hay
525.600 minutos en un año, así que establezcamos ese valor en n :

Bien, solo estamos ganando fracciones cada vez más pequeñas de un centavo cuanto más
frecuentemente calculamos. Entonces, si sigo haciendo estos períodos infinitamente más pequeños
hasta el punto de capitalizarlos continuamente, ¿adónde lleva esto?
Permítame presentarle el número e de Euler, que es aproximadamente 2,71828. Aquí está la
fórmula para capitalizar "continuamente", lo que significa que estamos capitalizando sin parar:

Volviendo a nuestro ejemplo, calculemos el saldo de nuestro préstamo después de dos años si
capitalizamos continuamente:

Esto no es demasiado sorprendente considerando que la capitalización de cada minuto nos dio un
saldo de 149.1824584. Eso nos acercó mucho a nuestro valor de 149.1824698 al capitalizar
continuamente.

21
Por lo general, usa e como base de exponente en Python, Excel y otras plataformas que usan la
función exp(). Descubrirá que e se usa con tanta frecuencia que es la base predeterminada para
las funciones de exponente y logaritmo.
El ejemplo 1-14 calcula el interés continuo en Python usando lafunción exp().
Ejemplo 1-14. Cálculo de interés continuo en Python
from math import exp
p = 100 # principal, starting amount
r = .20 # interest rate, by year
t = 2.0 # time, number of years
a = p * exp(r*t)
print(a) # prints 149.18246976412703
Entonces, ¿de dónde derivamos esta constante e? Compara la fórmula de interés compuesto y la
fórmula de interés continuo. Estructuralmente se ven similares pero tienen algunas diferencias:

Más técnicamente hablando, e es el valor resultante de la expresión a medida que n


crece cada vez más, acercándose así al infinito. Intente experimentar con valores cada vez más
grandes para n. Al hacerlo cada vez más grande notarás algo:

A medida que aumenta n, hay un rendimiento decreciente y converge aproximadamente en el valor


2.71828, que es nuestro valor e. Encontrará que este e se usa no solo para estudiar
poblaciones y su crecimiento. Desempeña un papel clave en muchas áreas de las matemáticas.
Más adelante en el libro, usaremos el número de Euler para construir distribuciones normales en el
Capítulo 3 y regresiones logísticas en el Capítulo 6.

Logaritmos naturales
Cuando usamos e como nuestra base para un logaritmo, lo llamamos logaritmo natural.
Dependiendo de la plataforma, podemos usar ln() en lugar de log() para especificar un logaritmo
natural. Entonces, en lugar de expresar un logaritmo natural expresado como log e10 para
encontrar la potencia elevada en e para obtener 10, lo abreviaríamos como ln(10):
loge10 = ln (10)
Sin embargo, en Python, la función log() especifica un logaritmo natural. Como se mencionó
anteriormente, la base predeterminada para la función log() es e. Simplemente deje vacío el
segundo argumento para la base y usará de forma predeterminada e como la base que se
muestra en el Ejemplo 1-15.

22
Ejemplo 1-15. Cálculo del logaritmo natural de 10 en Python
from math import log
# e raised to what power gives us 10?
x = log(10)
print(x) # prints 2.302585092994046

Usaremos e en varios lugares a lo largo de este libro. Siéntase libre de experimentar con
exponentes y logaritmos utilizando Excel, Python, Desmos.com o cualquier otra plataforma de
cálculo de su elección. Haz gráficos y siéntete cómodo con el aspecto de estas funciones.

Límites
Como hemos visto con el número de Euler, surgen algunas ideas interesantes cuando siempre
aumentamos o disminuimos una variable de entrada y la variable de salida se acerca a un valor
pero nunca lo alcanza. Exploremos formalmente esta idea.
Tome esta función, que se representa en la figura 1-5 :

Figura 1-5. Una función que siempre tiende a 0 pero nunca llega a 0

Estamos buscando solo valores positivos de x. Tenga en cuenta que a medida que x aumenta para
siempre, f(x) se acerca a 0. Curiosamente, f(x) nunca llega a 0. Simplemente se acerca cada vez
más.
Por lo tanto, el destino de esta función es que, como x siempre se extiende hasta el infinito,
seguirá acercándose a 0 pero nunca llegará a 0. La forma en que expresamos un valor que
siempre se aproxima, pero nunca se alcanza, es a través de un límite:

La forma en que leemos esto es "cuando x tiende a infinito, la función 1/x tiende a 0 (pero nunca
llega a 0)". Verá mucho este tipo de comportamiento de "acercarse pero nunca tocarse",
especialmente cuando nos sumergimos en derivadas e integrales.
Usando SymPy, podemos calcular a qué valor nos acercamos para cuando x tiende a
infinito ∞ ( Ejemplo 1-16 ). Tenga en cuenta que ∞ se expresa hábilmente en SymPy con oo.
Ejemplo 1-16. Usando SymPy para calcular límites
from sympy import *
x = symbols('x')
f=1/x
result = limit(f, x, oo)
print(result) # 0

23
Como has visto, también descubrimos el número e de Euler de esta manera. Es el resultado de
extender n para siempre hasta el infinito para esta función:

Curiosamente, cuando calculamos el número de Euler con límites en SymPy (que se muestra en el
siguiente código), SymPy lo reconoce inmediatamente como el número de Euler. Podemos llamar a
evalf() para que podamos mostrarlo como un número:
from sympy import *
n = symbols('n')
f = (1 + (1/n))**n
result = limit(f, n, oo)
print(result) # E
print(result.evalf()) # 2.71828182845905

EL PODER DE SYMPY
SymPy es un poderoso y fantástico sistema de álgebra computarizada (CAS) para Python que usa el
cálculo simbólico exacto en lugar del cálculo aproximado usando decimales. Es útil para aquellas
situaciones en las que usaría "lápiz y papel" para resolver problemas de matemáticas y cálculo, con
el beneficio de usar la sintaxis familiar de Python. En lugar de representar la raíz cuadrada de 2
aproximando 1,4142135623730951, la conservará exactamente como s qrt (2).
Entonces, ¿por qué no usar SymPy para todo lo relacionado con las matemáticas? Si bien lo
usaremos a lo largo de este libro, es importante seguir sintiéndose cómodo haciendo matemáticas de
Python con decimales simples, ya que scikit-learn y otras bibliotecas de ciencia de datos adoptan
este enfoque. Es mucho más rápido para las computadoras usar decimales en lugar de símbolos.
SymPy también tiene problemas cuando las expresiones matemáticas comienzan a hacerse
demasiado grandes. Pero mantenga SymPy en su bolsillo trasero como su ventaja, y no se lo cuente
a sus hijos de secundaria y universitarios. Literalmente pueden usarlo para hacer su tarea de
matemáticas.

Derivados
Volvamos a hablar de funciones y mirémoslas desde una perspectiva de cálculo, comenzando con
las derivadas. Una derivada indica la pendiente de una función y es útil para medir la tasa de
cambio en cualquier punto de una función.
¿Por qué nos preocupamos por los derivados? A menudo se utilizan en el aprendizaje automático y
otros algoritmos matemáticos, especialmente con descenso de gradiente. Cuando la pendiente es
0, eso significa que estamos en el mínimo o máximo de una variable de salida. Este concepto será
útil más adelante cuando hagamos regresión lineal ( Capítulo 5 ), regresión logística ( Capítulo 6 ) y
redes neuronales ( Capítulo 7 ).
Comencemos con un ejemplo simple. Echemos un vistazo a la función en la Figura
1-6. ¿Qué tan “empinada” es la curva en x = 2 ?
Observe que podemos medir la "inclinación" en cualquier punto de la curva, y podemos visualizar
esto con una línea tangente. Piense en una línea tangente como una línea recta que "apenas toca"
la curva en un punto dado. También proporciona la pendiente en un punto dado. Puede estimar
crudamente una línea tangente en un valor x dado al crear una línea que interseque ese valor x y
un valor x vecino muy cercano en la función.
Tome x = 2 y un valor cercano x = 2.1, que cuando se pasa a la función f(x) = x 2 producirá f (2) = 4
y f (2.1) = 4.41 como se muestra en la Figura 1-7. La recta resultante que pasa por estos dos
puntos tiene una pendiente de 4,1.

24
Figura 1-6. Observando la pendiente en una parte dada de la función

Figura 1-7. Una forma tosca de calcular la pendiente.

Puede calcular rápidamente la pendiente m entre dos puntos usando la fórmula simple de
elevación sobre carrera:

m = 41

Si hiciera el paso x entre los dos puntos aún más pequeño, como x = 2 y x = 2,00001, lo que daría
como resultado f (2) = 4 y f (2,00001) = 4,00004, eso se acercaría mucho a la pendiente real de 4.
Entonces, cuanto menor sea el paso al valor vecino, más nos acercaremos al valor de la pendiente
en un punto dado de la curva. Como tantos conceptos importantes en matemáticas, encontramos
algo significativo cuando nos acercamos a valores infinitamente grandes o infinitamente pequeños.
El ejemplo 1-17 muestra una calculadora derivada implementada en Python.
Ejemplo 1-17. Una calculadora de derivadas en Python
def derivative_x(f, x, step_size):
m = (f(x + step_size) - f(x)) / ((x + step_size) - x)
return m
def my_function(x):
return x**2
slope_at_2 = derivative_x(my_function, 2, .00001)
print(slope_at_2) # prints 4.000010000000827

25
Ahora, la buena noticia es que hay una forma más limpia de calcular la pendiente en cualquier
parte de una función. Ya hemos estado usando SymPy para trazar gráficos, pero le mostraré cómo
también puede realizar tareas como derivadas utilizando la magia de la computación simbólica.
Cuando encuentre una función exponencial como f(x)= x2, la función derivada hará que el
exponente sea un multiplicador y luego lo reducirá en 1, dejándonos con la derivada . El
indica una derivada con respecto a x, lo que dice que estamos construyendo una derivada
apuntando al valor de x para obtener su pendiente. Entonces, si queremos encontrar la pendiente
en x = 2, y tenemos la función derivada, simplemente reemplazamos ese valor de x para obtener la
pendiente:
f(x) = x2

Si tiene la intención de aprender estas reglas para calcular derivadas a mano, hay muchos libros de
cálculo para eso. Pero hay algunas buenas herramientas para calcular derivadas simbólicamente
para ti. La biblioteca de Python SymPy es gratuita y de código abierto, y se adapta muy bien al uso
de la sintaxis de Python. El ejemplo 1-18 muestra cómo calcular la derivada de f(x) = x 2 en
SymPy.
Ejemplo 1-18. Cálculo de una derivada en SymPy
from sympy import *
# Declare 'x' to SymPy
x = symbols('x')
# Now just use Python syntax to declare function
f = x**2
# Calculate the derivative of the function
dx_f = diff(f)
print(dx_f) # prints 2*x¡
Guau! Entonces, al declarar variables usando la función de símbolos () en SymPy, puedo proceder
a usar la sintaxis normal de Python para declarar mi función. Después de eso, puedo usar diff()
para calcular la función derivada. En el ejemplo 1-19, podemos llevar nuestra función derivada de
vuelta a Python simple y simplemente declararla como otra función.
Ejemplo 1-19. Una calculadora de derivadas en Python
def f(x):
return x**2
def dx_f(x):
return 2*x
slope_at_2 = dx_f(2.0)
print(slope_at_2) # prints 4.0
Si quieres seguir usando SymPy, puede llamar a la función subs() para intercambiar la variable x
con el valor 2 como se muestra en el ejemplo 1-20.
Ejemplo 1-20. Uso de la función de sustitución en SymPy
# Calculate the slope at x = 2
print(dx_f.subs(x,2)) # prints 4

Derivadas parciales
Otro concepto que encontraremos en este libro es el de derivadas parciales, que usaremos en los
capítulos 5, 6 y 7. Estas son derivadas de funciones que tienen múltiples variables de entrada.
Piénsalo de esta manera. En lugar de encontrar la pendiente en una función unidimensional,
tenemos pendientes con respecto a múltiples variables en varias direcciones. Para cada derivada
variable dada, asumimos que las otras variables se mantienen constantes. Mire el gráfico 3D de

26
f( x, y) = 2x3 + 3y3 en la figura 1-8 y verá que tenemos pendientes en dos direcciones para dos
variables.
Tomemos la función f(x, y)= 2x3 + 3y3 . Las variables x e y obtienen cada una sus propias
derivadas . Estos representan los valores de pendiente con respecto a cada variable
en una superficie multidimensional. Técnicamente llamamos a estos gradientes de "pendientes"
cuando se trata de múltiples dimensiones. Estas son las derivadas de x e y, seguidas del código
SymPy para calcular esas derivadas.:

El ejemplo 1-21 y la figura 1-8 muestran cómo calculamos las derivadas parciales para x e y,
respectivamente, con SymPy.
Ejemplo 1-21. Cálculo de derivadas parciales con SymPy
from sympy import *
from sympy.plotting import plot3d
# Declare x and y to SymPy
x,y = symbols('x y')
# Now just use Python syntax to declare function
f = 2*x**3 + 3*y**3
# Calculate the partial derivatives for x and y
dx_f = diff(f, x)
dy_f = diff(f, y)
print(dx_f) # prints 6*x**2
print(dy_f) # prints 9*y**2
# plot the function
plot3d(f)

Figura 1-8. Trazar una función exponencial tridimensional

Así que para ( x, y ) valores (1,2), la pendiente con respecto a x es 6(1)=6 y la pendiente con
respecto a y es 9 (2) 2= 36 .

27
USO DE LÍMITES PARA CALCULAR DERIVADAS
¿Quiere ver dónde entran en juego los límites al calcular derivadas? Si te sientes bien con lo que
hemos aprendido hasta ahora, ¡continúa! Si todavía está digiriendo, tal vez considere volver a esta
barra lateral más tarde.
SymPy nos permite hacer algunas exploraciones interesantes sobre matemáticas. Tome nuestra
función f (x ) = x2; aproximamos una pendiente para x = 2 dibujando una línea a través de un
punto vecino cercano x = 2.0001 agregando un paso 0.0001. ¿Por qué no usar un límite para
disminuir para siempre ese paso s y ver a qué pendiente se acerca?

En nuestro ejemplo, estamos interesados en la pendiente donde x=2 , así que sustituyamos
eso:

Al acercarnos siempre a un tamaño de paso s a 0 pero nunca alcanzarlo (recuerde que el punto
vecino no puede tocar el punto en x = 2 , de lo contrario no tenemos línea), podemos usar un
límite para ver que convergemos en una pendiente de 4 como se muestra en el ejemplo 1-22.
Ejemplo 1-22. Uso de límites para calcular una pendiente
from sympy import *
# "x" and step size "s"
x, s = symbols('x s')
# declare function
f = x**2
# slope between two points with gap "s"
# substitute into rise-over-run formula
slope_f = (f.subs(x, x + s) - f) / ((x+s) - x)
# substitute 2 for x
slope_2 = slope_f.subs(x, 2)
# calculate slope at x = 2
# infinitely approach step size _s_ to 0
result = limit(slope_2, s, 0)
print(result) # 4

Ahora, ¿qué pasa si no asignamos un valor específico a x y lo dejamos en paz? ¿Qué sucede si
disminuimos nuestro tamaño de paso s infinitamente hacia 0? Veamos el ejemplo 1-23.
Ejemplo 1-23. Uso de límites para calcular una derivada
from sympy import *
# "x" and step size "s"
x, s = symbols('x s')
# declare function
f = x**2
# slope between two points with gap "s"
# substitute into rise-over-run formula
slope_f = (f.subs(x, x + s) - f) / ((x+s) - x)
# calculate derivative function
# infinitely approach step size +s+ to 0
result = limit(slope_f, s, 0)
print(result) # 2x
Eso nos dio nuestra función derivada 2x. SymPy fue lo suficientemente inteligente como para darse
cuenta de que nunca dejaría que nuestro tamaño de paso llegara a 0 sino que siempre se acercara
a 0. Esto converge f( x ) = x2 para llegar a su contraparte derivada 2x.

28
La regla de la cadena
The Chain Rule En el Capítulo 7, cuando construyamos una red neuronal, vamos a necesitar un
truco matemático especial llamado regla de la cadena. Cuando compongamos las capas de la red
neuronal, tendremos que desenredar las derivadas de cada capa. Pero por ahora aprendamos la
regla de la cadena con un ejemplo algebraico simple. Digamos que te dan dos funciones:
y = x2 + 1
z = y3 - 2
Observe que estas dos funciones están vinculadas, porque y es la variable de salida en la primera
función pero es la variable de entrada en la segunda. Esto significa que podemos sustituir la
primera función y en la segunda función z así:

Entonces, ¿cuál es la derivada de z con respecto a x ? Ya tenemos la sustitución expresando z en


términos de x. Usemos SymPypara calcular eso en el ejemplo 1-24.
Ejemplo 1-24. Encontrar la derivada de z con respecto a x
from sympy import *
z = (x**2 + 1)**3 - 2
dz_dx = diff(z, x)
print(dz_dx)
# 6*x*(x**2 + 1)**2
2
Entonces nuestra derivada de z con respecto a x es 6x (x2 +1) :

Pero mira esto. Comencemos de nuevo y tomemos un enfoque diferente. Si tomamos las derivadas
de las funciones y y z por separado, y luego las multiplicamos juntas, ¡esto también produce la
derivada de z con respecto a x ! Vamos a intentarlo:

Muy bien, 6 xy2 puede no parecerse a 6 x (x 2 +1) 2, pero eso es solo porque aún no hemos

sustituido la función y. Haga eso para que toda la derivada se exprese en términos de x sin
y.

Ahora vemos que tenemos la misma función derivada 6x (x2 +1)2 !


Esta es la regla de la cadena, que dice que para una función dada y (con variable de entrada x )
compuesta en otra función z (con variable de entrada y ), podemos encontrar la derivada de z con
respecto a x multiplicando las dos derivadas respectivas :

29
El ejemplo 1-25 muestra el código SymPy que hace esta comparación, mostrando que la derivada
de la regla de la cadena es igual a la derivada de la función sustituida.
Ejemplo 1-25. Calcular la derivada dz/dx con y sin la regla de la cadena, pero aún obteniendo la
misma respuesta
from sympy import *
x, y = symbols('x y')
# derivative for first function
# need to underscore y to prevent variable clash
_y = x**2 + 1
dy_dx = diff(_y)
# derivative for second function
z = y**3 - 2
dz_dy = diff(z)
# Calculate derivative with and without
# chain rule, substitute y function
dz_dx_chain = (dy_dx * dz_dy).subs(y, _y)
dz_dx_no_chain = diff(z.subs(y, _y))
# Prove chain rule by showing both are equal
print(dz_dx_chain) # 6*x*(x**2 + 1)**2
print(dz_dx_no_chain) # 6*x*(x**2 + 1)**2

La regla de la cadena es una parte clave del entrenamiento de una red neuronal con los pesos y
sesgos adecuados. En lugar de desenredar la derivada de cada nodo en forma de cebolla anidada,
podemos multiplicar las derivadas en cada nodo, lo cual es matemáticamente mucho más fácil.

Integrales
Lo contrario de una derivada es una integral, que encuentra el área bajo la curva para un rango
dado. En los Capítulos 2 y 3, encontraremos las áreas bajo distribuciones de probabilidad. Aunque
no usaremos integrales directamente, y en su lugar usaremos funciones de densidad acumulativa
que ya están integradas, es bueno saber cómo las integrales encuentran áreas bajo curvas. El
Apéndice A contiene ejemplos del uso de este enfoque en distribuciones de probabilidad.
Quiero adoptar un enfoque intuitivo para aprender integrales llamado Reimann Sums, uno que se
adapte de manera flexible a cualquier función continua. Primero, señalemos que encontrar el área
de un rango debajo de una línea recta es fácil. Digamos que tengo una función f( x ) = 2x y quiero
encontrar el área debajo de la línea entre 0 y 1, como se muestra en la figura 1-9.

30
Figura 1-9. Cálculo de un área bajo una función lineal

Observe que estoy encontrando el área delimitada entre la línea y el eje x, y en el rango x de 0,0 a
1,0. Si recuerdas las fórmulas básicas de geometría, el área A de un triángulo es donde b
es la longitud de la base y h es la altura. Podemos detectar visualmente que b = 1 y h = 2.
Entonces, al conectarnos a la fórmula, obtenemos para nuestra área 1.0 como se calcula aquí:

A=1
Eso no estuvo mal, ¿verdad? Pero veamos una función en la que es difícil encontrar el área debajo:
f ( x ) = x 2+ 1. ¿Cuál es el área entre 0 y 1 sombreada en la figura 1-10 ?

Figura 1-10. Calcular el área bajo funciones no lineales es menos sencillo


Nuevamente, estamos interesados en el área debajo de la curva y sobre el eje x, solo dentro del
rango x entre 0 y 1. La curvatura aquí no nos brinda una fórmula geométrica clara para encontrar el
área, pero aquí hay un pequeño truco inteligente. tu puedes hacer.

31
¿Qué pasa si empaquetamos cinco rectángulos de igual longitud debajo de la curva como se
muestra en la Figura 1-11, donde la altura de cada uno se extiende desde el eje x hasta donde el
punto medio toca la curva?
El área de un rectángulo es A = length × width A = largo × ancho , por lo que podríamos sumar
fácilmente las áreas de los rectángulos. ¿Nos daría eso una buena aproximación del área bajo la
curva? ¿Qué pasa si empacamos 100 rectángulos? 1,000? 100,000? A medida que aumentamos el
número de rectángulos mientras disminuimos su ancho, ¿no nos acercaríamos al área bajo la
curva? Sí, lo haríamos, y es otro caso más en el que aumentamos/disminuimos algo hacia el infinito
para acercarnos a un valor real.

Figura 1-11. Rectángulos de embalaje debajo de una curva para aproximar el área

Probémoslo en Python. Primero necesitamos una función que aproxime una integral que
llamaremos approximate_integral(). Los argumentos a y b especificarán el mínimo y el máximo del
rango x, respectivamente. n será el número de rectángulos a empaquetar y f será la función que
estamos integrando. Implementamos la función en el Ejemplo 1-26 y luego la usamos para integrar
nuestra función f ( x ) = x2+ 1 con cinco rectángulos, entre 0.0 y 1.0.
Ejemplo 1-26. Una aproximación integral en Python
def approximate_integral(a, b, n, f):
delta_x = (b - a) / n
total_sum = 0
for i in range(1, n + 1):
midpoint = 0.5 * (2 * a + delta_x * (2 * i - 1))
total_sum += f(midpoint)
return total_sum * delta_x
def my_function(x):
return x**2 + 1
area = approximate_integral(a=0, b=1, n=5, f=my_function)
print(area) # prints 1.33
Entonces obtenemos un área de 1.33. ¿Qué pasa si usamos 1,000 rectángulos? Probémoslo en el
ejemplo 1-27.
Ejemplo 1-27. Otra aproximación integral en Python
area = approximate_integral(a=0, b=1, n=1000, f=my_function)
print(area) # prints 1.333333250000001
Bien, estamos obteniendo algo más de precisión aquí y obteniendo algunos lugares
decimales más. ¿Qué pasa con un millón de rectángulos como se muestra en el Ejemplo
1-28 ?

32
Ejemplo 1-28. Otra aproximación integral en Python
area = approximate_integral(a=0, b=1, n=1_000_000, f=my_function)
print(area) # prints 1.3333333333332733
Bien, creo que estamos obteniendo un rendimiento decreciente aquí y convergiendo en el
valor 1. 333 ¯ donde la parte ".333" se repite para siempre. Si fuera un número racional,
probablemente 4/3 = 1. 333. A medida que aumentamos el número de rectángulos, la
aproximación comienza a alcanzar su límite con decimales cada vez más pequeños.
Ahora que tenemos cierta intuición sobre lo que estamos tratando de lograr y por qué,
hagamos un enfoque más exacto con SymPy, que es compatible con los números
racionales, en el Ejemplo 1-29.
Ejemplo 1-29. Uso de SymPy para realizar la integración
from sympy import *
# Declare 'x' to SymPy
x = symbols('x')
# Now just use Python syntax to declare function
f = x**2 + 1
# Calculate the integral of the function with respect to x
# for the area between x = 0 and 1
area = integrate(f, (x, 0, 1))
print(area) # prints 4/3¡

Enfriar! Entonces, el área en realidad es 4/3, que es en lo que convergió nuestro método
anterior. Desafortunadamente, Python simple (y muchos lenguajes de programación) solo
admiten decimales, pero los sistemas de álgebra computacional como SymPy nos brindan
números racionales exactos. Usaremos integrales para encontrar áreas bajo curvas en los
Capítulos 2 y 3, aunque scikit-learn hará el trabajo por nosotros.

CÁLCULO DE INTEGRALES CON LÍMITES


Para los súper curiosos, así es como calculamos integrales definidas usando límites en
SymPy. ¡Por favor! Omita o regrese a esta barra lateral más tarde si tiene suficiente para
digerir. Pero si te sientes bien y quieres profundizar en cómo se derivan las integrales
usando límites, continúa!
La idea principal sigue mucho de lo que hicimos antes: empaqueta rectángulos bajo una
curva y hazlos infinitamente más pequeños hasta que nos acerquemos al área exacta.
Pero, por supuesto, los rectángulos no pueden tener un ancho de 0.. solo tienen que seguir
acercándose a 0 sin llegar nunca a 0. Es otro caso de usar límites.
Khan Academy tiene un excelente artículo que explica cómo usar los límites para las
Sumas de Reimann, pero así es como lo hacemos en SymPy, como se muestra en el
Ejemplo 1-30.
Ejemplo 1-30. Usar límites para calcular integrales
from sympy import *
# Declare variables to SymPy
x, i, n = symbols('x i n')
# Declare function and range
f = x**2 + 1
lower, upper = 0, 1
# Calculate width and each rectangle height at index "i"
delta_x = ((upper - lower) / n)
x_i = (lower + delta_x * i)
fx_i = f.subs(x, x_i)
# Iterate all "n" rectangles and sum their areas
n_rectangles = Sum(delta_x * fx_i, (i, 1, n)).doit()
# Calculate the area by approaching the number

33
# of rectangles "n" to infinity
area = limit(n_rectangles, n, oo)
print(area) # prints 4/3

Aquí determinamos la longitud de cada rectángulo delta_x y el inicio de cada rectángulo x_i
donde i es el índice de cada rectángulo. fx_i es la altura de cada rectángulo en el índice i.
Declaramos un número n de rectángulos y sumamos sus áreas delta_x * fx_i, pero aún no
tenemos un valor de área porque no hemos asignado un número para n. En cambio, nos
acercamos a n hacia el infinito para ver en qué área convergemos, ¡y deberías obtener 4/3!

Conclusión
En este capítulo cubrimos algunos fundamentos que usaremos para el resto de este libro.
Desde la teoría de números hasta los logaritmos y las integrales de cálculo, destacamos
algunos conceptos matemáticos importantes relevantes para la ciencia de datos, el
aprendizaje automático y el análisis. Es posible que tenga preguntas acerca de por qué
estos conceptos son útiles. ¡Eso vendrá después!
Antes de pasar a discutir la probabilidad, tómate un poco de tiempo para repasar estos
conceptos una vez más y luego haz los siguientes ejercicios. Siempre puede volver a
visitar este capítulo a medida que avanza en este libro y actualizar según sea necesario
cuando comience a aplicar estas ideas matemáticas.

Ejercicios
1. ¿El valor 62.6738 es racional o irracional? ¿Por qué o por qué no?
2. Evalúa la expresión: 10710-5
3. Evalúa la expresión:
4. Evalúa la expresión:
5. Suponiendo que no se hagan pagos, ¿cuánto valdría un préstamo de $1,000
al 5% de interés compuesto mensualmente después de 3 años?
6. Suponiendo que no se hagan pagos, ¿cuánto valdría un préstamo de $1,000
al 5% de interés compuesto continuamente después de 3 años?
7. Para la función f( x ) = 3 x2 + 1 ¿cuál es la pendiente en x = 3?
8. Para la función f ( x ) = 3 x 2 + 1 ¿cuál es el área bajo la curva de x entre 0 y
2?
Las respuestas se encuentran en el Apéndice B.

34
Capítulo 2. Probabilidad
Cuando piensas en probabilidad, ¿qué imágenes te vienen a la mente? Tal vez piense en ejemplos
relacionados con los juegos de azar, como la probabilidad de ganar la lotería o conseguir un par
con dos dados. Tal vez esté prediciendo el rendimiento de las acciones, el resultado de una
elección política o si su vuelo llegará a tiempo. Nuestro mundo está lleno de incertidumbres que
queremos medir.
Quizá esa sea la palabra en la que deberíamos centrarnos: incertidumbre. ¿Cómo medimos algo
de lo que no estamos seguros?
Al final, la probabilidad es el estudio teórico de medir la certeza de que ocurrirá un evento. Es una
disciplina fundamental para las estadísticas, las pruebas de hipótesis, el aprendizaje automático y
otros temas de este libro. Mucha gente da por sentada la probabilidad y asume que la entiende. Sin
embargo, es más matizado y complicado de lo que la mayoría de la gente piensa. Si bien los
teoremas y las ideas de probabilidad son matemáticamente sólidos, se vuelve más complejo
cuando introducimos datos y nos aventuramos en las estadísticas. Cubriremos eso en el Capítulo 4
sobre estadística y prueba de hipótesis.
En este capítulo, discutiremos qué es la probabilidad. Luego cubriremos los conceptos matemáticos
de probabilidad, el teorema de Bayes, la distribución binomial y la distribución beta.

comprensión de la probabilidad
La probabilidad es la fuerza con la que creemos que ocurrirá un evento, a menudo expresada como
un porcentaje. Aquí hay algunas preguntas que podrían garantizar una probabilidad de respuesta:
 ¿Qué probabilidades hay de que salgan 7 caras en 10 lanzamientos de moneda justos?
 ¿Cuáles son mis posibilidades de ganar una elección?
 ¿Se retrasará mi vuelo?
 ¿Qué tan seguro estoy de que un producto es defectuoso?
La forma más popular de expresar la probabilidad es como un porcentaje, como en "Hay un 70% de
posibilidades de que mi vuelo llegue tarde". Llamaremos a esta probabilidad P( X ), donde X es el
evento de interés. Sin embargo, a medida que trabaja con probabilidades, es más probable que lo
vea expresado como un decimal (en este caso, 0,70), que debe estar entre 0,0 y 1,0:
P ( X ) =.70
La probabilidad es similar a la probabilidad, y es fácil confundirlos (muchos diccionarios también lo
hacen). Puede salirse con la suya usando "probabilidad" y "verosimilitud" indistintamente en una
conversación cotidiana. Sin embargo, debemos precisar estas diferencias. La probabilidad se trata
de cuantificar las predicciones de eventos que aún no han sucedido, mientras que la probabilidad
mide la frecuencia de los eventos que ya ocurrieron. En estadísticas y aprendizaje automático, a
menudo usamos la probabilidad (el pasado) en forma de datos para predecir la probabilidad (el
futuro).
Es importante tener en cuenta que la probabilidad de que ocurra un evento debe estar
estrictamente entre 0% y 100%, o 0.0 y 1.0. Lógicamente, esto significa que la probabilidad de que
un evento no suceda se calcula restando la probabilidad del evento de 1.0:
P ( X ) =.70
P ( not X ) = 1 -.70 =.30

Esta es otra distinción entre probabilidad y verosimilitud. Las probabilidades de todos los posibles
resultados mutuamente excluyentes para un evento (lo que significa que solo puede ocurrir un
resultado, no múltiples) deben sumar 1.0 o 100%. Las probabilidades, sin embargo, no están
sujetas a esta regla.
Alternativamente, la probabilidad se puede expresar como una probabilidad O ( X ) como 7:3, 7/3
o 2. 333 ¯ .
Para convertir una cuota O ( X ) en una probabilidad proporcional P( X ) , utilice esta fórmula:

Entonces, si tengo una probabilidad de 7/3, puedo convertirla en una probabilidad proporcional
como esta:

35
Por el contrario, puede convertir una cuota en una probabilidad simplemente dividiendo la
probabilidad de que ocurra el evento por la probabilidad de que no ocurra:

¡LAS PROBABILIDADES SON ÚTILES!


Si bien muchas personas se sienten más cómodas expresando probabilidades como porcentajes o
proporciones, las cuotas pueden ser una herramienta útil. Si tengo una probabilidad de 2.0, eso
significa que siento que un evento tiene dos veces más probabilidades de suceder que de no
suceder. Eso puede ser más intuitivo para describir una creencia que un porcentaje de 66. 666 %.
Por esta razón, las cuotas son útiles para cuantificar las creencias subjetivas, especialmente en un
contexto de juego/apuestas. Desempeña un papel en las estadísticas bayesianas (incluido el factor
de Bayes), así como en las regresiones logísticas con log-odds, que trataremos en el Capítulo 6.

Probabilidad Versus Estadística


A veces, las personas usan los términos probabilidad y estadística indistintamente y, si bien es
comprensible combinar las dos disciplinas, tienen distinciones. La probabilidad es puramente
teórica de la probabilidad de que suceda un evento y no requiere datos. La estadística, por otro
lado, no puede existir sin datos y los usa para descubrir probabilidades y proporciona herramientas
para describir datos.
Piense en predecir el resultado de tirar un 4 en un dado (ese es el singular de los dados). Al
abordar el problema con una mentalidad puramente probabilística, uno simplemente dice que hay
seis caras en un dado. Suponemos que cada lado tiene la misma probabilidad, por lo que la
probabilidad de obtener un 4 es 1/6, o 16,666 %.
Sin embargo, un estadístico celoso podría decir: “¡No! Necesitamos tirar el dado para obtener
datos. Si podemos sacar 30 tiradas o más, y cuantas más tiradas hagamos mejor, solo entonces
tendremos datos para determinar la probabilidad de sacar un 4”. Este enfoque puede parecer tonto
si asumimos que el dado es justo, pero ¿y si no lo es? Si ese es el caso, recopilar datos es la única
forma de descubrir la probabilidad de sacar un 4. Hablaremos sobre la prueba de hipótesis en el
Capítulo 3.

matemáticas de probabilidad
Cuando trabajamos con una sola probabilidad de un evento P ( X ), conocida como probabilidad
marginal, la idea es bastante sencilla, como se discutió anteriormente. Pero cuando comenzamos a
combinar probabilidades de diferentes eventos, se vuelve un poco menos intuitivo.

Probabilidades conjuntas
Digamos que tienes una moneda justa y un dado de seis caras justo. Quiere encontrar la
probabilidad de sacar cara y sacar un 6 en la moneda y el dado, respectivamente. Estas son dos
probabilidades separadas de dos eventos separados, pero queremos encontrar la probabilidad de
que ambos eventos ocurran juntos. Esto se conoce como probabilidad conjunta.

36
Piense en una probabilidad conjunta como un operador AND. Quiero encontrar la probabilidad de
sacar cara Y sacar un 6. Queremos que ambos eventos sucedan juntos, entonces, ¿cómo
calculamos esta probabilidad?
Hay dos lados en una moneda y seis lados en el dado, por lo que la probabilidad de cara es 1/2 y la
probabilidad de seis es 1/6. La probabilidad de que ocurran ambos eventos (suponiendo que sean
independientes, ¡más sobre esto más adelante!) es simplemente multiplicar los dos juntos:
P(A AND B) = P(A) × P(B)

Bastante fácil, pero ¿por qué es este el caso? Se pueden descubrir muchas reglas de probabilidad
generando todas las combinaciones posibles de eventos, lo que proviene de un área de
matemáticas discretas conocida como permutaciones y combinaciones. Para este caso, genere
todos los resultados posibles entre la moneda y el dado, emparejando cara (H) y cruz (T) con los
números del 1 al 6. Tenga en cuenta que puse asteriscos "*" alrededor del resultado de interés
donde obtenemos cara y un 6:
H1 H2 H3 H4 H5 *H6* T1 T2 T3 T4 T5 T6

Observe que hay 12 resultados posibles al lanzar nuestra moneda y lanzar nuestro dado. El único
que nos interesa es "H6", obtener cara y 6. Entonces, debido a que solo hay un resultado que
satisface nuestra condición, y hay 12 resultados posibles, la probabilidad de obtener cara y 6 es
1/12.
En lugar de generar todas las combinaciones posibles y contar las que nos interesen, nuevamente
podemos usar la multiplicación como un atajo para encontrar la probabilidad conjunta. Esto se
conoce como la regla del producto :
P(A AND B) = P(A) × P(B)

Unión de probabilidades
Discutimos las probabilidades conjuntas, que es la probabilidad de que dos o más eventos ocurran
simultáneamente. Pero, ¿qué pasa con la probabilidad de obtener el evento A o B?Cuando
tratamos con operaciones OR con probabilidades, esto se conoce como probabilidad de unión.
Comencemos con eventos mutuamente excluyentes, que son eventos que no pueden ocurrir
simultáneamente. Por ejemplo, si tiro un dado, no puedo obtener simultáneamente un 4 y un 6.
Solo puedo obtener un resultado. Obtener la probabilidad de unión para estos casos es fácil.
Simplemente los sumo. Si quiero encontrar la probabilidad de obtener un 4 o un 6 en una tirada de
dado, será 2/6 = 1/3:

Pero, ¿qué pasa con los eventos no mutuamente excluyentes, que son eventos que pueden ocurrir
simultáneamente? Volvamos al ejemplo del lanzamiento de la moneda y la tirada del dado. ¿Cuál

37
es la probabilidad de obtener cara O un 6? Antes de que tenga la tentación de agregar esas
probabilidades, generemos todos los resultados posibles nuevamente y resaltemos los que nos
interesan.:
*H1* *H2* *H3* *H4* *H5* *H6* T1 T2 T3 T4 T5 *T6*
Aquí estamos interesados en todos los resultados de cabeza, así como en los 6 resultados. Si
proporcionamos los 7 de los 12 resultados que nos interesan, 7/12, obtenemos una probabilidad
correcta de .58 333.
Pero, ¿qué sucede si sumamos las probabilidades de cara y 6 juntas? Obtenemos una respuesta
diferente (¡y equivocada!) de . 666:

¿Porqué es eso? Estudie las combinaciones de lanzamiento de moneda y resultados de dado


nuevamente y vea si puede encontrar algo sospechoso. ¡Observe que cuando sumamos las
probabilidades, contamos dos veces la probabilidad de obtener un 6 tanto en "H6" como en "T6"! Si
esto no está claro, intente encontrar la probabilidad de obtener cara o una tirada de 1 a 5:

Obtenemos una probabilidad del 133,333%, lo que definitivamente no es correcto porque la


probabilidad no debe ser superior al 100 % o 1,0. El problema nuevamente es que estamos
contando dos veces los resultados.
Si reflexiona lo suficiente, puede darse cuenta de que la forma lógica de eliminar el conteo doble en
una probabilidad de unión es restar la probabilidad conjunta. Esto se conoce como la regla de la
suma de probabilidades y asegura que cada evento conjunto se cuente solo una vez.:
P(A OR B) = P(A) + P(B) - P(A AND B)
P(A OR B) = P(A) + P(B) - P(A) × P(B)
Entonces, volviendo a nuestro ejemplo de calcular la probabilidad de obtener cara o 6, debemos
restar la probabilidad conjunta de obtener cara o 6 de la probabilidad de unión:

P(A OR B) = P(A) + P(B) - P(A) × P(B)

Tenga en cuenta que esta fórmula también se aplica a eventos mutuamente excluyentes. Si los
eventos son mutuamente excluyentes donde solo se permite un resultado A o B pero no ambos,

38
entonces la probabilidad conjunta P ( A Y B ) será 0 y, por lo tanto, se eliminará de la fórmula.
Entonces te queda simplemente sumar los eventos como lo hicimos antes.
En resumen, cuando tiene una probabilidad de unión entre dos o más eventos que no son
mutuamente excluyentes, asegúrese de restar la probabilidad conjunta para que no se cuenten dos
veces las probabilidades.
Probabilidad Condicional y Teorema de Bayes
Un tema de probabilidad que fácilmente confunde a las personas es el concepto de probabilidad
condicional, que es la probabilidad de que ocurra un evento A dado que ha ocurrido un evento B.
Normalmente se expresa como P (A DADO B) o P (A|B).
Digamos que un estudio afirma que el 85% de los pacientes con cáncer beben café. ¿Cómo
reacciona ante esta afirmación? ¿Esto te alarma y te da ganas de abandonar tu bebida matutina
favorita? Primero definamos esto como una probabilidad condicional P(Coffee given Cancer) or
P(Coffee|Cancer) P ( Café dado Cáncer ) o P ( Café | Cáncer ). Esto representa una probabilidad
de que las personas tomen café dado que tienen cáncer.
Dentro de los Estados Unidos, comparemos esto con el porcentaje de personas diagnosticadas con
cáncer (0.5% según cancer.gov ) y el porcentaje de personas que beben café (65% según
statista.com ):
P(Coffee) = .65
P(Cancer) = .005
P(Coffee|Cancer) = .85
Hmmmm.. estudie estos números por un momento y pregúntese si el café es realmente el
problema aquí. Observe nuevamente que solo el 0.5% de la población tiene cáncer en un momento
dado. Sin embargo, el 65% de la población bebe café regularmente. Si el café contribuye al cáncer,
¿no deberíamos tener cifras de cáncer mucho más altas que el 0,5 %? ¿No estaría más cerca del
65%?
Esto es lo engañoso de los números proporcionales. Pueden parecer significativos sin ningún
contexto dado, y los titulares de los medios ciertamente pueden explotar esto para obtener clics:
"Nuevo estudio revela que el 85% de los pacientes con cáncer beben café", podría leerse. Por
supuesto, esto es una tontería porque hemos tomado un atributo común (beber café) y lo hemos
asociado con uno poco común (tener cáncer).
La razón por la que las personas pueden confundirse tan fácilmente con las probabilidades
condicionales es porque la dirección de la condición importa, y las dos condiciones se combinan
como si fueran iguales. La “probabilidad de tener cáncer dado que es un bebedor de café” es
diferente de la “probabilidad de ser un bebedor de café dado que tiene cáncer”. En pocas palabras:
pocos bebedores de café tienen cáncer, pero muchos pacientes con cáncer beben café.
Si estamos interesados en estudiar si el café contribuye al cáncer, realmente nos interesa la
primera probabilidad condicional: la probabilidad de que alguien tenga cáncer dado que es un
bebedor de café.
P(Coffee|Cancer) = .85¿
P(Cancer|Coffee) =?

Cómo cambiamos la condición? Hay una pequeña y poderosa fórmula llamada Teorema de Bayes,
y podemos usarla para cambiar las probabilidades condicionales:

Si conectamos la información que ya tenemos en esta fórmula, podemos resolver la probabilidad de


que alguien tenga cáncer dado que bebe café:

39
Si desea calcular esto en Python, consulte el Ejemplo 2-1.
Ejemplo 2-1. Usando el teorema de Bayes en Python
p_coffee_drinker = .65
p_cancer = .005
p_coffee_drinker_given_cancer = .85
p_cancer_given_coffee_drinker = p_coffee_drinker_given_cancer *
p_cancer / p_coffee_drinker
# prints 0.006538461538461539
print(p_cancer_given_coffee_drinker)¡
Entonces la probabilidad de que alguien tenga cáncer dado que es un bebedor de café es solo del
0.65%! Este número es muy diferente de la probabilidad de que alguien sea un bebedor de café
dado que tiene cáncer, que es del 85 %. ¿Ahora ves por qué es importante la dirección de la
condición? El teorema de Bayes es útil por esta razón. También se puede usar para encadenar
varias probabilidades condicionales para seguir actualizando nuestras creencias en función de
nueva información.

¿QUÉ DEFINE A UN “BEBEDOR DE CAFÉ”?


Tenga en cuenta que podría haber tenido en cuenta otras variables aquí, en particular lo que
califica a alguien como "bebedor de café". Si alguien bebe café una vez al mes, a diferencia de
alguien que bebe café todos los días, ¿debo calificar a ambos por igual como “bebedores de café”?
¿Qué pasa con la persona que comenzó a tomar café hace un mes en comparación con alguien
que tomó café durante 20 años? ¿Con qué frecuencia y durante cuánto tiempo deben beber café
las personas antes de alcanzar el umbral de ser un "bebedor de café" en este estudio de cáncer?
Estas son preguntas importantes a considerar y muestran por qué los datos rara vez cuentan la
historia completa. Si alguien le da una hoja de cálculo de pacientes con una simple bandera de
"SÍ/NO" sobre si son bebedores de café, ¡ese umbral debe definirse! O necesitamos una métrica
más ponderada como “número de bebidas de café consumidas en los últimos tres años”. Mantuve
este experimento mental simple y no definí cómo alguien califica como un "bebedor de café", pero
tenga en cuenta que en el campo, siempre es una buena idea tirar de los hilos de los datos.
Discutiremos esto más en el Capítulo 3.

Si desea explorar la intuición detrás del Teorema de Bayes más profundamente, consulte el
Apéndice A. Por ahora, solo sé que nos ayuda a cambiar una probabilidad condicional. A
continuación, hablemos de cómo las probabilidades condicionales interactúan con las operaciones
conjuntas y de unión.

NAIVE BAYES
El teorema de Bayes juega un papel central en un algoritmo común de aprendizaje automático
llamado Naive Bayes. Joel Grus lo cubre en su libro Data Science from Scratch (O'Reilly).

Probabilidades Condicionales Conjuntas y Uniones


Revisemos las probabilidades conjuntas y cómo interactúan con las probabilidades condicionales.
Quiero encontrar la probabilidad de que alguien beba café Y tenga cáncer. ¿Debo multiplicar P
(Café) y P (Cáncer) ? ¿O debería usar P ( Coffee|Cancer ) en lugar de P ( Coffee ) si está
disponible? cual uso?
Option 1:
P(Coffee) × P(Cancer) = .65 × .005 = .00325

Option 2:
P(Coffee|Cancer) × P(Cancer) = .85 × .005 = .00425

40
Si ya hemos establecido que nuestra probabilidad se aplica solo a personas con cáncer, ¿no tiene
sentido usar P (Café|Cáncer) en lugar de P (Café) ? Uno es más específico y se aplica a una
condición que ya se ha establecido. Entonces deberíamos usar P ( Coffee|Cancer ) ya que P
( Cancer ) ya es parte de nuestra probabilidad conjunta. Esto quiere decir que la probabilidad de
que alguien tenga cáncer y sea bebedor de café es del 0,425%:
P(Coffee and Cancer) = P(Coffee|Cancer) × P(Cancer) = .85 × .005 = .00425
Esta probabilidad conjunta también se aplica en la otra dirección. Puedo encontrar la probabilidad
de que alguien sea un bebedor de café y tenga cáncer al multiplicar P (Cáncer|Café) y P (Café).
Como puedes observar, llego a la misma respuesta:
P(Cancer|Coffee) × P(Coffee) = .0065 × .65 = .00425
Si no tuviéramos ninguna probabilidad condicional disponible, entonces lo mejor que podemos
hacer es multiplicar P ( Bebedor de café ) y P (Cáncer) como se muestra aquí:
P(Coffee Drinker) × P(Cancer) = .65 × .005 = .00325
Ahora piense en esto: si el evento A no tiene impacto en el evento B, ¿qué significa eso para la
probabilidad condicional P ( B | A )? Eso significa que P ( B | A ) = P ( B ), lo que significa que la
ocurrencia del evento A no hace ninguna diferencia en la probabilidad de que ocurra el evento B.
Por lo tanto, podemos actualizar nuestra fórmula de probabilidad conjunta, independientemente de
si los dos eventos son dependientes, para que sea:
P(A AND B) = P(B) × P(A|B)
Y finalmente hablemos de uniones y probabilidad condicional. Si quisiera calcular la probabilidad de
que ocurra A o B, pero A puede afectar la probabilidad de B, actualizamos nuestra regla de suma
de esta manera:
P(A OR B) = P(A) + P(B) - P(A|B) × P(B)
Como recordatorio, esto también se aplica a eventos mutuamente excluyentes. La regla de la suma
P ( A | B ) × P ( B ) arrojaría 0 si los eventos A y B no pueden ocurrir simultáneamente.

Distribución binomial
En el resto de este capítulo, aprenderemos dos distribuciones de probabilidad: las distribuciones
binomial y beta. Si bien no los usaremos en el resto del libro, son herramientas útiles en sí mismas
y fundamentales para comprender cómo ocurren los eventos después de una serie de pruebas.
También serán una buena transición para comprender las distribuciones de probabilidad que
usaremos mucho en el Capítulo 3. Exploremos un caso de uso que podría ocurrir en un escenario
del mundo real.
Supongamos que está trabajando en un nuevo motor a reacción de turbina y realizó 10 pruebas.
Los resultados arrojaron ocho éxitos y dos fracasos:
✓✓✓✓✓✘✓✘✓✓
Esperaba obtener una tasa de éxito del 90 %, pero según estos datos concluye que sus pruebas
fallaron con solo un 80 % de éxito. Cada prueba lleva mucho tiempo y es costosa, por lo que decide
que es hora de volver a la mesa de dibujo para rediseñar el diseño.
Sin embargo, uno de sus ingenieros insiste en que debería haber más pruebas. “La única manera
de saberlo con certeza es realizar más pruebas”, argumenta. “¿Qué pasa si más pruebas arrojan
un 90% o más de éxito? Después de todo, si lanzas una moneda 10 veces y obtienes 8 caras, no
significa que la moneda esté fijada en un 80 %”.
Consideras brevemente el argumento de la ingeniera y te das cuenta de que tiene razón. Incluso un
lanzamiento de moneda justo no siempre tendrá un resultado dividido por igual, especialmente con
solo 10 lanzamientos. Lo más probable es que obtenga cinco cabezas, pero también puede obtener
tres, cuatro, seis o siete cabezas. Incluso podría obtener 10 cabezas, aunque esto es
extremadamente improbable. Entonces, ¿cómo se determina la probabilidad de un 80 % de éxito
asumiendo que la probabilidad subyacente es del 90 %?
Una herramienta que podría ser relevante aquí es la distribución binomial, que mide la probabilidad
de que se produzcan k éxitos en n intentos dada una probabilidad p.

41
Visualmente, una distribución binomial se parece a la Figura 2-1.
Aquí, vemos la probabilidad de éxitos k para cada barra de 10 intentos. Esta distribución binomial
supone una probabilidad p del 90 %, lo que significa que hay una probabilidad de 0,90 (o 90 %) de
que se produzca el éxito. Si esto es cierto, eso significa que hay una probabilidad de.1937 de que
obtendríamos 8 éxitos de 10 intentos. La probabilidad de obtener 1 éxito de 10 intentos es
extremadamente improbable,.000000008999, por lo que la barra ni siquiera es visible.
También podemos calcular la probabilidad de ocho o menos éxitos sumando barras para ocho o
menos éxitos. Esto nos daría una probabilidad de.2639 de ocho o menos éxitos.

Figura 2-1. Una distribución binomial

Entonces, ¿cómo implementamos la distribución binomial? Podemos hacerlo desde cero con
relativa facilidad (como se comparte en el Apéndice A ), o podemos usar bibliotecas como SciPy. El
ejemplo 2-2 muestra cómo usamos la función binom.pmf() de SciPy ( PMF significa "función de
masa de probabilidad") para imprimir las 11 probabilidades para nuestra distribución binomial de 0
a 10 éxitos.
Ejemplo 2-2. Usando SciPy para la distribución binomial
from scipy.stats import binom
n = 10
p = 0.9
for k in range(n + 1):
probability = binom.pmf(k, n, p)
print("{0} - {1}".format(k, probability))
# OUTPUT:
# 0 - 9.99999999999996e-11
# 1 - 8.999999999999996e-09
# 2 - 3.644999999999996e-07
# 3 - 8.748000000000003e-06
# 4 - 0.0001377809999999999
# 5 - 0.0014880347999999988
# 6 - 0.011160260999999996

42
# 7 - 0.05739562800000001
# 8 - 0.19371024449999993
# 9 - 0.38742048900000037
# 10 - 0.34867844010000004

Como puede ver, proporcionamos n como el número de intentos, p como la probabilidad de éxito
de cada intento y k como el número de éxitos para los que queremos buscar la probabilidad.
Iteramos cada número de éxitos x con la probabilidad correspondiente de que veríamos muchos
éxitos. Como podemos ver en la salida, el número más probable de éxitos es nueve.
Pero si sumamos la probabilidad de ocho o menos éxitos, obtendríamos.2639. Esto significa que
hay una probabilidad del 26,39 % de que veamos ocho éxitos o menos, incluso si la tasa de éxito
subyacente es del 90 %. Entonces, tal vez el ingeniero tenga razón: el 26,39% de probabilidad no
es nada y ciertamente es posible.
Sin embargo, hicimos una suposición aquí en nuestro modelo, que discutiremos a continuación con
la distribución beta.

DISTRIBUCIÓN BINOMIAL DESDE CERO


Vaya al Apéndice A para aprender cómo construir la distribución binomial desde cero sin scikit-
learn.

Distribución beta
¿Qué asumí con mi modelo de prueba de motor utilizando la distribución binomial? ¿Hay algún
parámetro que supuse que era cierto y luego construí todo mi modelo a su alrededor? Piensa con
cuidado y sigue leyendo.
Lo que podría ser problemático acerca de mi distribución binomial es que asumí que la tasa de
éxito subyacente es del 90 %. Eso no quiere decir que mi modelo sea inútil. Acabo de mostrar que
si la tasa de éxito subyacente es del 90 %, hay un 26,39 % de posibilidades de que vea 8 éxitos o
menos con 10 intentos. Por lo tanto, el ingeniero ciertamente no está equivocado en cuanto a que
podría haber una tasa de éxito subyacente del 90 %.
Pero cambiemos la pregunta y consideremos esto: ¿qué pasa si hay otras tasas subyacentes de
éxito que producirían 8/10 éxitos además del 90 %? ¿Podríamos ver 8/10 éxitos con una tasa de
éxito subyacente del 80 %? 70%? 30%? Cuando arreglamos los 8/10 éxitos, ¿podemos explorar
las probabilidades de las probabilidades?
En lugar de crear innumerables distribuciones binomiales para responder a esta pregunta, hay una
herramienta que podemos usar. La distribución beta nos permite ver la probabilidad de diferentes
probabilidades subyacentes de que ocurra un evento dados los éxitos alfa y los fracasos beta.
En la Figura 2-2 se muestra un gráfico de la distribución beta con ocho éxitos y dos fracasos.

43
Figura 2-2. distribución beta

DISTRIBUCIÓN BETA EN DESMOS


Si desea interactuar con la distribución beta, aquí se proporciona un gráfico de Desmos.
Observe que el eje x representa todas las tasas subyacentes de éxito de 0,0 a 1,0 (0 % a 100 %) y
el eje y representa la probabilidad de esa probabilidad dados ocho éxitos y dos fracasos. En otras
palabras, la distribución beta nos permite ver las probabilidades de probabilidades dadas 8/10
éxitos. ¡Piense en ello como una metaprobabilidad, así que tómese su tiempo para comprender
esta idea!
Observe también que la distribución beta es una función continua, lo que significa que forma una
curva continua de valores decimales (a diferencia de los enteros ordenados y discretos en la
distribución binomial). Esto hará que las matemáticas con la distribución beta sean un poco más
difíciles, ya que un valor de densidad dado en el eje y no es una probabilidad. En cambio,
encontramos probabilidades usando áreas bajo la curva.
La distribución beta es un tipo de distribución de probabilidad, lo que significa que el área bajo toda
la curva es 1,0 o 100 %. Para encontrar una probabilidad, necesitamos encontrar el área dentro de
un rango. Por ejemplo, si queremos evaluar la probabilidad de que 8/10 éxitos produzcan una tasa
de éxito del 90% o más, necesitamos encontrar el área entre 0,9 y 1,0, que es 0,225, como se
muestra en la figura 2-3.

44
Figura 2-3. El área entre 90% y 100%, que es 22.5%

Como hicimos con la distribución binomial, podemos usar SciPy para implementar la distribución
beta. Cada distribución de probabilidad continua tiene una función de densidad acumulada (CDF),
que calcula el área hasta un valor x dado. Digamos que quisiera calcular el área hasta el 90 % (0,0
a 0,90) como se muestra en la figura 2-4.

Figura 2-4. Cálculo del área hasta el 90% (0,0 a 0,90)

Es bastante fácil usar SciPy con su función beta.cdf() y los únicos parámetrosNecesito proporcionar
el valor x, la cantidad de éxitos a y la cantidad de fallas b como se muestra en el Ejemplo 2-3.
Ejemplo 2-3. Distribución beta usando SciPy
from scipy.stats import beta
a=8
b=2
p = beta.cdf(.90, a, b)
# 0.7748409780000001
print(p)
De acuerdo con nuestro cálculo, existe un 77,48 % de posibilidades de que la probabilidad
subyacente de éxito sea del 90 % o menos.

45
¿Cómo calculamos que la probabilidad de éxito sea del 90 % o más, como se muestra en la figura
2-5 ?

Figura 2-5. La probabilidad de éxito es del 90% o más.

Nuestro CDF calcula el área solo a la izquierda de nuestro límite, no a la derecha. Piensa en
nuestras reglas de probabilidad, y con una distribución de probabilidad el área total bajo la curva es
1.0. Si queremos encontrar la probabilidad opuesta de un evento (mayor que 0,90 en lugar de
menor que 0,90), simplemente reste la probabilidad de que sea menor que 0,90 de 1,0, y la
probabilidad restante capturará que sea mayor que 0,90. La figura 2-6 ilustra cómo hacemos esta
resta.

Figura 2-6. Encontrar la probabilidad de éxito mayor al 90%


El ejemplo 2-4 muestra cómo calculamos esta operación de resta en Python.
Ejemplo 2-4. Restar para obtener un área correcta en una distribución beta
from scipy.stats import beta
a=8
b=2
p = 1.0 - beta.cdf(.90, a, b)
# 0.22515902199999993
print(p)

Esto significa que de 8/10 pruebas de motor exitosas, solo hay un 22,5 % de posibilidades de que
la tasa de éxito subyacente sea del 90 % o más. Pero hay un 77,5 % de probabilidad de que sea

46
menos del 90 %. Las probabilidades no están a nuestro favor aquí de que nuestras pruebas hayan
tenido éxito, pero podríamos apostar a esa probabilidad del 22,5% con más pruebas si nos
sentimos afortunados. Si nuestro CFO concediera fondos para 26 pruebas más que resultaran en
30 éxitos y 6 fracasos, nuestra distribución beta se vería como la Figura 2-7.

Figura 2-7. Distribución beta después de 30 éxitos y 6 fallas

Observe que nuestra distribución se hizo más estrecha, por lo que se volvió más seguro de que la
tasa subyacente de éxito está en un rango más pequeño. Desafortunadamente, nuestra
probabilidad de cumplir con nuestra tasa mínima de éxito del 90 % ha disminuido, pasando del 22,5
% al 13,16 %, como se muestra en el ejemplo 2-5.
Ejemplo 2-5. Una distribución beta con más pruebas
from scipy.stats import beta
a = 30
b=6
p = 1.0 - beta.cdf(.90, a, b)
# 0.13163577484183708
print(p)
En este punto, podría ser una buena idea alejarse y dejar de hacer pruebas, a menos que quiera
seguir apostando contra esa probabilidad del 13,16 % y esperar que el pico se mueva hacia la
derecha.
Por último, pero no menos importante, ¿cómo calcularíamos un área en el medio? ¿Qué pasa si
quiero encontrar la probabilidad de que mi tasa subyacente de éxito esté entre 80% y 90% como se
muestra en la Figura 2-8 ?

47
Figura 2-8. Probabilidad de que la tasa subyacente de éxito esté entre el 80 % y el 90 %

Piense cuidadosamente cómo podría abordar esto. ¿Qué pasaría si restáramos el área detrás
de.80 del área detrás de.90 como en la figura 2-9 ?

Figura 2-9. Obteniendo el área entre.80 y.90

¿Eso nos daría el área entre.80 y.90? Sí lo sería, y arrojaría un área de.3386 o 33.86% de
probabilidad. Así es como lo calcularíamos en Python ( Ejemplo 2-6 ).
Ejemplo 2-6. Área media de distribución beta usando SciPy
from scipy.stats import beta
a=8
b=2
p = beta.cdf(.90, a, b) - beta.cdf(.80, a, b)
# 0.33863336200000016
print(p)
La distribución beta es una herramienta fascinante para medir la probabilidad de que un evento
ocurra frente a que no ocurra, en función de un conjunto limitado de observaciones. Nos permite
razonar sobre probabilidades de probabilidades, y podemos actualizarlo a medida que obtenemos

48
nuevos datos. También podemos usarlo para probar hipótesis, pero pondremos más énfasis en el
uso de la distribución normal y la distribución T para ese propósito en el Capítulo 3.
DISTRIBUCIÓN BETA DESDE CERO
Para saber cómo implementar la distribución beta desde cero, consulte el Apéndice A.

Conclusión
¡Cubrimos mucho en este capítulo! No solo discutimos los fundamentos de la probabilidad, sus
operadores lógicos y el teorema de Bayes, sino que también presentamos las distribuciones de
probabilidad, incluidas las distribuciones binomial y beta. En el próximo capítulo cubriremos una de
las distribuciones más famosas, la distribución normal, y cómo se relaciona con la prueba de
hipótesis.
Si desea obtener más información sobre la probabilidad y las estadísticas bayesianas, un gran libro
es Bayesian Statistics the Fun Way de Will Kurt (No Starch Press). También hay escenarios
interactivos de Katacoda disponibles en la plataforma O'Reilly.

Ejercicios
1. Hay un 30 % de probabilidad de lluvia hoy y un 40 % de probabilidad de que su pedido de
paraguas llegue a tiempo. ¡Estás ansioso por caminar bajo la lluvia hoy y no puedes hacerlo
sin ninguno de los dos!
¿Cuál es la probabilidad de que llueva Y llegue tu paraguas?
2. Hay un 30 % de probabilidad de lluvia hoy y un 40 % de probabilidad de que su pedido de
paraguas llegue a tiempo.
Podrás hacer mandados solo si no llueve o llega tu paraguas.
3. ¿Cuál es la probabilidad de que no llueva O llegue tu paraguas?
Hay un 30 % de probabilidad de lluvia hoy y un 40 % de probabilidad de que su pedido de
paraguas llegue a tiempo.
Sin embargo, descubrió que si llueve, solo hay un 20% de posibilidades de que su paraguas
llegue a tiempo.
¿Cuál es la probabilidad de que llueva Y tu paraguas llegue a tiempo?
4. Tienes 137 pasajeros reservados en un vuelo de Las Vegas a Dallas. Sin embargo, es Las
Vegas un domingo por la mañana y usted estima que cada pasajero tiene un 40 % de
probabilidades de no presentarse.
Estás tratando de calcular cuántos asientos reservar para que el avión no vuele vacío.
¿Qué probabilidad hay de que al menos 50 pasajeros no se presenten?
5. Lanzaste una moneda 19 veces y obtuviste cara 15 veces y cruz 4 veces.
¿Crees que esta moneda tiene alguna buena probabilidad de ser justa? ¿Por qué o por qué no?

Las respuestas se encuentran en el Apéndice B.

49
Capítulo 3. Estadística descriptiva e inferencial
Descriptive and Inferential Statistics La estadística es la práctica de recopilar y analizar datos para
descubrir hallazgos que sean útiles o predecir qué causa que esos hallazgos sucedan. La
probabilidad a menudo juega un papel importante en las estadísticas, ya que usamos datos para
estimar la probabilidad de que suceda un evento.
Puede que no siempre obtenga crédito, pero las estadísticas son el corazón de muchas
innovaciones basadas en datos. El aprendizaje automático en sí mismo es una herramienta
estadística que busca posibles hipótesis para correlacionar relaciones entre diferentes variables en
los datos. Sin embargo, hay muchos lados ciegos en las estadísticas, incluso para los estadísticos
profesionales. Podemos quedar atrapados fácilmente en lo que dicen los datos que olvidamos
preguntar de dónde provienen los datos. Estas preocupaciones se vuelven aún más importantes a
medida que los macrodatos, la minería de datos y el aprendizaje automático aceleran la
automatización de los algoritmos estadísticos. Por lo tanto, es importante tener una base sólida en
estadísticas y pruebas de hipótesis para no tratar estas automatizaciones como cajas negras.
En esta sección cubriremos los fundamentos de la estadística y la prueba de hipótesis.
Comenzando con estadísticas descriptivas, aprenderemos formas comunes de resumir datos.
Después de eso, nos aventuraremos en la estadística inferencial, donde trataremos de descubrir
los atributos de una población a partir de una muestra.

¿Qué son los datos?


Puede parecer extraño definir "datos", algo que todos usamos y damos por sentado. Pero creo que
hay que hacerlo. Lo más probable es que si le preguntas a cualquier persona qué son los datos,
podría responder con el efecto de “ya sabes… ¡datos! ¡Es.. ya sabes.. información! y no
aventurarse más allá de eso. Ahora parece que se comercializa como el todo y el final. La fuente no
solo de la verdad.. ¡sino de la inteligencia! Es el combustible de la inteligencia artificial y se cree
que cuantos más datos tengas, más verdad tendrás. Por lo tanto, nunca puede tener suficientes
datos. Desbloqueará los secretos necesarios para redefinir su estrategia comercial y tal vez incluso
crear inteligencia general artificial. Pero permítanme ofrecer una perspectiva pragmática sobre qué
son los datos. Los datos no son importantes en sí mismos. El análisis de los datos (y cómo se
producen) es el motor de todas estas innovaciones y soluciones.
Imagina que te proporcionaron una foto de una familia. ¿Puedes deducir la historia de esta familia
basándote en esta foto? ¿Qué pasaría si tuvieras 20 fotos? 200 fotos? 2000 fotos? ¿Cuántas fotos
necesitas para conocer su historia? ¿Necesitas fotos de ellos en diferentes situaciones? ¿Solos y
juntos? ¿Con familiares y amigos? ¿En casa y en el trabajo?
Los datos son como fotografías; proporciona instantáneas de una historia. La realidad continua y
los contextos no se capturan por completo, ni el número infinito de variables que impulsan esa
historia. Como discutiremos, los datos pueden estar sesgados. Puede tener lagunas y faltar
variables relevantes. ¡Idealmente, nos encantaría tener una cantidad infinita de datos que capturen
una cantidad infinita de variables, con tanto detalle que podríamos recrear virtualmente la realidad y
construir otras alternativas! ¿Pero es esto posible? Actualmente no. Ni siquiera las mejores
supercomputadoras del mundo combinadas pueden acercarse a capturar la totalidad del mundo
como datos.
Por lo tanto, tenemos que acotar nuestro alcance para que nuestros objetivos sean factibles. Unas
pocas fotos estratégicas del padre jugando al golf pueden decirnos fácilmente si es bueno jugando
al golf. ¿Pero tratar de descifrar toda la historia de su vida solo a través de fotos? Eso podría ser
imposible. Hay tantas cosas que no se pueden capturar en instantáneas. Estas preocupaciones
prácticas también deben aplicarse cuando se trabaja con proyectos de datos, porque los datos en
realidad son solo instantáneas de un momento dado que capturan solo lo que apuntan (muy
parecido a una cámara). Necesitamos mantener nuestros objetivos enfocados a medida que esto
se concentra en recopilar datos que sean relevantes y completos. Si hacemos que nuestros
objetivos sean amplios y abiertos, podemos tener problemas con hallazgos falses y conjuntos de
datos incompletos. Esta práctica, conocida como minería de datos, tiene un tiempo y un lugar pero
hay que hacerlo con cuidado. Volveremos sobre esto al final del capítulo.
Incluso con objetivos estrictamente definidos, aún podemos tener problemas con nuestros datos.
Volvamos a la cuestión de determinar si unas pocas fotos estratégicas pueden decir si el padre es
bueno en el golf. Quizás si tuvieras una foto de él en el medio del swing, podrías decir si estaba en
buena forma. O tal vez si lo viste animando y levantando el puño en un hoyo, puedes inferir que

50
obtuvo una buena puntuación. ¡Tal vez puedas tomar una foto de su tarjeta de puntuación! Pero es
importante tener en cuenta que todos estos casos pueden falsificarse o sacarse de contexto. Tal
vez estaba animando a otra persona, o tal vez la tarjeta de puntuación no era suya o ni siquiera era
falsa. Al igual que estas fotografías, los datos no capturan el contexto ni las explicaciones. Este es
un punto increíblemente importante porque los datos proporcionan pistas, no la verdad. Estas
pistas pueden llevarnos a la verdad o llevarnos a conclusiones erróneas.
Esta es la razón por la que tener curiosidad sobre el origen de los datos es una habilidad tan
importante. Haga preguntas sobre cómo se crearon los datos, quién los creó y qué datos no
capturan. Es demasiado fácil quedar atrapado en lo que dicen los datos y olvidarse de preguntar de
dónde provienen. Peor aún, hay sentimientos generalizados de que uno puede introducir datos en
algoritmos de aprendizaje automático y esperar que la computadora lo resuelva todo. Pero como
dice el adagio, “si entra basura, sale basura”. No es de extrañar que solo el 13 % de los proyectos
de aprendizaje automático tengan éxito, según VentureBeat. Los proyectos exitosos de aprendizaje
automático ponen el pensamiento y el análisis en los datos, así como en lo que produjo los datos.

VERDAD BÁSICA
Hablando en términos más generales, el ejemplo de la foto familiar presenta un problema de
verdad básica.
Cuando estaba dando una clase sobre la seguridad del sistema de inteligencia artificial, una vez me
hicieron una pregunta sobre cómo hacer que los autos sin conductor sean más seguros. "Cuando
un automóvil autónomo no reconoce a un peatón en el sensor de su cámara, ¿no hay alguna forma
de que reconozca la falla y se detenga?" Respondí que no, porque el sistema no tiene un marco
para la verdad fundamental, o un conocimiento verificado y completo de lo que es true. Si el
automóvil no reconoce a un peatón, ¿cómo se supone que reconocerá que no reconoce a un
peatón? No hay una verdad básica a la que recurrir, a menos que haya un operador humano que
pueda proporcionarla e intervenir.
En realidad, este es el statu quo de los automóviles y los servicios de taxi "autónomos". Algunos
sensores, como el radar, brindan verdades sobre el terreno modestamente confiables en preguntas
limitadas, como "¿Hay algo frente al vehículo?" Pero reconocer objetos basados en cámaras y
sensores LIDAR (en un entorno no controlado) es un problema de percepción mucho más borroso
con números astronómicos de combinaciones de píxeles que podría ver. Por lo tanto, la verdad
fundamental es inexistente.
¿Sus datos representan una realidad básica verificable y completa? ¿Son los sensores y las
fuentes fiables y precisos? ¿O se desconoce la verdad básica??

Estadística descriptiva versus estadística inferencial


¿Qué te viene a la mente cuando escuchas la palabra “estadística”? ¿Está calculando la media, la
mediana, la moda, los gráficos, las curvas de campana y otras herramientas para describir los
datos? Esta es la parte más comúnmente entendida de las estadísticas, llamada estadística
descriptiva, y la usamos para resumir datos. Después de todo, ¿es más significativo desplazarse
por un millón de registros de datos o resumirlos? Cubriremos esta área de estadísticas primero.
Las estadísticas inferenciales intentan descubrir atributos sobre una población más grande, a
menudo basándose en una muestra. A menudo se malinterpreta y es menos intuitiva que la
estadística descriptiva. A menudo estamos interesados en estudiar un grupo que es demasiado
grande para observar (por ejemplo, la estatura promedio de los adolescentes en América del Norte)
y tenemos que recurrir al uso de sólo unos pocos miembros de ese grupo para inferir conclusiones
sobre ellos. Como puede adivinar, esto no es fácil de hacer bien. Después de todo, estamos
tratando de representar una población con una muestra que puede no ser representativa.
Exploraremos estas advertencias a lo largo del camino.

Poblaciones, muestras y sesgo(bias)


Antes de profundizar en las estadísticas descriptivas e inferenciales, podría ser una buena idea
presentar algunas definiciones y relacionarlas con ejemplos tangibles.
Una población es un grupo particular de interés que queremos estudiar, como "todas las personas
mayores de 65 años en América del Norte", "todos los golden retrievers en Escocia" o "estudiantes
actuales de segundo año de secundaria en Los Altos High School". Observe cómo tenemos límites
para definir nuestra población. Algunos de estos límites son amplios y capturan un grupo grande en
una vasta geografía o grupo de edad. Otros son muy específicos y pequeños, como los estudiantes

51
de segundo año en la Escuela Secundaria Los Altos. Cómo perfeccionar la definición de una
población depende de lo que le interese estudiar.
Una muestra es un subconjunto de la población que es idealmente aleatorio e imparcial, que
usamos para inferir atributos sobre la población. A menudo tenemos que estudiar muestras porque
no siempre es posible encuestar a toda la población. Por supuesto, algunas poblaciones son más
fáciles de localizar si son pequeñas y accesibles. ¿Pero medir a todas las personas mayores de 65
años en América del Norte? Es poco probable que sea práctico!

¡LAS POBLACIONES PUEDEN SER ABSTRACTAS!


Es importante señalar que las poblaciones pueden ser teóricas y no físicamente tangibles. En estos
casos nuestra población actúa más como una muestra de algo abstracto. Este es mi ejemplo
favorito: estamos interesados en vuelos que salen entre las 2 p. Por lo tanto, podemos tratar esta
población como una muestra en lugar de una población subyacente de todos los vuelos teóricos
que despegan entre las 2 p. m. y las 3 p. m.
Problemas como este son la razón por la que muchos investigadores recurren a simulaciones para
generar datos. Las simulaciones pueden ser útiles, pero rara vez son precisas, ya que las
simulaciones capturan solo un número limitado de variables y tienen suposiciones incorporadas.
Si vamos a inferir atributos sobre una población a partir de una muestra, es importante que la
muestra sea lo más aleatoria posible para no sesgar nuestras conclusiones. Aquí hay un ejemplo.
Digamos que soy un estudiante universitario en la Universidad Estatal de Arizona. Quiero encontrar
el número promedio de horas que los estudiantes universitarios ven televisión por semana en los
Estados Unidos. Camino justo afuera de mi dormitorio y empiezo a encuestar a estudiantes
aleatorios que pasan caminando, terminando mi recopilación de datos en unas pocas horas. ¿Cuál
es el problema aquí??
El problema es que nuestra muestra de estudiantes tendrá un sesgo, lo que significa que
distorsionará nuestros hallazgos al sobrerepresentar a un determinado grupo a expensas de otros
grupos. Mi estudio definió la población como "estudiantes universitarios en los Estados Unidos", no
"estudiantes universitarios en la Universidad Estatal de Arizona". ¡Solo estoy encuestando a
estudiantes en una universidad específica para representar a todos los estudiantes universitarios
en todo Estados Unidos! ¿Es eso realmente justo??
Es poco probable que todas las universidades del país tengan los mismos atributos estudiantiles de
manera homogénea. ¿Qué pasa si los estudiantes del estado de Arizona miran mucha más
televisión que otros estudiantes de otras universidades? ¿Usarlos para representar a todo el país
no distorsionaría los resultados? Tal vez esto sea posible porque por lo general hace demasiado
calor para salir a la calle en Tempe, Arizona. Por lo tanto, la televisión es un pasatiempo común
(anecdóticamente, lo sabría; viví en Phoenix durante muchos años). Otros estudiantes
universitarios en climas más templados pueden hacer más actividades al aire libre y ver menos
televisión.
Esta es solo una posible variable que muestra por qué es una mala idea representar a los
estudiantes universitarios de todo Estados Unidos con solo una muestra de estudiantes de una
universidad. Idealmente, debería encuestar aleatoriamente a estudiantes universitarios de todo el
país en diferentes universidades. Así tengo una muestra más representativa.
Sin embargo, el sesgo no siempre es geográfico. Digamos que hago un esfuerzo sincero para
encuestar a los estudiantes de todo Estados Unidos. Organizo una campaña en las redes sociales
para que varias universidades compartan una encuesta en Twitter y Facebook. De esta manera,
sus estudiantes lo ven y, con suerte, lo completan. Recibo cientos de respuestas sobre los hábitos
televisivos de los estudiantes en todo el país y siento que he vencido a la bestia del prejuicio.. ¿o
no?
¿Qué pasa si los estudiantes que están lo suficiente en las redes sociales para ver la encuesta
también ven más televisión? Si están mucho en las redes sociales, probablemente no les importe el
tiempo recreativo frente a la pantalla. Es fácil imaginar que tienen Netflix y Hulu listos para
transmitir en esa otra pestaña! Este tipo particular de sesgo en el que es más probable que un
grupo específico se incluya en una muestra se conoce como sesgo de autoselección.
¡Maldita sea! Simplemente no puedes ganar, ¿verdad? Si lo piensas lo suficiente, ¡el sesgo de
datos parece inevitable! Y a menudo lo es. Tantas variables de confusión, o factores que no
tomamos en cuenta, pueden influir en nuestro estudio. Este problema de sesgo de datos es
costoso y difícil de superar, y el aprendizaje automático es especialmente vulnerable a él.

52
La forma de superar este problema es seleccionar estudiantes verdaderamente al azar de toda la
población, y no pueden elegirse a sí mismos para entrar o salir de la muestra voluntariamente. Esta
es la forma más efectiva de mitigar el sesgo, pero como puede imaginar, se necesitan muchos
recursos coordinados para hacerlo.

UN RECORRIDO VERTIGINOSO POR LOS TIPOS DE SESGO


Como humanos, estamos extrañamente programados para ser parciales. Buscamos patrones
aunque no existan. Quizás esto fue una necesidad para sobrevivir en nuestra historia temprana, ya
que encontrar patrones hace que la caza, la recolección y la agricultura sean más productivas.
Hay muchos tipos de sesgo, pero todos tienen el mismo efecto de distorsionar los hallazgos. El
sesgo de confirmación es recopilar solo datos que respalden su creencia, lo que incluso se puede
hacer sin saberlo. Un ejemplo de esto es seguir solo las cuentas de redes sociales con las que
estás políticamente de acuerdo, reforzando tus creencias en lugar de desafiarlas.
Acabamos de hablar sobre el sesgo de autoselección, que es cuando es más probable que ciertos
tipos de sujetos se incluyan en el experimento. Entrar en un vuelo y encuestar a los clientes si les
gusta la aerolínea sobre otras aerolíneas, y usar eso para clasificar la satisfacción del cliente entre
todas las aerolíneas, es una tontería. ¿Por qué? Es probable que muchos de esos clientes sean
clientes habituales y hayan creado un sesgo de autoselección. No sabemos cuántos son los que
vuelan por primera vez o los que repiten, y por supuesto, estos últimos preferirán esa aerolínea
sobre otras aerolíneas. Incluso los que vuelan por primera vez pueden ser sesgados y
autoseleccionados, porque eligieron volar en esa aerolínea y no estamos probando todas las
aerolíneas.
El sesgo de supervivencia captura solo sujetos vivos y sobrevivientes, mientras que los fallecidos
nunca se contabilizan. Es el tipo de sesgo más fascinante en mi opinión, porque los ejemplos son
diversos y no obvios.
Probablemente el ejemplo más famoso de sesgo de supervivencia es este: la Royal Air Force en la
Segunda Guerra Mundial estaba teniendo problemas con el fuego enemigo alemán que causaba
bajas en sus bombarderos. Su solución inicial fue blindar bombarderos donde se encontraran
agujeros de bala, razonando que esto mejoraría su probabilidad de supervivencia. Sin embargo, un
matemático llamado Abraham Wald les señaló que esto estaba fatalmente equivocado. Propuso
áreas de blindaje en el avión que no tenían agujeros de bala. ¿Estaba loco? Lejos de ahi. Los
bombarderos que regresaron obviamente no tuvieron daños fatales donde se encontraron agujeros
de bala. Cómo sabemos esto? ¡Porque regresaron de su misión! Pero, ¿y el avión que no regresó?
¿Dónde fueron golpeados? La teoría de Wald era "probable en las áreas intactas en el avión que
sobrevivióy regresé a la base”, y esto resultó ser correcto. Las áreas sin agujeros de bala fueron
blindadas y aumentó la capacidad de supervivencia de los aviones y los pilotos. A esta observación
poco ortodoxa se le atribuye haber cambiado el rumbo de la guerra a favor de los Aliados.
Hay otros ejemplos fascinantes de sesgo de sobreviviente que son menos obvios. A muchas
empresas de consultoría de gestión y editoriales de libros les gusta identificar las características de
las empresas/individuos exitosos y utilizarlas como predictores de éxitos futuros. Estos trabajos son
puro sesgo de supervivencia (y XKCD tiene una caricatura divertida sobre esto ). Estos trabajos no
dan cuenta de las empresas/individuos que fracasaron en la oscuridad, y estas cualidades de
"éxito" también pueden ser comunes con las fracasadas. Simplemente no hemos oído hablar de
ellos porque nunca tuvieron un centro de atención.
Un ejemplo anecdótico que me viene a la mente es Steve Jobs. En muchos aspectos, se decía que
era apasionado y temperamental.. pero también creó una de las empresas más valiosas de todos
los tiempos. Por lo tanto, algunas personas creían que ser apasionado e incluso temperamental
podría estar relacionado con el éxito. Nuevamente, este es un sesgo de sobreviviente. Estoy
dispuesto a apostar que hay muchas empresas dirigidas por líderes apasionados que fracasaron en
la oscuridad, pero nos obsesionamos y nos aferramos a historias de éxito atípicas como Apple.
Por último, en 1987 hubo un estudio veterinario que mostró que los gatos que caían desde seis
pisos o menos tenían mayores lesiones que los que caían desde más de seis pisos. Las teorías
científicas prevalecientes postularon que los gatos se enderezaban a unos cinco pisos, dándoles
tiempo suficiente para prepararse para el impacto y causar menos lesiones. Pero luego, una
publicación The Straight Dope planteó una pregunta importante: ¿qué pasó con los gatos muertos?
No es probable que las personas lleven un gato muerto al veterinario y, por lo tanto, no se informa
cuántos gatos murieron por caídas más altas. En palabras de Homero Simpson, “ ¡D'oh! ”

53
Muy bien, basta de hablar sobre poblaciones, muestras y sesgos. Pasemos a algunas matemáticas
y estadísticas descriptivas. Solo recuerde que las matemáticas y las computadoras no reconocen el
sesgo en sus datos. ¡Eso depende de usted como buen profesional de la ciencia de datos para
detectar! Siempre haga preguntas sobre cómo se obtuvieron los datos y luego analice cómo ese
proceso podría haber sesgado los datos.

MUESTRAS Y SESGO EN EL APRENDIZAJE AUTOMÁTICO


Estos problemas con el muestreo y el sesgo se extienden también al aprendizaje automático. Ya
sea regresión lineal, regresión logística o redes neuronales, se utiliza una muestra de datos para
inferir predicciones. Si esos datos están sesgados, dirigirán el algoritmo de aprendizaje automático
para sacar conclusiones sesgadas.
Hay muchos casos documentados de esto. La justicia penal ha sido una aplicación precaria del
aprendizaje automático porque ha demostrado repetidamente que está sesgada en todos los
sentidos de la palabra, discriminando a las minorías debido a conjuntos de datos con una gran
cantidad de minorías. En 2017, Volvo probó autos sin conductor que fueron enTrain ados en
conjuntos de datos que capturaban ciervos, alces y caribúes. Sin embargo, no tenía datos de
conducción en Australia y, por lo tanto, no podía reconocer a los canguros, ¡y mucho menos dar
sentido a sus movimientos de salto! Ambos son ejemplos de datos sesgados.

Estadísticas descriptivas
La estadística descriptiva es el área con la que la mayoría de la gente está familiarizada.
Tocaremos los conceptos básicos como la media, la mediana y la moda, seguidos de la varianza, la
desviación estándar y la distribución normal.

Media y media ponderada


Mean and Weighted Mean La media es el promedio de un conjunto de valores. La operación es
simple de hacer: suma los valores y divide por el número de valores. La media es útil porque
muestra dónde existe el "centro de gravedad" para un conjunto de valores observados.
La media se calcula de la misma manera tanto para poblaciones como para muestras. El ejemplo
3-1 muestra una muestra de ocho valores y cómo calcular su media en Python.
Ejemplo 3-1. Cálculo de la media en Python
# Number of pets each person owns
sample = [1, 3, 2, 5, 7, 0, 2, 3]
mean = sum(sample) / len(sample)
print(mean) # prints 2.875
Como puede ver, encuestamos a ocho personas sobre la cantidad de mascotas que tienen. La
suma de la muestra es 23 y el número de elementos de la muestra es 8, por lo que nos da una
media de 2,875 como 23/8 = 2,875.
Hay dos versiones de la media que verá: la media muestral y la media poblacional μ como se
expresa aquí:

Recuerde que el símbolo de suma ∑ significa sumar todos los elementos. La n y la N representan
el tamaño de la muestra y la población, respectivamente, pero matemáticamente representan lo
mismo: el número de elementos. Lo mismo ocurre con llamar a la media muestral (“barra x”) y a
la media poblacional μ (“mu”). Tanto como μ son el mismo cálculo, solo nombres diferentes
según se trate de una muestra o de una población con la que estemos trabajando.
Es probable que la media le resulte familiar, pero aquí hay algo menos conocido sobre la media: la
media es en realidad un promedio ponderado llamado media ponderada. La media que usamos
comúnmente le da igual importancia a cada valor. Pero podemos manipular la media y darle a cada
elemento un peso diferente:

54
Esto puede ser útil cuando queremos que algunos valores contribuyan a la media más que otros.
Un ejemplo común de esto es la ponderación de los exámenes académicos para dar una
calificación final. Si tiene tres exámenes y un examen final, y le damos a cada uno de los tres
exámenes un 20 % de peso y al examen final un 40 % de peso de la calificación final, cómo lo
expresamos es en el Ejemplo 3-2.
Ejemplo 3-2. Cálculo de una media ponderada en Python
# Three exams of .20 weight each and final exam of .40 weight
sample = [90, 80, 63, 87]
weights = [.20, .20, .20, .40]
weighted_mean = sum(s * w for s,w in zip(sample, weights)) / sum(weights)
print(weighted_mean) # prints 81.4
Ponderamos la puntuación de cada examen a través de la multiplicación correspondiente y, en
lugar de dividir por el recuento de valores, dividimos por la suma de los pesos. Las ponderaciones
no tienen que ser porcentajes, ya que cualquier número que se use para ponderar terminará siendo
proporcional. En el Ejemplo 3-3, ponderamos cada examen con "1" pero ponderamos el examen
final con "2", dándole el doble del peso de los exámenes. Seguiremos obteniendo la misma
respuesta de 81,4 ya que estos valores seguirán siendo proporcionales.
Ejemplo 3-3. Cálculo de una media ponderada en Python
# Three exams of .20 weight each and final exam of .40 weight
sample = [90, 80, 63, 87]
weights = [1.0, 1.0, 1.0, 2.0]
weighted_mean = sum(s * w for s,w in zip(sample, weights)) / sum(weights)
print(weighted_mean) # prints 81.4

Mediana
La mediana es el valor más medio en un conjunto de valores ordenados. Ordenas secuencialmente
los valores, y la mediana será el valor más central. Si tiene un número par de valores, promedia los
dos valores más centrales. Podemos ver en el Ejemplo 3-4 que la mediana del número de
mascotas en nuestra muestra es 7:
0, 1, 5, *7*, 9, 10, 14
Ejemplo 3-4. Cálculo de la mediana en Python
# Number of pets each person owns
sample = [0, 1, 5, 7, 9, 10, 14]
def median(values):
ordered = sorted(values)
print(ordered)
n = len(ordered)
mid = int(n / 2) - 1 if n % 2 == 0 else int(n/2)
if n % 2 == 0:
return (ordered[mid] + ordered[mid+1]) / 2.0
else:
return ordered[mid]
print(median(sample)) # prints 7

La mediana puede ser una alternativa útil a la media cuando los datos están sesgados por valores
atípicos o valores que son extremadamente grandes y pequeños en comparación con el resto de
los valores. Aquí hay una anécdota interesante para entender por qué. En 1986, el salario inicial
medio anual de los graduados en geografía de la Universidad de Carolina del Norte en Chapel Hill
era de 250.000 dólares. Otras universidades promediaron $22,000. Wow, UNC-CH debe tener un
programa de geografía increíble!
Pero en realidad, ¿qué tenía de lucrativo el programa de geografía de la UNC? Bueno.. Michael
Jordan fue uno de sus graduados. Uno de los jugadores de la NBA más famosos de todos los
tiempos se graduó con un título en geografía de la UNC. Sin embargo, comenzó su carrera jugando

55
baloncesto, no estudiando mapas. Obviamente, esta es una variable de confusión que ha creado
un gran valor atípico y sesgó en gran medida el promedio de ingresos.
Esta es la razón por la que la mediana puede ser preferible en situaciones con muchos valores
atípicos (como los datos relacionados con los ingresos) sobre la media. Es menos sensible a los
valores atípicos y corta los datos estrictamente por la mitad en función de su orden relativo, en
lugar de dónde se encuentran exactamente en una recta numérica. Cuando su mediana es muy
diferente de su media, eso significa que tiene un conjunto de datos sesgado con valores atípicos.

LA MEDIANA ES UN CUANTIL
Existe un concepto de cuantiles en estadística descriptiva. El concepto de cuantiles es
esencialmente el mismo que una mediana, simplemente cortando los datos en otros lugares
además del medio. La mediana es en realidad el cuantil del 50 %, o el valor detrás del cual se
encuentra el 50 % de los valores ordenados. Luego están los cuantiles del 25 %, 50 % y 75 %, que
se conocen como cuartiles porque cortan los datos en incrementos del 25 %.

Moda
La moda es el conjunto de valores que ocurre con más frecuencia. Principalmente se vuelve útil
cuando sus datos son repetitivos y desea encontrar qué valores ocurren con mayor frecuencia.
Cuando ningún valor aparece más de una vez, no hay moda. Cuando dos valores ocurren con la
misma frecuencia, el conjunto de datos se considera bimodal. En el Ejemplo 3-5, calculamos la
moda para nuestro conjunto de datos de mascotas y, efectivamente, vemos que esto es bimodal,
ya que tanto 2 como 3 ocurren con la mayor frecuencia (y con la misma frecuencia).
Ejemplo 3-5. Calculando el modo en Python
# Number of pets each person owns
from collections import defaultdict
sample = [1, 3, 2, 5, 7, 0, 2, 3]
def mode(values):
counts = defaultdict(lambda: 0)
for s in values:
counts[s] += 1
max_count = max(counts.values())
modes = [v for v in set(values) if counts[v] == max_count]
return modes
print(mode(sample)) # [2, 3]
En la práctica, el modo no se usa mucho a menos que sus datos sean repetitivos. Esto se
encuentra comúnmente con números enteros, categorías y otras variables discretas.

Varianza y desviación estándar


Variance and Standard Deviation Cuando empezamos a hablar de varianza y desviación estándar,
aquí es donde se pone interesante. Una cosa que confunde a las personas con la varianza y la
desviación estándar es que existen algunas diferencias de cálculo para la muestra frente a la
población. Haremos todo lo posible para cubrir estas diferencias claramente.

Varianza de la población y desviación estándar


Al describir datos, a menudo nos interesa medir las diferencias entre la media y cada punto de
datos. Esto nos da una idea de cuán "dispersos" están los datos.
Digamos que estoy interesado en estudiar la cantidad de mascotas que tienen los miembros de mi
personal de trabajo (tenga en cuenta que estoy definiendo esto como mi población, no como una
muestra). Tengo siete personas en mi plantilla.
Tomo la media de todas las mascotas que tienen y obtengo 6.571. Vamos a restar esta media de
cada valor. Esto nos mostrará qué tan lejos está cada valor de la media, como se muestra en la
Tabla 3-1.
Tabla 3-1. Número de mascotas que tiene mi personal
valor Significar Diferencia
0 6.571 -6.571
1 6.571 -5.571

56
5 6.571 -1.571
7 6.571 0.429
9 6.571 2.429
10 6.571 3.429
14 6.571 7.429
Visualicemos esto en una recta numérica con “X” mostrando la media en la Figura 3-1.

Figura 3-1. Visualizando la dispersión de nuestros datos, donde “X” es la media

Hmmm.. ahora considere por qué esta información puede ser útil. Las diferencias nos dan una idea
de qué tan dispersos están los datos y qué tan lejos están los valores de la media. ¿Hay alguna
manera de consolidar estas diferencias en un solo número para describir rápidamente qué tan
dispersos están los datos?
Es posible que tengas la tentación de sacar el promedio de las diferencias, pero los negativos y los
positivos se cancelarán entre sí cuando se sumen. Podríamos sumar los valores absolutos
(eliminar los signos negativos y hacer que todos los valores sean positivos). Un enfoque aún mejor
sería elevar al cuadrado estas diferencias antes de sumarlas. Esto no solo elimina los valores
negativos (porque elevar al cuadrado un número negativo lo convierte en positivo), sino que
amplifica diferencias más grandes y es matemáticamente más fácil trabajar con ellas (las derivadas
no son sencillas con valores absolutos). Después de eso, promedie las diferencias al cuadrado.
Esto nos dará la varianza, una medida de cuán dispersos están nuestros datos.
Aquí hay una fórmula matemática que muestra cómo calcular la varianza: varianza poblacional

Más formalmente, aquí está la varianza de una población:

Cálculo de la poblaciónLa variación de nuestro ejemplo favorito en Python se muestra en el


Ejemplo 3-6.
Ejemplo 3-6. Cálculo de la varianza en Python
# Number of pets each person owns
data = [0, 1, 5, 7, 9, 10, 14]
def variance(values):
mean = sum(values) / len(values)
_variance = sum((v - mean) ** 2 for v in values) / len(values)
return _variance
print(variance(data)) # prints 21.387755102040813

Entonces, la variación de la cantidad de mascotas que posee el personal de mi oficina es


21.387755. Está bien, pero ¿qué significa exactamente? Es razonable concluir que una varianza
más alta significa una mayor dispersión, pero ¿cómo relacionamos esto con nuestros datos? Este
número es mayor que cualquiera de nuestras observaciones porque elevamos y sumamos mucho,
poniéndolo en una métrica completamente diferente. Entonces, ¿cómo lo apretamos hacia abajo
para que vuelva a la escala con la que comenzamos?

57
El opuesto de un cuadrado es una raíz cuadrada, así que tomemos la raíz cuadrada de la varianza,
que nos da la desviación estándar. Esta es la variación escalada en un número expresado en
términos de "número de mascotas", lo que lo hace un poco más significativo.:

Para implementar en Python, podemos reutilizar la función variance() y sqrt() su resultado. Ahora
tenemos una función std_dev(), que se muestra en el Ejemplo 3-7.
Ejemplo 3-7. Cálculo de la desviación estándar en Python
from math import sqrt
# Number of pets each person owns
data = [0, 1, 5, 7, 9, 10, 14]
def variance(values):
mean = sum(values) / len(values)
_variance = sum((v - mean) ** 2 for v in values) / len(values)
return _variancedef std_dev(values):
def std_dev(values):
return sqrt(variance(values))
print(std_dev(data)) # prints 4.624689730353898

Al ejecutar el código en el ejemplo 3-7, verá que nuestra desviación estándar es de


aproximadamente 4,62 mascotas. Entonces podemos expresar nuestra dispersión en una escala
con la que comenzamos, y esto hace que nuestra varianza sea un poco más fácil de interpretar.
Veremos algunas aplicaciones importantes de la desviación estándar en el Capítulo 5.

¿POR QUÉ LA PLAZA?


WHY THE SQUARE? Con respecto a la varianza, si el exponente en σ2 te molesta, es porque te
pide que saques la raíz cuadrada para obtener la desviación estándar. Es un pequeño recordatorio
molesto de que estás tratando con valores cuadrados que deben tener raíces cuadradas.

Varianza muestral y desviación estándar


En la sección anterior hablamos sobre la varianza y la desviación estándar de una población. Sin
embargo, hay un ajuste importante que debemos aplicar a estas dos fórmulas cuando calculamos
para una muestra.:

¿Captaste la diferencia? Cuando promediamos las diferencias al cuadrado, dividimos por n –1 en


lugar del número total de elementos n. ¿Por qué haríamos esto? Hacemos esto para disminuir
cualquier sesgo en una muestra y no subestimar la varianza de la población basada en nuestra
muestra. Al contar valores inferiores a un elemento en nuestro divisor, aumentamos la varianza y,
por lo tanto, capturamos una mayor incertidumbre en nuestra muestra.

¿POR QUÉ RESTAMOS 1 PARA EL TAMAÑO DE LA MUESTRA?


En YouTube, Josh Starmer tiene una excelente serie de videos llamada StatQuest. En uno, brinda
un excelente desglose de por qué tratamos las muestras de manera diferente al calcular la varianza
y restamos un elemento de la cantidad de elementos.

Si los datos de nuestras mascotas fueran una muestra, no una población, deberíamos hacer ese
ajuste en consecuencia. En el Ejemplo 3-8, modifico mi código anterior de Python variance() y

58
std_dev() para proporcionar opcionalmente un parámetro is_sample, que si es True restará 1 del
divisor en la varianza.

Ejemplo 3-8. Cálculo de la desviación estándar de una muestra


from math import sqrt
# Number of pets each person owns
data = [0, 1, 5, 7, 9, 10, 14]
def variance(values, is_sample: bool = False):
mean = sum(values) / len(values)
_variance = sum((v - mean) ** 2 for v in values) /
(len(values) - (1 if is_sample else 0))
return _variance
def std_dev(values, is_sample: bool = False):
return sqrt(variance(values, is_sample))
print("VARIANCE = {}".format(variance(data, is_sample=True))) # 24.95238095238095
print("STD DEV = {}".format(std_dev(data, is_sample=True))) # 4.99523582550223

Observe en el Ejemplo 3-8 que mi varianza y desviación estándar han aumentado en comparación
con los ejemplos anteriores que los trataban como una población, no como una muestra. Recuerde
en el Ejemplo 3-7 que la desviación estándar fue de aproximadamente 4.62 tratándose como una
población. Pero aquí, tratándolo como una muestra (al restar 1 del denominador de la varianza),
obtenemos aproximadamente 4,99. Esto es correcto ya que una muestra podría estar sesgada e
imperfecta al representar a la población. Por lo tanto, aumentamos la varianza (y, por lo tanto, la
desviación estándar) para aumentar nuestra estimación de cuán dispersos están los valores. Una
varianza/desviación estándar más grande muestra menos confianza con un rango más grande.
Al igual que la media ( x ¯ para la muestra y μ para la población), a menudo verá ciertos
símbolos para la varianza y la desviación estándar. La desviación estándar para una muestra y la
media se especifican mediante s y σ, respectivamente. Aquí nuevamente están las fórmulas de
desviación estándar de la muestra y la población:

La varianza será el cuadrado de estas dos fórmulas, deshaciendo la raíz cuadrada. Por lo tanto, la
varianza para la muestra y la población son s2 y σ2, respectivamente:

Nuevamente, el cuadrado ayuda a implicar que se debe tomar una raíz cuadrada para
obtener la desviación estándar.

La distribución normal
Hablamos de las distribuciones de probabilidad en el último capítulo, en particular la
distribución binomial y la distribución beta. Sin embargo, la distribución más famosa de
todas es la distribución normal. La distribución normal, también conocida como distribución

59
gaussiana, es una distribución simétrica en forma de campana que tiene la mayor parte de
la masa alrededor de la media y su dispersión se define como una desviación estándar.
Las "colas" a ambos lados se vuelven más delgadas a medida que se aleja de la media.
La figura 3-2 es una distribución normal para los pesos de los golden retrievers. Observe
cómo la mayor parte de la masa está alrededor de la media de 64,43 libras.

Figura 3-2. Una distribución normal

Descubriendo la Distribución Normal


La distribución normal se ve mucho en la naturaleza, la ingeniería, la ciencia y otros dominios.
¿Cómo lo descubrimos? Digamos que tomamos una muestra del peso de 50 golden retrievers
adultos y los representamos en una recta numérica como se muestra en la figura 3-3.

Figura 3-3. Una muestra de 50 pesas golden retriever

Observe cómo tenemos más valores hacia el centro, pero a medida que nos movemos más hacia
la izquierda o hacia la derecha vemos menos valores. Según nuestra muestra, parece muy poco
probable que veamos un golden retriever con un peso de 57 o 71. ¿Pero con un peso de 64 o 65?
Sí, eso ciertamente parece probable.
¿Hay una mejor manera de visualizar esta probabilidad de ver qué pesos de golden retriever es
más probable que veamos muestreados de la población? Podemos intentar crear un histograma,
que agrupe (o "clasifique") valores en función de rangos numéricos de igual longitud, y luego use
un gráfico de barras que muestre la cantidad de valores dentro de cada rango. En la Figura 3-4
creamos un histograma que agrupa valores en rangos de 0,5 libras.
Este histograma no revela ninguna forma significativa para nuestros datos. La razón es que
nuestros contenedores son demasiado pequeños. No tenemos una cantidad de datos
extremadamente grande o infinita para tener suficientes puntos en cada contenedor. Por lo tanto,
tendremos que hacer nuestros contenedores más grandes. Hagamos que los contenedores tengan
cada uno una longitud de tres libras, como en la Figura 3-5.

60
Figura 3-4. Un histograma de pesos de golden retriever

Figura 3-5. Un histograma más productivo

¡Ahora estamos llegando a alguna parte! Como puede ver, si obtenemos los tamaños de
contenedor correctos (en este caso, cada uno tiene un rango de tres libras), comenzamos a
obtener una forma de campana significativa para nuestros datos. No es una forma de campana
perfecta porque nuestras muestras nunca serán perfectamente representativas de la población,
pero es probable que esto sea evidencia de que nuestra muestra sigue una distribución normal. Si
ajustamos un histograma con tamaños de contenedores adecuados y lo escalamos para que tenga
un área de 1,0 (lo que requiere una distribución de probabilidad), vemos una curva de campana
aproximada que representa nuestra muestra. Mostrémoslo junto con nuestros puntos de datos
originales en la Figura 3-6.
Mirando esta curva de campana, podemos esperar razonablemente que un golden retriever tenga
un peso de alrededor de 64.43 (la media) pero poco probable de 55 o 73. Cualquier cosa más
extrema que eso se vuelve muy poco probable.

61
Figura 3-6. Una distribución normal ajustada a puntos de datos

Propiedades de una distribución normal


La distribución normal tiene varias propiedades importantes que la hacen útil:
 Es simétrico; ambos lados se reflejan idénticamente en la media, que es el centro.
 La mayor parte de la masa está en el centro alrededor de la media.
 Tiene una extensión (ya sea estrecha o ancha) que se especifica mediante la desviación
estándar.
 Las "cruces" son los resultados menos probables y se acercan infinitamente a cero, pero
nunca tocan cero.
 Se asemeja a muchos fenómenos de la naturaleza y de la vida cotidiana, e incluso
generaliza problemas no normales por el teorema del límite central, del que hablaremos en
breve.
La función de densidad de probabilidad (PDF)
La desviación estándar juega un papel importante en la distribución normal, porque define qué tan
"dispersa" está. En realidad, es uno de los parámetros junto con la media. La función de densidad
de probabilidad (PDF) que crea la distribución normal es la siguiente:

Wow, eso es un bocado, ¿no? Incluso vemos el Número e de nuestro amigo Euler del Capítulo 1
y algunos exponentes locos. Así es como podemos expresarlo en Python en el Ejemplo 3-9.
Ejemplo 3-9. La función de distribución normal en Python
# normal distribution, returns likelihood
def normal_pdf(x: float, mean: float, std_dev: float) -> float:
return (1.0 / (2.0 * math.pi * std_dev ** 2) ** 0.5) *
math.exp(-1.0 * ((x - mean) ** 2 / (2.0 * std_dev ** 2)))

Hay mucho que desglosar aquí en esta fórmula, pero lo importante es que acepta una media y una
desviación estándar como parámetros, así como un valor x para que pueda buscar la probabilidad
en ese valor dado.
Al igual que la distribución beta del Capítulo 2, la distribución normal es continua. Esto significa que
para recuperar una probabilidad necesitamos integrar un rango de valores de x para encontrar un
área.
Sin embargo, en la práctica, usaremos SciPy para hacer estos cálculos por nosotros.

La función de distribución acumulativa (CDF Cumulative Distribution Function)


Con la distribución normal, el eje vertical no es la probabilidad sino la probabilidad de los datos.
Para encontrar la probabilidad, necesitamos mirar un rango dado y luego encontrar el área bajo la

62
curva para ese rango. Digamos que quiero encontrar la probabilidad de que un golden retriever
pese entre 62 y 66 libras. La figura 3-7 muestra el rango para el que queremos encontrar el área.

Figura 3-7. Un CDF que mide la probabilidad entre 62 y 66 libras

Ya hicimos esta tarea en el Capítulo 2 con la distribución beta y, al igual que la distribución beta,
existe una función de densidad acumulada (CDF cumulative density function). Sigamos este
enfoque.
Como aprendimos en el último capítulo, la CDF proporciona el área hasta un valor x dado para una
distribución dada. Veamos cómo se ve el CDF para nuestra distribución normal de golden retriever
y colóquelo junto al PDF como referencia en la Figura 3-8.

Figura 3-8. Un PDF junto con su CDF

Observe que hay una relación entre los dos gráficos. La CDF, que es una curva en forma de S
(llamada curva sigmoidea), proyecta el área hasta ese rango en la PDF. Observe en la Figura 3-9
que cuando capturamos el área desde el infinito negativo hasta 64,43 (la media), nuestra CDF
muestra un valor de exactamente 0,5 o 50 %.!

63
Figura 3-9. Un PDF y CDF para los pesos de golden retriever que miden la probabilidad hasta la
media

Esta área de 0,5 o 50 % hasta la media se conoce debido a la simetría de nuestra distribución
normal, y podemos esperar que el otro lado de la curva de campana también tenga el 50 % del
área.
Para calcular esta área hasta 64,43 en Python usando SciPy, use la función norm.cdf() como se
muestra en el Ejemplo 3-10.
Ejemplo 3-10. La distribución normal CDF en Python
from scipy.stats import norm

mean = 64.43
std_dev = 2.99

x = norm.cdf(64.43, mean, std_dev)

print(x) # prints 0.5


Al igual que hicimos en el Capítulo 2, podemos encontrar deductivamente el área de un rango
medio restando áreas. Si quisiéramos encontrar la probabilidad de observar un golden retriever
entre 62 y 66 libras, calcularíamos el área hasta 66 y restaríamos el área hasta 62 como se
muestra en la figura 3-10.

Figura 3-10. Encontrar un rango medio de probabilidad

64
Hacer esto en Python usando SciPy es tan simple como restar las dos operaciones CDF que se
muestran en el Ejemplo 3-11.
Ejemplo 3-11. Obtener una probabilidad de rango medio usando la CDF
from scipy.stats import norm

mean = 64.43
std_dev = 2.99

x = norm.cdf(66, mean, std_dev) - norm.cdf(62, mean, std_dev)


print(x) # prints 0.4920450147062894

Debe encontrar que la probabilidad de observar un golden retriever entre 62 y 66 libras es 0.4920,
o aproximadamente 49.2%.

La CDF inversa
Cuando comencemos a hacer pruebas de hipótesis más adelante en este capítulo, encontraremos
situaciones en las que necesitamos buscar un área en la CDF y luego devolver el valor x
correspondiente. Por supuesto, este es un uso inverso de la CDF, por lo que necesitaremos usar la
CDF inversa, que invierte los ejes como se muestra en la Figura 3-11.
De esta forma, ahora podemos buscar una probabilidad y luego devolver el valor x correspondiente,
y en SciPy usaríamos la función norm.ppf(). Por ejemplo, quiero encontrar el peso en el que se
encuentran el 95 % de los golden retrievers. Esto es fácil de hacer cuando uso la CDF inversa en el
ejemplo 3-12.

Figura 3-11. La CDF inversa, también llamada PPF o función cuantil

Ejemplo 3-12. Usando el CDF inverso (llamado ppf() ) en Python


from scipy.stats import norm
x = norm.ppf(.95, loc=64.43, scale=2.99)
print(x) # 69.3481123445849

Encuentro que el 95% de los golden retrievers pesan 69.348 libras o menos.
También puede usar la CDF inversa para generar números aleatorios que sigan la distribución
normal. Si quiero crear una simulación que genere mil pesos realistas de golden retriever, solo
genero un valor aleatorio entre 0.0 y 1.0, lo paso a la CDF inversa y devuelvo el valor del peso
como se muestra en el Ejemplo 3-13.
Ejemplo 3-13. Generación de números aleatorios a partir de una distribución normal
import random
from scipy.stats import norm
for i in range(0,1000):
random_p = random.uniform(0.0, 1.0)
random_weight = norm.ppf(random_p, loc=64.43, scale=2.99)
print(random_weight)

65
Por supuesto, NumPy y otras bibliotecas pueden generar valores aleatorios a partir de una
distribución para usted, pero esto destaca un caso de uso en el que la CDF inversa es útil.

CDF Y CDF INVERSA DESDE CERO


Para aprender a implementar la CDF y la CDF inversa desde cero en Python, consulte el Apéndice
A.

Puntuaciones Z
Z-Scores Es común cambiar la escala de una distribución normal para que la media sea 0 y la
desviación estándar sea 1, lo que se conoce como distribución normal estándar. Esto facilita la
comparación de la dispersión de una distribución normal con otra distribución normal, incluso si
tienen diferentes medias y varianzas.
De particular importancia con la distribución normal estándar es que expresa todos los valores de x
en términos de desviaciones estándar, conocidas como puntuaciones Z. Convertir un valor x en una
puntuación Z utiliza una fórmula de escala básica:

Aquí hay un ejemplo. Tenemos dos viviendas de dos barrios diferentes. El vecindario A tiene un
valor promedio de vivienda de $140,000 y una desviación estándar de $3,000. El vecindario B tiene
un valor medio de vivienda de $800 000 y una desviación estándar de $10 000.
μA = 140,000
μB = 800,000
σA = 3,000
σB = 10,000
Ahora tenemos dos casas de cada barrio. La casa A del barrio A vale $150 000 y la casa B del
barrio B vale $815 000. ¿Qué casa es más cara en relación con la casa promedio en su vecindario?
xA = 150,000
xB = 815,000
Si expresamos estos dos valores en términos de desviaciones estándar, podemos compararlos en
relación con la media de cada vecindario. Utilice la fórmula de puntuación Z:

Entonces, la casa en el vecindario A es en realidad mucho más cara en relación con su vecindario
que la casa en el vecindario B, ya que tienen puntajes Z de y 1.5, respectivamente.
Así es como podemos convertir un valor de x proveniente de una distribución dada con una media y
una desviación estándar en un puntaje Z, y viceversa, como se muestra en el Ejemplo 3-14.
Ejemplo 3-14. Convierta las puntuaciones Z en valores x y viceversa
def z_score(x, mean, std):
return (x - mean) / std
def z_to_x(z, mean, std):
return (z * std) + mean
mean = 140000
std_dev = 3000
x = 150000
# Convert to Z-score and then back to X
z = z_score(x, mean, std_dev)

66
back_to_x = z_to_x(z, mean, std_dev)
print("Z-Score: {}".format(z)) # Z-Score: 3.333
print("Back to X: {}".format(back_to_x)) # Back to X: 150000.0

La función z_score() tomará un valor x y lo escalará en términos de desviaciones estándar, dada


una media y una desviación estándar. La función z_to_x() toma una puntuación Z y la vuelve a
convertir en un valor x. Estudiando las dos funciones, puedes ver su relación algebraica, una
resolviendo para el puntaje Z y la otra para el valor de x. Luego convertimos un valor x de 8.0 en un
puntaje Z de y luego convertimos ese puntaje Z nuevamente en un valor x.

COEFICIENTE DE VARIACIÓN
Una herramienta útil para medir la dispersión es el coeficiente de variación. Compara dos
distribuciones y cuantifica la dispersión de cada una de ellas. Es simple de calcular: divide la
desviación estándar por la media. Aquí está la fórmula junto con el ejemplo que compara dos
vecindarios:

Como se ve aquí, el barrio A, aunque es más barato que el barrio B, tiene más dispersión y, por lo
tanto, más diversidad de precios que el barrio B.

Estadística inferencial
Inferential Statistics La estadística descriptiva, que hemos cubierto hasta ahora, se entiende
comúnmente. Sin embargo, cuando nos adentramos en la estadística inferencial, las relaciones
abstractas entre la muestra y la población entran en pleno juego. Estos matices abstractos no son
algo por lo que quieras apresurarte, sino que te tomes tu tiempo y los absorbas cuidadosamente.
Como se indicó anteriormente, estamos programados como humanos para ser parciales y llegar
rápidamente a conclusiones. Ser un buen profesional de la ciencia de datos requiere que suprimas
ese deseo primario y consideres la posibilidad de que puedan existir otras explicaciones. Es
aceptable (quizás incluso ilustrado) teorizar que no hay ninguna explicación y que un hallazgo es
solo una coincidencia y al azar.
Primero, comencemos con el teorema que sienta las bases para todas las estadísticas
inferenciales.

El teorema del límite central


Una de las razones por las que la distribución normal es útil es porque aparece mucho en la
naturaleza, como los pesos de los golden retriever adultos. Sin embargo, aparece en un contexto
más fascinante fuera de las poblaciones naturales. Cuando comenzamos a medir muestras lo
suficientemente grandes de una población, incluso si esa población no sigue una distribución
normal, la distribución normal sigue apareciendo.
Supongamos que estoy midiendo una población que es verdadera y uniformemente aleatoria.
Cualquier valor entre 0,0 y 1,0 es igualmente probable y ningún valor tiene preferencia. Pero
sucede algo fascinante cuando tomamos muestras cada vez más grandes de esta población,
tomamos el promedio de cada una y luego las representamos en un histograma. Ejecute este
código de Python en el Ejemplo 3-15 y observe la gráfica en la Figura 3-12.
Ejemplo 3-15. Explorando el teorema del límite central en Python
# Samples of the uniform distribution will average out to a normal distribution.
import random
import plotly.express as px
sample_size = 31
sample_count = 1000
# Central limit theorem, 1000 samples each with 31
# random numbers between 0.0 and 1.0
x_values = [(sum([random.uniform(0.0, 1.0) for i in range(sample_size)]) / \

67
sample_size)
for _ in range(sample_count)]
y_values = [1 for _ in range(sample_count)]
px.histogram(x=x_values, y = y_values, nbins=20).show()

Figura 3-12. Tomar las medias de las muestras (cada una de tamaño 31) y graficarlas
Espere, ¿cómo los números aleatorios uniformes, cuando se muestrearon como grupos de 31 y
luego se promediaron, formaron aproximadamente una distribución normal? Cualquier número es
igualmente probable, ¿verdad? ¿No debería la distribución ser plana en lugar de curva de
campana?
Esto es lo que está sucediendo. Los números individuales en las muestras por sí solos no crearán
una distribución normal. La distribución será plana donde cualquier número sea igualmente
probable (lo que se conoce como distribución uniforme ). Pero cuando los agrupamos como
muestras y los promediamos, forman una distribución normal.
Esto se debe al teorema del límite central, que establece que suceden cosas interesantes cuando
tomamos muestras lo suficientemente grandes de una población, calculamos la media de cada una
y las representamos como una distribución:
1. La media de las medias muestrales es igual a la media poblacional.
2. Si la población es normal, entonces las medias muestrales serán normales.
3. Si la población no es normal, pero el tamaño de la muestra es mayor que 30, las medias
de la muestra seguirán formando aproximadamente una distribución normal.
4. La desviación estándar de las medias de la muestra es igual a la desviación estándar de
la población dividida por la raíz cuadrada de n :

¿Por qué es importante todo lo anterior? Estos comportamientos nos permiten inferir cosas útiles
sobre poblaciones basadas en muestras, incluso para poblaciones no normales. Si modifica el
código anterior y prueba tamaños de muestra más pequeños de 1 o 2, no verá surgir una
distribución normal. Pero a medida que se acerca a 31 o más, verá que convergemos en una
distribución normal, como se muestra en la figura 3-13.

68
Figura 3-13. Los tamaños de muestra más grandes se aproximan a la distribución normal

Treinta y uno es el número de libro de texto en estadística porque es cuando nuestra distribución
de muestra a menudo converge en la distribución de población, particularmente cuando medimos
medias de muestra u otros parámetros. Cuando tiene menos de 31 elementos en su muestra, es
cuando tiene que confiar en la distribución T en lugar de la distribución normal, que tiene colas
cada vez más anchas cuanto más pequeño es el tamaño de la muestra. Hablaremos brevemente
de esto más adelante, pero primero supongamos que tenemos al menos 31 elementos en nuestras
muestras cuando hablamos de intervalos de confianza y pruebas.

¿CUÁNTA MUESTRA ES SUFICIENTE?


Si bien 31 es el número de libros de texto de elementos que necesita en una muestra para
satisfacer el teorema del límite central y ver una distribución normal, a veces este no es el caso.
Hay casos en los que necesitará una muestra aún más grande, como cuando la distribución
subyacente es asimétrica o multimodal (lo que significa que tiene varios picos en lugar de uno en la
media).
En resumen, tener muestras más grandes es mejor cuando no está seguro de la distribución de
probabilidad subyacente. Puedes leer más en este artículo.

Intervalos de confianza
Es posible que haya escuchado el término "intervalo de confianza", que a menudo confunde a los
recién llegados a la estadística y a los estudiantes. Un intervalo de confianza es un cálculo de
rango que muestra con qué confianza creemos que la media de una muestra (u otro parámetro)
cae en un rango para la media de la población.
Con base en una muestra de 31 golden retrievers con una media muestral de 64,408 y una
desviación estándar muestral de 2,05, estoy 95 % seguro de que la media poblacional se
encuentra entre 63,686 y 65,1296. ¿Cómo sé esto? Déjame mostrarte, y si te confundes, regresa a
este párrafo y recuerda lo que estamos tratando de lograr. Lo destaqué por una razón.!
Primero comienzo eligiendo un nivel de confianza (LOC level of confidence), que contendrá la
probabilidad deseada para el rango medio de la población. Quiero estar 95 % seguro de que la
media de mi muestra se encuentra en el rango de la media de la población que calcularé. Ese es mi
LOC. Podemos aprovechar el teorema del límite central e inferir cuál es este rango para la media
de la población. Primero, necesito el valor z crítico, que es el rango simétrico en una distribución
normal estándar que me da una probabilidad del 95 % en el centro, como se destaca en la Figura
3-14.
¿Cómo calculamos este rango simétrico que contiene.95 del área? Es más fácil de entender como
concepto que como cálculo. Es posible que instintivamente desee utilizar el CDF, pero luego puede
darse cuenta de que hay algunas partes móviles más aquí.
Primero necesitas aprovechar el CDF inverso. Lógicamente, para obtener el 95% del área simétrica
en el centro, cortaríamos las colas que tienen el 5% restante del área. Dividir el 5 % restante del
área por la mitad nos daría un 2,5 % de área en cada cola. Por lo tanto, las áreas para las que
queremos buscar los valores de x son.025 y.975, como se muestra en la Figura 3-15.

69
Figura 3-14. 95% de probabilidad simétrica en el centro de una distribución normal estándar

Figura 3-15. Queremos los valores de x que nos den áreas.025 y.975

Podemos buscar el valor x para el área 0,025 y el valor x para el área 0,975, y eso nos dará
nuestro rango central que contiene el 95 % del área. Luego devolveremos los valores z inferior y
superior correspondientes que contienen esta área. Recuerde, estamos usando la distribución
normal estándar aquí, por lo que serán iguales, aparte de ser positivos/negativos. Calculemos esto
en Python como se muestra en el Ejemplo 3-16.
Ejemplo 3-16. Recuperación de un valor z crítico
from scipy.stats import norm
def critical_z_value(p):
norm_dist = norm(loc=0.0, scale=1.0)
left_tail_area = (1.0 - p) / 2.0
upper_area = 1.0 - ((1.0 - p) / 2.0)
return norm_dist.ppf(left_tail_area), norm_dist.ppf(upper_area)
print(critical_z_value(p=.95))
# (-1.959963984540054, 1.959963984540054)
Bien, entonces obtenemos ±1.95996, que es nuestro valor z crítico que captura el 95 % de
probabilidad en el centro de la distribución normal estándar. A continuación, aprovecharé el
teorema del límite central para producir el margen de error (E), que es el rango alrededor de la
media de la muestra que contiene la media de la población en ese nivel de confianza. Recuerde
que nuestra muestra de 31 golden retrievers tiene una media de 64,408 y una desviación estándar
de 2,05. La fórmula para obtener este margen de error es:

70
E = ±0.72164
Si aplicamos ese margen de error contra la media de la muestra, ¡finalmente obtenemos el intervalo
de confianza!
95% confidence interval = 64.408 ± 0.72164
Así es como calculamoseste intervalo de confianza en Python de principio a fin en el Ejemplo 3-17.
Ejemplo 3-17. Cálculo de un intervalo de confianza en Python
from math import sqrt
from scipy.stats import norm
def critical_z_value(p):
norm_dist = norm(loc=0.0, scale=1.0)
left_tail_area = (1.0 - p) / 2.0
upper_area = 1.0 - ((1.0 - p) / 2.0)
return norm_dist.ppf(left_tail_area), norm_dist.ppf(upper_area)
def confidence_interval(p, sample_mean, sample_std, n):
# Sample size must be greater than 30
lower, upper = critical_z_value(p)
lower_ci = lower * (sample_std / sqrt(n))
upper_ci = upper * (sample_std / sqrt(n))
return sample_mean + lower_ci, sample_mean + upper_ci
print(confidence_interval(p=.95, sample_mean=64.408, sample_std=2.05, n=31))
# (63.68635915701992, 65.12964084298008)

Entonces, la forma de interpretar esto es "basado en mi muestra de 31 pesos de golden retriever


con una media de muestra de 64,408 y una desviación estándar de muestra de 2,05, tengo un 95
% de confianza en que la media de la población se encuentra entre 63,686 y 65,1296". Así es como
describimos nuestro intervalo de confianza.
Una cosa interesante a tener en cuenta aquí también es que en nuestra fórmula de margen de
error, cuanto más grande se vuelve n, más estrecho se vuelve nuestro intervalo de confianza. Esto
tiene sentido porque si tenemos una muestra más grande, tenemos más confianza en que la media
de la población cae en un rango más pequeño, por lo que se llama intervalo de confianza.
Una advertencia para poner aquí es que para que esto funcione, nuestro tamaño de muestra debe
ser de al menos 31 artículos. Esto se remonta al teorema del límite central. Si queremos aplicar un
intervalo de confianza a una muestra más pequeña, necesitamos usar una distribución con mayor
varianza (colas más gruesas que reflejan más incertidumbre). Para esto sirve la distribución T, y lo
veremos al final de este capítulo.
En el Capítulo 5 continuaremos usando intervalos de confianza para regresiones lineales.

Comprender los valores P


Cuando decimos que algo es estadísticamente significativo, ¿qué queremos decir con eso? Oímos
que se usa libremente y con frecuencia, pero ¿qué significa matemáticamente? Técnicamente,
tiene que ver con algo llamado valor p, que es un concepto difícil de comprender para muchas
personas. Pero creo que el concepto de valores p tiene más sentido cuando lo rastreas hasta su
invención. Si bien este es un ejemplo imperfecto, transmite algunas ideas importantes.
En 1925, el matemático Ronald Fisher estaba en una fiesta. Una de sus colegas, Muriel Bristol,
afirmó que podía detectar cuándo se vertía el té antes que la leche simplemente probándolo.
Intrigado por la afirmación, Ronald montó un experimento en el acto.
Preparó ocho tazas de té. A cuatro les sirvieron leche primero; a los otros cuatro les sirvieron el té
primero. Luego se los presentó a su colega experto y le pidió que identificara el orden de vertido de
cada uno. Sorprendentemente, los identificó a todos correctamente, y la probabilidad de que esto
suceda por casualidad es de 1 en 70, o 0,01428571.
Esta probabilidad del 1,4% es lo que llamamos el valor p, la probabilidad de que algo ocurra por
casualidad y no por una explicación hipotética. Sin caer en la madriguera del conejo de las

71
matemáticas combinatorias, la probabilidad de que Muriel haya acertado por completo las copas es
del 1,4 %. ¿Qué te dice eso exactamente?
Cuando enmarcamos un experimento, ya sea para determinar si las donas orgánicas causan
aumento de peso o si vivir cerca de las líneas eléctricas causa cáncer, siempre tenemos que
considerar la posibilidad de que la suerte aleatoria haya jugado un papel. Al igual que hay un 1,4 %
de posibilidades de que Muriel haya identificado correctamente las tazas de té simplemente
adivinando, siempre existe la posibilidad de que la aleatoriedad nos dé una buena mano como una
máquina tragamonedas. Esto nos ayuda a enmarcar nuestra hipótesis nula (H 0 ), diciendo que la
variable en cuestión no tuvo impacto en el experimento y que cualquier resultado positivo es solo
suerte aleatoria. La hipótesis alternativa (H 1 ) plantea que una variable en cuestión (llamada
variable controlada ) está provocando un resultado positivo.
Tradicionalmente, el umbral de significación estadística es un valor p del 5 % o menos, o 0,05.
Dado que.014 es menor que.05, esto significaría que podemos rechazar nuestra hipótesis nula de
que Muriel estaba adivinando al azar. Entonces podemos promover la hipótesis alternativa de que
Muriel tenía una habilidad especial para detectar si se sirvió té o leche primero.
Ahora, una cosa que este ejemplo de la fiesta del té no capturó es que cuando calculamos un valor
p, capturamos todas las probabilidades de ese evento o menos. Abordaremos esto a medida que
nos sumerjamos en el siguiente ejemplo usando la distribución normal.

Prueba de hipótesis
Estudios anteriores han demostrado que el tiempo medio de recuperación de un resfriado es de 18
días, con una desviación estándar de 1,5 días, y sigue una distribución normal.
Esto significa que hay aproximadamente un 95 % de posibilidades de que la recuperación tarde
entre 15 y 21 días, como se muestra en la Figura 3-16 y el Ejemplo 3-18.

Figura 3-16. Hay un 95% de posibilidades de recuperación entre 15 y 21 días

Ejemplo 3-18. Cálculo de la probabilidad de recuperación entre 15 y 21 días


from scipy.stats import norm
# Cold has 18 day mean recovery, 1.5 std dev
mean = 18
std_dev = 1.5
# 95% probability recovery time takes between 15 and 21 days.
x = norm.cdf(21, mean, std_dev) - norm.cdf(15, mean, std_dev)
print(x) # 0.9544997361036416

Podemos inferir entonces del 5 % de probabilidad restante que hay un 2,5 % de


posibilidades de que la recuperación tarde más de 21 días y un 2,5 % de que tarde menos
de 15 días. ¡Guarde esa información porque será crítica más adelante! Eso impulsa
nuestro valor p.
Ahora, digamos que se administró un nuevo medicamento experimental a un grupo de
prueba de 40 personas, y les tomó un promedio de 16 días recuperarse del resfriado, como
se muestra en la Figura 3-17.

72
Figura 3-17. Un grupo que tomaba una droga tardó 16 días en recuperarse

¿La droga tuvo un impacto? Si razona lo suficiente, puede darse cuenta de que lo que estamos
preguntando es esto: ¿el fármaco muestra un resultado estadísticamente significativo? ¿O el
medicamento no funcionó y la recuperación de 16 días fue una coincidencia con el grupo de
prueba? Esa primera pregunta enmarca nuestra hipótesis alternativa, mientras que la segunda
pregunta enmarca nuestra hipótesis nula.
Hay dos formas en que podemos calcular esto: la prueba de una cola y la de dos colas.
Comenzaremos con el de una cola.

Prueba de una cola


Cuando nos acercamos a la prueba de una cola, típicamente enmarcamos nuestras hipótesis nula
y alternativa usando desigualdades. Formulamos una hipótesis sobre la media de la población y
decimos que es mayor o igual a 18 (la hipótesis nula H 0) o menor que 18 (la hipótesis alternativa
H1):
H : population mean ≥ 18
0

H1 : population mean < 18


Para rechazar nuestra hipótesis nula, necesitamos demostrar que nuestra media muestral de los
pacientes que tomaron el fármaco probablemente no haya sido coincidente. Dado que un valor p
de.05 o menos tradicionalmente se considera estadísticamente significativo, lo usaremos como
nuestro umbral ( Figura 3-17 ). Cuando calculamos esto en Python usando el CDF inverso como se
muestra en la Figura 3-18 y el Ejemplo 3-19, encontramos que aproximadamente 15.53 es el
número de días de recuperación que nos da.05 de área en la cola izquierda.

Figura 3-18. Obtener el valor de x con el 5 % del área detrás

Ejemplo 3-19. Código de Python para obtener el valor x con el 5 % del área detrás
from scipy.stats import norm
# Cold has 18 day mean recovery, 1.5 std dev
mean = 18
std_dev = 1.5
# What x-value has 5% of area behind it?

73
x = norm.ppf(.05, mean, std_dev)
print(x) # 15.53271955957279
Por lo tanto, si logramos un promedio de 15,53 días o menos de tiempo de recuperación en nuestro
grupo de muestra, nuestro medicamento se considera estadísticamente lo suficientemente
significativo como para haber mostrado un impacto. Sin embargo, nuestra media muestral de
tiempo de recuperación es en realidad 16 días y no cae en esta zona de rechazo de hipótesis nula.
Por lo tanto, la prueba de significancia estadística ha fallado como se muestra en la Figura 3-19.

Figura 3-19. No hemos podido probar que el resultado de nuestra prueba de drogas sea
estadísticamente significativo.

El área hasta esa marca de 16 días es nuestro valor p, que es.0912, y lo calculamos en Python
como se muestra en el Ejemplo 3-20.
Ejemplo 3-20. Cálculo del valor p de una cola
from scipy.stats import norm
# Cold has 18 day mean recovery, 1.5 std dev
mean = 18
std_dev = 1.5
# Probability of 16 or less days
p_value = norm.cdf(16, mean, std_dev)
print(p_value) # 0.09121121972586788

Dado que el valor p de 0,0912 es mayor que nuestro umbral de significancia estadística de 0,05, no
consideramos que el ensayo del fármaco haya sido un éxito y no rechazamos nuestra hipótesis
nula.

Prueba de dos colas


Two-Tailed Test La prueba anterior que realizamos se llama prueba de una cola porque busca
significación estadística solo en una cola. Sin embargo, a menudo es más seguro y una mejor
práctica usar una prueba de dos colas. Explicaremos por qué, pero primero calculémoslo.
Para hacer una prueba de dos colas, enmarcamos nuestra hipótesis nula y alternativa en una
estructura "igual" y "no igual". En nuestra prueba de drogas, diremos que la hipótesis nula tiene un
tiempo medio de recuperación de 18 días. Pero nuestra hipótesis alternativa es que el tiempo
medio de recuperación no es de 18 días, gracias al nuevo fármaco:
H : population mean = 18
0

H1 : population mean ≠ 18
Esto tiene una implicación importante. Estamos estructurando nuestra hipótesis alternativa para no
probar si el fármaco mejora el tiempo de recuperación del frío, pero si tuvo algún impacto. Esto
incluye probar si aumentó la duración del resfriado. ¿Es esto útil? Sostenga ese pensamiento.

Naturalmente, esto significa que extendemos nuestro umbral de significancia estadística del valor p
a ambas colas, no solo a una. Si estamos probando una significación estadística del 5 %, entonces
la dividimos y le damos a cada 2,5 % la mitad de cada cruz. Si el tiempo medio de recuperación de

74
nuestro fármaco cae en cualquier región, nuestra prueba tiene éxito y rechazamos la hipótesis nula
( Figura 3-20 ).

Figura 3-20. Una prueba de dos colas

Los valores de x para la cola inferior y la cola superior son 15,06 y 20,93, lo que significa que si
estamos por debajo o por encima, respectivamente, rechazamos la hipótesis nula. Esos dos
valores se calculan utilizando la CDF inversa que se muestra en la Figura 3-21 y el Ejemplo 3-21.
Recuerde, para obtener la cola superior, tomamos.95 y luego le agregamos el umbral de
significancia de.025, lo que nos da.975.

Figura 3-21. Cálculo del 95% central del área de distribución normal

Ejemplo 3-21. Cálculo de un rango para una significancia estadística del 5 %


from scipy.stats import norm
# Cold has 18 day mean recovery, 1.5 std dev
mean = 18
std_dev = 1.5
# What x-value has 2.5% of area behind it?
x1 = norm.ppf(.025, mean, std_dev)
# What x-value has 97.5% of area behind it
x2 = norm.ppf(.975, mean, std_dev)
print(x1) # 15.060054023189918
print(x2) # 20.93994597681008

El valor medio de la muestra para el grupo de prueba de drogas es 16, y 16 no es inferior a 15,06 ni
superior a 20,9399. Entonces, al igual que la prueba de una cola, aún no podemos rechazar la

75
hipótesis nula. Nuestro fármaco aún no ha mostrado ninguna significación estadística para tener
algún impacto, como se muestra en la Figura 3-22.

Figura 3-22. La prueba de dos colas no ha podido probar la significación estadística

Pero, ¿cuál es el valor p? Aquí es donde se pone interesante con las pruebas de dos colas.
Nuestro valor p va a capturar no solo el área a la izquierda de 16, sino también el área equivalente
simétrica en la cola derecha. Dado que 16 está 4 días por debajo de la media, también
capturaremos el área por encima de 20, que está 4 días por encima de la media ( Figura 3-23 ).
Esto captura la probabilidad de un evento o más raro, en ambos lados de la curva de campana.

Figura 3-23. El valor p agrega lados simétricos para significación estadística

Cuando sumamos ambas áreas, obtenemos un valor p de.1824. Esto es mucho mayor que.05, por
lo que definitivamente no pasa nuestro umbral de valor p de.05 ( Ejemplo 3-22 ).
Ejemplo 3-22. Cálculo del valor p de dos colas
from scipy.stats import norm
# Cold has 18 day mean recovery, 1.5 std dev
mean = 18
std_dev = 1.5
# Probability of 16 or less days
p1 = norm.cdf(16, mean, std_dev)
# Probability of 20 or more days
p2 = 1.0 - norm.cdf(20, mean, std_dev)
# P-value of both tails
p_value = p1 + p2
print(p_value) # 0.18242243945173575

Entonces, ¿por qué también agregamos el área simétrica en el lado opuesto en una prueba de dos
colas? Puede que este no sea el concepto más intuitivo, pero primero recuerda cómo
estructuramos nuestras hipótesis:

76
H : population mean = 18
0

H1 : population mean ≠ 18
Si estamos probando en una capacidad de "igual a 18" versus "no igual a 18", tenemos que
capturar cualquier probabilidad que sea de igual o menor valor en ambos lados. Después de todo,
estamos tratando de probar la importancia, y eso incluye cualquier cosa que tenga las mismas o
menos probabilidades de suceder. No tuvimos esta consideración especial con la prueba de una
cola que usaba solo la lógica "mayor/menor que". Pero cuando tratamos con “iguales/no iguales”
nuestra área de interés va en ambas direcciones.
Entonces, ¿cuáles son las implicaciones prácticas de la prueba de dos colas? ¿Cómo afecta si
rechazamos la hipótesis nula? Pregúntese esto: ¿cuál establece un umbral más alto? Notará que
incluso cuando nuestro objetivo es mostrar que es posible que hayamos disminuido algo (el tiempo
de recuperación del resfriado usando un fármaco), reformular nuestra hipótesis para mostrar
cualquier impacto (mayor o menor) crea un umbral de significación más alto. Si nuestro umbral de
significación es un valor de p de 0,05 o menos, nuestra prueba de una cola estuvo más cerca de la
aceptación con un valor de p de 0,0912 en comparación con la prueba de dos colas, que fue
aproximadamente el doble con un valor de p de 0,182.
Esto significa que la prueba de dos colas hace que sea más difícil rechazar la hipótesis nula y exige
pruebas más sólidas para pasar la prueba. Piensa también en esto: ¿y si nuestro medicamento
pudiera empeorar los resfriados y hacerlos durar más? También puede ser útil capturar esa
probabilidad y tener en cuenta la variación en esa dirección. Esta es la razón por la cual las
pruebas de dos colas son preferibles en la mayoría de los casos. Tienden a ser más confiables y no
sesgan la hipótesis en una sola dirección.
Usaremos pruebas de hipótesis y valores p nuevamente en los capítulos 5 y 6.

¡CUIDADO CON EL P-HACKING!


Existe un problema para obtener más conciencia en la comunidad de investigación científica
llamada p-hacking, donde los investigadores compran valores p estadísticamente significativos
de.05 o menos. Esto no es difícil de hacer con big data, aprendizaje automático y minería de
datos, donde podemos atravesar cientos o miles de variables y luego encontrar relaciones
estadísticamente significativas (pero coincidentes) entre ellas.
¿Por qué tantos investigadores p-hackean? Muchos probablemente no son conscientes de que
lo están haciendo. Es fácil seguir ajustando y ajustando un modelo, omitiendo datos "ruidosos"
y cambiando parámetros, hasta que dé el resultado "correcto". Otros simplemente están bajo la
presión de la academia y la industria para producir resultados lucrativos, no objetivos.
Si Calvin Cereal Company lo contrata para estudiar si las bombas de azúcar con chocolate
helado causan diabetes, ¿espera hacer un análisis honesto y volver a ser contratado? ¿Qué
pasa si un gerente le pide que produzca un pronóstico que muestre $ 15 millones en ventas el
próximo trimestre para el lanzamiento de un nuevo producto? No tiene control sobre cuáles
serán las ventas, pero se le pide un modelo que produzca un resultado predeterminado. En el
peor de los casos, es posible que incluso se le haga responsable cuando resulte incorrecto.
Injusto, pero sucede!
Esta es la razón por la cual las habilidades blandas como la diplomacia pueden marcar la
diferencia en la carrera de un profesional de la ciencia de datos. Si puede compartir historias
difíciles e inconvenientes de una manera que atraiga productivamente a una audiencia; eso es
una hazaña tremenda. Solo tenga en cuenta el clima gerencial de la organización y siempre
proponga soluciones alternativas. Si terminas en una situación sin salida en la que se te pide
que hagas p-hack, y podrías ser responsable cuando falla, ¡entonces definitivamente cambia el
ambiente de trabajo!

La distribución T: tratar con muestras pequeñas


Abordemos brevemente cómo tratar con muestras más pequeñas de 30 o menos; lo necesitaremos
cuando hagamos la regresión lineal en el Capítulo 5. Ya sea que estemos calculando intervalos de
confianza o haciendo pruebas de hipótesis, si tenemos 30 o menos elementos en una muestra,
optaríamos por usar una distribución T en lugar de una distribución normal. La distribución T es
como una distribución normal pero tiene colas más anchas para reflejar más varianza e

77
incertidumbre. La figura 3-24 muestra una distribución normal (discontinua) junto con una
distribución T con un grado de libertad (continua).

Figura 3-24. La distribución T junto con una distribución normal; nota las colas más gordas

Cuanto menor sea el tamaño de la muestra, más gruesas serán las colas en una distribución T.
Pero lo interesante es que después de acercarse a 31 elementos, la distribución T es casi
indistinguible de la distribución normal, lo que refleja claramente las ideas detrás del teorema del
límite central.
El ejemplo 3-23 muestra cómo encontrar el valor t crítico para una confianza del 95 %. Puede usar
esto para intervalos de confianza y pruebas de hipótesis cuando tiene un tamaño de muestra de 30
o menos. Es conceptualmente lo mismo que el valor z crítico, pero estamos usando una
distribución T en lugar de una distribución normal para reflejar una mayor incertidumbre. Cuanto
menor sea el tamaño de la muestra, mayor será el rango, lo que refleja una mayor incertidumbre.
Ejemplo 3-23. Obtener un rango de valores críticos con una distribución T
from scipy.stats import t
# get critical value range for 95% confidence
# with a sample size of 25
n = 25
lower = t.ppf(.025, df=n-1)
upper = t.ppf(.975, df=n-1)
print(lower, upper)
-2.063898561628021 2.0638985616280205

Tenga en cuenta que df es el parámetro de "grados de libertad" y, como se indicó


anteriormente, debe ser uno menos del tamaño de la muestra.

MÁS ALLÁ DE LA MEDIA


Podemos usar intervalos de confianza y pruebas de hipótesis para medir otros parámetros
además de la media, incluida la varianza/desviación estándar, así como las proporciones
(p. ej., el 60 % de las personas reportan una mayor felicidad después de caminar una hora
al día). Estos requieren otras distribuciones como la distribución chi-cuadrado en lugar de
la distribución normal. Como se indicó, todo esto está más allá del alcance de este libro,
pero es de esperar que tenga una base conceptual sólida para extenderse a estas áreas si
es necesario.
Sin embargo, utilizaremos intervalos de confianza y pruebas de hipótesis en los capítulos 5
y 6.

78
Consideraciones sobre Big Data y la falacia del francotirador de Texas
Una reflexión final antes de cerrar este capítulo. Como hemos discutido, la aleatoriedad
juega un papel tan importante en la validación de nuestros hallazgos y siempre tenemos
que dar cuenta de su posibilidad. Desafortunadamente, con el big data, el aprendizaje
automático y otras herramientas de minería de datos, el método científico se ha convertido
repentinamente en una práctica hecha al revés. Esto puede ser precario; permítanme
demostrar por qué, adaptando un ejemplo del libro Standard Deviations de Gary Smith
(Overlook Press).
Supongamos que saco cuatro naipes de una baraja justa. Aquí no hay ningún juego u
objetivo más que sacar cuatro cartas y observarlas. Obtengo dos 10, un 3 y un 2. “Esto es
interesante”, digo. “Obtuve dos 10, un 3 y un 2. ¿Es esto significativo? ¿Las próximas
cuatro cartas que saque también serán dos números consecutivos y un par? ¿Cuál es el
modelo subyacente aquí?
¿Ves lo que hice ahí? Tomé algo que era completamente aleatorio y no solo busqué
patrones, sino que traté de hacer un modelo predictivo a partir de ellos. Lo que sucedió
sutilmente aquí es que nunca me propuse obtener estas cuatro cartas con estos patrones
particulares. Los observé después de que ocurrieron.
Esto es exactamente de lo que la minería de datos es víctima todos los días: encontrar
patrones coincidentes en eventos aleatorios. Con enormes cantidades de datos y
algoritmos rápidos que buscan patrones, es fácil encontrar cosas que parecen
significativas pero que en realidad son solo coincidencias aleatorias.
Esto también es análogo a mí disparando un arma a una pared. Luego dibujo un objetivo
alrededor del agujero y traigo a mis amigos para mostrarles mi increíble puntería. tonto,
cierto? Bueno, muchas personas en ciencia de datos hacen esto figurativamente todos los
días y se conoce como la falacia del francotirador de Texas. Se dispusieron a actuar sin un
objetivo, tropezaron con algo raro y luego señalaron que lo que encontraron de alguna
manera crea valor predictivo.
El problema es que la ley de los números realmente grandes dice que es probable que se
encuenTrain eventos raros; simplemente no sabemos cuáles. Cuando nos encontramos
con eventos raros, destacamos e incluso especulamos sobre qué podría haberlos causado.
El problema es este: la probabilidad de que una persona específica gane la lotería es muy
poco probable, pero aún así alguien ganará la lotería. ¿Por qué deberíamos sorprendernos
cuando hay un ganador? A menos que alguien predijera el ganador, no sucedió nada
significativo aparte de que una persona al azar tuvo suerte.
Esto también se aplica a las correlaciones, que estudiaremos en el Capítulo 5. Con un
enorme conjunto de datos con miles de variables, ¿es fácil encontrar resultados
estadísticamente significativos con un valor p de 0,05? ¡Puedes apostar! Encontraré miles
de esos. Incluso mostraré evidencia de que la cantidad de películas de Nicolas Cage se
correlaciona con la cantidad de ahogamientos en piscinas en un año.
Entonces, para evitar la falacia del francotirador de Texas y ser víctima de falacias de big
data, intente usar pruebas de hipótesis estructuradas y recopile datos para ese objetivo. Si
utiliza la minería de datos, intente obtener datos nuevos para ver si sus hallazgos aún se
mantienen. Finalmente, considere siempre la posibilidad de que las cosas puedan ser
coincidentes; si no hay una explicación de sentido común, entonces probablemente fue
una coincidencia.
Aprendimos a formular hipótesis antes de recopilar datos, pero la minería de datos recopila
datos y luego formula hipótesis. Irónicamente, a menudo somos más objetivos al comenzar
con una hipótesis, porque luego buscamos datos para probar y refutar deliberadamente
nuestra hipótesis.

Conclusión
Aprendimos mucho en este capítulo, y deberías sentirte bien por haber llegado tan lejos.
¡Este fue probablemente uno de los temas más difíciles de este libro! No solo aprendimos

79
estadísticas descriptivas desde la media hasta la distribución normal, sino que también
abordamos los intervalos de confianza y las pruebas de hipótesis.
Con suerte, usted ve los datos un poco diferente. Son instantáneas de algo más que una
captura completa de la realidad. Los datos por sí solos no son muy útiles, y necesitamos
contexto, curiosidad y análisis de su origen antes de que podamos obtener información
significativa con ellos. Cubrimos cómo describir datos e inferir atributos sobre una
población más grande en función de una muestra. Finalmente, abordamos algunas de las
falacias de minería de datos con las que podemos tropezar si no tenemos cuidado, y cómo
remediarlo con datos nuevos y sentido común.
No se sienta mal si necesita volver atrás y revisar parte del contenido de este capítulo,
porque hay mucho que digerir. También es importante tener una mentalidad de prueba de
hipótesis si desea tener éxito en una carrera de ciencia de datos y aprendizaje automático.
Pocos profesionales se toman el tiempo para vincular las estadísticas y los conceptos de
prueba de hipótesis con el aprendizaje automático, y eso es desafortunado.
La comprensibilidad y la explicabilidad son la próxima frontera del aprendizaje automático,
así que continúe aprendiendo e integrando estas ideas a medida que avanza en el resto de
este libro y el resto de su carrera.

Ejercicios
1. Has comprado una bobina de filamento de 1,75 mm para tu impresora 3D. Desea
medir qué tan cerca está realmente el diámetro del filamento de 1,75 mm. Utiliza
una herramienta de calibre y toma muestras del diámetro cinco veces en el carrete:
1.78, 1.75, 1.72, 1.74, 1.77
Calcule la media y la desviación estándar para este conjunto de valores.
2. Un fabricante dice que el teléfono inteligente Z-Phone tiene una vida media de
consumo de 42 meses con una desviación estándar de 8 meses. Suponiendo una
distribución normal, ¿cuál es la probabilidad de que un Z-Phone aleatorio dado dure
entre 20 y 30 meses?
3. Dudo que el filamento de mi impresora 3D no tenga un diámetro medio de 1,75
mm como se anuncia. Tomé muestras de 34 medidas con mi herramienta. La media
muestral es 1,715588 y la desviación estándar muestral es 0,029252.
¿Cuál es el intervalo de confianza del 99 % para la media de toda mi bobina de
filamento?
4. Su departamento de marketing ha iniciado una nueva campaña publicitaria y
quiere saber si afectó las ventas, que en el pasado promediaron $10 345 por día con
una desviación estándar de $552. La nueva campaña publicitaria duró 45 días y
promedió $11,641 en ventas.
¿La campaña afectó las ventas? ¿Por qué o por qué no? (Use una prueba de dos colas
para una significación más confiable).

Las respuestas se encuentran en el Apéndice B.

80
Capítulo 4. Álgebra lineal
Cambiando un poco de tema, aventurémonos de la probabilidad y la estadística y adentrémonos en
el álgebra lineal. A veces la gente confunde el álgebra lineal con el álgebra básica, pensando que
tal vez tiene que ver con trazar líneas usando la función algebraica y = mx + b. Esta es la razón por
la cual el álgebra lineal probablemente debería haberse llamado "álgebra vectorial" o "álgebra
matricial" porque es mucho más abstracta. Los sistemas lineales juegan un papel pero de una
manera mucho más metafísica.
Entonces, ¿qué es exactamente el álgebra lineal? Bueno, el álgebra lineal se ocupa de los
sistemas lineales pero los representa a través de espacios vectoriales y matrices. Si no sabes qué
es un vector o una matriz, ¡no te preocupes! Los definiremos y exploraremos en profundidad. El
álgebra lineal es muy fundamental para muchas áreas aplicadas de las matemáticas, la estadística,
la investigación de operaciones, la ciencia de datos y el aprendizaje automático. Cuando trabaja
con datos en cualquiera de estas áreas, está utilizando álgebra lineal y tal vez ni siquiera lo sepa.
Puede salirse con la suya sin aprender álgebra lineal por un tiempo, utilizando bibliotecas de
estadísticas y aprendizaje automático que lo hacen todo por usted. Pero si va a obtener intuición
detrás de estas cajas negras y ser más efectivo al trabajar con datos, es inevitable comprender los
fundamentos del álgebra lineal. El álgebra lineal es un tema enorme que puede llenar libros de
texto gruesos, por lo que, por supuesto, no podemos obtener un dominio total en solo un capítulo
de este libro. Sin embargo, podemos aprender lo suficiente para sentirnos más cómodos con él y
navegar el dominio de la ciencia de datos de manera efectiva. También habrá oportunidades para
aplicarlo en los capítulos restantes de este libro, incluidos los capítulos 5 y 7.

¿Qué es un vector?
En pocas palabras, un vector es una flecha en el espacio con una dirección y longitud específicas,
que a menudo representa un dato. Es el componente central del álgebra lineal, incluidas las
matrices y las transformaciones lineales. En su forma fundamental, no tiene concepto de ubicación,
así que siempre imagine que su cola comienza en el origen de un plano cartesiano (0,0).
La figura 4-1 muestra un vector que se mueve tres pasos en dirección horizontal y dos pasos en
dirección vertical.

Figura 4-1. un vector sencillo

Para enfatizar nuevamente, el propósito del vector es representar visualmente una pieza de datos.
Si tiene un registro de datos de los pies cuadrados de una casa de 18 000 pies cuadrados y su
valoración de $260 000, podríamos expresarlo como un vector [18 000, 2600 000], con 18 000
pasos en dirección horizontal y 260 000 pasos en dirección vertical.
Declaramos un vector matemáticamente así:

81
Podemos declarar un vector usando una colección de Python simple, como una lista de Python
como se muestra en el Ejemplo 4-1.
Ejemplo 4-1. Declarar un vector en Python usando una lista
v = [3, 2]
print(v)
Sin embargo, cuando empezamos a hacer cálculos matemáticos con vectores, especialmente
cuando hacemos tareas como el aprendizaje automático, probablemente deberíamos usar la
biblioteca NumPy, ya que es más eficiente que Python simple. También puede usar SymPy para
realizar operaciones de álgebra lineal, y lo usaremos ocasionalmente en este capítulo cuando los
decimales se vuelvan inconvenientes. Sin embargo, NumPy es lo que probablemente usará en la
práctica, por lo que nos apegaremos principalmente.
Para declarar un vector, puede usar la función array() de NumPy y luego puede pasarle una
colección de números como se muestra en el Ejemplo 4-2.
Ejemplo 4-2. Declarar un vector en Python usando NumPy
import numpy as np
v = np.array([3, 2])
print(v)

PYTHON ES LENTO, SUS BIBLIOTECAS NUMÉRICAS NO LO SON


Python es una plataforma de lenguaje computacionalmente lenta, ya que no se compila en código
de máquina de nivel inferior ni en código de bytes como Java, C#, C, etc. Se interpreta
dinámicamente en tiempo de ejecución. Sin embargo, las bibliotecas numéricas y científicas de
Python no son lentas. Las bibliotecas como NumPy generalmente se escriben en lenguajes de bajo
nivel como C y C ++, por lo que son computacionalmente eficientes. Python realmente actúa como
un "código adhesivo" que integra estas bibliotecas para sus tareas.

Un vector tiene innumerables aplicaciones prácticas. En física, a menudo se piensa en un vector


como una dirección y una magnitud. En matemáticas, es una dirección y escala en un plano XY,
algo así como un movimiento. En informática, es una matriz de números que almacenan datos. El
contexto de la informática es con el que nos familiarizaremos más como profesionales de la ciencia
de datos. Sin embargo, es importante que nunca olvidemos el aspecto visual para que no
pensemos en los vectores como cuadrículas esotéricas de números. Sin una comprensión visual,
es casi imposible comprender muchos conceptos fundamentales del álgebra lineal, como la
dependencia lineal y los determinantes.
Aquí hay algunos ejemplos más de vectores. En la figura 4-2 observe que algunos de estos
vectores tienen direcciones negativas en las escalas X e Y. Los vectores con direcciones negativas
tendrán un impacto cuando los combinemos más tarde, esencialmente restándolos en lugar de
sumarlos.

82
Figura 4-2. Una muestra de diferentes vectores.
¿POR QUÉ SON ÚTILES LOS VECTORES?
Una lucha que muchas personas tienen con los vectores (y el álgebra lineal en general) es
entender por qué son útiles. Son un concepto muy abstracto pero tienen muchas aplicaciones
tangibles. Es más fácil trabajar con los gráficos por computadora cuando se dominan los vectores y
las transformaciones lineales (la fantástica biblioteca de visualización de Manim define animaciones
y transformaciones con vectores). Cuando se realizan trabajos de estadísticas y aprendizaje
automático, los datos a menudo se importan y se convierten en vectores numéricos para que
podamos trabajar con ellos. Los solucionadores como el de Excel o Python PuLP usan
programación lineal, que usa vectores para maximizar una solución mientras cumple con esas
restricciones. Incluso los videojuegos y los simuladores de vuelo usan vectores y álgebra lineal
para modelar no solo gráficos sino también física. Creo que lo que hace que los vectores sean tan
difíciles de comprender no es que su aplicación no sea obvia, sino que estas aplicaciones son tan
diversas que es difícil ver la generalización.
Tenga en cuenta que también los vectores pueden existir en más de dos dimensiones. A
continuación, declaramos un vector tridimensional a lo largo de los ejes x, y, y z:

Para crear este vector, estamos dando cuatro pasos en la dirección x, uno en la dirección y y dos
en la dirección z. Aquí se visualiza en la Figura 4-3. Tenga en cuenta que ya no estamos
mostrando un vector en una cuadrícula bidimensional, sino un espacio tridimensional con tres ejes:
x, y y z.

Figura 4-3. Un vector tridimensional

Naturalmente, podemos expresar este vector tridimensional en Python usando tres valores
numéricos, como se declara en el Ejemplo 4-3.
Ejemplo 4-3. Declarar un vector tridimensional en Python usando NumPy
import numpy as np
v = np.array([4, 1, 2])
print(v)

Como muchos modelos matemáticos, visualizar más de tres dimensiones es un desafío y es algo
en lo que no gastaremos energía en este libro. Pero numéricamente, sigue siendo sencillo. El
ejemplo 4-4 muestra cómo declaramos matemáticamente un vector de cinco dimensiones en
Python.

Ejemplo 4-4. Declarar un vector de cinco dimensiones en Python usando NumPy

83
import numpy as np
v = np.array([6, 1, 5, 8, 3])
print(v)
Adición y combinación de vectores
Por sí solos, los vectores no son terriblemente interesantes. Expresas una dirección y un tamaño,
algo así como un movimiento en el espacio. Pero cuando empiezas a combinar vectores, lo que se
conoce como suma de vectores, empieza a ponerse interesante. Combinamos efectivamente los
movimientos de dos vectores en un solo vector.
Digamos que tenemos dos vectores como se muestra en la figura 4-4. ¿Cómo sumamos
estos dos vectores?

Figura 4-4. Sumar dos vectores juntos

Veremos por qué es útil agregar vectores en un momento. Pero si quisiéramos combinar estos dos
vectores, incluida su dirección y escala, ¿cómo sería eso? Numéricamente, esto es sencillo.
Simplemente agregue los valores x respectivos y luego los valores y en un nuevo vector como se
muestra en el ejemplo 4-5.

Ejemplo 4-5. Agregar dos vectores en Python usando NumPy

from numpy import array


v = array([3,2])
w = array([2,-1])
# sum the vectors
v_plus_w = v + w
# display summed vector
print(v_plus_w) # [5, 1]

84
Pero, ¿qué significa esto visualmente? Para sumar visualmente estos dos vectores, conecte un
vector tras otro y camine hasta la punta del último vector ( Figura 4-5 ). El punto en el que terminas
es un nuevo vector, el resultado de sumar los dos vectores.

Figura 4-5. Agregar dos vectores en un nuevo vector

Como se ve en la Figura 4-5, cuando caminamos hasta el final del último vector terminamos
con un nuevo vector [5, 1]. Este nuevo vector es el resultado de sumar En la práctica, esto
puede consistir simplemente en sumar datos. Si tuviéramos que sumar los valores de las viviendas
y sus pies cuadrados en un área, estaríamos sumando varios vectores en un solo vector de esta
manera.
Tenga en cuenta que no importa si agregamos antes de o viceversa, lo que significa que es
conmutativo y el orden de operación no importa. Si caminamos antes de terminamos con el
mismo vector resultante [5, 1] como se visualiza en la figura 4-6.

Figura 4-6. La suma de vectores es conmutativa

Vectores de escala

85
Escalar es aumentar o reducir la longitud de un vector. Puede hacer crecer/reducir un vector
multiplicándolo o escalando con un solo valor, conocido como escalar. La figura 4-7 es el siendo
escalado por un factor de 2, lo que lo duplica.

Figura 4-7. Escalar un vector


Matemáticamente, multiplicas cada elemento del vector por el valor escalar:

Realizando esta operación de escalado en Pythones tan fácil como multiplicar un vector por el
escalar, como se codifica en el Ejemplo 4-6.
Ejemplo 4-6. Escalar un número en Python usando NumPy
from numpy import array
v = array([3,1])
# scale the vector
scaled_v = 2.0 * v
# display scaled vector
print(scaled_v) # [6 2]
Aquí en la Figura 4-8 v → está siendo reducido por un factor de.5, lo que lo reduce a la mitad.

Figura 4-8. Reducir un vector a la mitad

86
MANIPULAR DATOS ES MANIPULAR VECTORES
Cada operación de datos se puede pensar en términos de vectores, incluso promedios simples.
Tome la escala, por ejemplo. Digamos que estamos tratando de obtener el valor promedio de la
casa y el promedio de pies cuadrados para todo un vecindario. Agregaríamos los vectores para
combinar su valor y pies cuadrados respectivamente, dándonos un vector gigante que contiene
tanto el valor total como el total de pies cuadrados. Luego, reducimos la escala del vector
dividiendo por el número de casas N, que en realidad se multiplica por 1/ N. Ahora tenemos un
vector que contiene el valor promedio de la casa y el promedio de pies cuadrados.
Un detalle importante a tener en cuenta aquí es que escalar un vector no cambia su dirección, solo
su magnitud. Pero hay una pequeña excepción a esta regla, como se muestra en la figura 4-9.
Cuando multiplicas un vector por un número negativo, cambia la dirección del vector como se
muestra en la imagen.

Figura 4-9. Un escalar negativo invierte la dirección del vector.

Sin embargo, cuando lo piensa, la escala por un número negativo realmente no ha cambiado de
dirección en el sentido de que todavía existe en la misma línea. Esto da paso a un concepto clave
llamado dependencia lineal.

Intervalo y dependencia lineal


Estas dos operaciones, sumar dos vectores y escalarlos, genera una idea simple pero poderosa.
Con estas dos operaciones, podemos combinar dos vectores y escalarlos para crear cualquier
vector resultante que queramos. La figura 4-10 muestra seis ejemplos de tomar dos vectores y

→, escalarlos y combinarlos. Estos vectores y , fijos en dos direcciones diferentes, se


pueden escalar y sumar para crear cualquier nuevo vector + .

87
Figura 4-10. Escalar dos vectores agregados nos permite crear cualquier vector nuevo

Una vez más, tienen una dirección fija, excepto para voltear con escalares negativos, pero
podemos usar la escala para crear libremente cualquier vector compuesto por .
Todo este espacio de posibles vectores se llama span y, en la mayoría de los casos, nuestro span
puede crear vectores ilimitados a partir de esos dos vectores, simplemente al escalarlos y
sumarlos. Cuando tenemos dos vectores en dos direcciones diferentes, son linealmente
independientes y tienen este lapso ilimitado.
Pero, ¿en qué caso estamos limitados en los vectores que podemos crear? Piénsalo y sigue
leyendo.
¿Qué sucede cuando existen dos vectores en la misma dirección, o existen en la misma línea? La
combinación de esos vectores también está atascada en la misma línea, lo que limita nuestro lapso
solo a esa línea. No importa cómo lo escale, el vector de suma resultante también está atascado en
esa misma línea. Esto los hace linealmente dependientes, como se muestra en la Figura 4-11.

Figura 4-11. Vectores linealmente dependientes

El lapso aquí está atascado en la misma línea que los dos vectores de los que está hecho. Debido
a que los dos vectores existen en la misma línea subyacente, no podemos crear de manera flexible
ningún vector nuevo a través de la escala.

88
En tres o más dimensiones, cuando tenemos un conjunto de vectores linealmente dependientes, a
menudo nos quedamos atascados en un plano en un número menor de dimensiones. Este es un
ejemplo de estar atascado en un plano bidimensional aunque tengamos vectores tridimensionales
como se declara en la figura 4-12.

Figura 4-12. Dependencia lineal en tres dimensiones; tenga en cuenta que nuestro lapso está
limitado a un plano plano

Más adelante aprenderemos una herramienta simple llamada determinante para verificar la
dependencia lineal, pero ¿por qué nos importa si dos vectores son linealmente dependientes o
independientes?? Muchos problemas se vuelven difíciles o irresolubles cuando son linealmente
dependientes. Por ejemplo, cuando aprendamos acerca de los sistemas de ecuaciones más
adelante en este capítulo, un conjunto de ecuaciones linealmente dependientes puede hacer que
las variables desaparezcan y que el problema sea imposible de resolver. Pero si tiene
independencia lineal, esa flexibilidad para crear cualquier vector que necesite a partir de dos o más
vectores se vuelve invaluable para encontrar una solución.!

Transformaciones lineales
Este concepto de sumar dos vectores con dirección fija, pero escalarlos para obtener diferentes
vectores combinados, es muy importante. Este vector combinado, salvo en los casos de
dependencia lineal, puede apuntar en cualquier dirección y tener la longitud que elijamos. Esto
establece una intuición para las transformaciones lineales donde usamos un vector para
transformar otro vector de manera similar a una función.

Vectores base
Imagina que tenemos dos vectores simples ("i-sombrero" y "j-sombrero"). Estos se conocen
como vectores base, que se utilizan para describir transformaciones en otros vectores. Por lo
general, tienen una longitud de 1 y apuntan en direcciones perpendiculares positivas, como se
muestra en la Figura 4-13.

Figura 4-13. Vectores base

89
Piense en los vectores base como bloques de construcción para construir o transformar cualquier
vector. Nuestro vector base se expresa en una matriz de 2 × 2, donde la primera columna es y la
segunda columna es :

Una matriz es una colección de vectores (como ) que pueden tener múltiples filas y columnas
y es una forma conveniente de empaquetar datos. Podemos usar para crear cualquier
vector que queramos al escalarlos y agregarlos. Comencemos con cada uno con una longitud de 1
y mostrando el vector resultante en la Figura 4-14.

Figura 4-14. Crear un vector a partir de vectores base

Quiero que el vector aterrice en [3, 2]. ¿Qué sucede con si estiramos por un factor de 3
y por un factor de 2? Primero los escalamos individualmente como se muestra aquí:

Si estiramos el espacio en estas dos direcciones, ¿qué le hace esto a ? Bueno, se va a estirar
con . Esto se conoce como transformación lineal, en la que transformamos un vector con
estiramiento, aplastamiento, corte o rotación mediante el seguimiento de los movimientos del vector
base. En este caso ( Figura 4-15 ), escalar ha estirado el espacio junto con nuestro vector

90
Figura 4-15. Una transformación lineal
Pero, ¿dónde aterriza ? Es fácil ver dónde aterriza aquí, que es [3, 2]. Recuerda que el vector
se compone de sumar . Así que simplemente tomamos . estirados y los sumamos
para ver dónde ha aterrizado el vector :

Generalmente, con transformaciones lineales, hay cuatro movimientospuede lograr, como se


muestra en la Figura 4-16.

Figura 4-16. Se pueden lograr cuatro movimientos con transformaciones lineales.

91
Estas cuatro transformaciones lineales son una parte central del álgebra lineal. Escalar un vector lo
estirará o apretará. Las rotaciones cambiarán el espacio vectorial y las inversiones cambiarán el
espacio vectorial para que intercambien sus respectivos lugares.
Es importante tener en cuenta que no puede tener transformaciones que no sean lineales, lo que
da como resultado transformaciones con curvas o onduladas que ya no respetan una línea recta.
Es por eso que lo llamamos álgebra lineal, no álgebra no lineal.!

Multiplicación de vectores de matrices


Esto nos lleva a nuestra próxima gran idea en álgebra lineal. Este concepto de rastrear dónde
aterrizan después de una transformación es importante porque nos permite no solo crear
vectores sino también transformar vectores existentes. Si desea una verdadera iluminación de
álgebra lineal, piense por qué crear vectores y transformar vectores son en realidad lo mismo. Todo
es una cuestión de relatividad dado que sus vectores base son un punto de partida antes y
después de una transformación.
La fórmula para transformar un vector vectores base dados empaquetados como una
matriz es:

es la primera columna [ a, c ] y es la columna [ b, d ]. Empaquetamos ambos vectores base


como una matriz, que nuevamente es una colección de vectores expresados como una cuadrícula
de números en dos o más dimensiones. Esta transformación de un vector mediante la aplicación de
vectores base se conoce como multiplicación de vectores de matriz. Esto puede parecer artificial al
principio, pero esta fórmula es un atajo para escalar y agregar y tal como lo hicimos
anteriormente al agregar dos vectores y aplicar la transformación a cualquier vector .
Entonces, en efecto, una matriz es realmente una transformación expresada como vectores base.
Para ejecutar esta transformación en Python usando NumPy, necesitaremos declarar nuestros
vectores base como una matriz y luego aplicarla al vector v → usando el operador dot() (
Ejemplo 4-7 ). El operador dot() realizará esta escala y suma entre nuestra matriz y el vector como
acabamos de describir. Esto se conoce como el producto escalar y lo exploraremos a lo largo de
este capítulo.
Ejemplo 4-7. Multiplicación de matrices vectoriales en NumPy
from numpy import array
# compose basis matrix with i-hat and j-hat
basis = array(
[[3, 0],
[0, 2]]
)
# declare vector v
v = array([1,1])
# create new vector
# by transforming v with dot product
new_v = basis.dot(v)
print(new_v) # [3, 2]
Cuando pienso en términos de vectores base, prefiero dividir los vectores base y luego
componerlos en una matriz. Solo tenga en cuenta que deberá transponer o intercambiar las
columnas y filas. Esto se debe a que la función array() de NumPy hará la orientación opuesta que

92
queremos, completando cada vector como una fila en lugar de una columna. La transposición en
NumPy se demuestra en el Ejemplo 4-8.

Ejemplo 4-8. Separando los vectores base y aplicándolos como una transformación
from numpy import array
# Declare i-hat and j-hat
i_hat = array([2, 0])
j_hat = array([0, 3])
# compose basis matrix using i-hat and j-hat
# also need to transpose rows into columns
basis = array([i_hat, j_hat]).transpose()
# declare vector v
v = array([1,1])
# create new vector
# by transforming v with dot product
new_v = basis.dot(v)
print(new_v) # [2, 3]
Aquí hay otro ejemplo. Comencemos con el vector siendo [2, 1] y y comienzan en [1, 0] y
[0, 1], respectivamente. Luego transformamos y en [2, 0] y [0, 3]. ¿Qué sucede con el vector
? Trabajando esto matemáticamente a mano usando nuestra fórmula, obtenemos esto:

El ejemplo 4-9 muestra esta solución en Python.


Ejemplo 4-9. Transformando un vector usando NumPy
from numpy import array
# Declare i-hat and j-hat
i_hat = array([2, 0])
j_hat = array([0, 3])
# compose basis matrix using i-hat and j-hat
# also need to transpose rows into columns
basis = array([i_hat, j_hat]).transpose()
# declare vector v 0
v = array([2,1])
# create new vector
# by transforming v with dot product
new_v = basis.dot(v)
print(new_v) # [4, 3]

El vector ahora aterriza en [4, 3]. La figura 4-17 muestra cómo se ve esta transformación.

93
Figura 4-17. Una transformación lineal de estiramiento

Aquí hay un ejemplo que salta las cosas un poco. Tomemos el vector de valor [2, 1]. y
comienzan en [1, 0] y [0, 1], pero luego se transforman y terminan en [2, 3] y [2, -1]. ¿Qué sucede
con ? Veamos la Figura 4-18 y el Ejemplo 4-10.

Figura 4-18. Una transformación lineal que hace una rotación, corte y volteo del espacio.

Ejemplo 4-10. Una transformación más complicada

from numpy import array


# Declare i-hat and j-hat
i_hat = array([2, 0])
j_hat = array([0, 3])
# compose basis matrix using i-hat and j-hat
# also need to transpose rows into columns
basis = array([i_hat, j_hat]).transpose()
# declare vector v 0
v = array([2,1])
# create new vector
# by transforming v with dot product
new_v = basis.dot(v)
print(new_v) # [4, 3]

Mucho ha pasado aquí. No solo escalamos i^ y j^ y alargamos el vector . De hecho,


también cortamos, rotamos y volteamos el espacio. Sabes que el espacio se invirtió cuando y

94
cambian de lugar en su orientación en el sentido de las agujas del reloj, y aprenderemos cómo
detectar esto con determinantes más adelante en este capítulo.

VECTORES BASE EN 3D Y MÁS ALLÁ


Quizás se pregunte cómo pensamos en las transformaciones vectoriales en tres dimensiones o
más. El concepto de vectores base se extiende bastante bien. Si tengo un espacio vectorial
tridimensional, entonces tengo vectores base Sigo agregando más letras del alfabeto
para cada nueva dimensión ( Figura 4-19 ).

Figura 4-19. vector base 3D

Otra cosa que vale la pena señalar es que algunas transformaciones lineales pueden cambiar un
espacio vectorial a menos o más dimensiones, y eso es exactamente lo que harán las matrices no
cuadradas (donde el número de filas y columnas no es igual). En interés del tiempo no podemos
explorar este. Pero 3Blue1Brown explica y anima este concepto maravillosamente.

Multiplicación de matrices
Aprendimos a multiplicar un vector y una matriz, pero ¿qué se logra exactamente al multiplicar dos
matrices? Piense en la multiplicación de matrices como la aplicación de múltiples transformaciones
a un espacio vectorial. Cada transformación es como una función, donde primero aplicamos la más
interna y luego aplicamos cada transformación posterior hacia afuera.
Así es como aplicamos una rotación y luego un corte a cualquier vector con valor [ x, y ]:

De hecho, podemos consolidar estas dos transformaciones usando esta fórmula, aplicando una
transformación sobre la última. Multiplicas y sumas cada fila de la primera matriz a cada columna
respectiva de la segunda matriz, en un "arriba y abajo". arriba y abajo!” patrón:

Entonces podemos consolidar estas dos transformaciones separadas (rotación y corte) en una sola
transformación:

95
Para ejecutar esto en Python usando NumPy, puede combinar las dos matrices simplemente
usando el operador matmul() o @ ( Ejemplo 4-11 ). Luego daremos la vuelta y usaremos esta
transformación consolidada y la aplicaremos a un vector [1, 2].

Ejemplo 4-11. Combinando dos transformaciones


from numpy import array
# Transformation 1
i_hat1 = array([0, 1])
j_hat1 = array([-1, 0])
transform1 = array([i_hat1, j_hat1]).transpose()
# Transformation 2
i_hat2 = array([1, 0])
j_hat2 = array([1, 1])
transform2 = array([i_hat2, j_hat2]).transpose()
# Combine Transformations
combined = transform2 @ transform1
# Test
print("COMBINED MATRIX:\n {}".format(combined))
v = array([1, 2])
print(combined.dot(v)) # [-1, 1]

USANDO DOT() VERSUS MATMUL() Y @


En general, desea preferir matmul() y su abreviatura @ para combinar matrices en lugar del
operador dot() en NumPy. El primero generalmente tiene una política preferible para matrices de
dimensiones superiores y cómo se transmiten los elementos.

Si le gusta sumergirse en este tipo de detalles de implementación, esta pregunta de StackOverflow


es un buen lugar para comenzar.
Tenga en cuenta que también podríamos haber aplicado cada transformación individualmente al
vector y aún así haber obtenido el mismo resultado. Si reemplaza la última línea con estas tres
líneas aplicando cada transformación, aún obtendrá [-1, 1] en ese nuevo vector:
rotated = transform1.dot(v)
sheered = transform2.dot(rotated)
print(sheered) # [-1, 1]¡
Tenga en cuenta que el orden en que aplica cada transformación es importante! Si aplicamos
transform1 en transform2, obtenemos un resultado diferente de [-2, 3] como se calculó en el
Ejemplo 4-12. Por lo tanto, los productos de matriz de puntos no son conmutativos, lo que significa
que no puede invertir el orden y esperar el mismo resultado.
Ejemplo 4-12. Aplicando las transformaciones a la inversa
from numpy import array
# Transformation 1
i_hat1 = array([0, 1])
j_hat1 = array([-1, 0])
transform1 = array([i_hat1, j_hat1]).transpose()
# Transformation 2
i_hat2 = array([1, 0])
j_hat2 = array([1, 1])
transform2 = array([i_hat2, j_hat2]).transpose()
# Combine Transformations, apply sheer first and then rotation
combined = transform1 @ transform2
# Test
print("COMBINED MATRIX:\n {}".format(combined))
v = array([1, 2])
print(combined.dot(v)) # [-2, 3]

96
Piense en cada transformación como una función, y las aplicamos de la más interna a la más
externa, como llamadas a funciones anidadas.

TRANSFORMACIONES LINEALES EN LA PRÁCTICA


Quizás se pregunte qué tienen que ver todas estas transformaciones y matrices lineales
con la ciencia de datos y el aprendizaje automático. ¡La respuesta es todo! Desde la
importación de datos hasta operaciones numéricas con regresión lineal, regresión logística
y redes neuronales, las transformaciones lineales son el corazón de los datos manipulados
matemáticamente.
En la práctica, sin embargo, rara vez se tomará el tiempo de visualizar geométricamente
sus datos como espacios vectoriales y transformaciones lineales. Estarás lidiando con
demasiadas dimensiones para hacer esto de manera productiva. ¡Pero es bueno tener en
cuenta la interpretación geométrica solo para entender lo que hacen estas operaciones
numéricas de aspecto artificial! De lo contrario, solo está memorizando patrones de
operaciones numéricas sin ningún contexto. También hace que los nuevos conceptos de
álgebra lineal como los determinantes sean más obvios.

Determinantes
Cuando realizamos transformaciones lineales, a veces "expandimos" o "aplastamos" el espacio y el
grado en que esto sucede puede ser útil. Tome un área muestreada del espacio vectorial de la
figura 4-20 : ¿qué le sucede después de escalar y ?

Figura 4-20. Un determinante mide cómo una transformación lineal escala un área

Tenga en cuenta que aumenta en área por un factor de 6.0, y este factor se conoce como
determinante. Los determinantes describen cuánto cambia en escala un área muestreada en un
espacio vectorial con transformaciones lineales, y esto puede proporcionar información útil sobre la
transformación.
El ejemplo 4-13 muestra cómo calcular este determinante en Python.
Ejemplo 4-13. Cálculo de un determinante
from numpy.linalg import det
from numpy import array
i_hat = array([3, 0])
j_hat = array([0, 2])
basis = array([i_hat, j_hat]).transpose()
determinant = det(basis)
print(determinant) # prints 6.0
Los cortes y rotaciones simples no deberían afectar el determinante, ya que el área no cambiará.
La figura 4-21 y el ejemplo 4-14 muestran un cortante simple y el determinante sigue siendo un
factor 1.0, lo que muestra que no cambia.

97
Figura 4-21. Un simple cortante no cambia el determinante.

Ejemplo 4-14. Un determinante para un cortante


from numpy.linalg import det
from numpy import array
i_hat = array([1, 0])
j_hat = array([1, 1])
basis = array([i_hat, j_hat]).transpose()
determinant = det(basis)
print(determinant) # prints 1.0
Pero la escala aumentará o disminuirá el determinante, ya que aumentará/disminuirá el área
muestreada. Cuando la orientación cambia ( intercambian posiciones en el sentido de las
agujas del reloj), el determinante será negativo. La figura 4-22 y el ejemplo 4-15 ilustran un
determinante que muestra una transformación que no solo escaló sino que también invirtió la
orientación del espacio vectorial.

Figura 4-22. Un determinante en un espacio invertido es negativo

Ejemplo 4-15. Un determinante negativo


from numpy.linalg import det
from numpy import array
i_hat = array([-2, 1])

98
j_hat = array([1, 2])
basis = array([i_hat, j_hat]).transpose()
determinant = det(basis)
print(determinant) # prints -5.0
Debido a que este determinante es negativo, vemos rápidamente que la orientación se ha invertido.
Pero, con mucho, la información más crítica que te dice el determinante es si la transformación es
linealmente dependiente. Si tiene un determinante de 0, eso significa que todo el espacio se ha
aplastado en una dimensión menor.
En la Figura 4-23 vemos dos transformaciones linealmente dependientes, donde un espacio 2D se
comprime en una dimensión y un espacio 3D se comprime en dos dimensiones. ¡El área y el
volumen respectivamente en ambos casos son 0!

Figura 4-23. Dependencia lineal en 2D y 3D


El ejemplo 4-16 muestra el código del ejemplo 2D anterior comprimiendo un espacio 2D completo
en una única recta numérica unidimensional.

Ejemplo 4-16. Un determinante de cero


from numpy.linalg import det
from numpy import array
i_hat = array([-2, 1])
j_hat = array([3, -1.5])
basis = array([i_hat, j_hat]).transpose()
determinant = det(basis)
print(determinant) # prints 0.0
Por lo tanto, la prueba de un determinante 0 es muy útil para determinar si una transformación tiene
una dependencia lineal. Cuando te encuentres con esto, es probable que encuentres un problema
difícil o irresoluble en tus manos.

Tipos especiales de matrices


Hay algunos casos notables de matrices que deberíamos cubrir.

Matriz cuadrada
La matriz cuadrada es una matriz que tiene igual número de filas y columnas:

Se utilizan principalmente para representar transformaciones lineales y son un requisito para


muchas operaciones como la descomposición propia.

Matriz de identidad

99
La matriz identidad es una matriz cuadrada que tiene una diagonal de 1s mientras que los otros
valores son 0:

¿Cuál es el problema con las matrices de identidad? Bueno, cuando tienes una matriz de identidad,
esencialmente has deshecho una transformación y encontrado tus vectores base iniciales. Esto
jugará un papel importante en la resolución de sistemas de ecuaciones en la siguiente sección.

Matriz inversa
Una matriz inversa es una matriz que deshace la transformación de otra matriz. Digamos que tengo
la matriz A :

La inversa de la matriz A se llama A -1. Aprenderemos a calcular la inversa usando Sympy o


NumPy en la siguiente sección, pero esto es lo que es la inversa de la matriz A :

Cuando realizamos la multiplicación de matrices entre A -1 y A, terminamos con una matriz


identidad. Veremos esto en acción con NumPy y Sympy en la siguiente sección sobre sistemas de
ecuaciones.

Matriz diagonal
Similar a la matriz identidad es la matriz diagonal, que tiene una diagonal de valores distintos de
cero mientras que el resto de los valores son 0. Las matrices diagonales son deseables en ciertos
cálculos porque representan escalares simples que se aplican a un espacio vectorial. Aparece en
algunas operaciones de álgebra lineal.

matriz triangular
Similar a la matriz diagonal es la matriz triangular, que tiene una diagonal de valores distintos de
cero delante de un triángulo de valores, mientras que el resto de los valores son 0.

Las matrices triangulares son deseables en muchas tareas de análisis numérico porque, por lo
general, son más fáciles de resolver en sistemas de ecuaciones. También aparecen en ciertas
tareas de descomposición como LU Decomposition.

100
Matriz dispersa
Ocasionalmente, se encontrará con matrices que en su mayoría son ceros y tienen muy pocos
elementos distintos de cero. Estas se llaman matrices dispersas. Desde un punto de vista
matemático puro, no son terriblemente interesantes. Pero desde el punto de vista informático,
brindan oportunidades para crear eficiencia. Si una matriz tiene principalmente 0, una
implementación de matriz dispersa no desperdiciará espacio almacenando un montón de 0 y, en
cambio, solo realizará un seguimiento de las celdas que no sean cero.

Cuando tiene matrices grandes que son escasas, puede usar explícitamente una función escasa
para crear su matriz.

Sistemas de Ecuaciones y Matrices Inversas


Uno de los casos de uso básicos del álgebra lineal es la resolución de sistemas de ecuaciones.
También es una buena aplicación para aprender sobre matrices inversas. Digamos que tiene las
siguientes ecuaciones y necesita resolver para x, y y z :
4x + 2y + 4z = 44
5x + 3y + 7z = 56
9x + 3y + 6z = 72
Puede intentar experimentar manualmente con diferentes operaciones algebraicas para aislar las
tres variables, pero si desea que una computadora lo resuelva, deberá expresar este problema en
términos de matrices, como se muestra a continuación. Extraiga los coeficientes en la matriz A, los
valores del lado derecho de la ecuación en la matriz B y las variables desconocidas en la matriz X :

La función para un sistema lineal de ecuaciones es AX = B. Necesitamos transformar la matriz A


con alguna otra matriz X que dará como resultado la matriz B :
AX = B

Necesitamos "deshacer" A para poder aislar X y obtener los valores para x, y y z. La forma de
deshacer A es tomar el inverso de A denotado por A-1 y aplicarlo a A a través de la multiplicación de
matrices. Podemos expresar esto algebraicamente:
AX = B
A-1AX = A-1B
X = A-1B

Para calcular la inversa de la matriz A, probablemente usemos una computadora en lugar de


buscar soluciones a mano usando la eliminación gaussiana, algo en lo que no nos aventuraremos
en este libro. Aquí está la inversa de la matriz A :

101
Tenga en cuenta que cuando multiplicamos la matriz A -1 contra A, se creará una matriz de
identidad, una matriz de todos los ceros excepto los 1 en la diagonal. La matriz de identidad es el
álgebra lineal equivalente a multiplicar por 1, lo que significa que esencialmente no tiene ningún
efecto y aislará de manera efectiva los valores de x, y y z :

Para ver esta matriz de identidad en acción en Python, querrá usar SymPy en lugar de NumPy. Los
decimales de punto flotante en NumPy no harán que la matriz de identidad sea tan obvia, pero al
hacerlo simbólicamente en el Ejemplo 4-17, veremos una salida simbólica limpia.Tenga en cuenta
que para hacer la multiplicación de matrices en SymPy usamos el asterisco * en lugar de @.
Ejemplo 4-17. Usando SymPy para estudiar la matriz inversa e identidad
from sympy import *
# 4x + 2y + 4z = 44
# 5x + 3y + 7z = 56
# 9x + 3y + 6z = 72
A = Matrix([
[4, 2, 4],
[5, 3, 7],
[9, 3, 6]
])
# dot product between A and its inverse
# will produce identity function
inverse = A.inv()
identity = inverse * A
# prints Matrix([[-1/2, 0, 1/3], [11/2, -2, -4/3], [-2, 1, 1/3]])
print("INVERSE: {}".format(inverse))
# prints Matrix([[1, 0, 0], [0, 1, 0], [0, 0, 1]])
print("IDENTITY: {}".format(identity))

En la práctica, la falta de precisión de punto flotante no afectará demasiado nuestras respuestas,


por lo que usar NumPy debería estar bien para resolver x. El ejemplo 4-18 muestra una solución
con NumPy.
Ejemplo 4-18. Usando NumPy para resolver un sistema de ecuaciones

102
from numpy import array
from numpy.linalg import inv
# 4x + 2y + 4z = 44
# 5x + 3y + 7z = 56
# 9x + 3y + 6z = 72
A = array([
[4, 2, 4],
[5, 3, 7],
[9, 3, 6]
])
B = array([
44,
56,
72
])
X = inv(A).dot(B)
print(X) # [ 2. 34. -8.]

Entonces x = 2, y = 34 y z = –8. El ejemplo 4-19 muestra la solución completa en SymPy como


alternativa a NumPy.
Ejemplo 4-19. Usando SymPy para resolver un sistema de ecuaciones
from sympy import *
# 4x + 2y + 4z = 44
# 5x + 3y + 7z = 56
# 9x + 3y + 6z = 72
A = Matrix([
[4, 2, 4],
[5, 3, 7],
[9, 3, 6]
])
B = Matrix([
44,
56,
72
])
X = A.inv() * B
print(X) # Matrix([[2], [34], [-8]])

Aquí está la solución en notación matemática:


A-1B = X

Con suerte, esto le dio una intuición para las matrices inversas y cómo se pueden usar para
resolver un sistema de ecuaciones.

SISTEMAS DE ECUACIONES EN PROGRAMACIÓN LINEAL


Este método de resolución de sistemas de ecuaciones también se utiliza para la programación
lineal, donde las desigualdades definen restricciones y un objetivo se minimiza/maximiza.

103
PatrickJMT tiene muchos buenos videos sobre programación lineal. También lo cubrimos
brevemente en el Apéndice A.
En la práctica, rara vez encontrará necesario calcular matrices inversas a mano y puede hacer que
una computadora lo haga por usted. Pero si tiene una necesidad o tiene curiosidad, querrá
aprender sobre la eliminación gaussiana. PatrickJMT en YouTube tiene una serie de videos que
demuestran la eliminación de Gauss.

Vectores propios y valores propios


La descomposición de matrices consiste en descomponer una matriz en sus componentes básicos,
al igual que la factorización de números (p. ej., 10 se puede factorizar en 2 × 5).
La descomposición de matrices es útil para tareas como encontrar matrices inversas y calcular
determinantes, así como regresión lineal. Hay muchas formas de descomponer una matriz
dependiendo de su tarea. En el Capítulo 5 utilizaremos una técnica de descomposición de matrices,
descomposición QR, para realizar una regresión lineal.
Pero en este capítulo, centrémonos en un método común llamado descomposición propia, que a
menudo se usa para el aprendizaje automático y el análisis de componentes principales. A este
nivel no tenemos el ancho de banda para sumergirnos en cada una de estas aplicaciones.Por
ahora, sepa que la descomposición propia es útil para dividir una matriz en componentes con los
que es más fácil trabajar en diferentes tareas de aprendizaje automático.Tenga en cuenta que solo
funciona en matrices cuadradas.
En la descomposición propia, hay dos componentes: los valores propios indicados por lambda λ
y el vector propio por v que se muestran en la Figura 4-24.

Figura 4-24. El vector propio y los valores propios


Si tenemos una matriz cuadrada A, tiene la siguiente ecuación de valores propios:
Av = λv
Si A es la matriz original, está compuesta por el vector propio v y el valor propio λ. Hay un
vector propio y un valor propio para cada dimensión de la matriz principal, y no todas las matrices
se pueden descomponer en un vector propio y un valor propio. A veces incluso resultarán números
complejos (imaginarios).
El ejemplo 4-20 es cómo calculamos los vectores propios y los valores propios en NumPy para una
matriz A.
Ejemplo 4-20. Realización de autodescomposición en NumPy
from numpy import array, diag
from numpy.linalg import eig, inv
A = array([
[1, 2],
[4, 5]
])
eigenvals, eigenvecs = eig(A)
print("EIGENVALUES")
print(eigenvals)
print("\nEIGENVECTORS")
print(eigenvecs)

104
"""
EIGENVALUES
[-0.46410162 6.46410162]
EIGENVECTORS
[[-0.80689822 -0.34372377]
[ 0.59069049 -0.9390708 ]]
"""
Entonces, ¿cómo reconstruimos la matriz A a partir de los vectores propios y los valores propios?
Recuerda esta fórmula:
Av = λv
Necesitamos hacer algunos ajustes a la fórmula para reconstruir A :
A = QΛQ-1

En esta nueva fórmula, Q son los vectores propios, Λ son los valores propios en forma diagonal y
Q -1 es la matriz inversa de Q. La forma diagonal significa que el vector se rellena en una matriz de
ceros y ocupa la línea diagonal en un patrón similar a una matriz de identidad.
El ejemplo 4-21 completa el círculo del ejemplo en Python, comenzando con la descomposición de
la matriz y luego recomponiéndola.
Ejemplo 4-21. Descomponer y recomponer una matriz en NumPy
from numpy import array, diag
from numpy.linalg import eig, inv
A = array([
[1, 2],
[4, 5]
])
eigenvals, eigenvecs = eig(A)
print("EIGENVALUES")
print(eigenvals)
print("\nEIGENVECTORS")
print(eigenvecs)
print("\nREBUILD MATRIX")
Q = eigenvecs
R = inv(Q)
L = diag(eigenvals)
B=Q@L@R
print(B)
"""
EIGENVALUES
[-0.46410162 6.46410162]
EIGENVECTORS
[[-0.80689822 -0.34372377]
[ 0.59069049 -0.9390708 ]]
REBUILD MATRIX
[[1. 2.]
[4. 5.]]
"""
Como puede ver, la matriz que reconstruimos es con la que comenzamos.

Conclusión
El álgebra lineal puede ser enloquecedoramente abstracta y está llena de misterios e ideas para
reflexionar. Puede encontrar que todo el tema es una gran madriguera de conejo, ¡y tendría razón!
Sin embargo, es una buena idea seguir sintiendo curiosidad al respecto si desea tener una carrera
larga y exitosa en ciencia de datos.Es la base para la computación estadística, el aprendizaje
automático y otras áreas de ciencia de datos aplicada. En última instancia, es la base de la

105
informática en general. Ciertamente puede salirse con la suya sin saberlo por un tiempo, pero
encontrará limitaciones en su comprensión en algún momento.
Puede preguntarse cómo estas ideas son prácticas, ya que pueden parecer teóricas. No te
preocupes; veremos algunas aplicaciones prácticas a lo largo de este libro. Pero la teoría y las
interpretaciones geométricas son importantes para tener intuición cuando trabaja con datos, y al
comprender las transformaciones lineales visualmente, está preparado para asumir conceptos más
avanzados que se le pueden presentar más adelante en sus actividades.
Si desea obtener más información sobre la programación lineal, no hay mejor lugar que la lista de
reproducción de YouTube de 3Blue1Brown "Essence of Linear Algebra". Los videos de álgebra
lineal de PatrickJMT también son útiles.
Si desea sentirse más cómodo con NumPy, se recomienda leer el libro de O'Reilly Python for Data
Analysis (2.ª edición) de Wes McKinney. No se enfoca mucho en el álgebra lineal, pero brinda
instrucciones prácticas sobre el uso de NumPy, Pandas y Python en conjuntos de datos.

Ejercicios
1. El vector tiene un valor de [1, 2] pero luego ocurre una transformación. aterriza en [2,
0] y aterriza en [0, 1.5]. ¿Dónde cae ?
2. El vector tiene un valor de [1, 2] pero luego ocurre una transformación. i ^ aterriza en
[-2, 1] y aterriza en [1, -2]. ¿Dónde cae ?
3. Una transformación aterriza en [1, 0] y aterriza en [2, 2]. ¿Cuál es el determinante de
esta transformación?
4. ¿Se pueden hacer dos o más transformaciones lineales en una sola transformación lineal?
¿Por qué o por qué no?
5. Resuelva el sistema de ecuaciones para x, y y z :
3x + 1y + 0z == 54
2x + 4y + 1z = 12
3x + 1y + 8z = 6
6. ¿La siguiente matriz es linealmente dependiente? ¿Por qué o por qué no?

Las respuestas se encuentran en el Apéndice B.

106
Capítulo 5. Regresión lineal
Una de las técnicas más prácticas en el análisis de datos es ajustar una línea a través de los
puntos de datos observados para mostrar una relación entre dos o más variables. Una regresión
intenta ajustar una función a los datos observados para hacer predicciones sobre nuevos datos.
Una regresión lineal ajusta una línea recta a los datos observados, intentando demostrar una
relación lineal entre las variables y hacer predicciones sobre nuevos datos aún por observar.
Podría tener más sentido ver una imagen en lugar de leer una descripción de la regresión lineal.
Hay un ejemplo de una regresión lineal en la Figura 5-1.
La regresión lineal es un caballo de batalla de la ciencia de datos y las estadísticas y no solo aplica
los conceptos que aprendimos en los capítulos anteriores, sino que establece nuevas bases para
temas posteriores como las redes neuronales ( Capítulo 7 ) y la regresión logística ( Capítulo 6 ).
Esta técnica relativamente simple existe desde hace más de doscientos años y actualmente se
considera una forma de aprendizaje automático.
Los profesionales del aprendizaje automático a menudo adoptan un enfoque diferente para la
validación, comenzando con una división de datos de prueba de entrenamiento. Es más probable
que los estadísticos utilicen métricas como intervalos de predicción y correlación para la
significancia estadística. Cubriremos ambas escuelas de pensamiento para que los lectores puedan
cerrar la brecha cada vez mayor entre las dos disciplinas y, por lo tanto, se encuenTrain mejor
equipados para usar ambos sombreros.

Figura 5-1. Ejemplo de una regresión lineal, que ajusta una línea a los datos observados

ESPERA, ¿LA REGRESIÓN ES APRENDIZAJE AUTOMÁTICO?


El aprendizaje automático tiene varias técnicas bajo su paraguas, pero la que tiene más casos de
uso actualmente es el aprendizaje supervisado, y las regresiones juegan un papel importante aquí.
Esta es la razón por la cual la regresión lineal se califica como una forma de aprendizaje
automático. De manera confusa, los estadísticos pueden referirse a sus modelos de regresión
como aprendizaje estadístico, mientras que los profesionales de la ciencia de datos y el aprendizaje
automático llaman a sus modelos aprendizaje automático.
Si bien el aprendizaje supervisado suele ser una regresión, el aprendizaje automático no
supervisado tiene más que ver con la agrupación en clústeres y la detección de anomalías. El
aprendizaje por refuerzo a menudo combina el aprendizaje automático supervisado con la
simulación para generar rápidamente datos sintéticos.
Aprenderemos dos formas más de aprendizaje automático supervisado en el Capítulo 6 sobre
regresión logística y el Capítulo 7 sobre redes neuronales.

Una regresión lineal básica


Quiero estudiar la relación entre la edad de un perro y el número de visitas veterinarias que tuvo.
En una muestra fabricada tenemos 10 perros al azar. Soy fanático de comprender técnicas
complejas con conjuntos de datos simples (reales o no), por lo que comprendemos las fortalezas y

107
limitaciones de la técnica sin que los datos complejos enturbien el agua. Tracemos este conjunto de
datos como se muestra en la Figura 5-2.

Figura 5-2. Trazar una muestra de 10 perros con su edad y número de visitas al veterinario

Podemos ver claramente que hay una correlación lineal aquí, lo que significa que cuando una de
estas variables aumenta/disminuye, la otra aumenta/disminuye en una cantidad aproximadamente
proporcional. Podríamos trazar una línea a través de estos puntos para mostrar una correlación
como esta en la figura 5-3.

Figura 5-3. Ajustar una línea a través de nuestros datos

Mostraré cómo calcular esta línea ajustada más adelante en este capítulo. También exploraremos
cómo calcular la calidad de esta línea ajustada. Por ahora, concentrémonos en los beneficios de
realizar una regresión lineal. Nos permite hacer predicciones sobre datos que no hemos visto
antes. No tengo un perro en mi muestra que tenga 8.5 años, pero puedo mirar esta línea y estimar
que el perro tendrá 21 visitas veterinarias en su vida. Solo miro la línea donde x = 8.5 y veo que y =
21.218 como se muestra en la Figura 5-4. Otro beneficio es que podemos analizar las variables en
busca de posibles relaciones e hipotetizar que las variables correlacionadas son causales entre sí.
Ahora, ¿cuáles son las desventajas de una regresión lineal? No puedo esperar que todos los
resultados caigan exactamente en esa línea. Después de todo, los datos del mundo real son
ruidosos y nunca perfectos y no seguirán una línea recta. ¡Es posible que ni remotamente siga una
línea recta! Habrá un error alrededor de esa línea, donde el punto caerá por encima o por debajo

108
de la línea. Cubriremos esto matemáticamente cuando hablemos de los valores p, la significación
estadística y los intervalos de predicción, que describen qué tan confiable es nuestra regresión
lineal. Otro inconveniente es que no debemos usar la regresión lineal para hacer predicciones fuera
del rango de datos que tenemos, lo que significa que no debemos hacer predicciones donde x < 0 y
x > 10 porque no tenemos datos fuera de esos valores.

Figura 5-4. Haciendo una predicción usando una regresión lineal, viendo que se predice que un
perro de 8.5 años tendrá alrededor de 21.2 visitas al veterinario

¡NO OLVIDE EL SESGO DE MUESTREO!


Deberíamos cuestionar estos datos y cómo se tomaron muestras para detectar sesgos. ¿Fue esto
en una sola clínica veterinaria? ¿Múltiples clínicas al azar? ¿Existe un sesgo de autoselección al
usar datos veterinarios, solo perros de votación que visitan al veterinario? Si los perros fueron
muestreados en la misma geografía, ¿eso puede influir en los datos? Tal vez los perros en climas
desérticos cálidos acuden más al veterinario por agotamiento por calor y mordeduras de serpiente,
y esto inflaría nuestras visitas veterinarias en nuestra muestra.
Como se discutió en el Capítulo 3, se ha puesto de moda hacer de los datos un oráculo de la
verdad. Sin embargo, los datos son simplemente una muestra de una población, y debemos
practicar el discernimiento sobre qué tan bien representada está nuestra muestra. Esté tan
interesado (si no más) en de dónde provienen los datos y no solo en lo que dicen los datos.

Regresión lineal básica con SciPy


Tenemos mucho que aprender con respecto a la regresión lineal en este capítulo, pero
comencemos con algo de código para ejecutar lo que sabemos hasta ahora.
Hay muchas plataformas para realizar una regresión lineal, desde Excel hasta Python y R. Pero
nos quedaremos con Python en este libro, comenzando con scikit-learn para que haga el trabajo
por nosotros. Mostraré cómo construir una regresión lineal "desde cero" más adelante en este
capítulo para que comprendamos conceptos importantes como el descenso de gradiente y los
mínimos cuadrados.
El ejemplo 5-1 es cómo usamos scikit-learn para realizar una regresión lineal básica no validada en
la muestra de 10 perros. Obtenemos estos datos usando Pandas, los convertimos en arreglos
NumPy, realizamos una regresión lineal usando scikit-learn y usamos Plotly para mostrarlos en un
gráfico.
Ejemplo 5-1. Usando scikit-learn para hacer una regresión lineal
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# Import points
df = pd.read_csv('https://bit.ly/3goOAnt', delimiter=",")

109
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Fit a line to the points
fit = LinearRegression().fit(X, Y)
# m = 1.7867224, b = -16.51923513
m = fit.coef_.flatten()
b = fit.intercept_.flatten()
print("m = {0}".format(m))
print("b = {0}".format(b))
# show in chart
plt.plot(X, Y, 'o') # scatterplot
plt.plot(X, m*X+b) # line
plt.show()

Primero importamos los datos de este CSV en GitHub. Separamos las dos columnas en conjuntos
de datos X e Y usando Pandas. Luego fit() el modelo de regresión lineal a los datos de entrada X y
los datos de salida Y. Entonces podemos obtener los coeficientes m y b que describen nuestra
función lineal ajustada.
En el gráfico, seguramente obtendrá una línea ajustada que pasa por estos puntos que se
muestran en la Figura 5-5.

Figura 5-5. SciPy ajustará una línea de regresión a sus datos

¿Qué decide la mejor línea de ajuste a estos puntos? Vamos a discutir eso a continuación.

Residuos y errores cuadráticos


¿Cómo las herramientas estadísticas como scikit-learn crean una línea que se ajusta a estos
puntos? Todo se reduce a dos preguntas que son fundamentales para la capacitación en
aprendizaje automático:
 ¿Qué define un "mejor ajuste"?
 ¿Cómo llegamos a ese “mejor ajuste”?
La primera pregunta tiene una respuesta bastante establecida: minimizamos los cuadrados, o más
específicamente la suma de los cuadrados de los residuos. Analicemos eso. Dibuja cualquier línea
a través de los puntos. El residual es la diferencia numérica entre la línea y los puntos, como se
muestra en la Figura 5-6.

110
Figura 5-6. Los residuales son las diferencias entre la recta y los puntos.

Los puntos por encima de la línea tendrán un residuo positivo y los puntos por debajo de la línea
tendrán un residuo negativo. En otras palabras, es la diferencia sustraída entre los valores de y
pronosticados (derivados de la línea) y los valores de y reales (que provienen de los datos). Otro
nombre para los residuos son errores, porque reflejan cuán equivocada está nuestra línea al
predecir los datos.
Calculemos estas diferencias entre estos 10 puntos y la línea y = 1.93939 x + 4.73333 en el
Ejemplo 5-2 y los residuos para cada punto en el Ejemplo 5-3.

Ejemplo 5-2. Cálculo de los residuos para una línea y datos dados
import pandas as pd
# Import points
points = pd.read_csv('https://bit.ly/3goOAnt',
delimiter=",").itertuples()
# Test with a given line
m = 1.93939
b = 4.73333
# Calculate the residuals
for p in points:
y_actual = p.y
y_predict = m*p.x + b
residual = y_actual - y_predict
print(residual)

Ejemplo 5-3. Los residuos para cada punto


-1.67272
1.3878900000000005
-0.5515000000000008
2.5091099999999997
-0.4302799999999998
-1.3696699999999993f
0.6909400000000012
-2.2484499999999983
2.812160000000002
-1.1272299999999973

111
Si ajustamos una línea recta a través de nuestros 10 puntos de datos, probablemente queramos
minimizar estos residuos en total para que haya la menor brecha posible entre la línea y los puntos.
Pero, ¿cómo medimos el “total”? El mejor enfoque es tomar la suma de cuadrados, que
simplemente eleva al cuadrado cada residual, o multiplica cada residual por sí mismo, y los suma.
Tomamos cada valor y real y le restamos el valor y predicho tomado de la línea, luego elevamos al
cuadrado y sumamos todas esas diferencias.

¿POR QUÉ NO VALORES ABSOLUTOS?


Quizás se pregunte por qué tenemos que elevar al cuadrado los residuos antes de sumarlos. ¿Por
qué no simplemente sumarlos sin elevarlos al cuadrado? Eso no funcionará porque los negativos
cancelarán los positivos. ¿Qué pasa si sumamos los valores absolutos, donde convertimos todos
los valores negativos en valores positivos? Eso suena prometedor, pero los valores absolutos son
matemáticamente inconvenientes. Más específicamente, los valores absolutos no funcionan bien
con las derivadas de cálculo que usaremos más adelante para el descenso de gradiente. Es por
eso que elegimos los residuos al cuadrado como nuestra forma de totalizar la pérdida.

En la Figura 5-7 se muestra una forma visual de pensarlo, donde superponemos un cuadrado en
cada residual y cada lado es la longitud del residual. Sumamos el área de todos estos cuadrados, y
luego aprenderemos cómo encontrar la suma mínima que podemos lograr identificando los mejores
m y b.

Figura 5-7. Visualizar la suma de cuadrados, que sería la suma de todas las áreas donde cada
cuadrado tiene una longitud de lado igual al residual

Modifiquemos nuestro código en el Ejemplo 5-4 para encontrar la suma de los cuadrados.
Ejemplo 5-4. Cálculo de la suma de cuadrados para una línea y datos dados
import pandas as pd
# Import points
points = pd.read_csv("https://bit.ly/2KF29Bd").itertuples()
# Test with a given line
m = 1.93939
b = 4.73333
sum_of_squares = 0.0
# calculate sum of squares
for p in points:
y_actual = p.y
y_predict = m*p.x + b
residual_squared = (y_predict - y_actual)**2
sum_of_squares += residual_squared

112
print("sum of squares = {}".format(sum_of_squares))
# sum of squares = 28.096969704500005

Siguiente pregunta: ¿cómo encontramos los valores m y b que producirán la suma mínima de
cuadrados, sin usar una biblioteca como scikit-learn? Veamos eso a continuación.

Encontrar la mejor línea de ajuste


Ahora tenemos una forma de medir la calidad de una línea determinada frente a los puntos de
datos: la suma de cuadrados. Cuanto más bajo podamos hacer ese número, mejor será el ajuste.
Ahora, ¿cómo encontramos los valores correctos de m y b que crean la mínima suma de cuadrados
??
Hay un par de algoritmos de búsqueda que podemos emplear, que intentan encontrar el conjunto
correcto de valores para resolver un problema determinado. Puede probar un enfoque de fuerza
bruta, generando valores m y b aleatorios millones de veces y eligiendo los que producen la menor
suma de cuadrados. Esto no funcionará bien porque llevará una cantidad interminable de tiempo
encontrar incluso una aproximación decente. Necesitaremos algo un poco más guiado.
Seleccionaré cinco técnicas que puede usar: forma cerrada, inversión de matriz, descomposición
de matriz, descenso de gradiente y descenso de gradiente estocástico. Hay otros algoritmos de
búsqueda, como la escalada de colinas, que podrían usarse (y están cubiertos en el Apéndice A ),
pero nos apegaremos a lo que es común.

EL ENTRENAMIENTO DE APRENDIZAJE AUTOMÁTICO SE AJUSTA A UNA REGRESIÓN


Este es el corazón del “entrenamiento” de un algoritmo de aprendizaje automático. Proporcionamos
algunos datos y una función objetivo (la suma de cuadrados) y encontrará los coeficientes m y b
correctos para cumplir ese objetivo. Entonces, cuando "enTrain amos" un modelo de aprendizaje
automático, realmente estamos minimizando una función de pérdida.

Ecuación de forma cerrada


Algunos lectores pueden preguntar si existe una fórmula (llamada ecuación de forma cerrada ) para
ajustar una regresión lineal mediante un cálculo exacto. La respuesta es sí, pero solo para una
regresión lineal simple con una variable de entrada. Este lujo no existe para muchos problemas de
aprendizaje automático con varias variables de entrada y una gran cantidad de datos. Podemos
usar técnicas de álgebra lineal para escalar, y hablaremos de esto en breve. También
aprovecharemos para aprender sobre algoritmos de búsqueda como el descenso de gradiente
estocástico.
Para una regresión lineal simple con solo una entrada y una variable de salida, aquí están las
ecuaciones de forma cerrada para calcular m y b. El ejemplo 5-5 muestra cómo puede hacer estos
cálculos en Python.

Ejemplo 5-5. Cálculo de m y b para una regresión lineal simple

import pandas as pd
# Load the data
points = list(pd.read_csv('https://bit.ly/2KF29Bd',
delimiter=",").itertuples())
n = len(points)
m = (n*sum(p.x*p.y for p in points) - sum(p.x for p in points) *
sum(p.y for p in points)) / (n*sum(p.x**2 for p in points) -
sum(p.x for p in points)**2)

113
b = (sum(p.y for p in points) / n) - m * sum(p.x for p in points) / n
print(m, b)
# 1.9393939393939394 4.7333333333333325

Estas ecuaciones para calcular m y b se derivan del cálculo, y haremos algunos cálculos con
SymPy más adelante en este capítulo si tiene ganas de descubrir de dónde provienen las fórmulas.
Por ahora, puede ingresar la cantidad de puntos de datos n, así como iterar los valores x e y para
realizar las operaciones que se acaban de describir.
En el futuro, aprenderemos enfoques que están más orientados a las técnicas contemporáneas que
manejan grandes cantidades de datos. Las ecuaciones de forma cerrada tienden a no escalar bien.

COMPLEJIDAD COMPUTACIONAL
La razón por la que las ecuaciones de forma cerrada no se escalan bien con conjuntos de datos
más grandes se debe a un concepto informático llamado complejidad computacional, que mide
cuánto tiempo tarda un algoritmo a medida que crece el tamaño del problema. Puede valer la pena
familiarizarse con esto; aquí hay dos excelentes videos de YouTube sobre el tema:
 “P vs. NP y el Zoológico de la Complejidad Computacional”
 “¿Qué es la notación Big O?”

Técnicas de matriz inversa


En el futuro, alternaré a veces los coeficientes m y b con diferentes nombres β1 and β0
respectivamente. Esta es la convención que verás con más frecuencia en el mundo profesional, por
lo que podría ser un buen momento para graduarte.
Si bien dedicamos un capítulo completo al álgebra lineal en el Capítulo 4, aplicarlo puede ser un
poco abrumador cuando eres nuevo en matemáticas y ciencia de datos. Esta es la razón por la cual
la mayoría de los ejemplos en este libro usarán Python simple o scikit-learn. Sin embargo, agregaré
álgebra lineal donde tenga sentido, solo para mostrar cómo es útil el álgebra lineal. Si encuentra
esta sección abrumadora, siéntase libre de continuar con el resto del capítulo y regresar más tarde.
Podemos usar matrices transpuestas e inversas, que cubrimos en el Capítulo 4, para ajustar una
regresión lineal. A continuación, calculamos un vector de coeficientes b dada una matriz de
valores de variables de entrada X y un vector de valores de variables de salida y. Sin caer en
un agujero de conejo de cálculo y pruebas de álgebra lineal, aquí está la fórmula:
b = (XT X)-1 XT y

Notará que las operaciones transpuestas e inversas se realizan en la matriz X y se combinan con la
multiplicación de matrices. Así es como realizamos esta operación en NumPy en el Ejemplo 5-6
para obtener nuestros coeficientes m y b.
Ejemplo 5-6. Usar matrices inversas y transpuestas para ajustar una regresión lineal
import pandas as pd
from numpy.linalg import inv
import numpy as np
# Import points
df = pd.read_csv('https://bit.ly/3goOAnt', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1].flatten()
# Add placeholder "1" column to generate intercept
X_1 = np.vstack([X, np.ones(len(X))]).T
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Calculate coefficents for slope and intercept
b = inv(X_1.transpose() @ X_1) @ (X_1.transpose() @ Y)
print(b) # [1.93939394, 4.73333333]
# Predict against the y-values
y_predict = X_1.dot(b)

114
No es intuitivo, pero tenga en cuenta que tenemos que apilar una "columna" de 1 al lado de nuestra
columna X. La razón es que esto generará el coeficiente de intersección β0. Dado que esta
columna es todo 1, genera efectivamente la intersección y no solo una pendiente β1.
Cuando tiene muchos datos con muchas dimensiones, las computadoras pueden comenzar a
ahogarse y producir resultados inestables. Este es un caso de uso para la descomposición de
matrices, que aprendimos en el Capítulo 4 sobre álgebra lineal. En este caso específico, tomamos
nuestra matriz X, agregamos una columna adicional de 1 para generar la intersección β0 como
antes, y luego la descomponemos en dos matrices de componentes Q y R :
X=Q⋅R
Evitando más madrigueras de cálculo, así es como usamos Q y R para encontrar los valores del
coeficiente beta en la forma matricial b :
b = R-1 ⋅ QT ⋅ y
Y el Ejemplo 5-7 muestra cómo usamos la fórmula de descomposición QR anterior en Python
usando NumPy para realizar una regresión lineal.
Ejemplo 5-7. Uso de la descomposición QR para realizar una regresión lineal
import pandas as pd
from numpy.linalg import qr, inv
import numpy as np
# Import points
df = pd.read_csv('https://bit.ly/3goOAnt', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1].flatten()
# Add placeholder "1" column to generate intercept
X_1 = np.vstack([X, np.ones(len(X))]).transpose()
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# calculate coefficents for slope and intercept
# using QR decomposition
Q, R = qr(X_1)
b = inv(R).dot(Q.transpose()).dot(Y)
print(b) # [1.93939394, 4.73333333]
Por lo general, la descomposición QR es el método utilizado por muchas bibliotecas científicas para
la regresión lineal porque maneja grandes cantidades de datos más fácilmente y es más estable.
¿Qué quiero decir con estable ? La estabilidad numérica es qué tan bien un algoritmo mantiene los
errores minimizados, en lugar de amplificar los errores en las aproximaciones. Recuerde que las
computadoras funcionan solo con tantos decimales y tienen que aproximar, por lo que es
importante que nuestros algoritmos no se deterioren con errores compuestos en esas
aproximaciones.

¿ABRUMADA?
Si encuentra abrumadores estos ejemplos de álgebra lineal de regresión lineal, ¡no se preocupe!
Solo quería brindar exposición a un caso de uso práctico para el álgebra lineal. En el futuro, nos
centraremos en otras técnicas que puede utilizar.

Descenso de gradiente
El descenso de gradiente es una técnica de optimización que utiliza derivadas e iteraciones para
minimizar/maximizar un conjunto de parámetros frente a un objetivo. Para aprender sobre el
descenso de gradiente, hagamos un experimento mental rápido y luego aplíquelo en un ejemplo
simple.

Un experimento mental sobre el descenso de gradiente


Imagina que estás en una cadena montañosa de noche y te dan una linterna. Estás tratando de
llegar al punto más bajo de la cordillera. Puedes ver la pendiente a tu alrededor incluso antes de

115
dar un paso. Da un paso en direcciones donde la pendiente desciende visiblemente. Da pasos más
grandes para pendientes más grandes y pasos más pequeños para pendientes más pequeñas. En
última instancia, se encontrará en un punto bajo donde la pendiente es plana, un valor de 0. Suena
bastante bien, ¿verdad? Este acercamiento con la linterna se conoce como descenso de pendiente,
donde pisamos en direcciones donde la pendiente va hacia abajo.
En el aprendizaje automático, a menudo pensamos en todas las posibles sumas de pérdidas
cuadradas que encontraremos con diferentes parámetros como un paisaje montañoso. Queremos
minimizar nuestra pérdida y navegamos por el panorama de la pérdida para hacerlo. Para resolver
este problema, el descenso de gradiente tiene una característica atractiva: la derivada parcial es
esa linterna, que nos permite ver las pendientes para cada parámetro (en este caso m y b, o β0
and β1). Damos un paso en direcciones para m y b donde la pendiente va hacia abajo. Damos
pasos más grandes para pendientes más grandes y pasos más pequeños para pendientes más
pequeñas. Simplemente podemos calcular la longitud de este paso tomando una fracción de la
pendiente. Esta fracción se conoce como nuestra tasa de aprendizaje. Cuanto mayor sea la tasa de
aprendizaje, más rápido se ejecutará a costa de la precisión. Pero cuanto menor sea la tasa de
aprendizaje, más tiempo llevará enTrain ar y requerirá más iteraciones.
Decidir una tasa de aprendizaje es como elegir entre una hormiga, un humano o un gigante para
bajar la pendiente. Una hormiga (velocidad de aprendizaje pequeña) dará pequeños pasos y
tardará un tiempo inaceptablemente largo en llegar al fondo, pero lo hará con precisión. Un gigante
(gran tasa de aprendizaje) puede seguir superando el mínimo hasta el punto de que nunca lo
alcance, sin importar cuántos pasos dé. El ser humano (tasa de aprendizaje moderada)
probablemente tiene el tamaño de paso más equilibrado, teniendo el intercambio correcto entre
velocidad y precisión para llegar al mínimo.

Caminemos antes de correr


Para la función f (x) = (x - 3) + 4, , encontremos el valor de x que produce el punto más bajo de
2

esa función. Si bien podemos resolver esto algebraicamente, usemos el gradiente descendente
para hacerlo.
Esto es visualmente lo que estamos tratando de hacer. Como se muestra en la figura 5-8,
queremos "paso" x hacia el mínimo donde la pendiente es 0.

Figura 5-8. Caminando hacia el mínimo local donde la pendiente se aproxima a 0

En el ejemplo 5-8, la función f(x) y su derivada con respecto ax es dx_f(x). Recuerde que cubrimos
en el Capítulo 1 cómo usar SymPy para calcular derivadas. Después de encontrar la derivada,
procedemos a realizar un descenso de gradiente.
Ejemplo 5-8. Uso del descenso de gradiente para encontrar el mínimo de una parábola
import random
def f(x):
return (x - 3) ** 2 + 4

116
def dx_f(x):
return 2*(x - 3)
# The learning rate
L = 0.001
# The number of iterations to perform gradient descent
iterations = 100_000
# start at a random x
x = random.randint(-15,15)
for i in range(iterations):
# get slope
d_x = dx_f(x)
# update x by subtracting the (learning rate) * (slope)
x -= L * d_x
print(x, f(x)) # prints 2.999999999999889 4.0

Si graficamos la función (como se muestra en la Figura 5-8 ), deberíamos ver que el punto más
bajo de la función es claramente donde x = 3, y el código anterior debería acercarse mucho a eso.
La tasa de aprendizaje se usa para tomar una fracción de la pendiente y restarla del valor x en
cada iteración. Las pendientes más grandes darán como resultado pasos más grandes y las
pendientes más pequeñas darán como resultado pasos más pequeños. Después de suficientes
iteraciones, x terminará en el punto más bajo de la función (o lo suficientemente cerca de él) donde
la pendiente es 0.

Descenso de gradiente y regresión lineal


Ahora puede que se pregunte cómo usamos esto para la regresión lineal. Bueno, es la misma idea
excepto que nuestras "variables" son m y b (o β0 and β1) en lugar de x. Este es el motivo: en una
regresión lineal simple, ya conocemos los valores x e y porque se proporcionan como datos de
entrenamiento. Las "variables" que necesitamos resolver son en realidad los parámetros m y b, por
lo que podemos encontrar la línea de mejor ajuste que luego aceptará una variable x para predecir
un nuevo valor de y.
¿Cómo calculamos las pendientes de m y b ? Necesitamos las derivadas parciales de cada uno de
estos. ¿De qué función estamos tomando la derivada? Recuerde que estamos tratando de
minimizar la pérdida y que será la suma de los cuadrados. Así que necesitamos encontrar las
derivadas de nuestra función de suma de cuadrados con respecto a m y b.
Implementé estas dos derivadas parciales para m y b como se muestra en el ejemplo 5-9.
Aprenderemos cómo hacer esto en breve en SymPy. Luego realizo un descenso de gradiente para
encontrar m y b : 100,000 iteraciones con una tasa de aprendizaje de.001 serán suficientes. Tenga
en cuenta que cuanto más pequeña sea la tasa de aprendizaje, más lenta será y necesitará más
iteraciones. Pero si lo hace demasiado alto, correrá rápido pero tendrá una mala aproximación.
Cuando alguien dice que un algoritmo de aprendizaje automático está "aprendiendo" o "enTrain
ando", realmente se está ajustando a una regresión como esta.
Ejemplo 5-9. Descenso de gradiente para una regresión lineal
import pandas as pd
# Import points from CSV
points = list(pd.read_csv("https://bit.ly/2KF29Bd").itertuples())
# Building the model
m = 0.0
b = 0.0
# The learning Rate
L = .001
# The number of iterations
iterations = 100_000
n = float(len(points)) # Number of elements in X
# Perform Gradient Descent
for i in range(iterations):
# slope with respect to m

117
D_m = sum(2 * p.x * ((m * p.x + b) - p.y) for p in points)
# slope with respect to b
D_b = sum(2 * ((m * p.x + b) - p.y) for p in points)
# update m and b¡
m -= L * D_m
b -= L * D_b
print("y = {0}x + {1}".format(m, b))
# y = 1.9393939393939548x + 4.733333333333227
Bien no está mal! Esa aproximación se acercó a nuestra solución de ecuación de forma cerrada.
¿Pero cuál es el truco? El hecho de que hayamos encontrado la "línea de mejor ajuste"
minimizando la suma de cuadrados, eso no significa que nuestra regresión lineal sea buena.
¿Minimizar la suma de cuadrados garantiza un gran modelo para hacer predicciones? No
exactamente. Ahora que le mostré cómo ajustar una regresión lineal, demos un paso atrás,
revisemos el panorama general y determinemos si una regresión lineal dada es la forma correcta
de hacer predicciones en primer lugar. Pero antes de hacer eso, aquí hay un desvío más que
muestra la solución SymPy.

Descenso de gradiente para regresión lineal usando SymPy


Si desea el código SymPy que se le ocurrió con estos dos derivados para la función de suma de
cuadrados, para m y b respectivamente, este es el código del Ejemplo 5-10.
Ejemplo 5-10. Cálculo de derivadas parciales para m y b
from sympy import *
m, b, i, n = symbols('m b i n')
x, y = symbols('x y', cls=Function)
sum_of_squares = Sum((m*x(i) + b - y(i)) ** 2, (i, 0, n))
d_m = diff(sum_of_squares, m)
d_b = diff(sum_of_squares, b)
print(d_m)
print(d_b)
# OUTPUTS
# Sum(2*(b + m*x(i) - y(i))*x(i), (i, 0, n))
# Sum(2*b + 2*m*x(i) - 2*y(i), (i, 0, n))
Verá impresas las dos derivadas de m y b, respectivamente. Tenga en cuenta que la función Sum()
iterará y agregará elementos (en este caso, todos los puntos de datos), y tratamos x e y como
funciones que buscan un valor para un punto dado en el índice i.
En notación matemática, donde e ( x ) representa la función de pérdida de suma de cuadrados,
aquí están las derivadas parciales para m y b :

Si desea aplicar nuestro conjunto de datos y ejecutar una regresión lineal mediante el descenso de
gradiente, deberá realizar algunos pasos adicionales, como se muestra en el Ejemplo 5-11.
Tendremos que sustituir los valores n, x(i) e y(i), iterando todos nuestros puntos de datos para las
funciones derivadas d_m y d_b. Eso debería dejar solo las variables m y b, en las que buscaremos
los valores óptimos usando el descenso de gradiente.
Ejemplo 5-11. Resolviendo regresión lineal usando SymP

118
import pandas as pd
from sympy import *
# Import points from CSV
points = list(pd.read_csv("https://bit.ly/2KF29Bd").itertuples())
m, b, i, n = symbols('m b i n')
x, y = symbols('x y', cls=Function)
sum_of_squares = Sum((m*x(i) + b - y(i)) ** 2, (i, 0, n))
d_m = diff(sum_of_squares, m) \
.subs(n, len(points) - 1).doit() \
.replace(x, lambda i: points[i].x) \
.replace(y, lambda i: points[i].y)
d_b = diff(sum_of_squares, b) \
.subs(n, len(points) - 1).doit() \
.replace(x, lambda i: points[i].x) \
.replace(y, lambda i: points[i].y)
# compile using lambdify for faster computation
d_m = lambdify([m, b], d_m)
d_b = lambdify([m, b], d_b)
# Building the model
m = 0.0
b = 0.0
# The learning Rate
L = .001
# The number of iterations
iterations = 100_000
# Perform Gradient Descent
for i in range(iterations):
# update m and b
m -= d_m(m,b) * L
b -= d_b(m,b) * L
print("y = {0}x + {1}".format(m, b))
# y = 1.939393939393954x + 4.733333333333231

Como se muestra en el Ejemplo 5-11, es una buena idea llamar a lambdify() en nuestras dos
funciones derivadas parciales para convertirlas de SymPy a una función de Python optimizada.
Esto hará que los cálculos se realicen mucho más rápido cuando hagamos un descenso de
gradiente. Las funciones de Python resultantes están respaldadas por NumPy, SciPy o cualquier
biblioteca numérica que SymPy detecte que tenga disponible. Después de eso, podemos realizar
un descenso de gradiente.
Finalmente, si tiene curiosidad acerca de cómo se ve la función de pérdida para esta regresión
lineal simple, el ejemplo 5-12 muestra el código SymPy que conecta los valores x, y y n en nuestra
función de pérdida y luego traza m y b como la entrada Variables. Nuestro algoritmo de descenso
de gradiente nos lleva al punto más bajo en este paisaje de pérdida que se muestra en la Figura 5-
9.
Ejemplo 5-12. Trazado de la función de pérdida para la regresión lineal
from sympy import *
from sympy.plotting import plot3d
import pandas as pd
points = list(pd.read_csv("https://bit.ly/2KF29Bd").itertuples())
m, b, i, n = symbols('m b i n')
x, y = symbols('x y', cls=Function)
sum_of_squares = Sum((m*x(i) + b - y(i)) ** 2, (i, 0, n)) \
.subs(n, len(points) - 1).doit() \

119
. replace(x, lambda i: points[i].x) \
.replace(y, lambda i: points[i].y)
plot3d(sum_of_squares)

Figura 5-9. El panorama de pérdidas para una regresión lineal simple

Sobreajuste y varianza
Overfitting and Variance Adivina esto: si realmente quisiéramos minimizar la pérdida, como reducir
la suma de los cuadrados a 0, ¿qué haríamos? ¿Existen otras opciones además de la regresión
lineal? Una conclusión a la que puede llegar es simplemente ajustar una curva que toque todos los
puntos. Diablos, ¿por qué no simplemente conectar los puntos en segmentos y usarlos para hacer
predicciones como se muestra en la Figura 5-10 ? Eso nos da una pérdida de 0!
Vaya, ¿por qué pasamos por todos esos problemas con la regresión lineal y no hicimos esto en su
lugar? Bueno, recuerde que nuestro objetivo general no es minimizar la suma de cuadrados, sino
hacer predicciones precisas sobre nuevos datos. Este modelo de conectar los puntos está
severamente sobreajustado, lo que significa que moldeó la regresión a los datos de entrenamiento
con demasiada exactitud hasta el punto de que predecirá mal en los datos nuevos. Este modelo
simple de conectar los puntos es sensible a los valores atípicos que están lejos del resto de los
puntos, lo que significa que tendrá una gran variación en las predicciones. Si bien los puntos en
este ejemplo están relativamente cerca de una línea, este problema será mucho peor con otros
conjuntos de datos con más dispersión y valores atípicos. Debido a que el sobreajuste aumenta la
varianza, ¡las predicciones van a estar por todas partes!

Figura 5-10. Realizar una regresión simplemente conectando los puntos, lo que da como resultado
una pérdida cero

120
EL SOBREAJUSTE ES MEMORIZACIÓN
Cuando escucha a alguien decir que una regresión "memorizó" los datos en lugar de
generalizarlos, está hablando de sobreajuste.
Como puede adivinar, queremos encontrar generalizaciones efectivas en nuestro modelo en lugar
de memorizar datos. De lo contrario, nuestra regresión simplemente se convierte en una base de
datos donde buscamos valores.
Esta es la razón por la cual en el aprendizaje automático encontrará que se agrega sesgo al
modelo, y la regresión lineal se considera un modelo altamente sesgado. Esto no es lo mismo que
el sesgo en los datos, del que hablamos extensamente en el Capítulo 3. El sesgo en un modelo
significa que priorizamos un método (p. ej., mantener una línea recta) en lugar de doblarlo y
ajustarlo exactamente a lo que dicen los datos. Un modelo sesgado deja cierto margen de
maniobra con la esperanza de minimizar la pérdida de datos nuevos para obtener mejores
predicciones, en lugar de minimizar la pérdida de datos en los que se enTrain ó. Supongo que se
podría decir que agregar sesgo a un modelo contrarresta el sobreajuste con el ajuste insuficiente, o
que se ajuste menos a los datos de entrenamiento.
Como puedes imaginar, este es un acto de equilibrio porque se trata de dos objetivos
contradictorios. En el aprendizaje automático, básicamente decimos: “Quiero ajustar una regresión
a mis datos, pero no quiero ajustarla demasiado. Necesito algo de margen de maniobra para las
predicciones sobre nuevos datos que serán diferentes”.

REGRESIÓN DE LAZO Y CRESTA


Dos variantes algo populares de regresión lineal son la regresión de lazo y la regresión de cresta.
La regresión de cresta agrega un sesgo adicional a una regresión lineal en forma de penalización,
lo que hace que se ajuste menos a los datos. La regresión de Lasso intentará marginar las
variables ruidosas, lo que la hace útil cuando desea eliminar automáticamente las variables que
pueden ser irrelevantes.
Aún así, no podemos simplemente aplicar una regresión lineal a algunos datos, hacer algunas
predicciones con ellos y asumir que todo está bien. Una regresión lineal puede sobreajustarse
incluso con el sesgo de una línea recta. Por lo tanto, debemos verificar y mitigar tanto el ajuste
excesivo como el ajuste insuficiente para encontrar el punto óptimo entre los dos. Es decir, a
menos que no haya ninguno, en cuyo caso debe abandonar el modelo por completo.

Descenso de gradiente estocástico


Stochastic Gradient Descent En un contexto de aprendizaje automático, es poco probable que
realice un descenso de gradiente en la práctica como lo hicimos antes, donde enTrain amos en
todos los datos de entrenamiento (llamado batch gradient descent descenso de gradiente por
lotes ). En la práctica, es más probable que realice un descenso de gradiente estocástico, que
enTrain ará solo en una muestra del conjunto de datos en cada iteración. En el descenso de
gradiente de mini lotes, se utilizan múltiples muestras del conjunto de datos (por ejemplo, 10 o 100
puntos de datos) en cada iteración.
¿Por qué usar solo una parte de los datos en cada iteración? Los profesionales del aprendizaje
automático citan algunos beneficios. En primer lugar, reduce significativamente el cálculo, ya que
cada iteración no tiene que atravesar todo el conjunto de datos de entrenamiento, sino solo una
parte. El segundo beneficio es que reduce el sobreajuste. Exponer el algoritmo de entrenamiento a
solo una parte de los datos en cada iteración sigue cambiando el panorama de pérdida para que no
se asiente en el mínimo de pérdida. Después de todo, minimizar la pérdida es lo que causa el
sobreajuste, por lo que introducimos algo de aleatoriedad para crear un poco de subajuste (pero
esperemos que no demasiado).
Por supuesto, nuestra aproximación se vuelve suelta, por lo que debemos tener cuidado. Es por
eso que hablaremos sobre las divisiones de entrenamiento/prueba en breve, así como otras
métricas para evaluar la confiabilidad de nuestra regresión lineal.

El ejemplo 5-13 muestra cómo realizar un descenso de gradiente estocástico en Python. Si cambia
el tamaño de la muestra para que sea más de 1, realizará un descenso de gradiente de mini lotes.
Ejemplo 5-13. Descenso de gradiente estocástico para una regresión lineal

121
import pandas as pd
import numpy as np
# Input data
data = pd.read_csv('https://bit.ly/2KF29Bd', header=0)
X = data.iloc[:, 0].values
Y = data.iloc[:, 1].values
n = data.shape[0] # rows
# Building the model
m = 0.0
b = 0.0
sample_size = 1 # sample size
L = .0001 # The learning Rate
epochs = 1_000_000 # The number of iterations to perform gradient
descent
# Performing Stochastic Gradient Descent
for i in range(epochs):
idx = np.random.choice(n, sample_size, replace=False)
x_sample = X[idx]
y_sample = Y[idx]
# The current predicted value of Y
Y_pred = m * x_sample + b
# d/dm derivative of loss function
D_m = (-2 / sample_size) * sum(x_sample * (y_sample - Y_pred))
# d/db derivative of loss function
D_b = (-2 / sample_size) * sum(y_sample - Y_pred)
m = m - L * D_m # Update m
b = b - L * D_b # Update b
# print progress
if i % 10000 == 0:
print(i, m, b)
print("y = {0}x + {1}".format(m, b))

Cuando ejecuté esto, obtuve una regresión lineal de y = 1.9382830354181135 x +


4.753408787648379. Obviamente, sus resultados serán diferentes y, debido al descenso de
gradiente estocástico, en realidad no vamos a converger hacia un mínimo específico, sino que
terminaremos en un vecindario más amplio.

¿ES MALA LA ALEATORIEDAD?


Si esta aleatoriedad se siente incómoda cuando obtiene una respuesta diferente cada vez
que ejecuta un código, ¡bienvenido al mundo del aprendizaje automático, la optimización y
los algoritmos estocásticos! Muchos algoritmos que realizan aproximaciones se basan en
el azar y, aunque algunos son extremadamente útiles, otros pueden ser descuidados y
funcionar mal, como era de esperar.
Muchas personas ven el aprendizaje automático y la IA como una herramienta que brinda
respuestas objetivas y precisas, pero eso no puede estar más lejos de la verdad. El
aprendizaje automático produce aproximaciones con un grado de incertidumbre, a menudo
sin verdad básica una vez en producción. El aprendizaje automático puede ser mal
utilizado si uno no es consciente de cómo funciona, y es negligente no reconocer su
naturaleza no determinista y aproximada.
Si bien la aleatoriedad puede crear algunas herramientas poderosas, también se puede
abusar de ella. Tenga cuidado de no usar valores iniciales y aleatoriedad para piratear un
resultado "bueno", y esfuércese en analizar sus datos y modelo.

122
El coeficiente de correlación
Eche un vistazo a este diagrama de dispersión en la Figura 5-11 junto con su regresión lineal. ¿Por
qué una regresión lineal podría no funcionar muy bien aquí??

Figura 5-11. Un diagrama de dispersión de datos con alta varianza

El problema aquí es que los datos tienen una gran variación. Si los datos están extremadamente
dispersos, aumentará la varianza hasta el punto en que las predicciones se volverán menos
precisas y útiles, lo que dará como resultado grandes residuos. Por supuesto, podemos introducir
un modelo más sesgado, como la regresión lineal, para no doblar y responder a la varianza tan
fácilmente. Sin embargo, el ajuste insuficiente también socavará nuestras predicciones porque los
datos están muy dispersos. Necesitamos medir numéricamente qué tan "apagadas" están nuestras
predicciones.
Entonces, ¿cómo se miden estos residuos en conjunto? ¿Cómo se obtiene también una idea de
cuán mala es la variación en los datos? Permítame presentarle el coeficiente de correlación,
también llamado correlación de Pearson, que mide la fuerza de la relación entre dos variables
como un valor entre -1 y 1. Un coeficiente de correlación más cercano a 0 indica que no hay
correlación. Un coeficiente de correlación más cercano a 1 indica una fuerte correlación positiva, lo
que significa que cuando una variable aumenta, la otra aumenta proporcionalmente. Si está más
cerca de -1, indica una fuerte correlación negativa, lo que significa que a medida que una variable
aumenta, la otra disminuye proporcionalmente.
Tenga en cuenta que el coeficiente de correlación a menudo se denota como r. Los datos
altamente dispersos de la figura 5-11 tienen un coeficiente de correlación de 0,1201. Dado que está
mucho más cerca de 0 que de 1, podemos inferir que los datos tienen poca correlación.
Aquí hay otros cuatro diagramas de dispersión en la figura 5-12 que muestran sus coeficientes de
correlación. Observe que cuanto más sigan los puntos una línea, más fuerte será la correlación.
Los puntos más dispersos dan como resultado correlaciones más débiles.

123
Figura 5-12. Coeficientes de correlación para cuatro diagramas de dispersión

Como puedes imaginar, el coeficiente de correlación es útil para ver si existe una posible relación
entre dos variables. Si hay una fuerte relación positiva-negativa, será útil en nuestra regresión
lineal. Si no hay una relación, es posible que solo agreguen ruido y dañen la precisión del modelo.
¿Cómo usamos Python para calcular el coeficiente de correlación? Usemos el conjunto de datos
simple de 10 puntos que usamos anteriormente. Una forma rápida y sencilla de analizar las
correlaciones de todos los pares de variables es utilizar la función corr() de Pandas. Esto facilita ver
el coeficiente de correlación entre cada par de variables en un conjunto de datos, que en este caso
solo será x e y. Esto se conoce como matriz de correlación. Eche un vistazo al ejemplo 5-14.
Ejemplo 5-14. Usando Pandas para ver el coeficiente de correlación entre cada par de variables
import pandas as pd
# Read data into Pandas dataframe
df = pd.read_csv('https://bit.ly/2KF29Bd', delimiter=",")
# Print correlations between variables
correlations = df.corr(method='pearson')
print(correlations)
# OUTPUT:
#xy
# x 1.000000 0.957586
# y 0.957586 1.000000
Como puede ver, el coeficiente de correlación 0.957586 entre x e y indica una fuerte correlación
positiva entre las dos variables. Puede ignorar las partes de la matriz donde x o y se establece en
sí mismo y tiene un valor de 1.0. Obviamente, cuando x o y se establece en sí mismo, la
correlación será perfecta en 1.0, porque los valores coinciden exactamente. Cuando tiene más de
dos variables, la matriz de correlación mostrará una cuadrícula más grande porque hay más
variables para emparejar y comparar.
Si cambia el código para usar un conjunto de datos diferente con mucha variación, donde los datos
están dispersos, verá que el coeficiente de correlación disminuye. Esto nuevamente indica una
correlación más débil.

CÁLCULO DEL COEFICIENTE DE CORRELACIÓN


Para aquellos que tienen curiosidad matemática sobre cómo se calcula el coeficiente de
correlación, aquí está la fórmula:

)
Si desea ver esto completamente implementado en Python, me gusta usar bucles for de una línea
para hacer esas sumas. El ejemplo 5-15 muestra un coeficiente de correlación implementado
desde cero en Python.
Ejemplo 5-15. Cálculo del coeficiente de correlación desde cero en Python
import pandas as pd
from math import sqrt
# Import points from CSV
points = list(pd.read_csv("https://bit.ly/2KF29Bd").itertuples())
n = len(points)
numerator = n * sum(p.x * p.y for p in points) - \
sum(p.x for p in points) * sum(p.y for p in points)
denominator = sqrt(n*sum(p.x**2 for p in points) - sum(p.x for p in
points)**2) \
* sqrt(n*sum(p.y**2 for p in points) - sum(p.y for p in
points)**2)
corr = numerator / denominator
print(corr)
# OUTPUT:
# 0.9575860952087218

124
Significancia estadística
Aquí hay otro aspecto de una regresión lineal que debe considerar: ¿mi correlación de datos es
coincidente? En el Capítulo 3 estudiamos la prueba de hipótesis y los valores p, y vamos a
extender esas ideas aquí con una regresión lineal.
LA BIBLIOTECA DE MODELOS ESTADÍSTICOS
Si bien no vamos a presentar otra biblioteca más en este libro, vale la pena mencionar que
statsmodel es digno de mención si desea realizar análisis estadísticos.
Scikit-learn y otras bibliotecas de aprendizaje automático no brindan herramientas para la
significación estadística y los intervalos de confianza por razones que discutiremos en otra barra
lateral. Vamos a codificar esas técnicas nosotros mismos. ¡Pero sepa que esta biblioteca existe y
vale la pena echarle un vistazo!
Comencemos con una pregunta fundamental: ¿es posible que vea una relación lineal en mis datos
debido al azar? ¿Cómo podemos estar 95% seguros de que la correlación entre estas dos
variables es significativa y no coincidente? Si esto suena como una prueba de hipótesis del
Capítulo 3, ¡es porque lo es! Necesitamos no solo expresar el coeficiente de correlación, sino
también cuantificar qué tan seguros estamos de que el coeficiente de correlación no ocurrió por
casualidad.
En lugar de estimar una media como hicimos en el Capítulo 3 con el ejemplo de la prueba de
drogas, estamos estimando el coeficiente de correlación de la población con base en una muestra.
Denotamos el coeficiente de correlación de la población con el símbolo griego ρ (Rho), mientras
que nuestro coeficiente de correlación de la muestra es r. Tal como hicimos en el Capítulo 3,
tendremos una hipótesis nula H0 y una hipótesis alternativa H1:
H0 : ρ = 0 (implies no relationship)
H1 : ρ ≠ 0 (relationship is present)
Nuestra hipótesis nula H0 es que no hay relación entre dos variables, o más técnicamente, el
coeficiente de correlación es 0. La hipótesis alternativa H 1 es que hay una relación, y puede ser
una correlación positiva o negativa. Es por esto que la hipótesis alternativa se define como ρ ≠ 0
para sustentar una correlación tanto positiva como negativa.
Volvamos a nuestro conjunto de datos de 10 puntos como se muestra en la Figura 5-13. ¿Qué tan
probable es que veamos estos puntos de datos por casualidad? ¿Y resultan producir lo que parece
una relación lineal?

Figura 5-13. ¿Qué tan probable es que veamos estos datos, que parecen tener una correlación
lineal, por casualidad aleatoria?

Ya calculamos el coeficiente de correlación para este conjunto de datos en el ejemplo 5-14, que es
0,957586. Esa es una correlación positiva fuerte y convincente. Pero nuevamente, necesitamos
evaluar si esto fue por suerte al azar. Prosigamos nuestra prueba de hipótesis con un 95 % de

125
confianza usando una prueba de dos colas, explorando si existe una relación entre estas dos
variables.
Hablamos sobre la distribución T en el Capítulo 3, que tiene colas más anchas para capturar más
varianza e incertidumbre. Usamos una distribución T en lugar de una distribución normal para hacer
pruebas de hipótesis con regresión lineal. Primero, tracemos una distribución T con un rango de
valores críticos del 95 % como se muestra en la figura 5-14. Tomamos en cuenta el hecho de que
hay 10 registros en nuestra muestra y, por lo tanto, tenemos 9 grados de libertad (10 – 1 = 9).

Figura 5-14. Una distribución T con 9 grados de libertad, ya que hay 10 registros y restamos 1

El valor crítico es aproximadamente ±2.262 y podemos calcularlo en Python como se muestra en el


ejemplo 5-16. Esto captura el 95 % del área central de nuestra distribución en T.
Ejemplo 5-16. Cálculo del valor crítico de una distribución T
from scipy.stats import t
n = 10
lower_cv = t(n-1).ppf(.025)
upper_cv = t(n-1).ppf(.975)
print(lower_cv, upper_cv)
# -2.262157162740992 2.2621571627409915
Si nuestro valor de prueba cae fuera de este rango de (-2.262, 2.262), entonces podemos rechazar
nuestra hipótesis nula. Para calcular el valor de prueba t, necesitamos usar la siguiente fórmula.
Nuevamente, r es el coeficiente de correlación y n es el tamaño de la muestra:

Pongamos la prueba completa en Python como se muestra en el Ejemplo 5-17. Si nuestro valor de
prueba cae fuera del rango crítico del 95% de confianza, aceptamos que nuestra correlación no fue
por casualidad.
Ejemplo 5-17. Prueba de significación para datos de apariencia lineal
from scipy.stats import t
from math import sqrt
# sample size
n = 10
lower_cv = t(n-1).ppf(.025)
upper_cv = t(n-1).ppf(.975)
# correlation coefficient
# derived from data https://bit.ly/2KF29Bd

126
r = 0.957586
# Perform the test
test_value = r / sqrt((1-r**2) / (n-2))
print("TEST VALUE: {}".format(test_value))
print("CRITICAL RANGE: {}, {}".format(lower_cv, upper_cv))
if test_value < lower_cv or test_value > upper_cv:
print("CORRELATION PROVEN, REJECT H0")
else:
print("CORRELATION NOT PROVEN, FAILED TO REJECT H0 ")
# Calculate p-value
if test_value > 0:
p_value = 1.0 - t(n-1).cdf(test_value)
else:
p_value = t(n-1).cdf(test_value)
# Two-tailed, so multiply by 2
p_value = p_value * 2
print("P-VALUE: {}".format(p_value))

El valor de la prueba aquí es de aproximadamente 9,39956, que definitivamente está fuera del
rango de (-2,262, 2,262), por lo que podemos rechazar la hipótesis nula y decir que nuestra
correlación es real. Eso es porque el valor p es notablemente significativo:.000005976. Esto está
muy por debajo de nuestro umbral de 0,05, por lo que prácticamente no es una coincidencia: existe
una correlación. Tiene sentido que el valor p sea tan pequeño porque los puntos se parecen mucho
a una línea. Es muy poco probable que estos puntos se hayan dispuesto al azar cerca de una línea
tan cerca por casualidad.
La figura 5-15 muestra algunos otros conjuntos de datos con sus coeficientes de correlación y
valores p. Analiza cada uno de ellos. ¿Cuál es probablemente el más útil para las predicciones?
¿Cuáles son los problemas con los otros?

Figura 5-15. Diferentes conjuntos de datos y sus coeficientes de correlación y valores p

Ahora que ha tenido la oportunidad de trabajar en el análisis de los conjuntos de datos de la Figura
5-15, repasemos los hallazgos. La figura de la izquierda tiene una correlación positiva alta, pero
solo tiene tres puntos. La falta de datos aumenta significativamente el valor p a 0,34913 y aumenta
la probabilidad de que los datos se hayan producido por casualidad. Esto tiene sentido porque
tener solo tres puntos de datos hace probable ver un patrón lineal, pero no es mucho mejor que
tener dos puntos que simplemente conectarán una línea entre ellos. Esto trae a colación una regla
importante: tener más datos disminuirá su valor p, especialmente si esos datos gravitan hacia una
línea.
La segunda figura es lo que acabamos de cubrir. Tiene solo 10 puntos de datos, pero forma un
patrón lineal tan bien que no solo tenemos una fuerte correlación positiva sino también un valor p
extremadamente bajo. Cuando tiene un valor de p tan bajo, puede apostar que está midiendo un
proceso diseñado y estrictamente controlado, no algo sociológico o natural.

127
Las dos imágenes de la derecha en la figura 5-15 no logran identificar una relación lineal. Su
coeficiente de correlación es cercano a 0, lo que indica que no hay correlación, y los valores p,
como era de esperar, indican que la aleatoriedad desempeñó un papel.
La regla es esta: cuantos más datos tenga que se asemejen consistentemente a una línea, más
significativo será el valor p para su correlación. Cuanto más dispersos o escasos sean los datos,
más aumentará el valor p y, por lo tanto, indicará que su correlación ocurrió por casualidad.
Coeficiente de determinación
Aprendamos una métrica importante que verá mucho en estadísticas y regresiones de aprendizaje
automático. El coeficiente de determinación, llamado r 2 , mide cuánta variación en una variable se
explica por la variación de la otra variable. También es el cuadrado del coeficiente de correlación
r. A medida que r se acerca a una correlación perfecta (–1 o 1), r 2 se acerca a 1.
Esencialmente, r muestra cuánto interactúan dos variables entre sí.
2

Continuemos viendo nuestros datos de la Figura 5-13. En el Ejemplo 5-18, tome nuestro código de
marco de datos anterior que calcula el coeficiente de correlación y luego simplemente cuadrelo.
Eso multiplicará cada coeficiente de correlación por sí mismo.
Ejemplo 5-18. Creando una matriz de correlación en Pandas
import pandas as pd
# Read data into Pandas dataframe
df = pd.read_csv('https://bit.ly/2KF29Bd', delimiter=",")
# Print correlations between variables
coeff_determination = df.corr(method='pearson') ** 2
print(coeff_determination)
# OUTPUT:
#xy
# x 1.000000 0.916971
# y 0.916971 1.000000
Un coeficiente de determinación de 0,916971 se interpreta como que el 91,6971% de la variación
de x es explicada por y (y viceversa), y el 8,3029% restante es ruido provocado por otras variables
no captadas; 0,916971 es un coeficiente de determinación bastante bueno, que muestra que x e y
explican la varianza de cada uno. Pero podría haber otras variables en juego que compongan ese
0.083029 restante. Recuerde, la correlación no es igual a la causalidad, por lo que podría haber
otras variables que contribuyan a la relación que estamos viendo.

¡CORRELACIÓN NO ES CAUSALIDAD!
Es importante tener en cuenta que si bien ponemos mucho énfasis en medir la correlación y
construir métricas a su alrededor, ¡recuerde que la correlación no es causalidad! Probablemente
hayas escuchado ese mantra antes, pero quiero explicar por qué los estadísticos lo dicen.
El hecho de que veamos una correlación entre x e y no significa que x cause y. ¡En realidad podría
ser y causa x ! O tal vez hay una tercera variable z no capturada que está causando x e y. Podría
ser que x e y no se causen entre sí en absoluto y la correlación sea solo una coincidencia, por lo
que es importante que midamos la significación estadística.
Ahora tengo una pregunta más apremiante para usted. ¿Pueden las computadoras discernir entre
correlación y causalidad? La respuesta es un rotundo "¡NO!" Las computadoras tienen el concepto
de correlación pero no de causalidad. Supongamos que cargo un conjunto de datos en scikit-learn
que muestra los galones de agua consumidos y mi factura de agua. Mi computadora, o cualquier
programa que incluya scikit-learn, no tiene idea de si un mayor uso de agua provoca una factura
más alta o si una factura más alta provoca un mayor uso de agua. Un sistema de IA podría concluir
fácilmente esto último, por absurdo que sea. Esta es la razón por la que muchos proyectos de
aprendizaje automático requieren un ser humano al tanto para inyectar sentido común.
En la visión por computadora, esto también sucede. La visión por computadora a menudo usa una
regresión en los píxeles numéricos para predecir una categoría. Si enTrain o un sistema de visión
por computadora para que reconozca vacas usando imágenes de vacas, puede hacer
correlaciones fácilmente con el campo en lugar de con las cows vacas. Por lo tanto, si muestro una
imagen de un campo vacío, ¡etiquetará la hierba como vacas! Nuevamente, esto se debe a que las
computadoras no tienen un concepto de causalidad (la forma de la vaca debería causar la etiqueta
"vaca cow ") y, en cambio, se pierden en las correlaciones que no nos interesan.

128
Error estándar de la estimación
Una forma de medir el error general de una regresión lineal es el SSE, o suma de errores al
cuadrado. Aprendimos sobre esto antes, cuando elevamos al cuadrado cada residual y los
sumamos. Si (pronunciado “y-hat”) es cada valor predicho de la línea e y representa cada valor
real de y de los datos, este es el cálculo:

Sin embargo, todos estos valores cuadrados son difíciles de interpretar, por lo que
podemos usar alguna lógica de raíz cuadrada para escalar las cosas a sus unidades
originales. También promediaremos todos ellos, y esto es lo que hace el error estándar de
la estimación ( Se). Si n es el número de puntos de datos, el Ejemplo 5-19 muestra cómo
calculamos el error estándar Se en Python.

Ejemplo 5-19. Cálculo del error estándar de la estimación

Here is how we calculate it in Python:


import pandas as pd
from math import sqrt
# Load the data
points = list(pd.read_csv('https://bit.ly/2KF29Bd',
delimiter=",").itertuples())
n = len(points)
# Regression line
m = 1.939
b = 4.733
# Calculate Standard Error of Estimate
S_e = sqrt((sum((p.y - (m*p.x +b))**2 for p in points))/(n-2))
print(S_e)
# 1.87406793500129
Por qué n-2 en lugar de n-1 , como hicimos en tantos cálculos de varianza en el
Capítulo 3 ? Sin profundizar mucho en demostraciones matemáticas, esto se debe a que
una regresión lineal tiene dos variables, no solo una, por lo que tenemos que aumentar la
incertidumbre en uno más en nuestros grados de libertad.
Notará que el error estándar de la estimación se parece notablemente a la desviación
estándar que estudiamos en el Capítulo 3. Esto no es por accidente. Eso es porque es la
desviación estándar para una regresión lineal.

Intervalos de predicción
Como se mencionó anteriormente, nuestros datos en una regresión lineal son una muestra
de una población. Por lo tanto, nuestra regresión es tan buena como nuestra muestra.
Nuestra línea de regresión lineal también tiene una distribución normal a lo largo de ella.
Efectivamente, esto hace que cada valor de y pronosticado sea una estadística de muestra
como la media. De hecho, la "media" se desplaza a lo largo de la línea.

¿Recuerdas cuando hablamos de estadística en el Capítulo 2 sobre la varianza y la


desviación estándar? Los conceptos se aplican aquí también. Con una regresión lineal,
esperamos que los datos sigan una distribución normal de forma lineal. Una línea de
regresión sirve como la "media" móvil de nuestra curva de campana, y la dispersión de los
datos alrededor de la línea refleja la varianza/desviación estándar, como se muestra en la
Figura 5-16.

129
Figura 5-16. Una regresión lineal supone que una distribución normal sigue la línea

Cuando tenemos una distribución normal que sigue una línea de regresión lineal, no solo tenemos
una variable, sino también una segunda variable que dirige la distribución. Hay un intervalo de
confianza alrededor de cada predicción y, y esto se conoce como intervalo de predicción.
Traigamos un poco de contexto con nuestro ejemplo veterinario, estimando la edad de un perro y el
número de visitas al veterinario. Quiero saber el intervalo de predicción para el número de visitas al
veterinario con un 95 % de confianza para un perro de 8,5 años. El aspecto de este intervalo de
predicción se muestra en la Figura 5-17. Tenemos un 95% de confianza en que un perro de 8,5
años tendrá entre 16.462 y 25.966 visitas al veterinario.

Figura 5-17. Un intervalo de predicción para un perro que tiene 8,5 años con un 95 % de confianza

¿Cómo calculamos esto? Necesitamos obtener el margen de error y más/menos alrededor del valor
y predicho. Es una ecuación bestial que implica un valor crítico de la distribución T, así como el
error estándar de la estimación. Vamos a ver:

El valor de x que nos interesa se especifica como x 0 , que en este caso es 8.5. Así es como
resolvemos esto en Python, que se muestra en el Ejemplo 5-20.

130
Ejemplo 5-20. Cálculo de un intervalo de predicción de visitas al veterinario para un perro de 8,5
años
import pandas as pd
from scipy.stats import t
from math import sqrt
# Load the data
points = list(pd.read_csv('https://bit.ly/2KF29Bd',
delimiter=",").itertuples())
n = len(points)
# Linear Regression Line
m = 1.939
b = 4.733
# Calculate Prediction Interval for x = 8.5
x_0 = 8.5
x_mean = sum(p.x for p in points) / len(points)
t_value = t(n - 2).ppf(.975)
standard_error = sqrt(sum((p.y - (m * p.x + b)) ** 2 for p in points) /
(n - 2))
margin_of_error = t_value * standard_error * \
sqrt(1 + (1 / n) + (n * (x_0 - x_mean) ** 2) / \¡
(n * sum(p.x ** 2 for p in points) - \
sum(p.x for p in points) ** 2))
predicted_y = m*x_0 + b
# Calculate prediction interval
print(predicted_y - margin_of_error, predicted_y + margin_of_error)
# 16.462516875955465 25.966483124044537
Oye! Eso es mucho cálculo y, desafortunadamente, SciPy y otras bibliotecas de ciencia de datos
convencionales no hacen esto. Pero si te inclinas por el análisis estadístico, esta es una
información muy útil. No solo creamos una predicción basada en una regresión lineal (p. ej., un
perro de 8,5 años tendrá 21,2145 visitas al veterinario), sino que también podemos decir algo
mucho menos absoluto: hay un 95 % de probabilidad de que un perro de 8,5 años visitará al
veterinario entre 16,46 y 25,96 veces. Brillante, ¿verdad? Y es una afirmación mucho más segura
porque captura un rango en lugar de un solo valor y, por lo tanto, representa la incertidumbre.

INTERVALOS DE CONFIANZA PARA LOS PARÁMETROS


Cuando lo piensa, la línea de regresión lineal en sí misma es una estadística de muestra, y hay una
línea de regresión lineal para toda la población que estamos tratando de inferir. Esto significa que
parámetros como m y b tienen sus propias distribuciones, y podemos modelar intervalos de
confianza alrededor de m y b individualmente para reflejar la pendiente de la población y la
intersección con el eje y. Esto va más allá del alcance de este libro, pero vale la pena señalar que
este tipo de análisis se puede hacer.
Puede encontrar recursos para hacer estos cálculos desde cero, pero podría ser más fácil usar las
herramientas o bibliotecas de regresión de Excel para Python.

Train /Divisiones de prueba


Train/Test Splits Lamentablemente, este análisis que acabo de hacer con el coeficiente de
correlación, la significación estadística y el coeficiente de determinación no siempre lo realizan los
profesionales. A veces, manejan tantos datos que no tienen el tiempo o la capacidad técnica para
hacerlo. Por ejemplo, una imagen de 128 × 128 píxeles tiene al menos 16 384 variables. ¿Tiene
tiempo para hacer un análisis estadístico de cada una de esas variables de píxeles?
¡Probablemente no! Desafortunadamente, esto lleva a muchos científicos de datos a no aprender
estas métricas estadísticas en absoluto.
En un oscuro foro en línea, una vez leí una publicación que decía que la regresión estadística es un
bisturí, mientras que el aprendizaje automático es una motosierra. Cuando se opera con cantidades
masivas de datos y variables, no se puede filtrar todo eso con un bisturí. Tienes que recurrir a una
motosierra y mientras pierdes explicabilidad y precisión, al menos puedes escalar para hacer
predicciones más amplias sobre más datos. Dicho esto, las preocupaciones estadísticas como el

131
sesgo de muestreo y el sobreajuste no desaparecen. Pero hay algunas prácticas que se pueden
emplear para una validación rápida.

¿POR QUÉ NO HAY INTERVALOS DE CONFIANZA NI VALORES P EN SCIKIT-LEARN?


Scikit-learn no admite intervalos de confianza ni valores P, ya que estas dos técnicas son
problemas abiertos para datos de mayor dimensión. Esto solo enfatiza la brecha entre los
estadísticos y los profesionales del aprendizaje automático. Como uno de los mantenedores de
scikit-learn, Gael Varoquaux, dijo: “En general, calcular los valores p correctos requiere
suposiciones sobre los datos que no se cumplen con los datos utilizados en el aprendizaje
automático (sin multicolinealidad, suficientes datos en comparación con la dimensionalidad) ….Los
valores P son algo que se espera que estén bien comprobados (son una guardia en la investigación
médica). Implementarlos es buscar problemas.. Podemos dar valores p solo en configuraciones
muy estrechas [con pocas variables]".
Si quieres ir por la madriguera del conejo, hay algunas discusiones interesantes en GitHub:
 https://github.com/scikit-learn/scikit-learn/issues/6773
 https://github.com/scikit-learn/scikit-learn/issues/16802

Como se mencionó anteriormente, statsmodel es una biblioteca que proporciona herramientas


útiles para el análisis estadístico. Solo sepa que es probable que no se escale a modelos de
dimensiones más grandes debido a las razones antes mencionadas.
Una técnica básica que usan los profesionales del aprendizaje automático para mitigar el
sobreajuste es una práctica llamada división de entrenamiento/prueba, en la que normalmente 1/3
de los datos se reserva para la prueba y los otros 2/3 se usan para el entrenamiento (otras
proporciones se pueden usar como bien). El conjunto de datos de entrenamiento se usa para
ajustar la regresión lineal, mientras que el conjunto de datos de prueba se usa para medir el
rendimiento de la regresión lineal en datos que no se han visto antes. Esta técnica se usa
generalmente para todo el aprendizaje automático supervisado, incluida la regresión logística y las
redes neuronales. La Figura 5-18 muestra una visualización de cómo dividimos nuestros datos en
2/3 para entrenamiento y 1/3 para prueba.

ESTE ES UN PEQUEÑO CONJUNTO DE DATOS


Como veremos más adelante, hay otras formas de dividir un conjunto de datos de
entrenamiento/prueba además de 2/3 y 1/3. Si tiene un conjunto de datos tan pequeño,
probablemente estará mejor con 9/10 y 1/10 combinados con validación cruzada, o incluso dejar
una validación cruzada. Consulte "¿Las divisiones de entrenamiento/prueba tienen que ser
tercios?" aprender más.

Figura 5-18. Dividir en datos de entrenamiento/prueba: la línea se ajusta a los datos de


entrenamiento (azul oscuro) usando mínimos cuadrados, mientras que los datos de prueba (rojo
claro) se analizan después para ver qué tan mal están las predicciones en datos que no se vieron
antes

El ejemplo 5-21 muestra cómo realizar una división de entrenamiento/prueba con scikit-learn,
donde 1/3 de los datos se reserva para la prueba y los otros 2/3 se usan para el entrenamiento.

EL ENTRENAMIENTO ES AJUSTAR UNA REGRESIÓN

132
Recuerde que “fitting ajustar” una regresión es sinónimo de “training entrenar”. La última palabra
es utilizada por los profesionales del aprendizaje automático.
Ejemplo 5-21. Haciendo una división de Train /prueba en regresión lineal
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import train_test_split
# Load the data
df = pd.read_csv('https://bit.ly/3cIH97A', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Separate training and testing data
# This leaves a third of the data out for testing
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=1/3)
model = LinearRegression()
model.fit(X_train, Y_train)
result = model.score(X_test, Y_test)
print("r^2: %.3f" % result)
Tenga en cuenta que train_test_split() tomará nuestro conjunto de datos ( columnas X e Y ), lo
barajará y luego devolverá nuestros conjuntos de datos de entrenamiento y prueba en función del
tamaño de nuestro conjunto de datos de prueba. Usamos la función fit() de LinearRegression para
ajustar los conjuntos de datos de entrenamiento X_train y Y_train. Luego usamos la función score()
en los conjuntos de datos de prueba X_test e Y_test para evaluar el r 2, lo que nos da una idea de
cómo se comporta la regresión en datos que no se han visto antes. Cuanto mayor sea el r 2 para
nuestro conjunto de datos de prueba, mejor. Tener ese número más alto indica que la regresión
funciona bien en datos que no ha visto antes.

USO DE R-SQUARE PARA PRUEBAS


Tenga en cuenta que r2 se calcula un poco diferente aquí ya que tenemos una regresión lineal
predefinida del entrenamiento. Estamos comparando los datos de prueba con una línea de
regresión construida a partir de datos de entrenamiento. El objetivo sigue siendo el mismo: estar
más cerca de 1,0 es deseable para mostrar que la correlación de regresión es sólida incluso con
los datos de entrenamiento, mientras que estar más cerca de 0,0 indica que el conjunto de datos de
prueba tiene un rendimiento deficiente. Así es como se calcula, donde es cada valor real de y,
es cada valor predicho de y e es el valor promedio de y para todos los puntos de datos:

La figura 5-19 muestra diferentesvalores de r2

133
Figura 5-19. Un r 2 aplicado a diferentes conjuntos de datos de prueba con una regresión lineal
enTrain ada

También podemos alternar el conjunto de datos de prueba en cada 1/3 de pliegue. Esto se conoce
como validación cruzada y, a menudo, se considera el estándar de oro de las técnicas de
validación. La figura 5-20 muestra cómo cada 1/3 de los datos se convierte en el conjunto de datos
de prueba.

Figura 5-20. Una visualización de validación cruzada con tres pliegues

El código del Ejemplo 5-22 muestra una validación cruzada realizada en tres pliegues, y luego la
métrica de puntuación (en este caso, la suma media de los cuadrados [MSE mean sum of
squares]) se promedia junto con su desviación estándar para mostrar la consistencia de cada
prueba realizada.
Ejemplo 5-22. Uso de validación cruzada triple para una regresión lineal
import pandas as pd
from sklearn.linear_model import LinearRegression¿
from sklearn.model_selection import KFold, cross_val_score
df = pd.read_csv('https://bit.ly/3cIH97A', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)\
Y = df.values[:, -1]
# Perform a simple linear regression
kfold = KFold(n_splits=3, random_state=7, shuffle=True)
model = LinearRegression()
results = cross_val_score(model, X, Y, cv=kfold)
print(results)
print("MSE: mean=%.3f (stdev-%.3f)" % (results.mean(), results.std()))

LAS DIVISIONES DE ENTRENAMIENTO/PRUEBA TIENEN QUE SER TERCIOS?

134
No tenemos que doblar nuestros datos por tercios. Puede usar la validación de k-fold para dividir en
cualquier proporción. Por lo general, se usa 1/3, 1/5 o 1/10 para la proporción de datos de prueba,
pero 1/3 es el más común.
En general, el k que elija tiene que dar como resultado un conjunto de datos de prueba que tenga
una muestra lo suficientemente grande para el problema. También necesita suficientes conjuntos
de datos de prueba alternados/mezclados para proporcionar una estimación justa del rendimiento
de los datos que no se habían visto antes. Los conjuntos de datos de tamaño modesto pueden usar
valores k de 3, 5 o 10. La validación cruzada de dejar uno fuera (LOOCV Leaveone-out cross-
validation) alternará cada registro de datos individual como la única muestra en el conjunto de
datos de prueba, y esto puede ser útil cuando todo el conjunto de datos es pequeño.

Cuando le preocupa la varianza en su modelo, una cosa que puede hacer, en lugar de una simple
división de entrenamiento/prueba o validación cruzada, es usar la validación de pliegues aleatorios
para barajar repetidamente y dividir sus datos de entrenamiento/prueba una cantidad ilimitada de
veces. y agregar los resultados de las pruebas. En el Ejemplo 5-23 hay 10 iteraciones de muestreo
aleatorio de 1/3 de los datos para prueba y los otros 2/3 para entrenamiento. Luego, esos 10
resultados de prueba se promedian junto con sus desviaciones estándar para ver qué tan
consistentemente se desempeñan los conjuntos de datos de prueba.
¿Cuál es el truco? Es computacionalmente muy costoso ya que estamos enTrain ando la regresión
muchas veces.
Ejemplo 5-23. Uso de una validación aleatoria para una regresión lineal
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import cross_val_score, ShuffleSplit
df = pd.read_csv('https://bit.ly/38XwbeB', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)\
Y = df.values[:, -1]
# Perform a simple linear regression
kfold = ShuffleSplit(n_splits=10, test_size=.33, random_state=7)
model = LinearRegression()
results = cross_val_score(model, X, Y, cv=kfold)
print(results)
print("mean=%.3f (stdev-%.3f)" % (results.mean(), results.std()))
Entonces, cuando tiene poco tiempo o sus datos son demasiado voluminosos para analizarlos
estadísticamente, una división de entrenamiento/prueba proporcionará una manera de medir qué
tan bien funcionará su regresión lineal en datos que no ha visto antes.

LAS DIVISIONES DE ENTRENAMIENTO/PRUEBA NO SON GARANTÍAS


Es importante tener en cuenta que el hecho de que aplique las mejores prácticas de aprendizaje
automático para dividir sus datos de entrenamiento y prueba no significa que su modelo vaya a
funcionar bien. Puede sobreajustar fácilmente su modelo y obtener un buen resultado de prueba,
solo para descubrir que no funciona bien en el mundo real. Esta es la razón por la que a veces es
necesario mantener otro conjunto de datos llamado conjunto de validación, especialmente si está
comparando diferentes modelos o configuraciones. De esa manera, sus ajustes en los datos de
entrenamiento para obtener un mejor rendimiento en los datos de prueba no filtran información en
el entrenamiento. Puede usar el conjunto de datos de validación como un último recurso provisional
para ver si el p-hacking hizo que se ajustara demasiado a su conjunto de datos de prueba.
Incluso entonces, todo su conjunto de datos (incluido el entrenamiento, las pruebas y la validación)
podría haber estado sesgado para empezar, y ninguna división lo mitigará. Andrew Ng discutió esto
como un gran problema con el aprendizaje automático durante su sesión de preguntas y
respuestas con DeepLearning.AI y Stanford HAI. Examinó un ejemplo que muestra por qué el
aprendizaje automático no ha reemplazado a los radiólogos.

Regresión lineal múltiple

135
Nos enfocamos casi exclusivamente en hacer una regresión lineal en una variable de entrada y una
variable de salida en este capítulo. Sin embargo, los conceptos que aprendimos aquí deberían
aplicarse en gran medida a la regresión lineal multivariable. Se pueden usar métricas como r 2, error
estándar e intervalos de confianza, pero se vuelve más difícil con más variables. El ejemplo 5-24 es
un ejemplo de una regresión lineal con dos variables de entrada y una variable de salida usando
scikit-learn.
Ejemplo 5-24. Una regresión lineal con dos variables de entrada
import pandas as pd
from sklearn.linear_model import LinearRegression
# Load the data
df = pd.read_csv('https://bit.ly/2X1HWH7', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)\
Y = df.values[:, -1]
# Training
fit = LinearRegression().fit(X, Y)
# Print coefficients
print("Coefficients = {0}".format(fit.coef_))
print("Intercept = {0}".format(fit.intercept_))
print("z = {0} + {1}x + {2}y".format(fit.intercept_, fit.coef_[0],
fit.coef_[1]))

Hay un grado de precariedad cuando un modelo se inunda tanto con variables que comienza a
perder la capacidad de explicación, y aquí es cuando las prácticas de aprendizaje automático
comienzan a aparecer y tratan al modelo como una caja negra. Espero que esté convencido de que
las preocupaciones estadísticas no desaparecen y que los datos se vuelven cada vez más escasos
a medida que agrega más variables. Pero si da un paso atrás y analiza las relaciones entre cada
par de variables utilizando una matriz de correlación, y busca comprender cómo interactúa cada par
de variables, ayudará en sus esfuerzos para crear un modelo productivo de aprendizaje
automático.

Conclusión
Cubrimos mucho en este capítulo. Intentamos ir más allá de una comprensión superficial de la
regresión lineal y hacer que las divisiones de entrenamiento/prueba sean nuestra única validación.
Quería mostrarle tanto el bisturí (estadísticas) como la motosierra (aprendizaje automático) para
que pueda juzgar cuál es mejor para un problema determinado que encuentre. Hay muchas
métricas y métodos de análisis disponibles solo en la regresión lineal, y cubrimos varios de ellos
para comprender si una regresión lineal es confiable para las predicciones. Es posible que se
encuentre en una posición para hacer regresiones como aproximaciones amplias o analizar y
combinar meticulosamente sus datos utilizando herramientas estadísticas. El enfoque que utilice
depende de la situación y, si desea obtener más información sobre las herramientas estadísticas
disponibles para Python, consulte la biblioteca statsmodel.
En el Capítulo 6 que cubre la regresión logística, revisaremos el r 2 y la significancia estadística.
Espero que este capítulo lo haya convencido de que hay formas de analizar los datos de manera
significativa y que la inversión puede marcar la diferencia en un proyecto exitoso.

Ejercicios
Aquí se proporciona un conjunto de datos de dos variables, x e y.
1. Realice una regresión lineal simple para encontrar los valores m y b que minimizan la
pérdida (suma de cuadrados).
2. Calcule el coeficiente de correlación y la significación estadística de estos datos (al 95 %
de confianza). ¿Es útil la correlación?
3. Si predigo donde x = 50, ¿cuál es el intervalo de predicción del 95% para el valor predicho
de y ?
4. Comience su regresión nuevamente y haga una división de entrenamiento/prueba.
Siéntase libre de experimentar con la validación cruzada y la validación aleatoria. ¿La

136
regresión lineal funciona bien y consistentemente en los datos de prueba? ¿Por qué o por
qué no?
Las respuestas se encuentran en el Apéndice B.

137
Capítulo 6. Regresión logística y clasificación
Logistic Regression and Classification En este capítulo vamos a cubrir la regresión logística, un tipo de
regresión que predice la probabilidad de un resultado dada una o más variables independientes.
Esto, a su vez, se puede usar para la clasificación, que predice categorías en lugar de números
reales, como hicimos con la regresión lineal.
No siempre estamos interesados en representar las variables como continuas, donde pueden
representar un número infinito de valores decimales reales. Hay situaciones en las que
preferiríamos que las variables fueran discretas o representativas de números enteros, enteros o
booleanos (1/0, true/false). La regresión logística se enTrain a en una variable de salida que es
discreta (un 1 o 0 binario) o un número categórico (que es un número entero). Emite una variable
continua en forma de probabilidad, pero eso se puede convertir en un valor discreto con un umbral.
La regresión logística es fácil de implementar y bastante resistente frente a valores atípicos y otros
desafíos de datos. Muchos problemas de aprendizaje automático se pueden resolver mejor con la
regresión logística, que ofrece más practicidad y rendimiento que otros tipos de aprendizaje
automático supervisado.
Al igual que hicimos en el Capítulo 5 cuando cubrimos la regresión lineal, intentaremos recorrer la
línea entre la estadística y el aprendizaje automático, utilizando herramientas y análisis de ambas
disciplinas. La regresión logística integrará muchos conceptos que hemos aprendido de este libro,
desde la probabilidad hasta la regresión lineal.

Comprender la regresión logística


Imagine que hubo un pequeño accidente industrial y está tratando de comprender el impacto de la
exposición química. Tiene 11 pacientes que estuvieron expuestos durante diferentes números de
horas a este químico (tenga en cuenta que estos son datos fabricados). Algunos han mostrado
síntomas (valor de 1) y otros no han mostrado síntomas (valor de 0). Representémoslos en la
Figura 6-1, donde el eje x son las horas de exposición y el eje y es si han mostrado síntomas o no
(1 ó 0).

Figura 6-1. Trazar si los pacientes mostraron síntomas (1) o no (0) durante x horas de exposición

¿A qué tiempo los pacientes comienzan a mostrar síntomas? Bueno, es fácil de ver en casi cuatro
horas, pasamos inmediatamente de pacientes que no muestran síntomas (0) a pacientes que
muestran síntomas (1). En la Figura 6-2, vemos los mismos datos con una curva predictiva.

138
Figura 6-2. Después de cuatro horas, vemos un salto claro donde los pacientes comienzan a
mostrar síntomas.
Haciendo un análisis superficial de esta muestra, podemos decir que hay casi un 0 % de
probabilidad de que un paciente expuesto durante menos de cuatro horas muestre síntomas, pero
hay un 100 % de probabilidad durante más de cuatro horas. Entre estos dos grupos, hay un salto
inmediato para mostrar síntomas aproximadamente a las cuatro horas.
Por supuesto, nunca nada es tan claro en el mundo real. Supongamos que recopiló más datos,
donde el medio del rango tiene una combinación de pacientes que muestran síntomas versus
pacientes que no muestran síntomas, como se muestra en la Figura 6-3.

Figura 6-3. Existe una mezcla de pacientes que muestran síntomas (1) y no muestran síntomas (0)
en el medio

La forma de interpretar esto es que la probabilidad de que los pacientes muesTrain síntomas
aumenta gradualmente con cada hora de exposición. Visualicemos esto con una función logística, o
una curva en forma de S donde la variable de salida se comprime entre 0 y 1, como se muestra en
la Figura 6-4.

Figura 6-4. Ajuste de una función logística a los datos


Debido a esta superposición de puntos en el medio, no existe un límite definido cuando los
pacientes muestran síntomas, sino una transición gradual del 0 % de probabilidad al 100 % de
probabilidad (0 y 1). Este ejemplo demuestra cómo una regresión logística da como resultado una
curva que indica una probabilidad de pertenecer a la categoría verdadera (un paciente mostró
síntomas) a través de una variable independiente (horas de exposición).
Podemos reutilizar una regresión logística no solo para predecir una probabilidad para
determinadas variables de entrada, sino también para agregar un umbral para predecir si pertenece
a esa categoría. Por ejemplo, si obtengo un nuevo paciente y descubro que ha estado expuesto
durante seis horas, predigo un 71,1 % de posibilidades de que muestre síntomas como se muestra

139
en la Figura 6-5. Si mi umbral es de al menos un 50% de probabilidad de presentar síntomas,
simplemente clasificaré que el paciente presentará síntomas.

Figura 6-5. Podemos esperar que un paciente expuesto durante seis horas tenga un 71,1 % de
probabilidades de tener síntomas, y debido a que eso es mayor que el umbral del 50 %,
predecimos que mostrarán síntomas

Realización de una regresión logística


Entonces, ¿cómo realizamos una regresión logística? Primero echemos un vistazo a la función
logística y exploremos las matemáticas detrás de ella.

Función Logística
La función logística es una curva en forma de S (también conocida como curva sigmoidea ) que,
para un conjunto dado de variables de entrada, produce una variable de salida entre 0 y 1. Debido
a que la variable de salida está entre 0 y 1, se puede usar para representan una probabilidad.
Aquí está la función logística que genera una probabilidad y para una variable de entrada x :

Tenga en cuenta que esta fórmula usa el número e de Euler , que cubrimos en el Capítulo 1. La
variable x es la variable independiente/de entrada. β0 and β1 son los coeficientes que necesitamos
resolver.
β0 and β1 están empaquetados dentro de un exponente que se asemeja a una función lineal, que
puede recordar que se ve idéntica a y = mx + b or y = β0 + β1x. Esto no es una coincidencia; la
regresión logística en realidad tiene una estrecha relación con la regresión lineal, de la que
hablaremos más adelante en este capítulo. β0 de hecho es el intercepto (que llamamos b en
una regresión lineal simple) y β1 es la pendiente de x (que llamamos m en una regresión lineal
simple). Esta función lineal en el exponente se conoce como la función log-odds, pero por ahora
solo sepa que toda esta función logística produce esta curva en forma de S que necesitamos para
generar una probabilidad de cambio en un valor x.
Para declarar la función logística en Python, use la función exp() del paquete matemático para
declarar el exponente e como se muestra en el ejemplo 6-1.
Ejemplo 6-1. La función logística en Python para una variable independiente
import math
def predict_probability(x, b0, b1):
p = 1.0 / (1.0 + math.exp(-(b0 + b1 * x)))
return p
Grafiquemos para ver cómo se ve y supongamos que Β 0 = –2.823 y Β 1 = 0.62. Usaremos SymPy
en el Ejemplo 6-2 y el gráfico de salida se muestra en la Figura 6-6.
Ejemplo 6-2. Uso de SymPy para trazar una función logística
from sympy import *
b0, b1, x = symbols('b0 b1 x')
p = 1.0 / (1.0 + exp(-(b0 + b1 * x)))
p = p.subs(b0,-2.823)
p = p.subs(b1, 0.620)

140
print(p)
plot(p)

Figura 6-6. Una función logística

En algunos libros de texto, también puede ver la función logística declarada así:

No te preocupes por eso, porque es la misma función, solo que expresada algebraicamente de
manera diferente. Tenga en cuenta que, al igual que la regresión lineal, también podemos extender
la regresión logística a más de una variable de entrada ( x1, x2, . . . xn), como se muestra en esta
fórmula. Solo agregamos más coeficientes β x:

Ajuste de la curva logística


¿Cómo se ajusta la curva logística a un conjunto de datos de entrenamiento determinado? Primero,
los datos pueden tener cualquier combinación de variables decimales, enteras y binarias, pero la
variable de salida debe ser binaria (0 o 1). Cuando realmente hacemos una predicción, la variable
de salida estará entre 0 y 1, asemejándose a una probabilidad.
Los datos proporcionan nuestros valores de variables de entrada y salida, pero necesitamos
resolver los coeficientes β0 y β1 para que se ajusten a nuestra función logística. Recuerda cómo
usamos los mínimos cuadrados en el Capítulo 5. Sin embargo, esto no se aplica aquí. En su lugar,
utilizamos la estimación de máxima verosimilitud, que, como su nombre indica, maximiza la
probabilidad de que una curva logística dada genere los datos observados.
Para calcular la estimación de máxima verosimilitud, realmente no existe una ecuación de forma
cerrada como en la regresión lineal. Todavía podemos usar el descenso de gradiente o hacer que
una biblioteca lo haga por nosotros. Abarquemos ambos enfoques comenzando con la biblioteca
SciPy.

Usando SciPy
Lo bueno de SciPy es que los modelos a menudo tienen un conjunto estandarizado de funciones y
API, lo que significa que en muchos casos puede copiar/pegar su código y luego reutilizarlo entre
modelos. En el Ejemplo 6-3, verá una regresión logística realizada en los datos de nuestros
pacientes. Si lo compara con nuestro código de regresión lineal en el Capítulo 5, verá que tiene un
código casi idéntico para importar, separar y ajustar nuestros datos. La principal diferencia es que
uso LogisticRegression() para mi modelo en lugar de LinearRegression().
Ejemplo 6-3. Usando una regresión logística simple en SciPy
import pandas as pd
from sklearn.linear_model import LogisticRegression
# Load the data
df = pd.read_csv('https://bit.ly/33ebs2R', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)

141
Y = df.values[:, -1]
# Perform logistic regression
# Turn off penalty
model = LogisticRegression(penalty='none')
model.fit(X, Y)
# print beta1
print(model.coef_.flatten()) # 0.69267212
# print beta0
print(model.intercept_.flatten()) # -3.17576395

HACIENDO PREDICCIONES
Para hacer predicciones específicas, use las funciones predict() y predict_prob() en el objeto
modelo en SciPy, ya sea una regresión logística o cualquier otro tipo de modelo de clasificación. La
función predict() predecirá una clase específica (por ejemplo, True 1.0 o False 1.0) mientras que
predict_prob() generará probabilidades para cada clase.
Después de ejecutar el modelo en SciPy, obtengo una regresión logística donde β 0 = –3.17576395
y β 1 = 0.69267212. Cuando trace esto, debería verse bastante bien como se muestra en la Figura
6-7.

Figura 6-7. Trazar la regresión logística

Hay un par de cosas a tener en cuenta aquí. Cuando creé el modelo LogisticRegression(), no
especifiqué ningún argumento de penalización, que elige una técnica de regularización como l1 o
l2. Si bien esto está más allá del alcance de este libro, he incluido breves conocimientos en la
siguiente nota "Aprendiendo sobre los parámetros de SciPy" para que tenga referencias útiles a
mano.
Finalmente, voy a flatten() el coeficiente y el intercepto, que resultan como matrices
multidimensionales pero con un elemento. Aplanar significa colapsar una matriz de números en
dimensiones menores, particularmente cuando hay menos elementos que dimensiones. Por
ejemplo, aquí uso flatten() para tomar un solo número anidado en una matriz bidimensional y
extraerlo como un valor único. Luego tengo mis coeficientes β0 y β1.

APRENDER SOBRE LOS PARÁMETROS DE SCIPY


SciPy ofrece muchas opciones en sus modelos de regresión y clasificación. Desafortunadamente,
no hay suficiente ancho de banda o páginas para cubrirlos, ya que este no es un libro que se centre
exclusivamente en el aprendizaje automático.
Sin embargo, los documentos de SciPy están bien escritos y la página sobre regresión logística se
encuentra aquí.
Si muchos términos no le resultan familiares, como la regularización y las sanciones l1 y l2, hay
otros excelentes libros de O'Reilly que exploran estos temas. Uno de los textos más útiles que he
encontrado es Aprendizaje automático práctico con Scikit-Learn, Keras y TensorFlow de Aurélien
Géron.

Uso de probabilidad máxima y descenso de gradiente


Como he hecho a lo largo de este libro, mi objetivo es proporcionar información sobre técnicas de
construcción desde cero, incluso si las bibliotecas pueden hacerlo por nosotros. Hay varias formas
de ajustar una regresión logística nosotros mismos, pero todos los métodos generalmente recurren
a la estimación de máxima verosimilitud (MLE maximum likelihood estimation). MLE maximiza la
probabilidad de que una curva logística dada genere los datos observados. Es diferente a la suma
de cuadrados, pero aún podemos aplicar el descenso de gradiente o el descenso de gradiente
estocástico para resolverlo.

142
Intentaré simplificar la jerga matemática y minimizar el álgebra lineal aquí. Esencialmente, la idea
es encontrar los coeficientes β0 y β1 que lleven nuestra curva logística a esos puntos lo más cerca
posible, indicando que es más probable que haya producido esos puntos. Si recuerdas del Capítulo
2 cuando estudiamos la probabilidad, combinamos las probabilidades (o posibilidades) de múltiples
eventos multiplicándolos entre sí. En esta aplicación, estamos calculando la probabilidad de que
veamos todos estos puntos para una curva de regresión logística determinada.
Aplicando la idea de probabilidades conjuntas, cada paciente tiene una probabilidad de mostrar
síntomas según la función logística ajustada como se muestra en la Figura 6-8.

Figura 6-8. Cada valor de entrada tiene una probabilidad correspondiente en la curva logística

Obtenemos cada probabilidad de la curva de regresión logística por encima o por debajo de cada
punto. Si el punto está por debajo de la curva de regresión logística, debemos restar la probabilidad
resultante de 1,0 porque también queremos maximizar los casos falses.
Dados los coeficientes β 0 = –3,17576395 y β 1 = 0,69267212, el ejemplo 6-4 muestra cómo
calculamos la probabilidad conjunta de estos datos en Python.
Ejemplo 6-4. Cálculo de la probabilidad conjunta de observar todos los puntos para una regresión
logística dada
import math
import pandas as pd
patient_data = pd.read_csv('https://bit.ly/33ebs2R', delimiter=",").itertuples()
b0 = -3.17576395
b1 = 0.69267212
def logistic_function(x):
p = 1.0 / (1.0 + math.exp(-(b0 + b1 * x)))
return p
# Calculate the joint likelihood
joint_likelihood = 1.0
for p in patient_data:
if p.y == 1.0:
joint_likelihood *= logistic_function(p.x)
elif p.y == 0.0:
joint_likelihood *= (1.0 - logistic_function(p.x))
print(joint_likelihood) # 4.7911180221699105e-05

Aquí hay un truco matemático que podemos hacer para comprimir esa expresión if. Como cubrimos
en el Capítulo 1, cuando establece cualquier número a la potencia de 0, siempre será 1. Eche un
vistazo a esta fórmula y observe el manejo de los casos true (1) y false (0) en los exponentes:

Para hacer esto en Python, comprima todo dentro de ese bucle for en el Ejemplo 6-5.
Ejemplo 6-5. Comprimir el cálculo de probabilidad conjunta sin una expresión if

143
for p in patient_data:
joint_likelihood *= logistic_function(p.x) ** p.y * \(1.0 - logistic_function(p.x)) ** (1.0 - p.y)¿

Qué hice exactamente? Observe que hay dos mitades en esta expresión, una para cuando y = 1 y
la otra para y = 0. Cuando cualquier número se eleva al exponente 0, dará como resultado 1. Por
lo tanto, si y es 1 o 0, hará que la condición opuesta en el otro lado se evalúe como 1 y no tenga
efecto en la multiplicación. Llegamos a expresar nuestra expresión if pero lo hacemos
completamente en una expresión matemática. No podemos hacer derivadas en expresiones que
usan if, por lo que esto será útil.
Tenga en cuenta que las computadoras pueden abrumarse al multiplicar varios decimales
pequeños, lo que se conoce como subdesbordamiento de punto flotante. Esto significa que a
medida que los decimales se hacen cada vez más pequeños, lo que puede suceder en la
multiplicación, la computadora se encuentra con limitaciones para llevar la cuenta de esa cantidad
de lugares decimales. Hay un ingenioso truco matemático para evitar esto. Puede tomar el log() de
cada decimal que está multiplicando y, en su lugar, sumarlos. Esto es gracias a las propiedades
aditivas de los logaritmos que cubrimos en el Capítulo 1. Esto es más estable numéricamente, y
luego puede llamar a la función exp () para convertir la suma total nuevamente para obtener el
producto.
Revisemos nuestro código para usar la suma logarítmica en lugar de la multiplicación (vea el
Ejemplo 6-6 ). Tenga en cuenta que la función log () se establecerá de forma predeterminada en la
base e y, aunque cualquier base técnicamente funciona, esto es preferible porque e x es la
derivada de sí misma y computacionalmente será más eficiente.
Ejemplo 6-6. Usando la suma logarítmica
# Calculate the joint likelihood
joint_likelihood = 0.0
for p in patient_data:
joint_likelihood += math.log(logistic_function(p.x) ** p.y * \(1.0 - logistic_function(p.x)) ** (1.0 - p.y))
joint_likelihood = math.exp(joint_likelihood)

Para expresar el código Python anterior en notación matemática:

¿Le gustaría calcular las derivadas parciales para β 0 y β 1 en la expresión anterior? No lo


creo. es una bestia Dios mío, expresar esa función solo en SymPy es un bocado.! Mire esto en el
ejemplo 6-7.
Ejemplo 6-7. Expresar una probabilidad conjunta para la regresión logística en SymPy
verosimilitud_articulación
joint_likelihood = Sum(log((1.0 / (1.0 + exp(-(b + m * x(i)))))**y(i) * \
(1.0 - (1.0 / (1.0 + exp(-(b + m * x(i))))))**(1-y(i))), (i, 0, n))

Así que dejemos que SymPy haga las derivadas parciales por nosotros, para β0 y β1
respectivamente. Luego los compilaremos inmediatamente y los usaremos para el descenso de
gradiente, como se muestra en el Ejemplo 6-8.
Ejemplo 6-8. Uso del descenso de gradiente en la regresión logística
from sympy import *
import pandas as pd
points = list(pd.read_csv("https://tinyurl.com/y2cocoo7").itertuples())
b1, b0, i, n = symbols('b1 b0 i n')
x, y = symbols('x y', cls=Function)
joint_likelihood = Sum(log((1.0 / (1.0 + exp(-(b0 + b1 * x(i))))) ** y(i) \
* (1.0 - (1.0 / (1.0 + exp(-(b0 + b1 * x(i)))))) ** (1 - y(i))), (i, 0, n))
# Partial derivative for m, with points substituted
d_b1 = diff(joint_likelihood, b1) \
.subs(n, len(points) - 1).doit() \
.replace(x, lambda i: points[i].x) \

144
.replace(y, lambda i: points[i].y)
# Partial derivative for m, with points substituted
d_b0 = diff(joint_likelihood, b0) \
.subs(n, len(points) - 1).doit() \
.replace(x, lambda i: points[i].x) \
.replace(y, lambda i: points[i].y)
# compile using lambdify for faster computation
d_b1 = lambdify([b1, b0], d_b1)
d_b0 = lambdify([b1, b0], d_b0)
# Perform Gradient Descent
b1 = 0.01
b0 = 0.01
L = .01
for j in range(10_000):
b1 += d_b1(b1, b0) * L
b0 += d_b0(b1, b0) * L
print(b1, b0)
# 0.6926693075370812 -3.175751550409821

Después de calcular las derivadas parciales de β0 y β1, sustituimos los valores de x e y, así como
el número de puntos de datos n. Luego usamos lambdify() para compilar la función derivada por
eficiencia (usa NumPy detrás de escena). Después de eso, realizamos un descenso de gradiente
como lo hicimos en el Capítulo 5, pero dado que estamos tratando de maximizar en lugar de
minimizar, sumamos cada ajuste a β0 y β1 en lugar de restar como en los mínimos cuadrados.
Como puede ver en el Ejemplo 6-8, obtuvimos β0 = –3.17575 y β1 = 0.692667. Esto es altamente
comparable a los valores de coeficiente que obtuvimos en SciPy anteriormente.
Como aprendimos a hacer en el Capítulo 5, también podemos usar el descenso de gradiente
estocástico y solo muestrear uno o un puñado de registros en cada iteración. Esto extendería los
beneficios de aumentar la velocidad y el rendimiento computacional y evitaría el sobreajuste. Sería
redundante cubrirlo nuevamente aquí, así que seguiremos adelante.

Regresión logística multivariable


Probemos un ejemplo que usa regresión logística en múltiples variables de entrada. La Tabla 6-1
muestra una muestra de algunos registros de un conjunto de datos ficticio que contiene algunos
datos de retención de empleo (el conjunto de datos completo está aquí ).
Tabla 6-1. Muestra de datos de retención de empleo
SEX AÑO PROMOCION AÑOS_EMPLEA DID_QU
O S ES DO IT

1 32 3 7 0
1 34 2 5 0
1 29 2 5 1
0 42 4 10 0
1 43 4 10 0
Hay 54 registros en este conjunto de datos. Digamos que queremos usarlo para predecir si otros
empleados van a renunciar y la regresión logística se puede utilizar aquí (aunque nada de esto es
una buena idea, y explicaré por qué más adelante). Recuerde que podemos admitir más de una
variable de entrada como se muestra en esta fórmula:

Crearé coeficientes β para cada una de las variables sexo, edad, promociones y
años_empleados. La variable de salida did_quit es binaria y eso impulsará el resultado de la

145
regresión logística que estamos pronosticando. Debido a que estamos tratando con múltiples
dimensiones, será difícil visualizar el hiperplano con curvas que es nuestra curva logística. Así que
nos mantendremos alejados de la visualización.
Hagámoslo interesante. Usaremos scikit-learn pero haremos un shell interactivo con el que
podamos evaluar a los empleados. El ejemplo 6-9 muestra el código y, cuando lo ejecutemos, se
realizará una regresión logística y luego podremos ingresar nuevos empleados para predecir si
renunciarán o no. ¿Qué puede ir mal? Nada, estoy seguro. Solo hacemos predicciones sobre los
atributos personales de las personas y tomamos decisiones en consecuencia. estoy seguro de que
estará bien.
(Si no quedó claro, estoy siendo muy irónico).
Ejemplo 6-9. Hacer una regresión logística multivariable en los datos de los empleados
import pandas as pd
from sklearn.linear_model import LogisticRegression
employee_data = pd.read_csv("https://tinyurl.com/y6r7qjrp")
# grab independent variable columns
inputs = employee_data.iloc[:, :-1]
# grab dependent "did_quit" variable column
output = employee_data.iloc[:, -1]
# build logistic regression
fit = LogisticRegression(penalty='none').fit(inputs, output)
# Print coefficients:
print("COEFFICIENTS: {0}".format(fit.coef_.flatten()))
print("INTERCEPT: {0}".format(fit.intercept_.flatten()))
# Interact and test with new employee data
def predict_employee_will_stay(sex, age, promotions, years_employed):
prediction = fit.predict([[sex, age, promotions, years_employed]])
probabilities = fit.predict_proba([[sex, age, promotions, years_employed]])
if prediction == [[1]]:
return "WILL LEAVE: {0}".format(probabilities)
else:
return "WILL STAY: {0}".format(probabilities)
# Test a prediction
while True:
n = input("Predict employee will stay or leave {sex},
{age},{promotions},{years employed}: ")
(sex, age, promotions, years_employed) = n.split(",")
print(predict_employee_will_stay(int(sex), int(age), int(promotions),
int(years_employed)))

La figura 6-9 muestra el resultado si se prevé que un empleado renuncie. El empleado es del sexo
“1”, tiene 34 años de edad, tuvo 1 ascenso y tiene 5 años en la empresa. Efectivamente, la
predicción es "SE irá".

Figura 6-9. Hacer una predicción de si un empleado de 34 años con 1 promoción y 5 años dejará
de trabajar

146
Tenga en cuenta que la función predict_proba() generará dos valores, el primero es la probabilidad
de 0 (false) y el segundo es 1 (true).
Notará que los coeficientes para sexo, edad, promociones y años_empleados se muestran en ese
orden. Por el peso de los coeficientes, puede ver que el sexo y la edad juegan un papel muy
pequeño en la predicción (ambos tienen un peso cercano a 0). Sin embargo, las promociones y los
años_empleados tienen pesos significativos de –2,504 y 0,97. Aquí hay un secreto con este
conjunto de datos de juguetes: lo fabriqué para que un empleado renuncie si no obtiene un ascenso
aproximadamente cada dos años. Efectivamente, mi regresión logística recogió este patrón y
también puede probarlo con otros empleados. Sin embargo, si se aventura fuera de los rangos de
datos en los que se enTrain ó, es probable que las predicciones comiencen a desmoronarse (por
ejemplo, si incluye a un empleado de 70 años que no ha sido ascendido en tres años, es difícil
decir qué este modelo servirá ya que no tiene datos alrededor de esa edad).
Por supuesto, la vida real no siempre es tan limpia. Es probable que un empleado que ha estado en
una empresa durante ocho años y nunca haya obtenido un ascenso se sienta cómodo con su
puesto y no se vaya pronto. Si ese es el caso, variables como la edad podrían desempeñar un
papel y ser ponderadas. Luego, por supuesto, podemos preocuparnos por otras variables
relevantes que no se capturan. Consulte la siguiente advertencia para obtener más información.

¡CUIDADO CON LAS CLASIFICACIONES DE LAS PERSONAS!


Una forma rápida y segura de dispararte a ti mismo es recopilar datos sobre personas y usarlos
para hacer predicciones al azar. No solo pueden surgir preocupaciones sobre la privacidad de los
datos, sino que también pueden surgir problemas legales y de relaciones públicas si se determina
que el modelo es discriminatorio. Las variables de entrada como la raza y el género pueden
ponderarse a partir del entrenamiento de aprendizaje automático. Después de eso, se infligen
resultados indeseables en esos datos demográficos, como no ser contratado o que se le nieguen
los préstamos. Las aplicaciones más extremas incluyen ser marcado falsamente por los sistemas
de vigilancia o que se le niegue la libertad condicional criminal. Tenga en cuenta también que se ha
encontrado que variables aparentemente benignas como el tiempo de viaje se correlacionan con
variables discriminatorias.
En el momento de escribir este artículo, varios artículos han mencionado la discriminación del
aprendizaje automático como un problema.:
 Katyanna Quach, "Adolescente se alejó de la pista de patinaje después de que AI la
identificara erróneamente como alborotadora prohibida", The Register, 16 de julio de 2021.
 Kashmir Hill, “Injustamente acusado por un algoritmo”, New York Times, 24 de junio de
2020.
A medida que las leyes de privacidad de datos continúan evolucionando, es recomendable pecar
de precavido y diseñar los datos personales con cuidado. Piense en qué decisiones automatizadas
se propagarán y cómo eso puede causar daño. A veces es mejor dejar un "problema" solo y seguir
haciéndolo manualmente.
Finalmente, en este ejemplo de retención de empleados, piense de dónde provienen estos datos.
Sí, inventé este conjunto de datos, pero en el mundo real siempre quieres preguntarte qué proceso
creó los datos. ¿De qué período de tiempo provino esta muestra? ¿Hasta cuándo buscamos
empleados que renuncien? ¿Qué constituye un empleado que se quedó? ¿Son empleados
actuales en este momento? ¿Cómo sabemos que no están a punto de dejar de fumar, lo que los
convierte en un false negativo? Los científicos de datos caen fácilmente en trampas analizando
solo lo que dicen los datos, pero sin cuestionar de dónde provienen y qué suposiciones se basan
en ellos.
La mejor manera de obtener respuestas a estas preguntas es comprender para qué se utilizan las
predicciones. ¿Es para decidir cuándo dar ascensos a las personas para retenerlas? ¿Puede esto
crear un sesgo circular que promueva a personas con un conjunto de atributos? ¿Se reafirmará ese
sesgo cuando esas promociones comiencen a convertirse en los nuevos datos de entrenamiento?
Todas estas son preguntas importantes, y quizás incluso inconvenientes que hacen que un alcance
no deseado se infiltre en el proyecto. Si este escrutinio no es bienvenido por su equipo o liderazgo
en un proyecto, considere empoderarse con un rol diferente donde la curiosidad se convierte en
una fortaleza.

Comprender las probabilidades de registro

147
En este punto, es hora de discutir la regresión logística y de qué está hecha matemáticamente.
Esto puede ser un poco vertiginoso, así que tómate tu tiempo aquí. Si te sientes abrumado,
siempre puedes volver a visitar esta sección más tarde.
A partir de la década de 1900, siempre ha sido de interés para los matemáticos tomar una función
lineal y escalar su salida para que caiga entre 0 y 1 y, por lo tanto, sea útil para predecir la
probabilidad. El log-odds, también llamado función logit, se presta a la regresión logística para este
propósito.
¿Recuerdas que antes señalé que el valor del exponente β0+β1x es una función lineal? Mire
nuestra función logística nuevamente:

Esta función lineal que se eleva a e se conoce como la función log-odds, que toma el logaritmo de
las probabilidades para el evento de interés. Su respuesta podría ser: “Espera, no veo ningún
registro() ni probabilidades. ¡Solo veo una función lineal!” Ten paciencia conmigo, te mostraré las
matemáticas ocultas.
Como ejemplo, usemos nuestra regresión logística anterior, donde Β0 = -3,17576395 y Β 1=
0,69267212. ¿Cuál es la probabilidad de mostrar síntomas después de seis horas, donde x =
6 ? Ya sabemos cómo hacer esto: inserte estos valores en nuestra función logística:

Introducimos estos valores y generamos una probabilidad de 0,72716. Pero veamos esto desde la
perspectiva de las probabilidades. Recuerde que en el Capítulo 2 aprendimos cómo calcular
probabilidades a partir de una probabilidad:

Entonces, a las seis horas, un paciente tiene 2,66517 veces más probabilidades de mostrar
síntomas que de no mostrar síntomas.
Cuando envolvemos la función de probabilidades en un logaritmo natural (un logaritmo con base
e ), lo llamamos función logit. El resultado de esta fórmula es lo que llamamos log-odds, llamado..
sorprendentemente.. porque tomamos el logaritmo de las probabilidades:

Nuestro log-odds a las seis horas es 0.9802687. ¿Qué significa esto y por qué nos importa?
Cuando estamos en el “país de probabilidades logarítmicas”, es más fácil comparar un conjunto de
probabilidades con otro. Tratamos cualquier valor superior a 0 como una probabilidad favorable de
que suceda un evento, mientras que cualquier valor inferior a 0 está en contra de un evento. Un
log-odds de –1,05 es linealmente la misma distancia de 0 que 1,05. Sin embargo, en probabilidades
simples, los equivalentes son 0,3499 y 2,857, respectivamente, lo que no es tan interpretable. Esa
es la conveniencia de log-odds.

PROBABILIDADES Y REGISTROS
ODDS AND LOGS Los logaritmos y las probabilidades tienen una relación interesante. Las
probabilidades están en contra de un evento cuando está entre 0,0 y 1,0, pero cualquier valor
superior a 1,0 favorece el evento y se extiende a un infinito positivo. Esta falta de simetría es
incómoda. Sin embargo, los logaritmos modifican la escala de una probabilidad para que sea
completamente lineal, donde una probabilidad logarítmica de 0,0 significa probabilidades justas.

148
Una probabilidad logarítmica de –1,05 es linealmente la misma distancia de 0 que 1,05, por lo que
la comparación de probabilidades es mucho más fácil.
Josh Starmer tiene un gran video que habla sobre esta relación entre probabilidades y registros.
Recuerde que dije que la función lineal en nuestra fórmula de regresión logística β0 +β1x es
nuestra función log-odds. Mira esto:
log-odds = β0 + β1x
log-odds = -3.17576395 + 0.69267212(6)
log-odds = 0.98026877
Es el mismo valor 0.98026877 que nuestro cálculo anterior, las probabilidades de nuestra regresión
logística en x = 6 y luego tomando el log() de eso! Entonces, ¿cuál es el enlace? ¿Qué une todo
esto? Dada una probabilidad de una regresión logística p y una variable de entrada x, es esta:

Tracemos la línea log-odds junto con la regresión logística, como se muestra en la figura 6-10.

Figura 6-10. La línea log-odds se convierte en una función logística que genera una probabilidad

Cada regresión logística en realidad está respaldada por una función lineal, y esa función lineal es
una función de probabilidades logarítmicas. Observe en la figura 6-10 que cuando el log-odds es
0,0 en la línea, entonces la probabilidad de la curva logística es 0,5. Esto tiene sentido porque
cuando nuestras probabilidades son justas de 1,0, la probabilidad será de 0,50, como se muestra
en la regresión logística, y las probabilidades logarítmicas serán de 0, como se muestra en la línea.
Otro beneficio que obtenemos al observar la regresión logística desde la perspectiva de las
probabilidades es que podemos comparar el efecto entre un valor de x y otro. Digamos que quiero
entender cuánto cambian mis probabilidades entre seis y ocho horas de exposición al químico.
Puedo tomar las probabilidades a las seis horas y luego a las ocho horas, y luego relacionar las dos
probabilidades entre sí en una razón de probabilidades. Esto no debe confundirse con una
probabilidad simple que, sí, es una razón, pero no es una razón de probabilidades.
Primero encontremos las probabilidades de síntomas durante seis horas y ocho horas,
respectivamente:

149
Ahora vamos a convertirlos en probabilidades, que declararemos como o x :

Finalmente, establece las dos probabilidades entre sí como una razón de probabilidades, donde las
probabilidades de ocho horas son el numerador y las probabilidades de seis horas son el
denominador. Obtenemos un valor de aproximadamente 3.996, lo que significa que nuestras
probabilidades de mostrar síntomas aumentan en casi un factor de cuatro con dos horas
adicionales de exposición:

Encontrará este valor de razón de probabilidades de 3,996 en cualquier rango de dos horas, como
de 2 horas a 4 horas, de 4 horas a 6 horas, de 8 horas a 10 horas, etc. Siempre que sea una
brecha de dos horas, encontrará que la relación de probabilidades se mantiene constante. Diferirá
para otras longitudes de rango.

R-cuadrado
Cubrimos bastantes métricas estadísticas para la regresión lineal en el Capítulo 5, e intentaremos
hacer lo mismo para la regresión logística. Todavía nos preocupamos por muchos de los mismos
problemas que en la regresión lineal, incluido el sobreajuste y la varianza. De hecho, podemos
tomar prestadas y adaptar varias métricas de la regresión lineal y aplicarlas a la regresión logística.
Comencemos con R2.
Al igual que la regresión lineal, existe un R2 para una regresión logística determinada. Si recuerda
del Capítulo 5, el R2 indica qué tan bien una variable independiente dada explica una variable
dependiente. Aplicando esto a nuestro problema de exposición química, tiene sentido que
queramos medir cuántas horas de exposición química explican la aparición de síntomas.
Realmente no hay un consenso sobre la mejor manera de calcular el R 2 en una regresión logística,
pero una técnica popular conocida como Pseudo R2 de McFadden imita de cerca el R2 utilizado en
la regresión lineal. Usaremos esta técnica en los siguientes ejemplos y aquí está la fórmula:

Aprenderemos a calcularel "ajuste logarítmico de verosimilitud" y la "verosimilitud logarítmica" para


que podamos calcular el R2.
No podemos usar residuos aquí como en la regresión lineal, pero podemos proyectar los resultados
nuevamente en la curva logística como se muestra en la Figura 6-11 y buscar sus probabilidades
correspondientes entre 0.0 y 1.0.

150
Figura 6-11. Proyectar los valores de salida de nuevo en la curva logística

Luego podemos tomar el log() de cada una de esas probabilidades y sumarlas. Esta será la
probabilidad logarítmica del ajuste ( Ejemplo 6-10 ). Al igual que hicimos al calcular la máxima
verosimilitud, convertiremos las probabilidades "falsas" restándolas de 1,0.
Ejemplo 6-10. Cálculo de la probabilidad logarítmica del ajuste
from math import log, exp
import pandas as pd
patient_data = pd.read_csv('https://bit.ly/33ebs2R', delimiter=",").itertuples()
b0 = -3.17576395
b1 = 0.69267212
def logistic_function(x):
p = 1.0 / (1.0 + exp(-(b0 + b1 * x)))
return p
# Sum the log-likelihoods
log_likelihood_fit = 0.0
for p in patient_data:
if p.y == 1.0:
log_likelihood_fit += log(logistic_function(p.x))
elif p.y == 0.0:
log_likelihood_fit += log(1.0 - logistic_function(p.x))
print(log_likelihood_fit) # -9.946161673231583
Usando algunas multiplicaciones binarias inteligentes y comprensiones de Python, podemos
consolidar ese bucle for y la expresión if en una línea que devuelve log_likelihood_fit. Similar a lo
que hicimos en la fórmula de máxima verosimilitud, podemos usar alguna resta binaria entre los
casos true y false para eliminar matemáticamente uno u otro. En este caso, multiplicamos por 0 y,
por lo tanto, aplicamos el caso true o false, pero no ambos, a la suma correspondiente ( Ejemplo 6-
11 ).
Ejemplo 6-11. Consolidando nuestra lógica de probabilidad de registro en una sola línea
log_likelihood_fit = sum(log(logistic_function(p.x)) * p.y +log(1.0 - logistic_function(p.x)) * (1.0 - p.y)
for p in patient_data)

Si tuviéramos que expresar la probabilidad del ajuste en notación matemática, así sería. Tenga en
cuenta que f (xi ) es la función logística para una variable de entrada dada x i :

Como se calculó en los ejemplos 6-10 y 6-11, tenemos -9.9461 como nuestro logaritmo de
probabilidad del ajuste. Necesitamos un punto de datos más para calcular el R 2: el logaritmo de
probabilidad que estima sin usar ninguna variable de entrada y simplemente usa el número de
casos trues dividido por todos los casos (dejando efectivamente solo la intersección). Tenga en
cuenta que podemos contar el número de casos sintomáticos sumando todos los valores de y
juntos ∑ yi , porque solo los 1 y no los 0 contarán en la suma. Aquí está la fórmula:

151
Aquí está el equivalente de Python expandido de esta fórmula aplicada en el Ejemplo 6-12.
Ejemplo 6-12. Log probabilidad de pacientes
import pandas as pd
from math import log, exp
patient_data = list(pd.read_csv('https://bit.ly/33ebs2R', delimiter=",") \
.itertuples())
likelihood = sum(p.y for p in patient_data) / len(patient_data)
log_likelihood = 0.0
for p in patient_data:
if p.y == 1.0:
log_likelihood += log(likelihood)
elif p.y == 0.0:
log_likelihood += log(1.0 - likelihood)
print(log_likelihood) # -14.341070198709906
Para consolidar esta lógica y reflejar la fórmula, podemos comprimir el ciclo for y la expresión if en
una sola línea, usando alguna lógica de multiplicación binaria para manejar casos trues y falses (
Ejemplo 6-13 ).
Ejemplo 6-13. Consolidar la probabilidad de registro en una sola línea
log_likelihood = sum(log(likelihood)*p.y + log(1.0 - likelihood)*(1.0 - p.y) \for p in patient_data)
Finalmente, simplemente ingrese estos valores y obtenga su R 2 :

Y aquí está el código de Python que se muestra en el Ejemplo 6-14, calculando el R2 en su


totalidad.
Ejemplo 6-14. Cálculo del R 2 para una regresión logística
import pandas as pd
from math import log, exp
patient_data = list(pd.read_csv('https://bit.ly/33ebs2R', delimiter=",") \.itertuples())
# Declare fitted logistic regression
b0 = -3.17576395
b1 = 0.69267212
def logistic_function(x):
p = 1.0 / (1.0 + exp(-(b0 + b1 * x)))
return p
# calculate the log likelihood of the fit
log_likelihood_fit = sum(log(logistic_function(p.x)) * p.y +
log(1.0 - logistic_function(p.x)) * (1.0 - p.y)
for p in patient_data)
# calculate the log likelihood without fit
likelihood = sum(p.y for p in patient_data) / len(patient_data)
log_likelihood = sum(log(likelihood) * p.y + log(1.0 - likelihood) * (1.0 - p.y) \
for p in patient_data)
# calculate R-Square
r2 = (log_likelihood - log_likelihood_fit) / log_likelihood
print(r2) # 0.306456105756576

152
Bien, obtuvimos un R2 = 0.306456, entonces, ¿las horas de exposición química explican si
alguien muestra síntomas? Como aprendimos en el Capítulo 5 sobre regresión lineal, un ajuste
pobre estará más cerca de un R 2 de 0.0 y un ajuste mayor estará más cerca de 1.0. Por lo tanto,
podemos concluir que las horas de exposición son mediocres para predecir síntomas, ya que el R 2
es 0.30645. Debe haber otras variables además del tiempo de exposición que predigan mejor si
alguien presentará síntomas. Esto tiene sentido porque tenemos una gran combinación de
pacientes que muestran síntomas frente a los que no muestran síntomas para la mayoría de
nuestros datos observados, como se muestra en la Figura 6-12.

Figura 6-12. Nuestros datos tienen un R2 mediocre de 0.30645 porque hay mucha variación en el
medio de nuestra curva.
Pero si tuviéramos una división clara en nuestros datos, donde los resultados 1 y 0 están
claramente separados como se muestra en la Figura 6-13, tendríamos un R 2 perfecto de 1.0.

Figura 6-13. Esta regresión logística tiene un R 2 perfecto de 1,0 porque hay una clara división en
los resultados predichos por las horas de exposición

Valores P
Al igual que la regresión lineal, no terminamos solo porque tenemos un R 2. Necesitamos
investigar qué tan probable es que hayamos visto estos datos por casualidad en lugar de por una
relación real. Esto significa que necesitamos un valor p.
Para hacer esto, necesitaremos aprender una nueva distribución de probabilidad llamada
distribución chi-cuadrado, anotada como distribución χ2 . Es continuo y se utiliza en varias áreas de
la estadística, incluida esta.!
Si tomamos cada valor en una distribución normal estándar (media de 0 y desviación estándar de
1) y lo elevamos al cuadrado, eso nos dará la distribución χ 2 con un grado de libertad. Para
nuestros propósitos, los grados de libertad dependerán de cuántos parámetros n haya en
nuestra regresión logística, que será n - 1. Puede ver ejemplos de diferentes grados de libertad
en la Figura 6-14.

153
Figura 6-14. Una distribución de χ2 con diferentes grados de libertad

Como tenemos dos parámetros (horas de exposición y si se presentaron síntomas), nuestro grado
de libertad será 1 porque 2 - 1 = 1.
Necesitaremos el ajuste de probabilidad logarítmica y la probabilidad logarítmica tal como se
calculó en la subsección anterior sobre R2. Aquí está la fórmula que producirá el valor de χ2 que
necesitamos buscar:
χ2 = 2 (log likelihood fit) - (log likelihood)
Luego tomamos ese valor y buscamos la probabilidad de la distribución χ 2. Eso nos dará
nuestro valor p:
p-value = chi(2((log likelihood fit) - (log likelihood))

El ejemplo 6-15 muestra nuestro valor p para una regresión logística ajustada dada. Usamos el
módulo chi2 de SciPy para usar la distribución chi-cuadrado.
Ejemplo 6-15. Cálculo de un valor p para una regresión logística dada
import pandas as pd
from math import log, exp
from scipy.stats import chi2
patient_data = list(pd.read_csv('https://bit.ly/33ebs2R', delimiter=",").itertuples())
# Declare fitted logistic regression
b0 = -3.17576395
b1 = 0.69267212
def logistic_function(x):
p = 1.0 / (1.0 + exp(-(b0 + b1 * x)))
return p
# calculate the log likelihood of the fit
log_likelihood_fit = sum(log(logistic_function(p.x)) * p.y +
log(1.0 - logistic_function(p.x)) * (1.0 - p.y)
for p in patient_data)
# calculate the log likelihood without fit
likelihood = sum(p.y for p in patient_data) / len(patient_data)
log_likelihood = sum(log(likelihood) * p.y + log(1.0 - likelihood) * (1.0 - p.y) \
for p in patient_data)
# calculate p-value
chi2_input = 2 * (log_likelihood_fit - log_likelihood)
p_value = chi2.pdf(chi2_input, 1) # 1 degree of freedom (n - 1)
print(p_value) # 0.0016604875618753787
Entonces tenemos un valor p de 0.00166, y si nuestro umbral de significación es.05, decimos que
estos datos son estadísticamente significativos y no fueron por casualidad.

Train /Divisiones de prueba

154
Como se trató en el Capítulo 5 sobre regresión lineal, podemos usar divisiones de
entrenamiento/prueba como una forma de validar algoritmos de aprendizaje automático. Este es el
enfoque más de aprendizaje automático para evaluar el rendimiento de una regresión logística. Si
bien es una buena idea confiar en métricas estadísticas tradicionales como R 2 y valores p,
cuando se trata de más variables, esto se vuelve menos práctico. Aquí es donde las divisiones de
entrenamiento/prueba resultan útiles una vez más. Para repasar, la Figura 6-15 visualiza una
validación cruzada triple que alterna un conjunto de datos de prueba.

Figura 6-15. Una validación cruzada triple que alterna cada tercio del conjunto de datos como un
conjunto de datos de prueba

En el Ejemplo 6-16, realizamos una regresión logística en el conjunto de datos de retención de


empleados, pero dividimos los datos en tercios. Luego alternamos cada tercio como los datos de
prueba. Finalmente, resumimos las tres precisiones con un promedio y desviación estándar.
Ejemplo 6-16. Realización de una regresión logística con validación cruzada triple
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.model_selection import KFold, cross_val_score
# Load the data
df = pd.read_csv("https://tinyurl.com/y6r7qjrp", delimiter=",")
X = df.values[:, :-1]
Y = df.values[:, -1]
# "random_state" is the random seed, which we fix to 7
kfold = KFold(n_splits=3, random_state=7, shuffle=True)
model = LogisticRegression(penalty='none')
results = cross_val_score(model, X, Y, cv=kfold)
print("Accuracy Mean: %.3f (stdev=%.3f)" % (results.mean(), results.std()))

También podemos usar la validación de plegado aleatorio, la validación cruzada dejando uno fuera
y todas las demás variantes de plegado que realizamos en el Capítulo 5. Con eso fuera del camino,
hablemos de por qué la precisión es una mala medida para la clasificación.

Matrices de confusión
Supongamos que un modelo observa a personas con el nombre "Michael" que renuncian a su
trabajo. La razón por la cual los nombres y apellidos se capturan como variables de entrada es
ciertamente cuestionable, ya que es dudoso que el nombre de alguien tenga algún impacto en su
renuncia. Sin embargo, para simplificar el ejemplo, vamos con él. Luego, el modelo predice que
cualquier persona llamada "Michael" dejará su trabajo.
Ahora aquí es donde la precisión se desmorona. Tengo cien empleados, incluido uno llamado
"Michael" y otro llamado "Sam". Se predice erróneamente que Michael renunciará, y es Sam quien
termina renunciando. ¿Cuál es la precisión de mi modelo? Es 98% porque solo hubo dos
predicciones incorrectas de cien empleados, como se visualiza en la Figura 6-16.

155
Figura 6-16. Se prevé que el empleado llamado "Michael" renuncie, pero en realidad es otro
empleado el que lo hace, lo que nos da un 98 % de precisión.

Especialmente para datos desequilibrados donde el evento de interés (por ejemplo, un empleado
que renuncia) es raro, la métrica de precisión es terriblemente engañosa para los problemas de
clasificación. Si un proveedor, consultor o científico de datos alguna vez intenta venderle un
sistema de clasificación alegando precisión, solicite una matriz de confusión.
Una matriz de confusión es una cuadrícula que desglosa las predicciones contra los resultados
reales que muestran los trues positivos, trues negativos, falses positivos (error tipo I) y falses
negativos (error tipo II). Aquí hay una matriz de confusión presentada en la Figura 6-17.

Figura 6-17. Una matriz de confusión simple


En general, queremos que los valores de la diagonal (de arriba a la izquierda a abajo a la derecha)
sean más altos porque reflejan las clasificaciones correctas. Queremos evaluar cuántos empleados
que se predijo que renunciarían realmente renunciaron (trues positivos). Por el contrario, también
queremos evaluar cuántos empleados que se predijo que se quedarían realmente se quedaron
(negativos trues).
Las otras celdas reflejan predicciones incorrectas, donde un empleado que se predijo que
renunciaría terminó quedándose (false positivo) y donde un empleado que se predijo que se
quedaría terminó renunciando (false negativo).
Lo que debemos hacer es dividir esa métrica de precisión en métricas de precisión más específicas
dirigidas a diferentes partes de la matriz de confusión. Veamos la Figura 6-18, que agrega algunas
medidas útiles.
De la matriz de confusión, podemos derivar todo tipo de métricas útiles más allá de la precisión.
Podemos ver fácilmente que la precisión (qué tan precisas fueron las predicciones positivas) y la
sensibilidad (tasa de positivos identificados) son 0, lo que significa que este modelo de aprendizaje
automático falla por completo en las predicciones positivas.

156
Figura 6-18. Agregar métricas útiles a la matriz de confusión

El ejemplo 6-17 muestra cómo usar la API de matriz de confusión en SciPy en una regresión
logística con una división de entrenamiento/prueba. Tenga en cuenta que la matriz de confusión
solo se aplica al conjunto de datos de prueba.
Ejemplo 6-17. Creación de una matriz de confusión para un conjunto de datos de prueba en SciPy
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
# Load the data
df = pd.read_csv('https://bit.ly/3cManTi', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)\
Y = df.values[:, -1]
model = LogisticRegression(solver='liblinear')
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=.33,
random_state=10)
model.fit(X_train, Y_train)
prediction = model.predict(X_test)
"""
The confusion matrix evaluates accuracy within each category.
[[truepositives falsenegatives]
[falsepositives truenegatives]]
The diagonal represents correct predictions,
so we want those to be higher
"""

157
matrix = confusion_matrix(y_true=Y_test, y_pred=prediction)
print(matrix)

Teorema y clasificación de Bayes


¿Recuerda el teorema de Bayes del capítulo 2 ? Puede usar el teorema de Bayes para incorporar
información externa para validar aún más los hallazgos en una matriz de confusión. La figura 6-19
muestra una matriz de confusión de mil pacientes examinados para una enfermedad.

Figura 6-19. Una matriz de confusión para una prueba médica que identifica una enfermedad

Nos dicen que de los pacientes que tienen un riesgo para la salud, el 99% serán identificados con
éxito (sensibilidad). Usando la matriz de confusión, podemos ver que esto se verifica
matemáticamente:

Pero, ¿y si le damos la vuelta a la condición? ¿Qué porcentaje de los que dieron positivo tienen el
riesgo para la salud (precisión)? Mientras estamos cambiando una probabilidad condicional, no
tenemos que usar el Teorema de Bayes aquí porque la matriz de confusión nos da todos los
números que necesitamos:

Bien, el 79,8 % no es terrible, y ese es el porcentaje de personas que dieron positivo y que en
realidad tienen la enfermedad. Pero pregúntese esto.. ¿qué estamos asumiendo acerca de
nuestros datos? ¿Es representativa de la población?
Algunas investigaciones rápidas encontraron que el 1% de la población en realidad tiene la
enfermedad. Hay una oportunidad de usar el Teorema de Bayes aquí. Podemos dar cuenta de la
proporción de la población que realmente tiene la enfermedad e incorporarla en los hallazgos de
nuestra matriz de confusión. Entonces descubrimos algo significativo.

P(At Risk if Positive) = .0339


Cuando tomamos en cuenta el hecho de que solo el 1 % de la población está en riesgo y el 20 %
de nuestros pacientes de prueba están en riesgo, ¡la probabilidad de estar en riesgo con una
prueba positiva es del 3,39 %! ¿Cómo cayó del 99%? Esto solo muestra cuán fácilmente podemos
ser engañados por probabilidades que son altas solo en una muestra específica como los mil
pacientes de prueba del proveedor. Entonces, si esta prueba tiene solo un 3,39% de probabilidad
de identificar con éxito un true positivo, probablemente no deberíamos usarla.

Características del operador del receptor/área bajo la curva


Cuando evaluamos diferentes configuraciones de aprendizaje automático, podemos terminar con
docenas, cientos o miles de matrices de confusión. Estos pueden ser tediosos de revisar, por lo
que podemos resumirlos todos con una curva característica del operador del receptor (ROC receiver
operator characteristic) como se muestra en la Figura 6-20. Esto nos permite ver cada instancia de

158
prueba (cada una representada por un punto negro) y encontrar un equilibrio agradable entre los
trues positivos y los falses positivos.
También podemos comparar diferentes modelos de aprendizaje automático creando curvas ROC
separadas para cada uno. Por ejemplo, si en la Figura 6-21 nuestra curva superior representa una
regresión logística y la curva inferior representa un árbol de decisiones (una técnica de aprendizaje
automático que no cubrimos en este libro), podemos ver el rendimiento de ambas una al lado de la
otra. El área bajo la curva (AUC area under the curve) es una buena métrica para elegir qué
modelo usar. Dado que la curva superior (regresión logística) tiene un área mayor, esto sugiere que
es un modelo superior.

Figura 6-20. Una curva característica del operador del receptor

Figura 6-21. Comparación de dos modelos por su área bajo la curva (AUC area under the curve)
con sus respectivas curvas ROC

Para usar el AUC como una métrica de puntuación, cambie el parámetro de puntuación en la API
de scikit-learn para usar roc_auc como se muestra para una validación cruzada en el ejemplo 6-18.
Ejemplo 6-18. Usando el AUC como el parámetro scikit-learn
# put Scikit_learn model here
results = cross_val_score(model, X, Y, cv=kfold, scoring='roc_auc')
print("AUC: %.3f (%.3f)" % (results.mean(), results.std()))
# AUC: 0.791 (0.051)

Desequilibrio de clases

159
Class Imbalance Hay una última cosa que cubrir antes de cerrar este capítulo. Como vimos
anteriormente cuando discutimos las matrices de confusión, el desequilibrio de clases, que ocurre
cuando los datos no se representan por igual en todas las clases de resultados, es un problema en
el aprendizaje automático. Desafortunadamente, muchos problemas de interés están
desequilibrados, como la predicción de enfermedades, las brechas de seguridad, la detección de
fraudes, etc. El desequilibrio de clases sigue siendo un problema abierto sin una gran solución. Sin
embargo, hay algunas técnicas que puedes probar.
Primero, puede hacer cosas obvias como recopilar más datos o probar diferentes modelos, así
como usar matrices de confusión y curvas ROC/AUC. Todo esto ayudará a rastrear predicciones
deficientes y detectar errores de manera proactiva.
Otra técnica común es duplicar muestras en la clase minoritaria hasta que esté igualmente
representada en el conjunto de datos. Puede hacer esto en scikit-learn como se muestra en el
Ejemplo 6-19 al realizar sus divisiones de prueba de entrenamiento. Pase la opción estratificar con
la columna que contiene los valores de la clase e intentará representar por igual los datos de cada
clase.
Ejemplo 6-19. Uso de la opción de estratificación en scikit-learn para equilibrar las clases en los
datos
X, Y = ...
X_train, X_test, Y_train, Y_test = \
train_test_split(X, Y, test_size=.33, stratify=Y)

También existe una familia de algoritmos denominada SMOTE, que generan muestras sintéticas de
la clase minoritaria. Sin embargo, lo más ideal sería abordar el problema de una manera que utilice
modelos de detección de anomalías, que están diseñados deliberadamente para buscar un evento
raro. Sin embargo, estos buscan valores atípicos y no son necesariamente una clasificación, ya que
son algoritmos no supervisados. Todas estas técnicas están más allá del alcance de este libro,
pero vale la pena mencionarlas, ya que pueden brindar mejores soluciones a un problema
determinado.

Conclusión
La regresión logística es el modelo caballo de batalla para predecir probabilidades y clasificaciones
de datos. Las regresiones logísticas pueden predecir más de una categoría en lugar de solo un
true/false. Simplemente construye un modelo de regresión logística separado, ya sea que
pertenezca o no a esa categoría, y el modelo que produce la probabilidad más alta es el que gana.
Es posible que descubra que scikit-learn, en su mayor parte, hará esto por usted y detectará
cuándo sus datos tienen más de dos clases.
En este capítulo, cubrimos no solo cómo ajustar una regresión logística usando gradiente
descendente y scikit-learn, sino también enfoques estadísticos y de aprendizaje automático para la
validación. En el frente estadístico, cubrimos el R2 y el valor p, y en el aprendizaje automático
exploramos divisiones de entrenamiento/prueba, matrices de confusión y ROC/AUC.
Si desea obtener más información sobre la regresión logística, probablemente el mejor recurso
para seguir adelante es la lista de reproducción StatQuest de Josh Starmer sobre regresión
logística. Tengo que dar crédito al trabajo de Josh por ayudar en algunas partes de este capítulo,
particularmente en cómo calcular los valores R 2 y p para la regresión logística. Por lo menos,
¡mira sus videos para ver los fantásticos jingles de apertura !
Como siempre, se encontrará caminando entre los dos mundos de las estadísticas y el aprendizaje
automático. Muchos libros y recursos en este momento cubren la regresión logística desde una
perspectiva de aprendizaje automático, pero trate de buscar también recursos estadísticos. Hay
ventajas y desventajas en ambas escuelas de pensamiento, y solo puedes ganar si te adaptas a
ambas.!

Ejercicios
Aquí se proporciona un conjunto de datos de tres variables de entrada ROJO, VERDE y AZUL, así
como una variable de salida LIGHT_OR_DARK_FONT_IND. Se utilizará para predecir si una fuente
clara/oscura (0/1 respectivamente) funcionará para un color de fondo dado (especificado por
valores RGB).

160
1. Realice una regresión logística sobre los datos anteriores, utilizando la validación cruzada
triple y la precisión como métrica.
2. Producir una matriz de confusión comparando las predicciones y los datos reales.
3. Elija algunos colores de fondo diferentes (puede usar una herramienta RGB como esta ) y
vea si la regresión logística elige con sensatez una fuente clara (0) u oscura (1) para cada
uno.
4. Con base en los ejercicios anteriores, ¿piensa que la regresión logística es efectiva para
predecir una fuente clara u oscura para un color de fondo dado?

Las respuestas se encuentran en el Apéndice B.

161
Capítulo 7. Redes neuronales
Una técnica de regresión y clasificación que ha disfrutado de un renacimiento en los últimos 10
años son las redes neuronales. En la definición más simple, una red neuronal es una regresión de
varias capas que contiene capas de pesos, sesgos y funciones no lineales que residen entre las
variables de entrada y las variables de salida. El aprendizaje profundo es una variante popular de
las redes neuronales que utiliza múltiples capas "ocultas" (o intermedias) de nodos que contienen
pesos y sesgos. Cada nodo se asemeja a una función lineal antes de pasar a una función no lineal
(llamada función de activación). Al igual que la regresión lineal, que aprendimos en el Capítulo 5,
las técnicas de optimización como el descenso de gradiente estocástico se utilizan para encontrar
los valores óptimos de peso y sesgo para minimizar los residuos.
Las redes neuronales ofrecen soluciones interesantes a problemas que antes eran difíciles de
resolver para las computadoras. Desde identificar objetos en imágenes hasta procesar palabras en
audio, las redes neuronales han creado herramientas que afectan nuestra vida cotidiana. Esto
incluye asistentes virtuales y motores de búsqueda, así como herramientas fotográficas en nuestros
iPhones.
Dado el alboroto de los medios y las afirmaciones audaces que dominan los titulares de las noticias
sobre las redes neuronales, puede sorprender que hayan existido desde la década de 1950. La
razón de su repentina popularidad después de 2010 se debe a la creciente disponibilidad de datos
y potencia informática. El desafío de ImageNet entre 2011 y 2015 fue probablemente el mayor
impulsor del renacimiento, aumentando el rendimiento al clasificar mil categorías en 1,4 millones de
imágenes con una precisión del 96,4 %.
Sin embargo, como cualquier técnica de aprendizaje automático, solo funciona en problemas
estrechamente definidos. Incluso los proyectos para crear autos que se conducen solos no utilizan
el aprendizaje profundo de extremo a extremo y utilizan principalmente sistemas de reglas
codificadas a mano con redes neuronales intrincadas que actúan como un "fabricante de etiquetas"
para identificar objetos en la carretera. Discutiremos esto más adelante en este capítulo para
comprender dónde se usan realmente las redes neuronales. Pero primero construiremos una red
neuronal simple en NumPy y luego usaremos scikit-learn como una implementación de biblioteca.

Cuándo usar redes neuronales y aprendizaje profundo


Las redes neuronales y el aprendizaje profundo se pueden usar para la clasificación y la regresión,
entonces, ¿cómo se comparan con la regresión lineal, la regresión logística y otros tipos de
aprendizaje automático? Es posible que hayas escuchado la expresión “cuando todo lo que tienes
es un martillo, todo empieza a parecer un clavo”. Hay ventajas y desventajas que son situacionales
para cada tipo de algoritmo. La regresión lineal y la regresión logística, así como los árboles
potenciados por gradientes (que no cubrimos en este libro), hacen un trabajo bastante fantástico al
hacer predicciones sobre datos estructurados. Piense en los datos estructurados como datos que
se representan fácilmente como una tabla, con filas y columnas. Pero los problemas de percepción,
como la clasificación de imágenes, están mucho menos estructurados, ya que estamos tratando de
encontrar correlaciones borrosas entre grupos de píxeles para identificar formas y patrones, no filas
de datos en una tabla. Tratar de predecir las próximas cuatro o cinco palabras en una oración que
se está escribiendo, o descifrar las palabras que se dicen en un clip de audio, también son
problemas de percepción y ejemplos de redes neuronales que se usan para el procesamiento del
lenguaje natural.
En este capítulo, nos centraremos principalmente en redes neuronales simples con una sola capa
oculta.

VARIANTES DE REDES NEURONALES


Las variantes de las redes neuronales incluyen redes neuronales convolucionales, que a menudo
se utilizan para el reconocimiento de imágenes. La memoria a corto plazo (LSTM) se utiliza para
predecir series temporales o pronósticos. Las redes neuronales recurrentes se utilizan a menudo
para aplicaciones de texto a voz.

¿ES EXCESIVO EL USO DE UNA RED NEURONAL?


El uso de redes neuronales para el próximo ejemplo probablemente sea excesivo, ya que una
regresión logística probablemente sería más práctica. Incluso se puede utilizar un enfoque basado
en fórmulas. Sin embargo, siempre he sido fanático de comprender técnicas complejas

162
aplicándolas a problemas simples. Aprende sobre las fortalezas y limitaciones de la técnica en
lugar de distraerse con grandes conjuntos de datos. Entonces, con eso en mente, trate de no usar
redes neuronales donde los modelos más simples serán más prácticos. Romperemos esta regla en
este capítulo para entender la técnica.

Una red neuronal simple


Aquí hay un ejemplo simple para tener una idea de las redes neuronales. Quiero predecir si una
fuente debe ser clara (1) u oscura (0) para un fondo de color determinado. Aquí hay algunos
ejemplos de diferentes colores de fondo en la Figura 7-1. La fila superior se ve mejor con una
fuente clara y la fila inferior se ve mejor con una fuente oscura.

Figura 7-1. Los colores de fondo claros se ven mejor con una fuente oscura y los colores de fondo
oscuros se ven mejor con una fuente clara

En informática, una forma de representar un color es con valores RGB, o los valores rojo, verde y
azul. Cada uno de estos valores está entre 0 y 255 y expresa cómo estos tres colores se mezclan
para crear el color deseado. Por ejemplo, si expresamos el RGB como (rojo, verde, azul), el naranja
oscuro tendría un RGB de (255,140,0) y el rosa sería (255,192,203). El negro sería (0,0,0) y el
blanco sería (255,255,255).
Desde una perspectiva de regresión y aprendizaje automático, tenemos tres variables de entrada
numéricas rojo, verde y azul para capturar un color de fondo determinado. Necesitamos ajustar una
función a estas variables de entrada y mostrar si se debe usar una fuente clara (1) u oscura (0)
para ese color de fondo.

REPRESENTACIÓN DE COLORES A TRAVÉS DE RGB


Hay cientos de paletas de selección de colores en línea para experimentar con valores RGB. W3
Schools tiene uno aquí.
Tenga en cuenta que este ejemplo no está lejos de cómo funcionan las redes neuronales al
reconocer imágenes, ya que cada píxel a menudo se modela como tres valores RGB numéricos.
En este caso, solo nos estamos enfocando en un "píxel" como color de fondo.
Comencemos a un nivel alto y dejemos de lado todos los detalles de implementación. Vamos a
abordar este tema como una cebolla, comenzando con una mayor comprensión y desgranándonos
lentamente hacia los detalles. Por ahora, es por eso que simplemente etiquetamos como
"matemáticas misteriosas" un proceso que toma entradas y produce salidas. Tenemos tres
variables de entrada numéricas R, G y B, que son procesadas por esta matemática misteriosa.
Luego genera una predicción entre 0 y 1, como se muestra en la Figura 7-2.

163
Figura 7-2. Tenemos tres valores RGB numéricos que se usan para hacer una predicción para una
fuente clara u oscura
Esta salida de predicción expresa una probabilidad. La salida de probabilidades es el modelo más
común para la clasificación con redes neuronales. Una vez que reemplazamos RGB con sus
valores numéricos, vemos que menos de 0,5 sugerirá una fuente oscura, mientras que más de 0,5
sugerirá una fuente clara, como se muestra en la Figura 7-3.

Figura 7-3. Si ingresamos un color de fondo rosa (255,192,203), entonces las matemáticas
misteriosas recomiendan una fuente clara porque la probabilidad de salida 0.89 es mayor que 0.5
Entonces, ¿qué está pasando dentro de esa misteriosa caja negra matemática? Echemos un
vistazo a la Figura 7-4.

Nos falta otra pieza de esta red neuronal, las funciones de activación, pero llegaremos a eso en
breve. Primero entendamos lo que está pasando aquí. La primera capa de la izquierda es
simplemente una entrada de las tres variables, que en este caso son los valores rojo, verde y azul.
En la capa oculta (media), observe que producimos tres nodos, o funciones de pesos y sesgos,
entre las entradas y las salidas. Cada nodo es esencialmente una función lineal con pendientes W i
e intersecciones Bi que se multiplican y se suman con variables de entrada X i. Hay un peso W i
entre cada nodo de entrada y nodo oculto, y otro conjunto de pesos entre cada nodo oculto y nodo
de salida. Cada nodo oculto y de salida obtiene un sesgo adicional B i agregado.

Figura 7-4. La capa oculta de la red neuronal aplica valores de peso y sesgo a cada variable de
entrada, y la capa de salida aplica otro conjunto de pesos y sesgos a esa salida.

Observe que el nodo de salida repite la misma operación, tomando las salidas ponderadas y
sumadas resultantes de la capa oculta y convirtiéndolas en entradas de la capa final, donde se
aplicará otro conjunto de ponderaciones y sesgos.
En pocas palabras, esta es una regresión como la regresión lineal o logística, pero con muchos
más parámetros para resolver. Los valores de peso y sesgo son análogos a los parámetros m y b,

164
o β 1 y β 0, en una regresión lineal . Usamos el descenso de gradiente estocástico y
minimizamos la pérdida al igual que la regresión lineal, pero necesitamos una herramienta adicional
llamada retropropagación para desenredar los valores de peso W i y sesgo Bi y calcular sus
derivadas parciales usando la regla de la cadena. Llegaremos a eso más adelante en este capítulo,
pero por ahora supongamos que tenemos los valores de peso y sesgo optimizados. Primero
debemos hablar sobre las funciones de activación.

Funciones de activación
Traigamos las funciones de activación a continuación. Una función de activación es una función no
lineal que transforma o comprime los valores ponderados y sumados en un nodo, lo que ayuda a la
red neuronal a separar los datos de manera efectiva para que puedan clasificarse. Echemos un
vistazo a la Figura 7-5. Si no tiene las funciones de activación, sus capas ocultas no serán
productivas y no funcionarán mejor que una regresión lineal.

Figura 7-5. Aplicación de funciones de activación

La función de activación de ReLU pondrá a cero cualquier salida negativa de los nodos ocultos. Si
los pesos, los sesgos y las entradas se multiplican y suman un número negativo, se convertirá en 0.
De lo contrario, la salida se deja sola. Aquí está el gráfico para ReLU ( Figura 7-6 ) usando SymPy (
Ejemplo 7-1 ).
Ejemplo 7-1. Trazar la función ReLU
from sympy import *
# plot relu
x = symbols('x')

165
relu = Max(0, x)
plot(relu)

Figura 7-6. Gráfico para la función ReLU

ReLU es la abreviatura de "unidad lineal rectificada", pero esa es solo una forma elegante de decir
"convertir los valores negativos en 0". ReLU se ha vuelto popular para las capas ocultas en las
redes neuronales y el aprendizaje profundo debido a su velocidad y mitigación del problema del
gradiente de fuga. Los gradientes que se desvanecen ocurren cuando las pendientes de derivadas
parciales se vuelven tan pequeñas que se acercan prematuramente a 0 y hacen que el
entrenamiento se detenga en seco.
La capa de salida tiene un trabajo importante: toma las pilas de matemáticas de las capas ocultas
de la red neuronal y las convierte en un resultado interpretable, como presentar predicciones de
clasificación. La capa de salida de esta red neuronal en particular utiliza la función de activación
logística, que es una curva sigmoidea simple. Si lee el Capítulo 6, la función logística (o sigmoidea)
le resultará familiar y demuestra que la regresión logística actúa como una capa en nuestra red
neuronal. El nodo de salida pondera, sesga y suma cada uno de los valores entrantes de la capa
oculta. Después de eso, pasa el valor resultante a través de la función logística, por lo que genera
un número entre 0 y 1. Muy parecido a la regresión logística del Capítulo 6., esto representa una
probabilidad de que la entrada de color dada en la red neuronal recomiende una fuente clara. Si es
mayor o igual a 0.5, la red neuronal sugiere una fuente clara, pero menor que eso recomendará
una fuente oscura.
Aquí está el gráfico para la función logística ( Figura 7-7 ) usando SymPy ( Ejemplo 7-2 ).
Ejemplo 7-2. Función de activación logística en SymPy
from sympy import *
# plot relu
x = symbols('x')
relu = Max(0, x)
plot(relu)

166
Figura 7-7. Función de activación logística
Tenga en cuenta que cuando pasamos el valor ponderado, sesgado y sumado de un nodo a través
de una función de activación, ahora lo llamamos salida activada, lo que significa que ha sido filtrado
a través de la función de activación. Cuando la salida activada deja la capa oculta, la señal está
lista para pasar a la siguiente capa. La función de activación podría haber fortalecido, debilitado o
dejado la señal como está. De aquí es de donde viene la metáfora del cerebro y la sinapsis para las
redes neuronales.
Dado el potencial de complejidad, es posible que se pregunte si existen otras funciones de
activación. Algunos comunes se muestran en la Tabla 7-1.
Tabla 7-1. Funciones de activación comunes
Capa típica
Nombre utilizada Descripción notas
Linear l Output Deja los valores como No se usa comúnmente
están
Logistic Output Curva sigmoidea en Comprime valores entre 0 y 1, a menudo ayuda a
forma de S la clasificación binaria
Tangent Hidden tanh, curva sigmoidea Ayuda a "centrar" los datos acercando la media a
Hyperbolic en forma de S entre -1 0
y1
ReLU Hidden Convierte los valores La activación popular es más rápida que sigmoid y
negativos en 0 tanh, mitiga los problemas de gradiente de fuga y
es económica desde el punto de vista
computacional.
Leaky Hidden Multiplica los valores Variante controvertida de ReLU que margina en
ReLU negativos por 0,01 lugar de eliminar los valores negativos
softmax Output Garantiza que todos Útil para clasificaciones múltiples y salidas de
los nodos de salida reescalado para que sumen 1.0
suman 1,0
Esta no es una lista completa de funciones de activación y, en teoría, cualquier función podría ser
una función de activación en una red neuronal.
Si bien esta red neuronal aparentemente admite dos clases (fuente clara u oscura), en realidad
está modelada en una clase: si una fuente debe ser clara o no (1) o no (0). Si quisiera admitir varias
clases, podría agregar más nodos de salida para cada clase. Por ejemplo, si intenta reconocer los
dígitos escritos a mano del 0 al 9, habría 10 nodos de salida que representan la probabilidad de
que una imagen dada sea cada uno de esos números. Podría considerar usar softmax como
activación de salida cuando también tenga varias clases. La Figura 7-8 muestra un ejemplo de
tomar una imagen pixelada de un dígito, donde los píxeles se dividen como entradas de red
neuronal individuales y luego pasan a través de dos capas intermedias, y luego una capa de salida
con 10 nodos que representan probabilidades para 10 clases (por los dígitos 0–9).

167
Figura 7-8. Una red neuronal que toma cada píxel como entrada y predice qué dígito contiene la
imagen

Un ejemplo del uso del conjunto de datos MNISTen una red neuronal se puede encontrar en el
Apéndice A.

¡NO SÉ QUÉ FUNCIÓN DE ACTIVACIÓN USAR!


Si no está seguro de qué activaciones usar, las mejores prácticas actuales gravitan hacia ReLU
para las capas intermedias y logística (sigmoide) para la capa de salida. Si tiene varias
clasificaciones en la salida, use softmax para la capa de salida.

Propagación hacia adelante


Forward Propagation Capturemos lo que hemos aprendido hasta ahora usando NumPy. Tenga en
cuenta que aún no he optimizado los parámetros (nuestros valores de peso y sesgo). Vamos a
inicializar aquellos con valores aleatorios.
El ejemplo 7-3 es el código de Python para crear una red neuronal de avance simple que aún no
está optimizada. Feed forward significa que simplemente estamos ingresando un color en la red
neuronal y viendo lo que genera. Los pesos y sesgos se inicializan aleatoriamente y se optimizarán
más adelante en este capítulo, por lo que no espere obtener resultados útiles todavía.
Ejemplo 7-3. Una red de propagación directa simple con valores aleatorios de peso y sesgo bias
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
all_data = pd.read_csv("https://tinyurl.com/y2qmhfsr")
# Extract the input columns, scale down by 255
all_inputs = (all_data.iloc[:, 0:3].values / 255.0)
all_outputs = all_data.iloc[:, -1].values
# Split train and test data sets
X_train, X_test, Y_train, Y_test = train_test_split(all_inputs, all_outputs,
test_size=1/3)
n = X_train.shape[0] # number of training records
# Build neural network with weights and biases
# with random initialization
w_hidden = np.random.rand(3, 3)
w_output = np.random.rand(1, 3)
b_hidden = np.random.rand(3, 1)
b_output = np.random.rand(1, 1)
# Activation functions
relu = lambda x: np.maximum(x, 0)

168
logistic = lambda x: 1 / (1 + np.exp(-x))
# Runs inputs through the neural network to get predicted outputs
def forward_prop(X):
Z1 = w_hidden @ X + b_hidden
A1 = relu(Z1)
Z2 = w_output @ A1 + b_output
A2 = logistic(Z2)
return Z1, A1, Z2, A2
# Calculate accuracy
test_predictions = forward_prop(X_test.transpose())[3] # grab only output layer, A2
test_comparisons = np.equal((test_predictions >= .5).flatten().astype(int), Y_test)
accuracy = sum(test_comparisons.astype(int) / X_test.shape[0])
print("ACCURACY: ", accuracy)

Un par de cosas a tener en cuenta aquí. El conjunto de datos que contiene los valores de entrada
RGB, así como el valor de salida (1 para claro y 0 para oscuro) se encuentran en este archivo CSV.
Estoy reduciendo los valores de las columnas de entrada R, G y B en un factor de 1/255 para que
estén entre 0 y 1. Esto ayudará al entrenamiento más adelante para que el espacio numérico se
comprima.
Tenga en cuenta que también separé 2/3 de los datos para el entrenamiento y 1/3 para las pruebas
con scikit-learn, que aprendimos a hacer en el Capítulo 5. n es simplemente el número de registros
de datos de entrenamiento.
Ahora dirija su atención a las líneas de código que se muestran en el Ejemplo 7-4.
Ejemplo 7-4. Las matrices de peso y los vectores de sesgo en NumPy
# Build neural network with weights and biases
# with random initialization
w_hidden = np.random.rand(3, 3)
w_output = np.random.rand(1, 3)
b_hidden = np.random.rand(3, 1)
b_output = np.random.rand(1, 1)
Estos declaran nuestros pesos y sesgos para las capas ocultas y de salida de nuestra red
neuronal. Esto puede no ser obvio todavía, pero la multiplicación de matrices hará que nuestro
código sea poderosamente simple usando álgebra lineal y NumPy.
Los pesos y sesgos se inicializarán como valores aleatorios entre 0 y 1. Veamos primero las
matrices de peso. Cuando ejecuté el código obtuve estas matrices:

Woutput = [ ]
Tenga en cuenta que Whidden son los pesos en la capa oculta. La primera fila representa los pesos
del primer nodo W1, W2 y W3. La segunda fila es el segundo nodo con pesos W4, W5, y W6. La
tercera fila es el tercer nodo con pesos W7, W8 y W 9.
La capa de salida tiene solo un nodo, lo que significa que su matriz tiene solo una fila con pesos
W10, W 11 y W 12.
¿Ves un patrón aquí? Cada nodo se representa como una fila en una matriz. Si hay tres nodos, hay
tres filas. Si hay un nodo, hay una fila. Cada columna contiene un valor de peso para ese nodo.
Veamos también los sesgos. Dado que hay un sesgo por nodo, habrá tres filas de sesgos para la
capa oculta y una fila de sesgos para la capa de salida. Solo hay un sesgo por nodo, por lo que
solo habrá una columna:

Boutput = [0.58018555]

169
Ahora comparemos estos valores de matriz con nuestra red neuronal visualizada, como se muestra
en la Figura 7-9.

Figura 7-9. Visualización de nuestra red neuronal contra los valores de la matriz de peso y sesgo

Entonces, además de ser esotéricamente compacto, ¿cuál es el beneficio de estos pesos y sesgos
en esta forma de matriz? Llamemos nuestra atención a estas líneas de código en el Ejemplo 7-5.
Ejemplo 7-5. Las funciones de activación y la función de propagación hacia adelante para nuestra
red neuronal.
# Activation functions
relu = lambda x: np.maximum(x, 0)
logistic = lambda x: 1 / (1 + np.exp(-x))
# Runs inputs through the neural network to get predicted outputs
def forward_prop(X):
Z1 = w_hidden @ X + b_hidden
A1 = relu(Z1)
Z2 = w_output @ A1 + b_output
A2 = logistic(Z2)
return Z1, A1, Z2, A2
Este código es importante porque ejecuta de forma concisa toda nuestra red neuronal mediante la
multiplicación de matrices y la multiplicación de matrices y vectores. Aprendimos acerca de estas
operaciones en el Capítulo 4. Ejecuta un color de tres entradas RGB a través de los pesos, sesgos
y funciones de activación en solo unas pocas líneas de código.
Primero declaro las funciones de activación relu() y logistic(), que literalmente toman un valor de
entrada dado y devuelven el valor de salida de la curva. La función forward_prop() ejecuta toda
nuestra red neuronal para una entrada de color dada X que contiene los valores R, G y B. Devuelve
las salidas de la matriz de cuatro etapas: Z1, A1, Z2 y A2. El “1” y el “2” indican que las operaciones
pertenecen a las capas 1 y 2 respectivamente. La "Z" indica una salida no activada de la capa y la
"A" es una salida activada de la capa.
La capa oculta está representada por Z1 y A1. Z1 son los pesos y sesgos aplicados a X. Luego, A1
toma esa salida de Z1 y la empuja a través de la función de activación ReLU. Z2 toma la salida de
A1 y aplica los pesos y sesgos de la capa de salida. Esa salida, a su vez, pasa por la función de
activación, la curva logística, y se convierte en A2. La etapa final, A2, es la probabilidad de
predicción de la capa de salida, que devuelve un valor entre 0 y 1. Lo llamamos A2 porque es la
salida "activada" de la capa 2.
Analicemos esto con más detalle comenzando con Z1 :
Z1 = WhiddenX + Bhidden

Primero realizamos la multiplicación de matriz-vector entre W hidden y el color de entrada X.


Multiplicamos cada fila de Whidden (cada fila es un conjunto de pesos para un nodo) con el vector X
(los valores de entrada de color RGB). Luego agregamos los sesgos a ese resultado, como se
muestra en la figura 7-10.

170
Figura 7-10. Aplicar los pesos y sesgos de la capa oculta a una entrada X mediante la
multiplicación de matrices y vectores, así como la suma de vectores
Ese vector Z1 es la salida sin procesar de la capa oculta, pero aún debemos pasarlo a través de la
función de activación para convertir Z 1 en A1. Suficientemente fácil. Simplemente pase cada
valor en ese vector a través de la función ReLU y nos dará A 1. Debido a que todos los valores son
positivos, no debería tener un impacto.
A1 = ReLU (Z1)

Ahora tomemos la salida A 1 de la capa oculta y pásela a través de la capa final para obtener Z 2
y luego A2. A1 se convierte en la entrada en la capa de salida.
Z2 = WoutputA1 + Boutput

Finalmente, pase este valor único en Z 2 a través de la función de activación para obtener A 2.
Esto producirá una predicción de aproximadamente 0.95425:
A2 = logistic (Z2)
A2 = logistic ([ ])
A2 = 0.954254478103241

Eso ejecuta toda nuestra red neuronal, aunque todavía no la hemos enTrain ado. Pero tómese un
momento para apreciar que hemos tomado todos estos valores de entrada, pesos, sesgos y
funciones no lineales y los hemos convertido en un solo valor que proporcionará una predicción.
Nuevamente, A2 es el resultado final que hace una predicción de si ese color de fondo necesita
una fuente clara (1) u oscura (1). Aunque nuestros pesos y sesgos aún no se han optimizado,
calculemos nuestra precisión como se muestra en el Ejemplo 7-6. Tome el conjunto de datos de
prueba X_test, transpóngalo y páselo a través de la función forward_prop() pero solo tome el vector
A2 con las predicciones para cada color de prueba. Luego compare las predicciones con los datos
reales y calcule el porcentaje de predicciones correctas.
Ejemplo 7-6. Precisión de cálculo

171
# Calculate accuracy
test_predictions = forward_prop(X_test.transpose())[3] # grab only A2
test_comparisons = np.equal((test_predictions >= .5).flatten().astype(int), Y_test)
accuracy = sum(test_comparisons.astype(int) / X_test.shape[0])
print("ACCURACY: ", accuracy)
Cuando ejecuto todo el código en el Ejemplo 7-3, obtengo aproximadamente entre un 55 % y un 67
% de precisión. Recuerde, los pesos y sesgos se generan aleatoriamente, por lo que las
respuestas variarán. Si bien esto puede parecer alto dado que los parámetros se generaron
aleatoriamente, recuerde que las predicciones de salida son binarias: claras u oscuras. Por lo tanto,
un lanzamiento de moneda al azar también podría producir este resultado para cada predicción, por
lo que este número no debería sorprender.

¡NO OLVIDE COMPROBAR SI HAY DATOS DESEQUILIBRADOS!


Como se discutió en el Capítulo 6, no olvide analizar sus datos para verificar si hay clases
desequilibradas. Todo este conjunto de datos de color de fondo está un poco desequilibrado: 512
colores tienen una salida de 0 y 833 tienen una salida de 1. Esto puede sesgar la precisión y podría
ser la razón por la cual nuestros pesos y sesgos aleatorios gravitan por encima del 50 % de
precisión. Si los datos están extremadamente desequilibrados (como en el 99% de los datos es una
clase), recuerde usar matrices de confusión para rastrear los falses positivos y falses negativos.
¿Tiene todo estructuralmente sentido hasta ahora? Siéntase libre de revisar todo hasta este punto
antes de continuar. Solo tenemos una pieza final que cubrir: optimizar los pesos y sesgos. ¡Golpee
la máquina de café espresso o la barra de café nitro, porque esta es la matemática más complicada
que haremos en este libro!

retropropagación
Antes de comenzar a usar el descenso de gradiente estocástico para optimizar nuestra red
neuronal, un desafío que tenemos es descubrir cómo cambiar cada uno de los valores de peso y
sesgo en consecuencia, aunque todos estén enredados para crear la variable de salida, que luego
se usa para calcular los residuos. ¿Cómo encontramos la derivada de cada variable de peso W i y
sesgo B i ? Necesitamos usar la regla de la cadena, que cubrimos en el Capítulo 1.

Cálculo de las derivadas de peso y sesgo


Todavía no estamos listos para aplicar el descenso de gradiente estocástico para enTrain ar
nuestra red neuronal. Tenemos que obtener las derivadas parciales con respecto a los pesos W i y
los sesgos Bi , y tenemos la regla de la cadena para ayudarnos.
Si bien el proceso es prácticamente el mismo, existe una complicación al utilizar el descenso de
gradiente estocástico en las redes neuronales. Los nodos en una capa alimentan sus pesos y
sesgos a la siguiente capa, que luego aplica otro conjunto de pesos y sesgos. Esto crea un
anidamiento similar a una cebolla que debemos desenredar, comenzando con la capa de salida.
Durante el descenso de gradiente, necesitamos averiguar qué pesos y sesgos deben ajustarse, y
en qué medida, para reducir la función de costo general. El costo de una sola predicción será la
salida al cuadrado de la red neuronal A2 menos el valor real Y :
C = (A2 - Y )2
Pero retiremos una capa. Esa salida A2 activada es solo Z2 con la función de activación:
A2 = sigmoid (Z2)
Z2 a su vez son los pesos y sesgos de salida aplicados a la salida de activación A 1 , que
proviene de la capa oculta:
Z2 = W2A1 + B2)
A 1 se construye a partir de Z 1 que se pasa a través de la función de activación de ReLU:
A1 = ReLU (Z1)
Finalmente, Z 1 son los valores x de entrada ponderados y sesgados por la capa oculta:
Z1 = W 1 X + B 1

Necesitamos encontrar los pesos y sesgos contenidos en las matrices y vectores W 1 , B1 , W2 y


B2 que minimizarán nuestra pérdida. Al empujar sus pendientes, podemos cambiar los pesos y
sesgos que tienen el mayor impacto en la minimización de pérdidas. Sin embargo, cada pequeño

172
empujón en un peso o sesgo se propagará hasta la función de pérdida en la capa exterior. Aquí es
donde la regla de la cadena puede ayudarnos a determinar este impacto.
Centrémonos en encontrar la relación entre un peso de la capa de salida W 2 y la función de costo
C. Un cambio en el peso W 2, da como resultado un cambio en la salida no activada Z 2. Eso
entonces cambia la salida activada A2 , lo que cambia la función de costo C. Usando la regla de
la cadena, podemos definir la derivada de C con respecto a W2 como sigue:

Cuando multiplicamos estos tres gradientes juntos, obtenemos una medida de cuánto un cambio en
W2 cambiará la función de costo C.
Ahora calcularemos estas tres derivadas. Usemos SymPy para calcular la derivada de la función de
costo con respecto a A2 en el ejemplo 7-7.

Ejemplo 7-7. Cálculo de la derivada de la función de coste con respecto a A 2


from sympy import *
A2, y = symbols('A2 Y')
C = (A2 - Y)**2
dC_dA2 = diff(C, A2)
print(dC_dA2) # 2*A2 - 2*Y

A continuación, obtengamos la derivada de A2 con respecto a Z2 ( Ejemplo 7-8 ). Recuerde que


A 2 es la salida de una función de activación, en este caso la función logística. Así que realmente
estamos tomando la derivada de una curva sigmoidea.

Ejemplo 7-8. Encontrar la derivada de A2 con respecto a Z2


from sympy import *
Z2 = symbols('Z2')
logistic = lambda x: 1 / (1 + exp(-x))
A2 = logistic(Z2)
dA2_dZ2 = diff(A2, Z2)
print(dA2_dZ2) # exp(-Z2)/(1 + exp(-Z2))**2
La derivada de Z2 con respecto a W 2 resultará ser A1 , ya que es solo una función lineal y
devolverá la pendiente ( Ejemplo 7-9 ).

Ejemplo 7-9. Derivada de Z2 con respecto a W2


from sympy import *
A1, W2, B2 = symbols('A1, W2, B2')
Z2 = A1*W2 + B2
dZ2_dW2 = diff(Z2, W2)
print(dZ2_dW2) # A1
Poniéndolo todo junto, aquí está la derivada para encontrar cuánto un cambio en un peso en W2
afecta la función de costo C:

173
Cuando ejecutamos una entrada X con los tres valores de entrada R, G y B, tendremos valores
para A1 , A2 , Z2 e y.

¡NO SE PIERDA EN LAS MATEMÁTICAS!


Es fácil perderse en las matemáticas en este punto y olvidar lo que intentaba lograr en primer lugar,
que es encontrar la derivada de la función de costo con respecto a un peso (W 2 ) en la capa de
salida. Cuando te encuentres en la maleza y olvides lo que estabas tratando de hacer, da un paso
atrás, sal a caminar, tómate un café y recuerda lo que estabas tratando de lograr. Si no puede,
debe comenzar de nuevo desde el principio y avanzar hasta el punto en que se perdió.
Sin embargo, este es solo un componente de la red neuronal, la derivada de W 2. Estos son los
cálculos de SymPy en el Ejemplo 7-10 para el resto de las derivadas parciales que necesitaremos
para encadenar.
Ejemplo 7-10. Calculando todas las derivadas parciales que necesitaremos para nuestra red
neuronal
from sympy import *
W1, W2, B1, B2, A1, A2, Z1, Z2, X, Y = \symbols('W1 W2 B1 B2 A1 A2 Z1 Z2 X Y')
# Calculate derivative of cost function with respect to A2
C = (A2 - Y)**2
dC_dA2 = diff(C, A2)
print("dC_dA2 = ", dC_dA2) # 2*A2 - 2*Y
# Calculate derivative of A2 with respect to Z2
logistic = lambda x: 1 / (1 + exp(-x))
_
A2 = logistic(Z2)
dA2_dZ2 = diff(_A2, Z2)
print("dA2_dZ2 = ", dA2_dZ2) # exp(-Z2)/(1 + exp(-Z2))**2
# Calculate derivative of Z2 with respect to A1
_Z2 = A1*W2 + B2
dZ2_dA1 = diff(_Z2, A1)
print("dZ2_dA1 = ", dZ2_dA1) # W2
# Calculate derivative of Z2 with respect to W2
dZ2_dW2 = diff(_Z2, W2)
print("dZ2_dW2 = ", dZ2_dW2) # A1
# Calculate derivative of Z2 with respect to B2
dZ2_dB2 = diff(_Z2, B2)
print("dZ2_dB2 = ", dZ2_dB2) # 1
# Calculate derivative of A1 with respect to Z1
relu = lambda x: Max(x, 0)
_A1 = relu(Z1)
d_relu = lambda x: x > 0 # Slope is 1 if positive, 0 if negative
dA1_dZ1 = d_relu(Z1)
print("dA1_dZ1 = ", dA1_dZ1) # Z1 > 0
# Calculate derivative of Z1 with respect to W1
_Z1 = X*W1 + B1
dZ1_dW1 = diff(_Z1, W1)
print("dZ1_dW1 = ", dZ1_dW1) # X
# Calculate derivative of Z1 with respect to B1
dZ1_dB1 = diff(_Z1, B1)
print("dZ1_dB1 = ", dZ1_dB1) # 1

Tenga en cuenta que ReLU se calculó manualmente en lugar de utilizar la función diff() de SymPy.
Esto se debe a que los derivados funcionan con curvas suaves, no con esquinas irregulares que
existen en ReLU. Pero es fácil modificar eso simplemente declarando que la pendiente es 1 para
números positivos y 0 para números negativos. Esto tiene sentido porque los números negativos
tienen una línea plana con pendiente 0. Pero los números positivos se dejan como están con una
pendiente de 1 a 1.

174
Estas derivadas parciales se pueden encadenar para crear nuevas derivadas parciales con
respecto a los pesos y sesgos. Obtengamos las cuatro derivadas parciales para los pesos en W 1 ,

W 2, B1 y B 2 con respecto a la función de costo. Ya caminamos por . Mostrémoslo junto con


las otras tres derivadas encadenadas que necesitamos:

Usaremos estos gradientes encadenados para calcular la pendiente de la función de costo C con
respecto a W1 , B 1, W2 y B 2.

DIFERENCIACIÓN AUTOMÁTICA
Como puede ver, desenredar derivados incluso con la regla de la cadena y bibliotecas simbólicas
como SymPy sigue siendo tedioso. Es por eso que están aumentando las bibliotecas de
programación diferenciables, como la biblioteca JAX hecha por Google. Es casi idéntico a NumPy,
excepto que permite calcular derivadas de parámetros empaquetados como matrices.
Si desea obtener más información sobre la diferenciación automática, este video de YouTube lo
explica muy bien.

Descenso de gradiente estocástico


Ahora estamos listos para integrar la regla de la cadena para realizar un descenso de gradiente
estocástico. Para mantener las cosas simples, vamos a probar solo un registro de entrenamiento
en cada iteración. El descenso de gradiente por lotes y minilotes se usa comúnmente en redes
neuronales y aprendizaje profundo, pero hay suficiente álgebra lineal y cálculo para hacer
malabarismos con solo una muestra por iteración.
Echemos un vistazo a nuestra implementación completa de nuestra red neuronal, con descenso de
gradiente estocástico propagado hacia atrás, en el ejemplo 7-11.
Ejemplo 7-11. Implementación de una red neuronal usando descenso de gradiente estocástico
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
all_data = pd.read_csv("https://tinyurl.com/y2qmhfsr")
# Learning rate controls how slowly we approach a solution
# Make it too small, it will take too long to run.
# Make it too big, it will likely overshoot and miss the solution.
L = 0.05
# Extract the input columns, scale down by 255
all_inputs = (all_data.iloc[:, 0:3].values / 255.0)
all_outputs = all_data.iloc[:, -1].values
# Split train and test data sets

175
X_train, X_test, Y_train, Y_test = train_test_split(all_inputs, all_outputs,
test_size=1 / 3)
n = X_train.shape[0]
# Build neural network with weights and biases
# with random initialization
w_hidden = np.random.rand(3, 3)
w_output = np.random.rand(1, 3)
b_hidden = np.random.rand(3, 1)
b_output = np.random.rand(1, 1)
# Activation functions
relu = lambda x: np.maximum(x, 0)
logistic = lambda x: 1 / (1 + np.exp(-x))
# Runs inputs through the neural network to get predicted outputs
def forward_prop(X):
Z1 = w_hidden @ X + b_hidden
A1 = relu(Z1)
Z2 = w_output @ A1 + b_output
A2 = logistic(Z2)
return Z1, A1, Z2, A2
# Derivatives of Activation functions
d_relu = lambda x: x > 0
d_logistic = lambda x: np.exp(-x) / (1 + np.exp(-x)) ** 2
# returns slopes for weights and biases
# using chain rule
def backward_prop(Z1, A1, Z2, A2, X, Y):
dC_dA2 = 2 * A2 - 2 * Y
dA2_dZ2 = d_logistic(Z2)
dZ2_dA1 = w_output
dZ2_dW2 = A1
dZ2_dB2 = 1
dA1_dZ1 = d_relu(Z1)
dZ1_dW1 = X
dZ1_dB1 = 1
dC_dW2 = dC_dA2 @ dA2_dZ2 @ dZ2_dW2.T
dC_dB2 = dC_dA2 @ dA2_dZ2 * dZ2_dB2
dC_dA1 = dC_dA2 @ dA2_dZ2 @ dZ2_dA1
dC_dW1 = dC_dA1 @ dA1_dZ1 @ dZ1_dW1.T
dC_dB1 = dC_dA1 @ dA1_dZ1 * dZ1_dB1
return dC_dW1, dC_dB1, dC_dW2, dC_dB2
# Execute gradient descent
for i in range(100_000):
# randomly select one of the training data
idx = np.random.choice(n, 1, replace=False)
X_sample = X_train[idx].transpose()
Y_sample = Y_train[idx]
# run randomly selected training data through neural network
Z1, A1, Z2, A2 = forward_prop(X_sample)
# distribute error through backpropagation
# and return slopes for weights and biases
dW1, dB1, dW2, dB2 = backward_prop(Z1, A1, Z2, A2, X_sample, Y_sample)
# update weights and biases
w_hidden -= L * dW1
b_hidden -= L * dB1
w_output -= L * dW2
b_output -= L * dB2

176
# Calculate accuracy
test_predictions = forward_prop(X_test.transpose())[3] # grab only A2
test_comparisons = np.equal((test_predictions >= .5).flatten().astype(int), Y_test)
accuracy = sum(test_comparisons.astype(int) / X_test.shape[0])
print("ACCURACY: ", accuracy)

Están sucediendo muchas cosas aquí, pero se basan en todo lo demás que aprendimos en este
capítulo. Realizamos 100.000 iteraciones de descenso de gradiente estocástico. Al dividir los datos
de entrenamiento y prueba en 2/3 y 1/3, respectivamente, obtengo una precisión de
aproximadamente 97 a 99 % en mi conjunto de datos de prueba, dependiendo de cómo funcione la
aleatoriedad. Esto significa que después del entrenamiento, mi red neuronal identifica
correctamente entre el 97 y el 99 % de los datos de prueba con las predicciones de fuentes
claras/oscuras correctas.
La funciónbackward_prop() es clave aquí, implementando la regla de la cadena para tomar el error
en el nodo de salida (el residuo al cuadrado), y luego dividirlo y distribuirlo hacia atrás a la salida y
pesos/sesgos ocultos para obtener las pendientes con respecto a cada peso/sesgo. Luego
tomamos esas pendientes y empujamos los pesos/sesgos en el ciclo for, respectivamente,
multiplicándolos con la tasa de aprendizaje L tal como lo hicimos en los Capítulos 5 y 6. Hacemos
algunas multiplicaciones de matrices y vectores para distribuir el error hacia atrás en función de las
pendientes, y transponemos matrices y vectores cuando es necesario para que las dimensiones
entre filas y columnas coincidan.
Si desea que la red neuronal sea un poco más interactiva, aquí hay un fragmento de código en el
Ejemplo 7-12 donde podemos escribir diferentes colores de fondo (a través de un valor R, G y B) y
ver si predice una luz o fuente oscura. Añádelo al final del código anterior Ejemplo 7-11 y ¡pruébalo!
Ejemplo 7-12. Agregar un caparazón interactivo a nuestra red neuronal
# Interact and test with new colors
def predict_probability(r, g, b):
X = np.array([[r, g, b]]).transpose() / 255
Z1, A1, Z2, A2 = forward_prop(X)
return A2
def predict_font_shade(r, g, b):
output_values = predict_probability(r, g, b)
if output_values > .5:
return "DARK"
else:
return "LIGHT"
while True:
col_input = input("Predict light or dark font. Input values R,G,B: ")
(r, g, b) = col_input.split(",")
print(predict_font_shade(int(r), int(g), int(b)))
Construir su propia red neuronal desde cero requiere mucho trabajo y matemáticas, pero le da una
idea de su verdadera naturaleza. Al trabajar a través de las capas, el cálculo y el álgebra lineal,
obtenemos una idea más clara de lo que hacen las bibliotecas de aprendizaje profundo como
PyTorch y TensorFlow detrás de escena.
Como ha deducido de la lectura de este capítulo completo, hay muchas partes móviles para hacer
que una red neuronal funcione. Puede ser útil colocar un punto de interrupción en diferentes partes
del código para ver qué está haciendo cada operación de matriz. También puede transferir el
código a un Jupyter Notebook para obtener más información visual de cada paso.

3BLUE1BROWN EN BACKPROPAGATION
3Blue1Brown tiene algunos videos clásicos que hablan sobre la retropropagación y el cálculo
detrás de las redes neuronales.

Usando scikit-learn
Hay algunas funciones de red neuronal limitadas en scikit-learn. Si te tomas en serio el aprendizaje
profundo, probablemente querrás estudiar PyTorch o TensorFlow y obtener una computadora con
una GPU potente (¡hay una gran excusa para obtener la computadora para juegos que siempre

177
quisiste!). Me han dicho que todos los chicos geniales están usando PyTorch ahora. Sin embargo,
scikit-learn tiene algunos modelos convenientes disponibles, incluido el MLPClassifier, que significa
"clasificador de perceptrón multicapa". Esta es una red neuronal diseñada para la clasificación y
utiliza una activación de salida logística por defecto.
El ejemplo 7-13 es una versión scikit-learn de la aplicación de clasificación de colores de fondo que
desarrollamos. El argumento de activación especifica la capa oculta.
Ejemplo 7-13. Uso del clasificador de redes neuronales scikit-learn
import pandas as pd
# load data
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
df = pd.read_csv('https://bit.ly/3GsNzGt', delimiter=",")
# Extract input variables (all rows, all columns but last column)
# Note we should do some linear scaling here
X = (df.values[:, :-1] / 255.0)
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Separate training and testing data
X_train, X_test, Y_train, Y_test = train_test_split(X, Y, test_size=1/3)
nn = MLPClassifier(solver='sgd',
hidden_layer_sizes=(3, ),
activation='relu',
max_iter=100_000,
learning_rate_init=.05)
nn.fit(X_train, Y_train)
# Print weights and biases
print(nn.coefs_ )
print(nn.intercepts_)
print("Training set score: %f" % nn.score(X_train, Y_train))
print("Test set score: %f" % nn.score(X_test, Y_test))

Al ejecutar este código, obtengo una precisión del 99,3% en mis datos de prueba.

EJEMPLO DE MNIST USANDO SCIKIT-LEARN


Para ver un ejemplo de scikit-learn que predice dígitos escritos a mano usando el conjunto de datos
MNIST, consulte el Apéndice A.

Limitaciones de las redes neuronales y el aprendizaje profundo


A pesar de todas sus fortalezas, las redes neuronales luchan con ciertos tipos de tareas. Esta
flexibilidad con capas, nodos y funciones de activación hace que se adapte a los datos de forma no
lineal.. probablemente demasiado flexible. ¿Por qué? Puede sobreajustarse a los datos. Andrew
Ng, pionero en educación de aprendizaje profundo y exjefe de Google Brain, mencionó esto como
un problema en una conferencia de prensa en 2021. Cuando se le preguntó por qué el aprendizaje
automático aún no ha reemplazado a los radiólogos, esta fue su respuesta en un artículo de IEEE
Spectrum :
Resulta que cuando recopilamos datos del Hospital de Stanford, luego enTrain amos y probamos
con datos del mismo hospital, de hecho, podemos publicar artículos que muestran que [los
algoritmos] son comparables a los radiólogos humanos para detectar ciertas condiciones.
Resulta [que cuando] llevas ese mismo modelo, ese mismo sistema de IA, a un hospital más
antiguo al final de la calle, con una máquina más antigua, y el técnico usa un protocolo de
imágenes ligeramente diferente, esos datos se desvían para provocar el rendimiento de la IA.
sistema se degrade significativamente. Por el contrario, cualquier radiólogo humano puede caminar
por la calle hasta el hospital más antiguo y hacerlo bien.
Entonces, aunque en un momento en el tiempo, en un conjunto de datos específico, podemos
mostrar que esto funciona, la realidad clínica es que estos modelos aún necesitan mucho trabajo
para llegar a la producción.

178
En otras palabras, el aprendizaje automático se adaptó al conjunto de datos de prueba y
capacitación del hospital de Stanford. Cuando se llevó a otros hospitales con maquinaria diferente,
el rendimiento se degradó significativamente debido al sobreajuste.
Los mismos desafíos ocurren con los vehículos autónomos y los autos sin conductor. ¡No es
suficiente simplemente enTrain ar una red neuronal en una señal de alto! Tiene que ser enTrain
ado en innumerables combinaciones de condiciones alrededor de esa señal de alto: buen clima,
clima lluvioso, noche y día, con graffiti, bloqueado por un árbol, en diferentes lugares, etc. En
escenarios de tráfico, piense en todos los diferentes tipos de vehículos, peatones, peatones
disfrazados y una infinidad de casos extremos que se encontrarán. Simplemente no existe una
forma eficaz de capturar cada tipo de evento que se encuentra en el camino simplemente teniendo
más pesos y sesgos en una red neuronal.
Esta es la razón por la que los propios vehículos autónomos no utilizan las redes neuronales de
forma integral. En cambio, se dividen diferentes módulos de software y sensores donde un módulo
puede usar una red neuronal para dibujar un cuadro alrededor de un objeto. Luego, otro módulo
usará una red neuronal diferente para clasificar el objeto en esa caja, como un peatón. A partir de
ahí, la lógica tradicional basada en reglas intentará predecir la ruta del peatón y la lógica codificada
elegirá entre diferentes condiciones sobre cómo reaccionar. El aprendizaje automático se limitó a la
actividad de creación de etiquetas, no a las tácticas y maniobras del vehículo. Además de eso, los
sensores básicos como el radar simplemente se detendrán si se detecta un objeto desconocido
frente al vehículo, y esta es solo otra pieza de la pila de tecnología que no utiliza el aprendizaje
automático o el aprendizaje profundo.
Esto puede resultar sorprendente dados todos los titulares de los medios sobre redes neuronales y
aprendizaje profundo que vencen a humanos en juegos como Chess and Go, o incluso superan a
pilotos en simulaciones de vuelo de combate. Es importante recordar que en entornos de
aprendizaje por refuerzo como estos, las simulaciones son mundos cerrados, donde se pueden
generar y aprender cantidades infinitas de datos etiquetados a través de un mundo finito virtual. Sin
embargo, el mundo real no es una simulación en la que podamos generar cantidades ilimitadas de
datos. Además, este no es un libro de filosofía, por lo que pasaremos las discusiones sobre si
vivimos en una simulación. ¡Lo siento, Elón! La recopilación de datos en el mundo real es costosa y
difícil. Además de eso, el mundo real está lleno de imprevisibilidad infinita y eventos raros. Todos
estos factores llevan a los profesionales del aprendizaje automático a recurrir al trabajo de ingreso
de datos para etiquetar imágenes de objetos de tráfico y otros datos. Las empresas emergentes de
vehículos autónomos a menudo tienen que combinar este tipo de trabajo de entrada de datos con
datos simulados, porque las millas y los escenarios de casos extremos necesarios para generar
datos de entrenamiento son demasiado astronómicos para recopilarlos simplemente conduciendo
una flota de vehículos millones de millas.
Todas estas son razones por las que a la investigación de IA le gusta usar juegos de mesa y
videojuegos, porque se pueden generar datos etiquetados ilimitados de manera fácil y limpia.
Francis Chollet, un ingeniero de renombre en Google que desarrolló Keras para TensorFlow (y
también escribió un gran libro, Aprendizaje profundo con Python ), compartió algunas ideas sobre
esto en un artículo de Verge :
La cuestión es que, una vez que eliges una medida, vas a tomar cualquier atajo disponible para
jugar con ella. Por ejemplo, si establece jugar al ajedrez como su medida de inteligencia (lo que
comenzamos a hacer en la década de 1970 hasta la década de 1990), terminará con un sistema
que juega al ajedrez, y eso es todo. No hay razón para suponer que será bueno para nada más.
Terminas con la búsqueda de árboles y minimax, y eso no te enseña nada sobre la inteligencia
humana. Hoy en día, buscar la habilidad en videojuegos como Dota o StarCraft como
representante de la inteligencia general cae exactamente en la misma trampa intelectual..
Si me propongo "resolver" Warcraft III a un nivel sobrehumano usando el aprendizaje profundo,
puede estar seguro de que lo lograré siempre que tenga acceso a suficiente talento de ingeniería y
poder de cómputo (que es del orden de decenas de millones de dólares por una tarea como esta).
Pero una vez que lo hubiera hecho, ¿qué habría aprendido sobre inteligencia o generalización?
Pues nada. En el mejor de los casos, habría desarrollado conocimientos de ingeniería sobre la
ampliación del aprendizaje profundo. Así que realmente no lo veo como una investigación científica
porque no nos enseña nada que no sepamos ya. No responde a ninguna pregunta abierta. Si la
pregunta era: "¿Podemos jugar X a un nivel sobrehumano?", La respuesta es definitivamente: "Sí,
siempre que pueda generar una muestra suficientemente densa de situaciones de entrenamiento y
alimentarlas en un modelo de aprendizaje profundo suficientemente expresivo.

179
Es decir, debemos tener cuidado de no combinar el rendimiento de un algoritmo en un juego con
capacidades más amplias que aún no se han resuelto. El aprendizaje automático, las redes
neuronales y el aprendizaje profundo funcionan estrechamente en problemas definidos. No pueden
razonar en términos generales o elegir sus propias tareas, o reflexionar sobre objetos que no han
visto antes. Como cualquier aplicación codificada, solo hacen aquello para lo que fueron
programadas.
Con la herramienta que haga falta, resuelve el problema. No debe haber parcialidad a las redes
neuronales o cualquier otra herramienta a su disposición. Con todo esto en mente, el uso de una
red neuronal podría no ser la mejor opción para la tarea que tiene por delante. Es importante
considerar siempre qué problema se está esforzando por resolver sin hacer de una herramienta
específica su objetivo principal. El uso del aprendizaje profundo debe ser estratégico y estar
garantizado. Ciertamente hay casos de uso, pero en la mayor parte de su trabajo diario
probablemente tendrá más éxito con modelos más simples y más sesgados como la regresión
lineal, la regresión logística o los sistemas tradicionales basados en reglas. Pero si tiene que
clasificar objetos en imágenes, y tiene el presupuesto y la mano de obra para construir ese
conjunto de datos, entonces el aprendizaje profundo será su mejor opción.

¿SE ACERCA UN INVIERNO DE IA?


¿Son útiles las redes neuronales y el aprendizaje profundo? ¡Absolutamente! Y definitivamente vale
la pena aprenderlos. Dicho esto, es muy probable que haya visto a los medios, los políticos y las
celebridades tecnológicas aclamar el aprendizaje profundo como una inteligencia artificial general
que puede igualar, si no superar, la inteligencia humana e incluso está destinada a controlar el
mundo. He asistido a charlas de figuras autorizadas en la comunidad de desarrollo de software
diciéndoles a los programadores que se quedarán sin trabajo en unos años debido al aprendizaje
automático y que la IA se encargará de escribir el código.
Casi una década después, estas predicciones todavía se retrasan en 2022 porque simplemente no
son ciertas. Hemos visto muchos más desafíos de IA que avances, y todavía tengo que conducir mi
propio automóvil y escribir mi propio código. Las redes neuronales están vagamente inspiradas en
el cerebro humano, pero de ninguna manera son una réplica de ellas. Sus capacidades no están ni
cerca de lo que ves en películas como The Terminator, Westworld o WarGames. En cambio, las
redes neuronales y el aprendizaje profundo funcionan de manera limitada en problemas
específicos, como reconocer fotos de perros y gatos después de optimizarlas en miles de
imágenes. Como se dijo anteriormente, no pueden razonar ni elegir sus propias tareas, ni
contemplar la incertidumbre o los objetos que no han visto antes. Las redes neuronales y el
aprendizaje profundo solo hacen aquello para lo que fueron programados.
Esta desconexión puede haber inflado la inversión y las expectativas, dando como resultado una
burbuja que podría estallar. Esto provocaría otro "invierno de IA", donde la desilusión y la
decepción agotarían los fondos para la investigación de IA. En América del Norte, Europa y Japón,
los inviernos de IA han ocurrido varias veces desde la década de 1960. Hay una buena posibilidad
de que otro invierno de IA esté a la vuelta de la esquina, pero eso no significa que las redes
neuronales y el aprendizaje profundo pierdan utilidad. Continuarán aplicándose en los problemas
en los que son buenos: visión por computadora, audio, lenguaje natural y algunos otros dominios.
¡Tal vez puedas descubrir nuevas formas de usarlos! Utilice lo que funcione mejor, ya sea una
regresión lineal, una regresión logística, un sistema tradicional basado en reglas o una red
neuronal. Hay mucho más poder en la simplicidad de emparejar la herramienta correcta con el
problema correcto.

Conclusión
Las redes neuronales y el aprendizaje profundo ofrecen algunas aplicaciones interesantes, y solo
rascamos la superficie en este capítulo. Desde el reconocimiento de imágenes hasta el
procesamiento del lenguaje natural, sigue habiendo casos de uso para aplicar redes neuronales y
sus diferentes sabores de aprendizaje profundo.
Desde cero, aprendimos cómo estructurar una red neuronal simple con una capa oculta para
predecir si se debe usar una fuente clara u oscura contra un color de fondo. También aplicamos
algunos conceptos de cálculo avanzado para calcular derivadas parciales de funciones anidadas y
lo aplicamos al descenso de gradiente estocástico para enTrain ar nuestra red neuronal. También
mencionamos bibliotecas como scikit-learn. Si bien no tenemos el ancho de banda en este libro

180
para hablar sobre TensorFlow, PyTorch y aplicaciones más avanzadas, existen excelentes
recursos para ampliar su conocimiento.
3Blue1Brown tiene una lista de reproducción fantástica sobre redes neuronales y retropropagación,
y vale la pena verla varias veces. La lista de reproducción StatQuest de Josh Starmer sobre redes
neuronales también es útil, particularmente para visualizar las redes neuronales como una
manipulación múltiple. Otro gran video sobre teoría múltiple y redes neuronales se puede encontrar
aquí en El arte del problema. Finalmente, cuando esté listo para profundizar, consulte Aprendizaje
automático práctico de Aurélien Géron con Scikit-Learn, Keras y TensorFlow (O'Reilly) y
Aprendizaje profundo con Python de Francois Chollet(Manning).
Si llegó al final de este capítulo y siente que absorbió todo dentro de lo razonable, ¡felicidades! No
solo ha aprendido efectivamente probabilidad, estadística, cálculo y álgebra lineal, sino que
también lo ha aplicado a aplicaciones prácticas como regresión lineal, regresión logística y redes
neuronales. Hablaremos sobre cómo puede proceder en el próximo capítulo y comenzar una nueva
etapa de su crecimiento profesional.

Ejercicio
Aplique una red neuronal a los datos de retención de empleados con los que trabajamos en el
Capítulo 6. Puede importar los datos aquí. Intente construir esta red neuronal para que prediga
sobre este conjunto de datos y use matrices de precisión y confusión para evaluar el rendimiento.
¿Es un buen modelo para este problema? ¿Por qué o por qué no?
Si bien puede construir la red neuronal desde cero, considere usar scikit-learn, PyTorch u otra
biblioteca de aprendizaje profundo para ahorrar tiempo.
Las respuestas se encuentran en el Apéndice B.

181
Capítulo 8. Asesoramiento profesional y el camino a seguir
Career Advice and the Path Forward Al llegar al final de este libro, es una buena idea evaluar a dónde
ir desde aquí. Aprendiste e integraste una amplia encuesta de temas matemáticos aplicados:
cálculo, probabilidad, estadística y álgebra lineal. Luego, aplicó estas técnicas a aplicaciones
prácticas, incluidas la regresión lineal, la regresión logística y las redes neuronales. En este
capítulo, cubriremos cómo usar este conocimiento en el futuro mientras navegamos por el extraño,
emocionante y extrañamente diverso panorama de una carrera en ciencia de datos.Enfatizaré la
importancia de tener una dirección y un objetivo tangible hacia el cual trabajar, en lugar de
memorizar herramientas y técnicas sin un problema real en mente.
Dado que nos estamos alejando de los conceptos fundamentales y los métodos aplicados, este
capítulo tendrá un tono diferente al resto del libro. Es posible que esté esperando aprender cómo
puede aplicar estas habilidades de modelado matemático a su carrera de manera enfocada y
tangible. Sin embargo, si desea tener éxito en una carrera de ciencia de datos, tendrá que aprender
algunas habilidades más duras como SQL y programación, así como habilidades blandas para
desarrollar una conciencia profesional. Estos últimos son especialmente importantes para que no
se pierda en la profesión cambiante que es la ciencia de datos y las fuerzas invisibles del mercado
lo tomen por sorpresa.
No voy a presumir de conocer sus objetivos profesionales o lo que espera lograr con esta
información. Sin embargo, haré algunas apuestas seguras, ya que estás leyendo este libro. Me
imagino que podría estar interesado en una carrera de ciencia de datos, o ha trabajado en análisis
de datos y desea formalizar su conocimiento analítico. Tal vez provenga de una formación en
ingeniería de software y busque comprender la IA y el aprendizaje automático. Tal vez sea un
gerente de proyecto de algún tipo y descubra que necesita comprender las capacidades de un
equipo de ciencia de datos o IA para poder alcanzar el alcance en consecuencia. Tal vez solo sea
un profesional curioso que se pregunta cómo las matemáticas pueden ser útiles a un nivel práctico,
no solo académico.
Haré todo lo posible para satisfacer las preocupaciones de todos estos grupos y, con suerte,
generalizaré algunos consejos profesionales que serán útiles para la mayoría de los lectores.
Comencemos con la redefinición de la ciencia de datos. Lo hemos estudiado objetivamente y ahora
lo veremos en el contexto del desarrollo profesional y el futuro del campo.

¿EL AUTOR ES ANECDÓTICO?


Es difícil no sonar anecdótico en tareas como esta, donde brindo consejos profesionales
compartiendo mis propias experiencias (y las experiencias de otros) en lugar de encuestas y
estudios amplios y controlados como los que propongo en el Capítulo 3. Pero este es mi
argumento: he trabajado en el mundo Fortune 500 durante más de una década y vi la
transformación que el movimiento de la ciencia de datos tuvo en las organizaciones. He hablado en
muchas conferencias tecnológicas en todo el mundo y he escuchado a innumerables compañeros
reaccionar con "¡esto también nos ha pasado a nosotros!" Leo muchos blogs y publicaciones
respetadas, desde el Wall Street Journal hasta Forbes., y he aprendido a reconocer las
desconexiones entre las expectativas populares y la realidad. Presto especial atención a los
hacedores de reyes, líderes y seguidores en diferentes industrias y cómo crean o siguen mercados
con ciencia de datos e inteligencia artificial. Actualmente, enseño y asesoro a las partes
interesadas en aplicaciones de inteligencia artificial críticas para la seguridad en la Universidad del
Sur de California, en el Programa de Seguridad y Protección de la Aviación.
Solo pongo un CV aquí para mostrar que si bien no he realizado encuestas y estudios formales, y
tal vez estoy recopilando información anecdótica, hay narrativas persistentes que he encontrado
con todas estas fuentes de información. Vicki Boykis, una astuta ingeniera de aprendizaje
automático en Tumblr, escribió un artículo de blog compartiendo hallazgos similares a los míos, y le
recomiendo que lo lea. Le invitamos a tomar mis hallazgos con cautela, pero preste mucha
atención a lo que sucede en su propio entorno de trabajo e identifique suposiciones que suscriban
su gerencia y sus colegas.

Redefiniendo la ciencia de datos


La ciencia de datos es el análisis de datos para obtener información procesable. En la práctica, es
una amalgama de diferentes disciplinas relacionadas con los datos en una sola: estadísticas,
análisis de datos, visualización de datos, aprendizaje automático, investigación de operaciones,

182
ingeniería de software.. solo por nombrar algunas. Prácticamente cualquier disciplina que toque
datos puede calificarse como "ciencia de datos". Esta falta de definición clara ha sido problemática
para el campo. Después de todo, cualquier cosa que carezca de definición está abierta a la
interpretación, como una obra de arte abstracto. Esta es la razón por la que los departamentos de
recursos humanos luchan con las ofertas de trabajo de "científico de datos", ya que tienden a estar
en todo el mapa. La figura 8-1 muestra un paraguas que abarca diferentes disciplinas y
herramientas que pueden incluirse en la ciencia de datos.

Figura 8-1. El paraguas de la ciencia de datos

¿Cómo llegamos aquí? ¿Y cómo algo que carece de definición como la ciencia de datos puede
convertirse en una fuerza tan convincente en el mundo empresarial? Lo más importante, ¿cómo
afecta su definición (o la falta de ella) a su carrera? Todas estas son preguntas importantes de las
que hablamos en este capítulo.
Es por eso que les digo a mis clientes que una mejor definición para la ciencia de datos es la
ingeniería de software con competencia en estadísticas, aprendizaje automático y optimización. Si
elimina cualquiera de esas cuatro disciplinas (ingeniería de software, estadísticas, aprendizaje
automático y optimización), el científico de datos corre el riesgo de no rendir. La mayoría de las
organizaciones se han esforzado por hacer distinciones claras sobre los conjuntos de habilidades
que hacen que un científico de datos sea efectivo, pero la definición proporcionada debería brindar
claridad. Si bien algunos pueden pensar que la ingeniería de software es un requisito controvertido,

183
creo que es muy necesario dada la dirección que están tomando las industrias. Abordaremos este
punto más adelante.
Pero primero, la mejor manera de entender la ciencia de datos es rastrear la historia del término.
Una breve historia de la ciencia de datos
Podríamos rastrear la ciencia de datos hasta el origen de las estadísticas, ya en el siglo XVII o
incluso en el siglo VIII. En aras de la brevedad, comencemos en la década de 1990. Los analistas,
estadísticos, investigadores, "cuantitativos" e ingenieros de datos a menudo mantuvieron roles
distintos. Las pilas de herramientas a menudo consistían en hojas de cálculo, R, MATLAB, SAS y
SQL.
Por supuesto, las cosas comenzaron a cambiar rápidamente después del año 2000. Internet y los
dispositivos conectados comenzaron a generar enormes cantidades de datos. Junto con el inicio de
Hadoop, Google llevó el análisis y la recopilación de datos a alturas inimaginables. A medida que
se acercaba el 2010, los ejecutivos de Google insistieron en que los estadísticos tendrán el trabajo
"sexy" en la próxima década. Lo que vino después fue profético.
En 2012, Harvard Business Review incorporó este concepto llamado ciencia de datos y lo declaró
el “trabajo más sexy del siglo XXI”. Después del artículo de Harvard Business Review, muchas
empresas y trabajadores corporativos se apresuraron a llenar el vacío de la ciencia de datos. Los
consultores de gestión estaban preparados y posicionados para educar a los líderes de Fortune
500 sobre cómo llevar la ciencia de datos a sus organizaciones. Los desarrolladores, analistas,
investigadores, estadísticos, estadísticos, ingenieros, físicos y una miríada de otros profesionales
de SQL se rebautizaron a sí mismos como "científicos de datos". Las empresas tecnológicas,
sintiendo que los títulos de roles tradicionales como "analista", "estadístico" o "investigador"
sonaban anticuados, cambiaron el nombre de los roles a "científico de datos".
Naturalmente, la gerencia de las empresas Fortune 500 se vio presionada por el C-suite para
subirse al carro de la ciencia de datos. El razonamiento inicial era que se recopilaban muchos
datos, por lo que el big data se estaba convirtiendo en una tendencia y se necesitaban científicos
de datos para obtener información de ellos. Alrededor de este tiempo, la palabra "basado en datos"
se convirtió en una máxima en todas las industrias. El mundo empresarial creía que, a diferencia de
las personas, los datos son objetivos e imparciales.

RECORDATORIO: ¡LOS DATOS NO SON OBJETIVOS NI IMPARCIALES!


Hasta el día de hoy, muchos profesionales y gerentes caen en la falacia de pensar que los datos
son objetivos e imparciales. Con suerte, después de leer este libro, sabrá que esto simplemente no
es cierto, y consulte el Capítulo 3 si necesita un repaso sobre por qué.
La gerencia y los recursos humanos en las empresas, incapaces de competir por doctorados
especializados en aprendizaje profundo que fueron engullidos por FAANG (Facebook, Amazon,
Apple, Netflix y Google) y aún bajo presión para marcar la casilla de ciencia de datos, hicieron un
movimiento interesante. Cambiaron el nombre de los equipos existentes de analistas,
desarrolladores de SQL y jinetes de Excel como "científicos de datos". Cassie Kozyrkov, directora
científica de decisiones de Google, describió este secreto a voces en un artículo de blog de 2018
sobre Hackernoon :
Con cada título de científico de datos que he tenido, ya había estado haciendo el trabajo con un
nombre diferente antes de que cambiar el nombre de czars in HR aplicara un pequeño cambio a la
base de datos de empleados. Mis deberes no cambiaron en lo más mínimo. Yo no soy la
excepción; mi círculo social está lleno de antiguos estadísticos, ingenieros de apoyo a la toma de
decisiones, analistas cuantitativos, profesores de matemáticas, especialistas en big data, expertos
en inteligencia comercial, líderes de análisis, científicos investigadores, ingenieros de software,
expertos en Excel, sobrevivientes de doctorados de nicho.. todos orgullosos científicos de datos de
hoy.
Técnicamente, la ciencia de datos no excluye a ninguno de estos profesionales, porque todos usan
datos para recopilar información. Por supuesto, hubo cierto rechazo por parte de la comunidad
científica, que se mostró reacia a coronar la ciencia de datos como una ciencia real. Después de
todo, ¿puedes pensar en una ciencia que no use datos?? En 2011, Pete Warden (que ahora
trabaja como líder de TensorFlow en Google) escribió una interesante defensa del movimiento de
ciencia de datos en un artículo de O'Reilly. También articuló claramente los argumentos de los
objetores sobre la falta de definición:
[Con respecto a la falta de definición de la ciencia de datos, esta] es probablemente la objeción
más profunda y la que tiene más dientes. No existe un límite ampliamente aceptado para lo que

184
está dentro y fuera del alcance de la ciencia de datos. ¿Es solo un cambio de marca caprichoso de
las estadísticas? No lo creo, pero tampoco tengo una definición completa. Creo que la reciente
abundancia de datos ha provocado algo nuevo en el mundo, y cuando miro a mi alrededor veo
personas con características compartidas que no encajan en las categorías tradicionales. Estas
personas tienden a trabajar más allá de las especialidades limitadas que dominan el mundo
corporativo e institucional, manejando todo, desde encontrar los datos, procesarlos a escala,
visualizarlos y escribirlos como una historia. También parecen comenzar observando lo que los
datos pueden decirles y luego eligiendo hilos interesantes para seguir,
Pete, irónicamente, tampoco pudo encontrar una definición para la ciencia de datos, pero
claramente explicó por qué la ciencia de datos es defectuosa pero útil. También destacó el cambio
de la investigación que abandona el método científico a favor de prácticas que alguna vez se
evitaron como la minería de datos, de la que hablamos en el Capítulo 3.
La ciencia de datos dio un giro interesante solo unos años después del artículo de Harvard
Business Review. Quizás fue más una fusión con la IA y el aprendizaje automático que un giro.
Independientemente, cuando el aprendizaje automático y el aprendizaje profundo dominaron los
titulares alrededor de 2014, los datos se vendieron como el "combustible" para crear inteligencia
artificial. Esto amplió naturalmente el alcance de la ciencia de datos y creó una confluencia con el
movimiento de aprendizaje automático/IA. En particular, el desafío de ImageNet despertó un
renovado interés en la IA y provocó un renacimiento del aprendizaje automático y el aprendizaje
profundo. Empresas como Waymo y Tesla prometieron autos sin conductor en cuestión de años
gracias a los avances en el aprendizaje profundo, lo que alimentó aún más los titulares de los
medios y las inscripciones en los campamentos de entrenamiento.
Este repentino interés en las redes neuronales y el aprendizaje profundo tuvo un efecto secundario
interesante. Las técnicas de regresión como los árboles de decisión, las máquinas de vectores de
soporte y la regresión logística, que han pasado décadas escondidas en la academia y las
profesiones estadísticas especializadas, se montaron en los faldones del aprendizaje profundo para
convertirse en el centro de atención del público. Al mismo tiempo, las bibliotecas como scikit-learn
crearon una barrera baja para ingresar al campo. Esto tenía un costo oculto de crear profesionales
de la ciencia de datos que no entendían cómo funcionaban estas bibliotecas o modelos, pero los
usaron de todos modos.
Debido a que la disciplina de la ciencia de datos ha evolucionado más rápido que la necesidad
percibida de definirla, no es raro que un rol de científico de datos sea un comodín completo. Conocí
a varias personas que tenían un título de científico de datos en compañías Fortune 500. Algunos
son altamente competentes en codificación e incluso pueden tener experiencia en ingeniería de
software, pero no tienen idea de qué es la importancia estadística. Otros permanecen confinados
en Excel y apenas saben SQL, mucho menos Python o R. Conocí a gente de ciencia de datos que
aprendieron algunas funciones en scikit-learn y rápidamente se encontraron tambaleándose porque
eso era todo lo que sabían.
¿Entonces que significa esto para usted? ¿Cómo floreces en un paisaje tan caótico y lleno de
palabras? Todo se reduce a qué tipos de problemas o industrias le interesan, y no depender
rápidamente de los empleadores para definir los roles. No es necesario ser un científico de datos
para hacer ciencia de datos. Hay una amplia gama de campos en los que puede trabajar a su favor
dado este conocimiento que ahora tiene. Puede ser analista, investigador, ingeniero de aprendizaje
automático, asesor, consultor y muchos otros roles que no necesariamente se denominan
científicos de datos.
Pero primero, abordemos algunas formas en que puede continuar aprendiendo y encontrar su
ventaja en el mercado laboral de ciencia de datos.

Encontrar su borde
El profesional práctico de la ciencia de datos necesita más que una comprensión de las
estadísticas y el aprendizaje automático para prosperar. En la mayoría de los casos, no es
razonable esperar que los datos estén fácilmente disponibles para el aprendizaje automático y
otros proyectos. En cambio, se encontrará persiguiendo fuentes de datos, guiones de ingeniería y
software, raspando documentos, raspando libros de Excel e incluso creando sus propias bases de
datos. Al menos el 95% de sus esfuerzos de codificación no estarán relacionados con el
aprendizaje automático o el modelado estadístico, sino con la creación, el movimiento y la
transformación de datos para que sean utilizables.

185
Además de eso, debe ser consciente del panorama general y la dinámica de su organización. Sus
gerentes pueden hacer suposiciones al definir su rol, y es importante identificar estas suposiciones
para que reconozca cómo lo afectan. Mientras confía en sus clientes y liderazgo para su
experiencia en la industria, debe estar en un rol para proporcionar conocimiento técnico y articular
lo que es factible. Veamos algunas habilidades duras y blandas que probablemente necesitará.
Dominio de SQL
SQL, también llamado lenguaje de consulta estructurado, es un lenguaje de consulta para
recuperar, transformar y escribir datos de tablas. Una base de datos relacional es la forma más
común de organizar datos, almacenándolos en tablas que están conectadas entre sí de forma muy
similar a BUSCARV en Excel. Las plataformas de bases de datos relacionales como MySQL,
Microsoft SQL Server, Oracle, SQLite y PostgreSQL admiten SQL. Como puede notar, SQL y las
bases de datos relacionales están tan estrechamente acopladas que "SQL" se usa a menudo en la
marca de la base de datos relacional, como "MySQL" y "Microsoft SQL Server".
El ejemplo 8-1 es una consulta SQL simple que recupera los campos CLIENTE_ID y NOMBRE de
una tabla CLIENTE, para registros que están en el ESTADO de 'TX'.
Ejemplo 8-1. Una consulta SQL simple
SELECT CUSTOMER_ID, NAME
FROM CUSTOMER
WHERE STATE = 'TX'

En pocas palabras, es difícil llegar a ningún lado como profesional de la ciencia de datos sin
competencia en SQL. Las empresas utilizan almacenes de datos y SQL es casi siempre el medio
para recuperar los datos. SELECT, WHERE, GROUP BY, ORDER BY, CASE, INNER JOIN y LEFT
JOIN deberían ser palabras clave familiares de SQL. Es aún mejor conocer las subconsultas, las
tablas derivadas, las expresiones de tablas comunes y las funciones de ventanas para obtener la
mayor utilidad de sus datos.

ENCHUFE DESVERGONZADO: ¡EL AUTOR TIENE UN LIBRO DE SQL!


He escrito un libro de SQL para principiantes para O'Reilly llamado Primeros pasos con SQL.
Apenas supera las cien páginas por lo que se puede terminar en un día. Cubre lo esencial,
incluidas las uniones y agregaciones, así como la creación de su propia base de datos. El libro
utiliza SQLite, que se puede configurar en menos de un minuto.
Hay otros grandes libros de SQL de O'Reilly, incluido Learning SQL, 3rd Ed. por Alan Beaulieu y
SQL Pocket Guide, 4.ª ed. por Alice Zhao. Después de leer rápidamente mi manual básico de cien
páginas, echa un vistazo a estos dos libros también.
SQL también es fundamental para hacer que Python u otros lenguajes de programación se
comuniquen fácilmente con las bases de datos. Si desea enviar consultas SQL a una base de
datos desde Python, puede recuperar los datos como Pandas DataFrames, colecciones de Python
y otras estructuras.
El ejemplo 8-2 muestra una consulta SQL simple ejecutada en Python utilizando la biblioteca
SQLAlchemy. Devuelve los registros como tuplas con nombre. Solo asegúrese de descargar este
archivo de base de datos SQLite y colocarlo en su proyecto de Python, así como ejecutar run pip
install sqlalchemy .
Ejemplo 8-2. Ejecutar una consulta SQL dentro de Python usando SQLAlchemy
from sqlalchemy import create_engine, text
engine = create_engine('sqlite:///thunderbird_manufacturing.db')
conn = engine.connect()
stmt = text("SELECT * FROM CUSTOMER")
results = conn.execute(stmt)
for customer in results:
print(customer)

¿Qué pasa con Pandas y NoSQL?


Con frecuencia recibo preguntas sobre "alternativas" a SQL como NoSQL o Pandas. Estas
realmente no son alternativas y, en cambio, son diferentes herramientas que residen en otra parte
de la cadena de herramientas de ciencia de datos. Tome Pandas, por ejemplo. En el ejemplo 8-3,

186
puedo crear una consulta SQL extrayendo todos los registros de la tabla CLIENTE y colocarlos en
un marco de datos de Pandas.
Ejemplo 8-3. Importación de una consulta SQL en un Pandas DataFrame
from sqlalchemy import create_engine, text
import pandas as pd
engine = create_engine('sqlite:///thunderbird_manufacturing.db')
conn = engine.connect()
df = pd.read_sql("SELECT * FROM CUSTOMER", conn)
print(df) # prints SQL results as DataFrame
SQL se usó aquí para cerrar la brecha entre la base de datos relacional y mi entorno de Python, y
cargar los datos en un Pandas DataFrame. Si tengo cálculos exigentes que SQL está equipado
para manejar, es más eficiente que lo haga en el servidor de la base de datos usando SQL en lugar
de localmente en mi computadora usando Pandas. En pocas palabras, Pandas y SQL pueden
trabajar juntos y no son tecnologías competidoras.
Lo mismo ocurre con NoSQL, que incluye plataformas como Couchbase y MongoDB. Si bien
algunos lectores pueden estar en desacuerdo y presentar argumentos válidos, creo que comparar
NoSQL con SQL es comparar manzanas y naranjas. Sí, ambos almacenan datos y brindan
capacidades de consulta, pero no creo que eso los ponga en competencia. Tienen diferentes
calidades para diferentes casos de uso. NoSQL significa "no solo SQL" y está mejor equipado para
almacenar datos no estructurados, como imágenes o artículos de texto de formato libre. SQL está
mejor equipado para almacenar datos estructurados. SQL mantiene la integridad de los datos de
manera más agresiva que NoSQL, aunque a costa de la sobrecarga informática y menos
escalabilidad.

SQL, LA LENGUA FRANCA DE LOS DATOS


En 2015, muchos especularon que NoSQL y las tecnologías de procesamiento de datos
distribuidos como Apache Spark reemplazarían a SQL y las bases de datos relacionales.
Irónicamente, SQL ha demostrado ser tan importante para los usuarios de datos que se agregaron
capas de SQL a estas plataformas debido a la demanda. Estas tecnologías de capas incluyen
Presto, BigQuery y Apache Spark SQL, por nombrar algunas. La mayoría de los problemas de
datos no son problemas de big data, y nada funciona como SQL en la consulta de datos. Por lo
tanto, SQL ha continuado prosperando y manteniendo su lugar como la lingua franca del mundo de
los datos.
En otra nota, la promoción de NoSQL y las plataformas de big data podría ser una lección sobre el
síndrome de Silver Bullet. Hadi Hariri de JetBrains dio una charla sobre este tema en 2015, y vale
la pena verla.

Competencia en programación
Por lo general, muchos científicos de datos no tienen la habilidad de codificar, al menos no al nivel
de un ingeniero de software. Sin embargo, cada vez es más importante que codifiquen. Esto brinda
la oportunidad de obtener una ventaja. Aprenda programación orientada a objetos, programación
funcional, pruebas unitarias, control de versiones (p. ej., Git y GitHub), análisis de algoritmos Big-O,
criptografía y otros conceptos informáticos relevantes y características del lenguaje que encuentre.
Aquí está el por qué. Supongamos que creó un modelo de regresión prometedor, como una
regresión logística o una red neuronal, en función de algunos datos de muestra que le dieron. Pide
a los programadores internos de su departamento de TI que lo "conecten" a una pieza de software
existente.
Miran tu lanzamiento con cautela. “Necesitamos reescribir esto en Java, no en Python”, dicen a
regañadientes. "¿Dónde están sus pruebas unitarias?" otro pregunta. “¿No tienes ninguna clase o
tipo definido? Tenemos que rediseñar este código para que esté orientado a objetos”. Además de
eso, no entienden las matemáticas de su modelo y, con razón, se preocupan de que se comporte
mal con los datos que no ha visto antes. Dado que no ha definido pruebas unitarias, lo que no es
fácil de hacer con el aprendizaje automático, no están seguros de cómo verificar la calidad de su
modelo. También preguntan cómo se van a gestionar dos versiones de código (Python y Java)?

Empiezas a sentirte fuera de tu elemento y dices: "No entiendo por qué el script de Python no se
puede simplemente conectar". Uno de ellos hace una pausa contemplativa y responde: “Podríamos

187
crear un servicio web con Flask y evitar tener que volver a escribir en Java. Sin embargo, las otras
preocupaciones no desaparecen. Entonces tenemos que preocuparnos por la escalabilidad y el alto
tráfico que llega al servicio web. Espere.. tal vez podamos implementar en la nube de Microsoft
Azure como un conjunto de escalado de máquinas virtuales, pero aún tenemos que diseñar los
backends. Mira, esto tiene que ser rediseñado sin importar cómo lo enfoques”.
Esta es precisamente la razón por la que muchos científicos de datos tienen un trabajo que nunca
sale de su computadora portátil. De hecho, poner el aprendizaje automático en producción se ha
vuelto tan difícil de lograr que se ha convertido en un tema candente en los últimos años. Existe
una brecha enorme entre los científicos de datos y los ingenieros de software, por lo que,
naturalmente, existe una presión para que los profesionales de la ciencia de datos se conviertan
ahora en ingenieros de software.
Esto puede sonar abrumador ya que la ciencia de datos ya tiene un alcance sobrecargado, con
muchas disciplinas y requisitos. Sin embargo, esto no es para demostrar que necesita aprender
Java. Puede ser un ingeniero de software efectivo en Python (o cualquier lenguaje que prefiera),
pero debe ser bueno en eso. Aprenda programación orientada a objetos, estructuras de datos,
programación funcional, concurrencia y otros patrones de diseño. Dos buenos libros para abordar
estos temas para Python incluyen Fluent Python, 2nd Ed. de Luciano Ramalho (O'Reilly) y Beyond
the Basic Stuff with Python de Al Sweigart (No Starch).

GOPHERS DE CIENCIA DE DATOS


Daniel Whitenack escribió un artículo "Data Science Gophers" para O'Reilly en 2016, promoviendo
los méritos del lenguaje de programación Go para la ciencia de datos. Lo que es notable es que
destacó el problema de poner en producción modelos de ciencia de datos mucho antes de que se
convirtiera en una discusión principal.
Después de eso, aprenda a resolver tareas prácticas que incluyen API de base de datos, servicios
web, análisis de JSON, expresiones regulares, web scraping, seguridad y criptografía, computación
en la nube (Amazon Web Services, Microsoft Azure) y cualquier otra cosa que lo ayude a ser
productivo al levantar una sistema.
Como se indicó anteriormente, el lenguaje de programación que domina no tiene que ser Python.
Puede ser otro idioma, pero se recomienda que el idioma sea universalmente utilizado y empleable.
Los lenguajes que tienen una mayor empleabilidad en el momento de escribir este artículo incluyen
Python, R, Java, C# y C++. Swift y Kotlin tienen una presencia dominante en los dispositivos Apple
y Android, y ambos son lenguajes fantásticos y bien soportados. Aunque muchos de estos
lenguajes no son convencionales para fines de ciencia de datos, puede ser útil aprender al menos
otro además de Python para obtener una mayor exposición.

¿QUÉ PASA CON LOS PORTÁTILES JUPYTER?


Los científicos de datos a menudo tienen una mala reputación por escribir un código deficiente. Hay
una serie de razones por las que este es el caso, pero un posible culpable podría ser los flujos de
trabajo fomentados por Jupyter Notebooks.
Tal vez se pregunte por qué no usé (ni alenté) los Jupyter Notebooks en este libro. Jupyter
Notebooks es una plataforma popular para escribir código de ciencia de datos, pero de alguna
manera puede colocar notas, fragmentos de código ejecutables y resultados de consola/gráfico en
un solo lugar. Pueden ser una herramienta útil y proporcionar una manera conveniente de contar
una historia con datos.
Dicho esto, los cuadernos simplemente no son un requisito para realizar trabajos de ciencia de
datos a menos que su empleador lo requiera. Todo lo que cubrimos en este libro se hizo en Python
simple sin cuadernos. Hice esto a propósito, ya que no quería agobiar a los lectores con la
configuración de herramientas adicionales. Esto puede ir en contra de las convenciones, pero
puedes tener una carrera saludable sin tocar los cuadernos.
Este es el motivo: los portátiles fomentan los malos hábitos de programación. Los cuadernos
fomentan flujos de trabajo que enfatizan la linealidad en lugar de la modularidad, lo que significa
que no son propicios para escribir código reutilizable. Podría decirse que la reutilización es el
objetivo más básico de la programación de software. Además de eso, las celdas del cuaderno que
contienen los fragmentos de código se pueden ejecutar en cualquier orden arbitrario o se pueden
volver a ejecutar varias veces. Si no tiene cuidado, puede crear estados confusos y errores que, en
el mejor de los casos, generarán errores flagrantes y, en el peor de los casos, errores de cálculo
sutiles que pasarán desapercibidos. Especialmente si eres un principiante, esta es una forma

188
enloquecedora de aprender Python, ya que estas trampas técnicas no son obvias para los recién
llegados. También es una forma de encontrar y presentar un hallazgo, solo para descubrir que fue
el resultado de un error y, por lo tanto, demasiado bueno para ser verdad.
No estoy abogando por que evites los cuadernos. Por todos los medios, ¡úsalos si te hacen feliz a ti
y a tu lugar de trabajo! Sin embargo, estoy abogando por no confiar en ellos. Joel Grus, autor de
Data Science from Scratch (O'Reilly), dio una charla en JupyterCon sobre este mismo tema que
puedes ver aquí.
SESGO DE ANCLAJE Y PRIMEROS LENGUAJES DE PROGRAMACIÓN
Es común que los profesionales técnicos se involucren emocionalmente con las tecnologías y las
plataformas, especialmente los lenguajes de programación. ¡Por favor, no hagas esto! Este tipo de
tribalismo no es productivo e ignora la realidad de que cada lenguaje de programación se adapta a
diferentes cualidades y casos de uso. Otra realidad es que algunos lenguajes de programación
prenden y otros no, a menudo por razones que no tienen nada que ver con los méritos en el diseño
de lenguajes. Si una gran empresa no paga por su apoyo, sus posibilidades de supervivencia son
escasas.
Hablamos sobre diferentes tipos de sesgos cognitivos en el Capítulo 3. Otro es el sesgo de anclaje,
que establece que podemos volvernos parciales con lo primero que aprendemos, como un lenguaje
de programación. Si te sientes obligado a aprender un nuevo idioma, ¡sé abierto y dale una
oportunidad! Ningún idioma es perfecto, y lo único que importa es que haga el trabajo.
Sin embargo, tenga cuidado si el soporte del idioma es cuestionable porque está en soporte vital,
no recibe actualizaciones o carece de un mantenedor corporativo. Ejemplos de esto incluyen VBA
de Microsoft, Ceylon de Red Hat y Haskell.

BIBLIOTECAS DE CIENCIA DE DATOS DE JAVA


Si bien no es tan popular como las bibliotecas de ciencia de datos de Python, Java tiene varias
bibliotecas equivalentes que son muy compatibles. ND4J es el NumPy para la máquina virtual Java
y SMILE es el scikit-learn. TableSaw es el equivalente de Java a Pandas.
Apache Spark en realidad está escrito en la plataforma Java, específicamente usando Scala.
Curiosamente, Apache Spark fue un impulsor durante algún tiempo que intentaba hacer de Scala
un lenguaje convencional para la ciencia de datos, aunque no alcanzó el grado en que la
comunidad de Scala probablemente esperaba. Es por eso que se hizo un gran esfuerzo para
agregar compatibilidad con Python, SQL y R y no solo con Java y Scala.

Visualización de datos
Otra habilidad técnica en la que debe tener cierto grado de competencia es la visualización de
datos. Siéntase cómodo haciendo tablas, gráficos y diagramas que no solo le cuenten historias a la
gerencia, sino que también ayuden a sus propios esfuerzos de exploración de datos. Puede
resumir los datos con un comando SQL, pero a veces un gráfico de barras o un diagrama de
dispersión le dará una mejor idea de sus datos en menos tiempo.
Cuando se trata de qué herramientas usar para la visualización de datos, esto es mucho más difícil
de responder porque hay mucha fragmentación y elección. Si trabaja en un entorno de oficina
tradicional, Excel y PowerPoint suelen ser las herramientas de visualización preferidas, ¿y sabe
qué? ¡Están bastante bien! No los uso para todo pero cumplen la gran mayoría de tareas.
¿Necesita un diagrama de dispersión en un conjunto de datos pequeño o mediano? ¿O un
histograma? ¡No hay problema! Puede tener uno integrado unos minutos después de copiar/pegar
sus datos en un libro de Excel. Esto es excelente para visualizaciones de gráficos de una sola vez,
y no hay que avergonzarse de usar Excel cuando funciona.
Sin embargo, hay situaciones en las que es posible que desee programar la creación de gráficos
para que sea repetible y reutilizable o se integre con su código Python. matplotlib ha sido el recurso
durante algún tiempo, y es difícil evitarlo cuando Python es su plataforma. Seaborn proporciona un
contenedor en la parte superior de matplotlib para que sea más fácil de usar para los tipos de
gráficos comunes. SymPy, que usamos mucho a lo largo de este libro, usa matplotlib como
backend. Sin embargo, algunos consideran que matplotlib es tan maduro que se acerca al estado
heredado. Las bibliotecas como Plotly han ido en aumento y son agradables de usar, y se basan en
la biblioteca JavaScript D3.js. Personalmente, estoy teniendo éxito con Manim. Las visualizaciones
de estilo 3Blue1Brown que produce son extraordinarias y tienen ese "¡Guau!" factor con los
clientes, y la API es sorprendentemente fácil de usar teniendo en cuenta el poder de animación que

189
tiene. Sin embargo, es una biblioteca joven y aún no ha alcanzado la madurez, lo que significa que
es posible que tenga cambios importantes en el código a medida que evoluciona con cada versión.
No puede equivocarse al explorar todas estas soluciones, y si su empleador/cliente no tiene una
preferencia, puede encontrar la que mejor se adapte a sus necesidades.
Hay plataformas comerciales con licencia como Tableau, que están bien hasta cierto punto. Se
propusieron crear un software patentado que se especialice en visualización y crear una interfaz de
arrastrar y soltar para que sea accesible para usuarios no técnicos. Tableau incluso tiene un
documento técnico titulado "Convierta a todos en su organización en científicos de datos", que no
ayuda con el problema de definición de científico de datos mencionado anteriormente. Los desafíos
que encontré con Tableau es que solo hace una buena visualización y requiere una licencia
considerable. Si bien puede integrar Python con TabPy de alguna manera, puede elegir usar las
bibliotecas de código abierto compatibles mencionadas anteriormente, a menos que su empleador
quiera usar Tableau.

LAS LICENCIAS DE SOFTWARE PUEDEN SER POLÍTICAS


Imagine que creó una aplicación Python o Java que solicita algunas entradas del usuario, recupera
y maneja diferentes fuentes de datos, ejecuta algunos algoritmos altamente personalizados y luego
presenta una visualización y una tabla que muestra el resultado. Lo presenta en una reunión
después de meses de arduo trabajo, pero luego uno de los gerentes levanta la mano y pregunta:
"¿Por qué no hacer esto en Tableau?"
Es una píldora difícil de tragar para algunos gerentes, sabiendo que han gastado miles de dólares
en licencias de software corporativo, y usted ingresa y usa una solución de código abierto más
capaz (aunque más compleja de usar) que no tiene costos de licencia. Puede enfatizar que
Tableau no admite estos algoritmos o flujos de trabajo integrados que tuvo que crear. Después de
todo, Tableau es solo un software de visualización. No es una plataforma de codificación desde
cero para crear una solución personalizada y altamente adaptada.
El liderazgo a menudo se vende con la impresión de que Tableau, Alteryx u otra herramienta
comercial puede hacerlo todo. Después de todo, gastaron mucho dinero en él y probablemente el
vendedor les dio un buen argumento de venta. Naturalmente, quieren justificar los costes y que el
mayor número posible de personas utilicen la licencia. Probablemente gastaron más presupuesto
para capacitar a los empleados en el uso del software y quieren que otros puedan mantener su
trabajo.
Sea sensible a esto. Si la gerencia le pide que use la herramienta por la que pagaron, explore si
puede hacer que funcione. Pero si tiene limitaciones o grandes compromisos de usabilidad en sus
tareas específicas, sea cortésmente sincero al respecto.

Conociendo su industria
Comparemos dos industrias: transmisión de películas (p. ej., Netflix) y defensa aeroespacial (p. ej.,
Lockheed Martin). ¿Tienen algo en común? ¡Difícilmente! Ambas son empresas impulsadas por la
tecnología, pero una transmite películas para los consumidores y la otra construye aviones con
artillería.
Cuando aconsejo sobre inteligencia artificial y seguridad del sistema, una de las primeras cosas
que señalo es que estas dos industrias tienen tolerancias de riesgo muy diferentes. Una empresa
de transmisión de películas puede promocionar que tiene un sistema de inteligencia artificial que
aprende qué películas recomendar a los consumidores, pero ¿qué tan catastrófico es cuando da
una mala recomendación? Bueno, en el peor de los casos, tiene un consumidor levemente irritado
que perdió dos horas viendo una película que no disfrutó.
Pero, ¿qué pasa con la compañía de defensa aeroespacial? Si un avión de combate tiene IA a
bordo que dispara automáticamente a los objetivos, ¿qué tan catastrófico sería si estuviera mal?
¡Estamos hablando de vidas humanas ahora, no de recomendaciones de películas!
La brecha de tolerancia al riesgo entre ambas industrias es amplia. Naturalmente, la compañía de
defensa aeroespacial será mucho más conservadora al implementar cualquier sistema
experimental. Esto significa que los grupos de trabajo burocráticos y de seguridad evalúan y
detienen cualquier proyecto que consideren de alto riesgo inaceptable, y con razón. Sin embargo,
lo que es interesante es el éxito de la IA en las nuevas empresas de Silicon Valley, la mayoría en
aplicaciones de bajo riesgo como recomendaciones de películas, han creado FOMO ("miedo a
perderse") con los ejecutivos y el liderazgo de la industria de defensa. Esto probablemente se deba
a que la disparidad en la tolerancia al riesgo entre estos dos dominios no se destaca lo suficiente.

190
Por supuesto, existe un amplio espectro de gravedad del riesgo entre estas dos industrias, entre
"usuario irritado" y "pérdida de vidas humanas". Los bancos pueden usar IA para determinar quién
calificará para préstamos, pero eso conlleva riesgos al discriminar ciertos datos demográficos. Los
sistemas de justicia penal han experimentado con IA en los sistemas de libertad condicional y
vigilancia, solo para encontrarse con los mismos problemas de discriminación. Las redes sociales
pueden usar IA para determinar qué publicaciones de usuarios son aceptables, pero enojan a sus
usuarios cuando suprimen contenido "inofensivo" (falses positivos), así como a los legisladores
cuando no suprimen contenido "dañino" (falses negativos).
Esto demuestra la necesidad de conocer su industria. Si desea hacer mucho aprendizaje
automático, probablemente querrá trabajar en industrias de bajo riesgo donde los falses positivos y
los falses negativos no pongan en peligro ni molesten a nadie. Pero si nada de eso le atrae y desea
trabajar en aplicaciones más audaces, como automóviles autónomos, aviación y medicina, espere
que sus modelos de aprendizaje automático sean rechazados con frecuencia.
En estas industrias de mayor riesgo, no se sorprenda si se requieren doctorados específicos y otras
credenciales formales. Incluso con un doctorado especializado, los falses positivos y los falses
negativos no desaparecen por arte de magia. Si no desea seguir una especialización tan
comprometida, probablemente será mejor que aprenda otras herramientas además del aprendizaje
automático, incluida la ingeniería de software, la optimización, las estadísticas y los
sistemas/heurística de reglas comerciales.

Aprendizaje Productivo
En un especial de stand-up de 2008, el comediante Brian Regan comparó su falta de curiosidad
con la de aquellos que leen periódicos. Al señalar que una historia de primera plana nunca
concluye, afirmó que no tiene ningún deseo de pasar a la página especificada para saber cómo
termina. "Y después de un juicio de nueve años, el jurado finalmente llegó con un veredicto de
continúa en la página 22 en la columna C.. Supongo que nunca lo sabré", bromea con desdén.
Luego contrasta con aquellos que pasan las páginas, exclamando: “¡Quiero aprender! ¡Quiero ser
un aprendiz de cosas!”
Si bien Brian Regan podría haber tenido la intención de ser autocrítico, tal vez tenía razón en algo.
Aprender un tema por el simple hecho de hacerlo difícilmente es una motivación, y ser
desinteresado no siempre es algo malo. Si elige un libro de texto de cálculo y no tiene ningún
propósito para aprenderlo, probablemente terminará desanimado y frustrado. Necesita tener un
proyecto u objetivo en mente, y si encuentra un tema poco interesante, ¿por qué molestarse en
aprenderlo? Personalmente, cuando me permití perder interés en temas que no encontraba
relevantes, fue increíblemente liberador. Aún más sorprendente, mi productividad se disparó.
No significa que debas ser poco curioso. Sin embargo, hay mucha información disponible y priorizar
lo que aprendes es una habilidad invaluable. Puede hacer preguntas sobre por qué algo es útil y, si
no puede obtener una respuesta directa, ¡permítase seguir adelante! ¿Está todo el mundo
hablando del procesamiento del lenguaje natural? ¡No significa que tengas que hacerlo! De todos
modos, la mayoría de las empresas no necesitan el procesamiento del lenguaje natural, por lo que
está bien decir que no vale la pena su esfuerzo o tiempo.
Ya sea que tenga proyectos en su trabajo o cree los suyos propios para el autoaprendizaje, tenga
algo tangible en lo que trabajar. Solo usted puede decidir qué vale la pena aprender, y puede
abandonar el FOMO en busca de cosas que le parezcan interesantes y relevantes.

Practicante versus asesor


Esto podría ser una generalización, pero hay dos tipos de expertos en conocimiento: profesionales
y asesores. Para encontrar su ventaja, discernir quién quiere ser y ajustar su desarrollo profesional
en consecuencia.
En el mundo de la ciencia y el análisis de datos, los profesionales son los que escriben código,
crean modelos, examinan datos e intentan crear valor directamente. Los asesores son como
consultores, le dicen a la gerencia si sus objetivos son sólidos, ayudan con la estrategia y brindan
orientación. A veces, un profesional puede abrirse camino hasta convertirse en asesor. A veces, los
asesores nunca fueron practicantes. Hay ventajas y desventajas para cada rol.
Un profesional puede disfrutar de la codificación, el análisis de datos y la realización de trabajos
tangibles que pueden crear valor directamente. Un beneficio para el practicante es que realmente
desarrollan y poseen habilidades duras. Sin embargo, sumergirse en el código, las matemáticas y
los datos hace que sea fácil perder de vista el panorama general y perder el contacto con el resto

191
de la organización y la industria. Una queja común que escuché de los gerentes es que su científico
de datos quiere trabajar en problemas que encuentran interesantes pero que no agregan valor a la
organización. También he escuchado quejas de practicantes que quieren exposición y movilidad
ascendente pero se sienten apartados y escondidos en su organización.
Es cierto que un asesor tiene un trabajo más cómodo en algunos aspectos. Brindan asesoramiento
e información a los gerentes y ayudan a proporcionar una dirección estratégica a una empresa. Por
lo general, no son los que escriben el código o rastrean los datos, pero ayudan a la gerencia a
contratar a las personas que lo hacen. El riesgo de carrera es diferente, ya que no se preocupan
por cumplir con los plazos de sprint, lidiar con errores de código o modelos que se comportan mal
como lo hacen los profesionales. Pero sí tienen que preocuparse por mantenerse informados,
creíbles y relevantes.
Para ser un asesor eficaz, debe ser realmenteconocedores y saben cosas que otras personas no
saben. Tiene que ser información crítica y relevante que se ajuste a las necesidades de su cliente.
Para mantenerse relevante, debe leer, leer y leer más todos los días.. buscando y sintetizando
información que otros pasan por alto. No es suficiente estar familiarizado con el aprendizaje
automático, las estadísticas y el aprendizaje profundo. Debe prestar atención a la industria de su
cliente, así como a otras industrias, rastreando quién está teniendo éxito y quién no. También debe
aprender a combinar la solución correcta con el problema correcto, en un panorama empresarial en
el que muchos buscan una bala de plata. Y para hacer todo esto, debe ser un comunicador efectivo
y compartir información de una manera que ayude a su cliente, no solo demostrar lo que sabe.
El mayor riesgo para un asesor es brindar información que termine siendo incorrecta. Algunos
consultores son bastante efectivos para redirigir la culpa a factores externos, como “nadie en la
industria vio venir esto” o “¡este es un evento de seis sigma!” lo que significa que un evento
indeseable tenía una posibilidad entre quinientos millones de ocurrir, pero lo hizo de todos modos.
Otro riesgo es no tener las habilidades duras de un profesional y desconectarse del aspecto técnico
del negocio. Es por eso que es una buena idea practicar regularmente la codificación y el modelado
en casa, o al menos hacer que los libros técnicos formen parte de su lectura.
Al final, un buen asesor trata de ser un puente entre el cliente y su objetivo final, a menudo llenando
un enorme vacío de conocimiento que existe. No se trata de facturar el número máximo de horas e
inventar trabajo pesado, sino de identificar realmente lo que le preocupa a su cliente y ayudarlo a
dormir por la noche.

EL ÉXITO NO SIEMPRE DEPENDE DE LA RENTABILIDAD


Discernir cómo su cliente está definiendo el "éxito". Las empresas buscan inteligencia artificial,
aprendizaje automático y ciencia de datos para tener éxito, ¿verdad? pero que es el exito?
¿Es la rentabilidad? No siempre. En nuestra economía altamente especulativa, el éxito podría ser
otra serie de fondos de capital de riesgo, tener un crecimiento de clientes o de ingresos, o una alta
valoración incluso si la empresa está perdiendo millones o miles de millones de dólares. Ninguna
de estas métricas tiene nada que ver con la rentabilidad.
¿Por qué está pasando esto? La tolerancia a las jugadas a largo plazo en el capital de riesgo ha
marginado la rentabilidad, creyendo que se logrará mucho más adelante. Sin embargo, es posible
que esto esté creando burbujas muy parecidas a lo que sucedió en el auge de las puntocom de
2000.
Al final, se debe lograr la rentabilidad para que una empresa tenga éxito a largo plazo, pero no
todos tienen ese objetivo. Muchos fundadores e inversores simplemente quieren aprovechar el
crecimiento y sacar dinero antes de que estalle la burbuja, a menudo cuando la empresa se vende
al público a través de una oferta pública inicial.
¿Qué significa esto para ti? Ya sea que sea un profesional o un asesor, que trabaje en una startup
o en Fortune 500, reconozca lo que motiva a su cliente o empleador. ¿Están buscando
valoraciones más altas? ¿Rentabilidad real? ¿Valor intrínseco o valor percibido? Esto afectará
directamente en lo que trabaja y lo que sus clientes quieren escuchar, y puede juzgar en
consecuencia si está en un lugar para ayudarlos o no.
Si desea obtener más información sobre el capital de riesgo, la valoración especulativa y los
efectos de la cultura de las empresas emergentes, The Cult of We, de los escritores del Wall Street
Journal, Eliot Brown y Maureen Farrell, es fantástico.

Cuando los proyectos se planifican sobre herramientas en lugar de problemas, existe una alta
probabilidad de que el proyecto no tenga éxito. Esto significa que, como asesor, debe perfeccionar

192
sus habilidades de escucha e identificar las preguntas que los clientes tienen dificultades para
hacer, y mucho menos tener las respuestas. Si una importante cadena de comida rápida lo ha
contratado para ayudar con la "estrategia de inteligencia artificial" y ve que su departamento de
recursos humanos se apresura a contratar talento de aprendizaje profundo, es su trabajo preguntar:
"¿Qué problemas con el aprendizaje profundo está tratando de resolver?" Si no puede obtener una
respuesta clara, desea alentar a la gerencia a dar un paso atrás y evaluar qué problemas reales
están enfrentando como industria. ¿Están teniendo ineficiencia en la programación del personal?
Bueno, no necesitan un aprendizaje profundo. ¡Necesitan programación lineal! Esto puede parecer
básico para algunos lectores, pero hoy en día mucha gerencia se esfuerza por hacer estas
distinciones. Más de una vez, me he encontrado con proveedores y consultores que califican sus
soluciones de programación lineal como IA, que luego pueden combinarse semánticamente con el
aprendizaje profundo.

Qué tener en cuenta en los trabajos de ciencia de datos


Para comprender el mercado laboral de la ciencia de datos, sería bueno hacer una comparación
con una pieza profunda de la televisión estadounidense.
En 2010, hubo una serie de televisión estadounidense Better Off Ted. Un episodio, titulado
“Jabberwocky” (temporada 1, episodio 12), capturó algo profundo sobre las palabras de moda
corporativas. En el programa, Ted, el personaje principal, inventa un proyecto ficticio "Jabberwocky"
en su empresa para ocultar la financiación. Con resultados humorísticos, su gerente, el CEO y, en
última instancia, toda la empresa comenzó a “trabajar” en el proyecto “Jabberwocky” sin siquiera
saber de qué se trata. Continúa escalando y miles de empleados fingen trabajar en "Jabberwocky"
mientras nadie se detiene a preguntar en qué están trabajando realmente. La razón: nadie quiere
admitir que está fuera de onda e ignorante de algo importante.
El efecto Jabberwocky es una teoría anecdótica de que una industria u organización puede
perpetuar una palabra de moda/proyecto incluso si nadie ha definido satisfactoriamente qué es. Las
organizaciones pueden ser víctimas cíclicas de este comportamiento, permitiendo que los términos
circulen sin definición, y el comportamiento del grupo permite la ambigüedad. Los ejemplos
comunes pueden incluir blockchain, inteligencia artificial, ciencia de datos, big data, Bitcoin, Internet
de las cosas, computación cuántica, NFT, estar "basado en datos", computación en la nube y
"disrupción digital". Incluso los proyectos tangibles, de alto perfil y específicos pueden convertirse
en misteriosas palabras de moda entendidas por unos pocos pero comentadas por muchos.
Para detener el efecto Jabberwocky, debe ser un catalizador para un diálogo productivo. Sea
curioso acerca de los métodos y medios (no solo las cualidades o los resultados) de un proyecto o
iniciativa. Cuando se trata de un puesto, ¿la empresa lo está contratando para trabajar en
"Jabberwocky" o proyectos prácticos y específicos? ¿Han sido víctimas de las palabras de moda y
te han contratado por FOMO (miedo a perderse algo)? ¿O realmente tienen necesidades
específicas y funcionales para las que lo están contratando? Hacer este discernimiento puede
significar la diferencia entre un buen ajuste que transcurre sin problemas o un bache frustrante en
su carrera.
Con ese telón de fondo, consideremos ahora algunas cosas a tener en cuenta en los trabajos de
ciencia de datos, comenzando con la definición de roles.

Definición de roles
Digamos que lo contratan como científico de datos. La entrevista fue genial. Hiciste preguntas
sobre el papel y obtuviste respuestas directas. Le ofrecen un trabajo y, lo más importante, debe
saber en qué proyectos trabajará.
Siempre quiere entrar en un rol que esté claramente definido y tenga objetivos tangibles. No se
puede adivinar en qué se supone que debes estar trabajando. Aún mejor, debe tener un liderazgo
con una visión clara que entienda lo que necesita el negocio. Te conviertes en el ejecutor de
objetivos claramente definidos y conoces a tu cliente.
Por el contrario, si lo contrataron para un puesto porque el departamento quiere estar "basado en
datos" o tener una ventaja competitiva en "ciencia de datos", esta es una señal de alerta. Lo más
probable es que tenga la carga de encontrar problemas para resolver y vender cualquier fruta que
encuentre. Cuando solicita orientación estratégica, se le dice que aplique el "aprendizaje
automático" al negocio. Pero claro, cuando lo único que tienes es un martillo, todo empieza a
parecer un clavo. Los equipos de ciencia de datos se sienten presionados para tener una solución
(p. ej., aprendizaje automático) incluso antes de tener un objetivo o un problema que resolver. Una

193
vez que se encuentra un problema, resulta difícil obtener la participación de las partes interesadas
y alinear los recursos, y el enfoque comienza a rebotar de una fruta al alcance de la mano a otra.
El problema aquí es que lo contrataron para un rol basado en una palabra de moda, no en una
función. La mala definición de roles tiende a propagarse a otros problemas que se analizan a
continuación. Pasemos al enfoque organizacional.

Enfoque organizacional y compromiso


Otro factor a tener en cuenta es qué tan alineada está la organización con los objetivos específicos
y si todas las partes están involucradas.
Desde el auge de la ciencia de datos, muchas organizaciones se reestructuraron para tener un
equipo central de ciencia de datos. La visión de los ejecutivos es hacer que el equipo de ciencia de
datos recorra, asesore y ayude a otros departamentos a ser impulsados por datos y emplear
técnicas innovadoras como el aprendizaje automático. También pueden encargarse de desglosar
los silos de datos entre los departamentos. Si bien esto suena como una buena idea en el papel,
muchas organizaciones descubren que esto está lleno de desafíos.
He aquí por qué: la gerencia crea un equipo de ciencia de datos pero no hay un objetivo claro. Por
lo tanto, este equipo tiene la tarea de buscar problemas para resolver en lugar de estar facultado
para resolver problemas conocidos. Como se indicó, esta es la razón por la cual los equipos de
ciencia de datos son conocidos por tener una solución (por ejemplo, aprendizaje automático) antes
de tener un objetivo. Están especialmente mal equipados para ser una fuerza impulsora para
romper los silos de datos, ya que esto está completamente fuera de su campo de experiencia.

¡ROMPER LOS SILOS DE DATOS ES UN TRABAJO DE TI!


Es un error utilizar un equipo de ciencia de datos para "romper los silos de datos" en una
organización. Los silos de datos a menudo se deben a la falta de infraestructura de
almacenamiento de datos, y los departamentos almacenan sus datos en hojas de cálculo y bases
de datos secretas en lugar de una base de datos centralizada y compatible.
Si los silos de datos se consideran un problema, necesita servidores, instancias en la nube,
administradores de bases de datos certificados, protocolos de seguridad y un grupo de trabajo de
TI para poner todo esto junto. Esto no es algo para lo que un equipo de ciencia de datos esté
equipado, ya que es probable que no tengan la experiencia, el presupuesto y la autoridad
organizativa necesarios para lograrlo, excepto en empresas muy pequeñas.
Una vez que se encuentra un problema, es difícil obtener la aceptación de las partes interesadas y
alinear los recursos. Si se encuentra una oportunidad, se necesita un liderazgo fuerte para hacer lo
siguiente:
 Tener un objetivo y una hoja de ruta claramente definidos
 Obtener presupuesto para recolectar datos y apoyar la infraestructura
 Obtener acceso a los datos y negociar la propiedad de los datos
 Incluir la participación de las partes interesadas y el conocimiento del dominio
 Presupuesto de tiempo y reuniones de las partes interesadas
Estos requisitos son mucho más difíciles de cumplir después de que se haya contratado un equipo
de ciencia de datos, en lugar de hacerlo antes, porque las funciones del equipo de ciencia de datos
se están determinando y presupuestando de forma reactiva. Si el liderazgo superior no ha alineado
los recursos y la aceptación de todas las partes necesarias, el proyecto de ciencia de datos no
tendrá éxito. Es por eso que no faltan artículos que culpan a las organizaciones por no estar
preparadas para la ciencia de datos, desde Harvard Business Review hasta MIT Sloan Review.
Es mejor trabajar en un equipo de ciencia de datos que desde el punto de vista organizativo esté en
el mismo departamento que su cliente. La información, los presupuestos y la comunicación se
comparten de forma más libre y coherente. De esa manera, hay menos tensión, ya que la política
interdepartamental se mitiga al poner a todos en el mismo equipo en lugar de competir
políticamente.

EL ACCESO A DATOS ES POLÍTICO


No es ningún secreto que las organizaciones protegen sus datos, pero esto no se debe solo a
preocupaciones de seguridad o desconfianza. Los datos en sí mismos son un activo altamente
político, y muchas personas son reacias a brindar acceso incluso a sus propios colegas. Incluso los
departamentos dentro de la misma organización no compartirán datos entre sí por este motivo: no
quieren que otros hagan su trabajo, y mucho menos hacerlo incorrectamente. Puede requerir su

194
experiencia de tiempo completo para interpretar los datos, y requiere su conocimiento del dominio.
¡Después de todo, sus datos son su negocio! Y si está solicitando acceso a sus datos, está
solicitando entrar en su negocio.
Además de eso, los científicos de datos pueden sobrestimar su capacidad para interpretar
conjuntos de datos extranjeros y la experiencia de dominio necesaria para usarlos. Para superar
este obstáculo, debe desarrollar la confianza y la aceptación de cada socio con experiencia,
negociar una transferencia de conocimientos y, si es necesario, otorgarles un papel importante en
el proyecto.

Recursos adecuados
Otro riesgo a tener en cuenta es no obtener los recursos adecuados para hacer su trabajo. Es difícil
ser arrojado a un rol y no tener lo que necesitas. Por supuesto, ser rudimentario e ingenioso es un
rasgo invaluable. Pero incluso el ingeniero de software/científico de datos más rudimentario puede
encontrarse rápidamente en un aprieto. A veces necesita cosas que cuestan dinero y su empleador
no puede presupuestarlas.
Supongamos que necesita una base de datos para realizar el trabajo de previsión. Tiene una
conexión deficiente a una base de datos de terceros, con tiempo de inactividad y desconexiones
frecuentes. Lo último que quiere escuchar es "hacer que funcione", pero esa es su situación.
Contempla replicar la base de datos localmente, pero para hacerlo, necesita almacenar 40 GB por
día y, por lo tanto, necesita un servidor o una instancia en la nube. ¡Ahora está claramente por
encima de su cabeza, un científico de datos que se convierte en un departamento de TI sin un
presupuesto de TI!
En estas situaciones, debe contemplar cómo puede tomar atajos sin dañar su proyecto. ¿Puede
retener solo los datos más recientes y eliminar el resto? ¿Puede crear una secuencia de comandos
de Python para el manejo de errores que se vuelva a conectar cuando ocurra una desconexión,
mientras divide los datos en lotes para que se recupere del último lote exitoso?
Si este problema/solución suena específico, sí, tuve que hacer esto, y sí, ¡funcionó! Es satisfactorio
encontrar soluciones alternativas y agilizar un proceso sin incurrir en más costos. Pero,
inevitablemente, para muchos proyectos de datos es posible que necesite canalizaciones de datos,
servidores, clústeres, estaciones de trabajo basadas en GPU y otros recursos computacionales que
una computadora de escritorio no puede ofrecer. En otras palabras, estas cosas pueden costar
dinero y es posible que su organización no pueda presupuestarlas.

¿DÓNDE ESTÁ EL MODELADO MATEMÁTICO?


Si se pregunta cómo lo contrataron para hacer regresión, estadísticas, aprendizaje automático y
otras matemáticas aplicadas solo para encontrarse haciendo un trabajo de TI deshonesto, esto no
es raro en el clima corporativo actual.
Sin embargo, está trabajando con datos y eso implícitamente puede conducir a un trabajo similar al
de TI. Lo importante es asegurarse de que sus habilidades aún coincidan con el trabajo y el
resultado necesario. Abordaremos esto a lo largo del resto de este capítulo.

Objetivos razonables
Este es uno grande a tener en cuenta. En un paisaje lleno de exageraciones y promesas
disparatadas, es fácil encontrar objetivos irrazonables.
Hay situaciones en las que un gerente contrata a un científico de datos y espera que entre sin
esfuerzo y agregue valor exponencial a la organización. Esto ciertamente puede suceder si la
organización todavía está haciendo trabajo manual y las oportunidades para automatizar están en
todas partes. Por ejemplo, si la organización está haciendo todo su trabajo en hojas de cálculo y los
pronósticos se hacen con puras conjeturas, esta es una gran oportunidad para que un profesional
de la ciencia de datos optimice los procesos en una base de datos y avance incluso con modelos
de regresión simples.

Por otro lado, si la organización contrata a un científico de datos para implementar el aprendizaje
automático en su software que reconoce específicamente objetos en imágenes, esto es mucho más
difícil. ¡Un científico de datos bien informado tiene que explicarle a la gerencia que este es un
esfuerzo que costará al menos cientos de miles de dólares! No solo hay que recopilar imágenes,
sino que se debe contratar mano de obra para etiquetar los objetos en las imágenes. ¡Y eso es solo
recopilar los datos!

195
Es común que un científico de datos pase sus primeros 18 meses explicando a la gerencia por qué
no ha cumplido, porque todavía está tratando de recopilar y limpiar datos, que es el 95 % de los
esfuerzos de aprendizaje automático. La gerencia puede desilusionarse con esto porque fueron
víctimas de una narrativa popular de que el aprendizaje automático y la IA eliminarían los procesos
manuales, solo para descubrir que cambiaron un conjunto de procesos manuales por otro: la
adquisición de datos etiquetados.

Por lo tanto, tenga cuidado con los entornos que establecen objetivos poco razonables y encuentre
formas diplomáticas de manejar las expectativas con la gerencia, especialmente cuando otros les
prometieron un "botón FÁCIL". Hay muchas afirmaciones de revistas de negocios de buena
reputación y consultorías de gestión de alto valor de que la IA superinteligente está a la vuelta de la
esquina. Los gerentes que carecen de experiencia técnica pueden ser víctimas de esta narrativa
exagerada.
¿CUI BONO?
La expresión latina cui bono significa “¿quién se beneficia?” Es una buena pregunta para hacer
cuando se encuentra tratando de dar sentido a los comportamientos cuando el efecto Jabberwocky
está en pleno apogeo. Cuando los medios promueven historias sobre inteligencia artificial, ¿quién
se beneficia de eso? Independientemente de su respuesta, los medios también se benefician de los
clics y los ingresos publicitarios. Las consultorías de gestión de alto valor crean más horas
facturables en torno a la "estrategia de IA". Un fabricante de chips puede promover el aprendizaje
profundo para vender más tarjetas gráficas, y las plataformas en la nube pueden vender más
almacenamiento de datos y tiempo de CPU para proyectos de aprendizaje automático.
¿Qué tienen en común todos estos partidos? No es solo que estén utilizando la IA como un medio
para vender sus productos, sino que no tienen ningún interés a largo plazo en el éxito de sus
clientes. Están vendiendo unidades, no el resultado de un proyecto, muy parecido a vender palas
durante la fiebre del oro.
Sin embargo, no estoy diciendo que estas motivaciones de los medios y los proveedores no sean
éticas. Es el trabajo de sus empleados ganar dinero para su empresa y mantener a sus familias.
Las afirmaciones que promocionan su producto pueden incluso ser legítimas y alcanzables. Sin
embargo, no se puede descartar que una vez que se promueve un reclamo, es difícil dar marcha
atrás, incluso cuando se reconoce que es inalcanzable. Muchas empresas podrían girar y redirigir
sus esfuerzos en lugar de admitir que sus afirmaciones no dieron resultado. Así que tenga en
cuenta esta dinámica y siempre pregunte "¿cui bono?"

Competir con los sistemas existentes


Esta precaución podría caer dentro de los "objetivos razonables", pero creo que esta situación es lo
suficientemente común como para merecer su propia categoría. Un tipo de rol sutil pero
problemático es el que compite con un sistema existente que en realidad no está roto. Estas
situaciones pueden surgir en entornos de trabajo que carecen de cosas que hacer y necesitan
parecer ocupados.
Su empleador contrató a un proveedor para instalar un sistema de pronóstico de ventas hace varios
años. Su gerente ahora le pide que mejore el sistema de pronóstico aumentando la precisión en un
1%.
¿Ves el problema estadístico aquí? Si lee el Capítulo 3, el 1 % no debería sentirse
estadísticamente significativo, y la aleatoriedad puede proporcionarle fácilmente ese 1 % sin ningún
esfuerzo de su parte. Por el contrario, la aleatoriedad puede girar en la dirección opuesta y las
fuerzas del mercado fuera de su control pueden anular cualquier esfuerzo que implemente. Un mal
trimestre de ventas y factores fuera de su control (como competidores que ingresan al mercado de
su empresa) reducen los ingresos en un -3 % en lugar del 1 % que inevitablemente perjudicó.
El problema general aquí, además de la redundancia del trabajo, es que el resultado no está en tu
esfera de influencia. Esto puede convertirse en una situación menos que óptima. Una cosa es si el
sistema existente con el que está compitiendo está roto y es rudimentario, o si se hace
completamente de forma manual sin automatización. Pero competir con un sistema que no está
roto es prepararte para un mal momento. Si es posible, corre hacia las colinas cuando veas este
tipo de proyectos.

“¿QUÉ DIRÍAS… QUE HACES AQUÍ?”

196
¿Se puede contratar a un científico de datos para un puesto que no produzca ningún valor, a pesar
del buen trabajo y los esfuerzos diligentes? Sí. Los factores fuera del control de uno pueden anular
incluso el mejor trabajo, y es importante estar atento a esto.
La película de comedia de Mike Judge de 1999 Office Space se convirtió en un clásico de culto
para muchos trabajadores corporativos en los Estados Unidos. En la película, el trabajador de TI y
protagonista Peter Gibbons sale mentalmente de un trabajo de codificación que reporta a ocho
gerentes diferentes. Cuando los consultores de reducción de personal le preguntan qué hace
durante el día, responde honestamente que hace "alrededor de 15 minutos de trabajo real". No
estropearé el resto de la película para lectores no iniciados, pero como cualquier gran comedia, el
resultado probablemente no sea el esperado.
Para profundizar en el ejemplo anterior, reemplazar un sistema que no está roto es lo que el difunto
antropólogo David Graeber describiría como un trabajo de mierda (perdón por mi francés). Según
Graeber, un trabajo de mierda es un empleo pagado que es tan completamente inútil, innecesario o
pernicioso que incluso el empleado no puede justificar su existencia, sino que tiene que fingir lo
contrario. En su libro Bullshit Jobs y su artículo viral de 2013, Graeber teoriza que estos trabajos se
están volviendo tan comunes que están cobrando un precio psicológico en la fuerza laboral y la
economía.
Si bien el trabajo de Graeber está plagado de sesgos de autoselección y hallazgos anecdóticos, y
la falta de evidencia empírica es un objetivo discutible para la crítica, es difícil afirmar que estos
trabajos de mierda no existen. En defensa de Graeber, esto es empíricamente difícil de medir y
pocos trabajadores responderán honestamente a una encuesta por temor a poner en peligro sus
propias carreras.
¿Están las carreras de ciencia de datos a salvo de estos problemas? Cassie Kozykrov, directora
científica de decisiones de Google, comparte una extraña anécdota que ayuda a responder esta
pregunta:
Hace varios años, un amigo director de ingeniería que trabaja en tecnología se lamentaba de sus
inútiles científicos de datos. “Creo que podría estar contratando científicos de datos de la misma
manera que un capo de la droga compra un tigre para su patio trasero”, le dije. “No sabes lo que
quieres con el tigre, pero todos los demás capos de la droga tienen uno”.
¡Ay! ¿Es posible que la gerencia contrate científicos de datos para aumentar la credibilidad
percibida y la posición corporativa de una organización? Si se encuentra en un trabajo que no está
diseñado para crear valor, piense estratégicamente cómo puede influir en un cambio positivo.
¿Puedes crear oportunidades en lugar de esperar a que otros te las proporcionen? ¿Puede tomar
posesión de manera significativa de las iniciativas que identifique y, por lo tanto, hacer crecer su
carrera? Si esto no es posible, empoderarse para buscar mejores oportunidades.

Un papel no es lo que esperabas


Cuando empiezas un papel y descubres que no es lo que esperabas, ¿qué haces? Por ejemplo, le
dijeron que su función sería la estadística y el aprendizaje automático, pero se encuentra haciendo
un trabajo similar al de TI, ya que la base de datos de la organización simplemente no está lo
suficientemente desarrollada para hacer aprendizaje automático.
Es posible que puedas hacer limonada. Sin duda, puede aceptar que su rol de científico de datos
se convierta en un rol de TI, y tal vez obtenga algunas habilidades de programación y bases de
datos en el proceso. Incluso puede volverse indispensable como experto residente en SQL o gurú
técnico, y puede ser cómodo profesionalmente. A medida que optimiza las operaciones de datos y
los flujos de trabajo de su empresa, está configurando su negocio para estar mejor preparado para
aplicaciones más sofisticadas en el futuro. A medida que sus operaciones funcionan sin problemas,
puede asignar tiempo para aprender y crecer profesionalmente en lo que le interesa.
Por otro lado, si esperaba hacer análisis estadísticos y aprendizaje automático y, en cambio, se
encuentra depurando hojas de cálculo rotas, Microsoft Access y macros de VBA, probablemente se
sentirá decepcionado. En esta situación, al menos conviértase en un defensor del cambio. Empuje
para modernizar las herramientas, abogando por el uso de Python y una plataforma de base de
datos moderna, como MySQL o incluso SQLite. Si puede lograr eso, entonces al menos estará en
una plataforma que permite más innovación y estará mucho más cerca de aplicar los conceptos de
este libro. Esto también beneficiará a la organización, ya que aumentará el soporte y la flexibilidad
de las herramientas, y el talento de Python estará más disponible que las tecnologías anticuadas
como Microsoft Access y VBA.

197
¿QUÉ ES SHADOW IT?
La tecnología de la información en la sombra (TI en la sombra) es un término que describe a los
trabajadores de oficina que crean sistemas fuera de su departamento de TI. Estos sistemas pueden
incluir bases de datos, scripts y procesos, así como software creado por proveedores y empleados
sin la participación del departamento de TI.
Shadow IT solía estar mal visto en las organizaciones, ya que no está regulado y opera fuera del
alcance de control del departamento de TI. Cuando los departamentos de finanzas, marketing y
otros departamentos que no son de TI deciden manipular sus propias operaciones de TI
deshonestas, ciertamente pueden crear costos ocultos para la organización debido a problemas de
ineficiencia y seguridad. Pueden surgir políticas desagradables cuando los departamentos de TI y
los departamentos que no son de TI chocan, acusándose mutuamente de no permanecer en su
carril o simplemente cooptando roles para la seguridad laboral.
Sin embargo, un beneficio del movimiento de la ciencia de datos es que ha hecho que la TI en la
sombra sea más aceptada como una necesidad para la innovación. Las personas que no son de TI
pueden crear prototipos y experimentar con la creación de conjuntos de datos, scripts de Python y
herramientas de regresión. Luego, el departamento de TI puede recoger estas innovaciones y
respaldarlas formalmente a medida que maduran. Esto también permite que el negocio se vuelva
más ágil. Un cambio de regla comercial puede ser una edición rápida de un script de Python o una
base de datos interna, en lugar de presentar un ticket con la mesa de ayuda de TI. Si ese cambio
debe estar sujeto a pruebas rigurosas y trámites burocráticos es ciertamente una compensación de
costos por la capacidad de respuesta.
En general, si se encuentra en una función de TI en la sombra (lo cual es probable), asegúrese de
comprender los riesgos y sea amable con el departamento de TI. Si tiene éxito, puede ser
fortalecedor y gratificante apoyar su negocio de esta manera. Si siente un posible conflicto con su
departamento de TI, sea sincero con su liderazgo y hágaselo saber. Si puede decir con sinceridad
que su trabajo es "creación de prototipos" y "exploración", entonces su liderazgo puede argumentar
que está fuera del ámbito de TI. Sin embargo, nunca se vuelva rebelde sin el apoyo de su liderazgo
y déjelos lidiar con la política interdepartamental.

¿El trabajo de tus sueños no existe?


Si bien siempre puede alejarse de un rol, siempre asegúrese de evaluar qué tan realistas son sus
expectativas también. ¿Son las tecnologías de punta que está persiguiendo quizás demasiado
vanguardistas??
Tomemos como ejemplo el procesamiento del lenguaje natural. Desea crear chatbots utilizando el
aprendizaje profundo. Sin embargo, la cantidad de trabajos reales que hacen esto es escasa, ya
que la mayoría de las empresas no tienen una necesidad práctica de chatbots. ¿Por qué? Los
chatbots simplemente no están allí todavía. Si bien empresas como OpenAI tienen investigaciones
interesantes como GPT-3, eso es principalmente lo que significa: investigaciones interesantes.
GPT-3 al final es un reconocedor de patrones basado en probabilidades que encadena palabras y,
por lo tanto, no tiene sentido común. Hay investigaciones que demuestran esto, incluidas algunas
realizadas por Gary Marcus en la Universidad de Nueva York.
Esto significa que la creación de chatbots con aplicaciones más amplias es un problema abierto y
aún tiene que ser una propuesta de valor para la gran mayoría de las empresas. Si el
procesamiento del lenguaje natural es algo que realmente desea seguir y está encontrando una
desconexión con las oportunidades profesionales, su mejor opción podría ser ingresar al mundo
académico e investigar. Si bien hay empresas como Alphabet que realizan investigaciones de tipo
académico, muchos de esos empleados procedían del mundo académico.
De nuevo, mantén tus expectativas realistas mientras navegas por el mercado laboral. Si sus
expectativas superan lo que el mercado laboral puede ofrecerle, considere seriamente la vía
académica. También debe considerar esta ruta cuando el tipo de trabajo que desea requiere con
frecuencia un doctorado o credenciales académicas específicas, y esto se convierte en una barrera
para hacer el trabajo de sus sueños.

¿Adónde voy ahora?


Ahora que cubrimos el panorama de la ciencia de datos, ¿a dónde vamos desde aquí? ¿Y cuál es
el futuro de la ciencia de datos??
Primero, considere las cargas de tener un título de trabajo de científico de datos. Lleva implícito el
requisito de tener un conocimiento sin límites, principalmente debido a la falta de una definición

198
estandarizada con un alcance restringido. Si aprendimos algo de los últimos 10 años observando el
movimiento de la ciencia de datos, la definición importa. Un científico de datos está evolucionando
para convertirse en un ingeniero de software con competencia en estadísticas, optimización y
aprendizaje automático. Es posible que un científico de datos ya ni siquiera tenga ese título de
científico de datos. Si bien este es un conjunto de requisitos mucho más amplio que cuando el
científico de datos fue declarado el "trabajo más sexy del siglo XXI", se está volviendo necesario
tener estas habilidades.
Otra opción es especializarse en favor de títulos más enfocados, y esto viene ocurriendo cada vez
más durante los últimos años. Los roles como ingeniero de visión por computadora, ingeniero de
datos, analista de datos, investigador, analista de investigación de operaciones y asesor/consultor
están regresando. Cada vez vemos menos roles de científicos de datos, y es probable que esta
tendencia continúe en los próximos 10 años, principalmente debido a la especialización de roles.
Sin duda es una opción para seguir esta tendencia.
Es fundamental tener en cuenta que el mercado laboral ha cambiado drásticamente, y es por eso
que necesita las ventajas competitivas que se enumeran en este capítulo. Mientras que los
científicos de datos eran vistos como unicornios en 2014 con salarios de seis cifras, hoy en día un
trabajo de científico de datos en cualquier empresa puede recibir fácilmente cientos o miles de
aplicaciones y solo ofrece un salario de cinco cifras. Los títulos y bootcamps de ciencia de datos
han creado un enorme auge en la oferta de profesionales de ciencia de datos. Por lo tanto, son
trabajos de aterrizaje competitivos comercializados como científico de datos o ciencia de datos en
general. ¡Es por eso que buscar roles como analista, investigación de operaciones y desarrollador
de software no es necesariamente una mala idea! Vicki Boykis, ingeniera de aprendizaje
automático en Tumblr, probablemente lo dice mejor en su artículo de blog "La ciencia de datos es
diferente ahora" :
Recuerde que el objetivo final.. es vencer a las hordas haciendo títulos de ciencia de datos,
bootcamps y trabajando a través de tutoriales.
Desea poner su pie en la puerta, obtener una posición adyacente a los datos y avanzar hacia el
trabajo de sus sueños, mientras descubre todo lo que pueda sobre la industria de la tecnología en
general.
No te dejes paralizar por el análisis. Escoge un pedazo pequeño de algo y comienza allí. Haz algo
pequeño. Aprende algo pequeño, construye algo pequeño. Dile a otras personas. Recuerde que su
primer trabajo en ciencia de datos probablemente no sea como científico de datos.

Conclusión
Este fue un capítulo diferente del resto de este libro, pero es importante si desea navegar por el
panorama laboral de la ciencia de datos y aplicar de manera efectiva el conocimiento de este libro.
Puede ser desconcertante aprender herramientas estadísticas y aprendizaje automático solo para
descubrir que gran parte del panorama laboral lo llevará a otro trabajo. Cuando esto suceda,
aproveche la oportunidad para seguir aprendiendo y adquiriendo habilidades. Cuando integre su
conocimiento matemático esencial con un dominio de la programación y la ingeniería de software,
su valor se multiplicará por diez solo por tener una comprensión de la brecha de TI y ciencia de
datos.
Recuerde evitar la exageración en favor de soluciones prácticas, y no se deje atrapar tanto por el
ámbito técnico que las fuerzas del mercado lo tomen por sorpresa. Comprender las motivaciones
de gestión y liderazgo, así como las motivaciones de las personas en general. Comprender por qué
funcionan las cosas, no solo cómo funcionan. Sea curioso por qué una técnica o herramienta
resuelve un problema, no solo cómo operan los aspectos técnicos de la misma.
No aprenda porque sí, sino para desarrollar capacidades y emparejar la herramienta correcta con el
problema correcto. Una de las formas más efectivas de aprender es elegir un problema (¡no una
herramienta!) que le parezca interesante. Tirar de ese hilo lleva a otra cosa por la que sentir
curiosidad, y luego a otra, y luego a otra. Tienes un objetivo en mente, así que sigue yendo por las
madrigueras correctas y sabe cuándo sacarte de los demás. Es absolutamente gratificante adoptar
este enfoque, y es sorprendente la cantidad de experiencia que puede obtener en un corto período
de tiempo.

199
Apéndice A. Temas complementarios
Uso de renderizado LaTeX con SymPy
A medida que se sienta más cómodo con la notación matemática, puede ser útil tomar sus
expresiones SymPy y mostrarlas en notación matemática.
La forma más rápida de hacer esto es usar la función latex() en SymPy en su expresión y luego
copiar el resultado a un visor matemático LaTeX.
El ejemplo A-1 es un ejemplo que toma una expresión simple y la convierte en una cadena LaTeX.
Por supuesto, podemos tomar los resultados de derivadas, integrales y otras operaciones de
SymPy y convertirlas también en LaTeX. Pero mantengamos el ejemplo sencillo.
Ejemplo A-1. Usando SymPy para convertir una expresión en LaTeX
from sympy import *
x,y = symbols('x y')
z = x**2 / sqrt(2*y**3 - 1)
print(latex(z))
# prints
# \frac{x^{2}}{\sqrt{2 y^{3} - 1}}

Esta cadena \frac{x^{2}}{\sqrt{2 y^{3} - 1}} tiene formato mathlatex, y hay una variedad de
herramientas y formatos de documentos que se pueden adaptar para admitirlo. Pero para
simplemente renderizar el mathlatex, vaya a un editor de ecuaciones de LaTeX. Aquí hay dos
diferentes que uso en línea:
 Editor de ecuaciones LaTeX de Lagrida
 Editor de ecuaciones CodeCogs
En la Figura A-1 utilizo el editor LaTeX de Lagrida para representar la expresión matemática.

Figura A-1. Usando un editor matemático para ver la salida de SymPy LaTeX

Si desea guardar el paso de copiar/pegar, puede agregar LaTeX directamente como un argumento
a la URL del editor CodeCogs LaTeX como se muestra en el Ejemplo A-2, y mostrará la ecuación
matemática renderizada en su navegador.
Ejemplo A-2. Abra una representación de Mathlatex usando CodeCogs

200
import webbrowser
from sympy import *
x,y = symbols('x y')
z = x**2 / sqrt(2*y**3 - 1)
webbrowser.open("https://latex.codecogs.com/png.image?\dpi{200}" + latex(z))

Si usa Jupyter, también puede usar complementos para renderizar mathlatex.

Distribución binomial desde cero


Si quieres implementar una distribución binomial desde cero, aquí están todas las piezas que
necesita en el Ejemplo A-3.
Ejemplo A-3. Construyendo una distribución binomial desde cero
# Factorials multiply consecutive descending integers down to 1
# EXAMPLE: 5! = 5 * 4 * 3 * 2 * 1
def factorial(n: int):
f=1
for i in range(n):
f *= (i + 1)
return f
# Generates the coefficient needed for the binomial distribution
def binomial_coefficient(n: int, k: int):
return factorial(n) / (factorial(k) * factorial(n - k))
# Binomial distribution calculates the probability of k events out of n trials
# given the p probability of k occurring
def binomial_distribution(k: int, n: int, p: float):
return binomial_coefficient(n, k) * (p ** k) * (1.0 - p) ** (n - k)
# 10 trials where each has 90% success probability
n = 10
p = 0.9
for k in range(n + 1):
probability = binomial_distribution(k, n, p)
print("{0} - {1}".format(k, probability))

Usando factorial() y binomial_coficient(), podemos construir una función de distribución binomial


desde cero. La función factorial multiplica un rango consecutivo de enteros de 1 a n. Por ejemplo,
un factorial de 5! sería 1 * 2 * 3 * 4 * 5 = 120.
La función de coeficiente binomial nos permite seleccionar k resultados de n posibilidades sin tener
en cuenta el orden. Si tiene k = 2 y n = 3, eso produciría los conjuntos (1,2) y (1,2,3),
respectivamente. Entre esos dos conjuntos, las posibles combinaciones distintas serían (1,3), (1,2)
y (2,3). Son tres combinaciones, por lo que sería un coeficiente binomial de 3. Por supuesto,
usando la función binomial_coficient() podemos evitar todo ese trabajo de permutación usando
factoriales y multiplicaciones en su lugar.

Al implementar binomial_distribution(), observe cómo tomamos el coeficiente binomial y lo


multiplicamos por la probabilidad de éxito p que ocurre k veces (de ahí el exponente). Luego lo
multiplicamos por el caso opuesto: la probabilidad de falla 1.0 – p que ocurre n – k veces. Esto nos
permite tener en cuenta la probabilidad p de que ocurra un evento frente a que no ocurra en varios
ensayos.

Distribución beta desde cero


Si tiene curiosidad sobre cómo construir una distribución beta desde cero, deberá reutilizar la
función factorial() que usamos para la distribución binomial, así como la función approach_integral()
que construimos en el Capítulo 2.

201
Tal como lo hicimos en el Capítulo 1, empaquetamos rectángulos debajo de la curva para el rango
que nos interesa, como se muestra en la Figura A-2.

Figura A-2. Rectángulos de empaque debajo de la curva para encontrar el área/probabilidad

Esto está usando solo seis rectángulos; obtendremos una mayor precisión si usáramos más
rectángulos. Implementemos beta_distribution() desde cero e integremos 1,000 rectángulos entre
0.9 y 1.0 como se muestra en el Ejemplo A-4.
Ejemplo A-4. Distribución beta desde cero
# Factorials multiply consecutive descending integers down to 1
# EXAMPLE: 5! = 5 * 4 * 3 * 2 * 1
def factorial(n: int):
f=1
for i in range(n):
f *= (i + 1)
return f

def approximate_integral(a, b, n, f):


delta_x = (b - a) / n
total_sum = 0
for i in range(1, n + 1):
midpoint = 0.5 * (2 * a + delta_x * (2 * i - 1))
total_sum += f(midpoint)
return total_sum * delta_x

def beta_distribution(x: float, alpha: float, beta: float) -> float:


if x < 0.0 or x > 1.0:
raise ValueError("x must be between 0.0 and 1.0")
numerator = x ** (alpha - 1.0) * (1.0 - x) ** (beta - 1.0)
denominator = (1.0 * factorial(alpha - 1) * factorial(beta - 1)) / \
(1.0 * factorial(alpha + beta - 1))
return numerator / denominator

greater_than_90 = approximate_integral(a=.90, b=1.0, n=1000,


f=lambda x: beta_distribution(x, 8, 2))
less_than_90 = 1.0 - greater_than_90
print("GREATER THAN 90%: {}, LESS THAN 90%: {}".format(greater_than_90,less_than_90))

202
Notará que con la función beta_distribution(), proporcionamos una probabilidad x dada, un valor alfa
que cuantifica los éxitos y un valor beta que cuantifica los fracasos. La función devolverá la
probabilidad de que observemos una probabilidad x dada. Pero nuevamente, para obtener una
probabilidad de observar la probabilidad x, necesitamos encontrar un área dentro de un rango de
valores x.
Afortunadamente, tenemos nuestra función approach_integral() definida y lista para funcionar
desde el Capítulo 2. Podemos calcular la probabilidad de que la tasa de éxito sea superior al 90 %
y también inferior al 90 %, como se muestra en las últimas líneas.

Derivación del teorema de Bayes


Si quiere entender por qué funciona el Teorema de Bayes en lugar de creer en mi palabra,
hagamos un experimento mental. Digamos que tengo una población de 100.000 personas.
Multiplíquelo con nuestras probabilidades dadas para obtener el conteo de personas que beben
café y el conteo de personas que tienen cáncer.:
N = 100,000
P(Coffee Drinker) = .65
P(Cancer) = .005
Coffee Drinkers = 65,000
Cancer Patients = 500

Tenemos 65.000 bebedores de café y 500 pacientes con cáncer. Ahora bien, de esos 500
pacientes con cáncer, ¿cuántos son bebedores de café? Nos proporcionaron una probabilidad
condicional P(Coffee|Cancer) que podemos multiplicar contra esas 500 personas, lo que
debería darnos 425 pacientes con cáncer que beben café:
P(Coffee Drinker|Cancer) = .85
Coffee Drinkers with Cancer = 500 × .85 = 425
Ahora bien, ¿cuál es el porcentaje de bebedores de café que tienen cáncer? ¿Qué dos números
dividimos? Ya tenemos el número de personas que toman café y tienen cáncer. Por lo tanto,
proporcionamos eso contra el número total de bebedores de café:

Espera un minuto, ¿acabamos de cambiar nuestra probabilidad condicional? ¡Si lo hicimos!


Comenzamos con P(Coffee Drinker|Cancer) y terminamos con P(Cancer|Coffee Drinker).
Al tomar dos subconjuntos de la población (65 000 bebedores de café y 500 pacientes con cáncer)
y luego aplicar una probabilidad conjunta usando la probabilidad condicional que teníamos,
terminamos con 425 personas en nuestra población que beben café y tienen cáncer. Luego lo
dividimos por el número de bebedores de café para obtener la probabilidad de cáncer dado que
uno es bebedor de café.
Pero, ¿dónde está el teorema de Bayes en esto? Centrémonos en la expresión P(Cancer|Coffee
Drinker) y ampliémosla con todas las expresiones que calculamos previamente:

Observe que la población N de 100 000 existe tanto en el numerador como en el denominador,
por lo que se cancela. ¿Esto te parece familiar ahora?

203
Efectivamente, ¡esto debería coincidir con el Teorema de Bayes!

Entonces, si se confunde con el teorema de Bayes o tiene problemas con la intuición que lo
respalda, intente tomar subconjuntos de una población fija en función de las probabilidades
proporcionadas. Luego puede rastrear su camino para voltear una probabilidad condicional.

CDF y CDF inversa desde cero


Para calcular áreas para la distribución normal, por supuesto que podemos usar el método de
empaquetamiento de rectángulos que aprendimos en el Capítulo 1 y que aplicamos a la distribución
beta anteriormente en el apéndice. No requiere la función de densidad acumulativa (CDF
cumulative density function), sino simplemente rectángulos empaquetados bajo la función de
densidad de probabilidad (PDF probability density function). Usando este método, podemos
encontrar la probabilidad de que un golden retriever pese entre 61 y 62 libras como se muestra en
el Ejemplo A-5, usando 1,000 rectángulos empaquetados contra el PDF normal.
Ejemplo A-5. La función de distribución normal en Python
import math
def normal_pdf(x: float, mean: float, std_dev: float) -> float:
return (1.0 / (2.0 * math.pi * std_dev ** 2) ** 0.5) *math.exp(-1.0 * ((x - mean) ** 2 / (2.0 * std_dev ** 2)))

def approximate_integral(a, b, n, f):


delta_x = (b - a) / n
total_sum = 0
for i in range(1, n + 1):
midpoint = 0.5 * (2 * a + delta_x * (2 * i - 1))
total_sum += f(midpoint)
return total_sum * delta_x
p_between_61_and_62 = approximate_integral(a=61, b=62, n=7,
f= lambda x: normal_pdf(x,64.43,2.99))
print(p_between_61_and_62) # 0.0825344984983386
Eso nos dará una probabilidad del 8,25 % de que un golden retriever pese entre 61 y 62 libras. Si
quisiéramos aprovechar un CDF que ya está integrado para nosotros y no requiere ningún
empaque rectangular, podemos declararlo desde cero como se muestra en el Ejemplo A-6.
Ejemplo A-6. Usando el CDF inverso (llamado ppf() ) en Python
import math
def normal_cdf(x: float, mean: float, std_dev: float) -> float:
return (1 + math.erf((x - mean) / math.sqrt(2) / std_dev)) / 2
mean = 64.43
std_dev = 2.99
x = normal_cdf(66, mean, std_dev) - normal_cdf(62, mean, std_dev)
print(x) # prints 0.49204501470628936

El math.erf() se conoce como la función de error y se usa a menudo para calcular distribuciones
acumulativas. Finalmente, para hacer el CDF inverso desde cero, necesitará usar el inverso de la
función erf() llamada erfinv(). El ejemplo A-7 calcula mil pesos de golden retriever generados
aleatoriamente usando un CDF inverso codificado desde cero.

Ejemplo A-7. Generando pesos aleatorios de golden retriever


import random
from scipy.special import erfinv
def inv_normal_cdf(p: float, mean: float, std_dev: float):
return mean + (std_dev * (2.0 ** 0.5) * erfinv((2.0 * p) - 1.0))

204
mean = 64.43
std_dev = 2.99
for i in range(0,1000):
random_p = random.uniform(0.0, 1.0)
print(inv_normal_cdf(random_p, mean, std_dev))

Use e para predecir la probabilidad de eventos a lo largo del tiempo


Veamos un caso de uso más para e que podría resultarle útil. Digamos que usted es un fabricante
de tanques de propano. Obviamente, no desea que el tanque tenga fugas o que eso pueda crear
peligros, particularmente alrededor de llamas abiertas y chispas. Al probar un nuevo diseño de
tanque, su ingeniero informa que hay un 5% de probabilidad en un año determinado de que tenga
fugas.
Usted sabe que este ya es un número inaceptablemente alto, pero desea saber cómo se agrava
esta probabilidad con el tiempo. Ahora se pregunta: “¿Cuál es la probabilidad de que ocurra una
fuga dentro de 2 años? ¿5 años? ¿10 años?" Cuanto más tiempo esté expuesto, ¿no aumentaría la
probabilidad de ver la fuga del tanque? ¡El número de Euler puede venir al rescate de nuevo!
Pleak = 1.0 - e-λT
Esta función modela la probabilidad de un evento a lo largo del tiempo, o en este caso, la fuga del
tanque después del tiempo T. e nuevamente es el número de Euler, lambda λ es la tasa de
fallas en cada unidad de tiempo (cada año) y T es la cantidad de tiempo transcurrido (número de
años).
Si graficamos esta función donde T es nuestro eje x, la probabilidad de una fuga es nuestro eje y, y
λ =.05, la Figura A-3 muestra lo que obtenemos.

Figura A-3. Predecir la probabilidad de una fuga a lo largo del tiempo

Así es como modelamos esta función en Python para λ =. 05 y T = 5 años en el Ejemplo A-


8.
Ejemplo A-8. Código para predecir la probabilidad de una fuga en el tiempo
from math import exp
# Probability of leak in one year
p_leak = .05
# number of years
t=5
# Probability of leak within five years
# 0.22119921692859512
p_leak_5_years = 1.0 - exp(-p_leak * t)
print("PROBABILITY OF LEAK WITHIN 5 YEARS: {}".format(p_leak_5_years))

La probabilidad de falla del tanque después de 2 años es de aproximadamente 9,5 %, 5 años es de


aproximadamente 22,1 % y 10 años es de 39,3 %. Cuanto más tiempo pase, más probable es que
el tanque tenga fugas. Podemos generalizar esta fórmula para predecir cualquier evento con una

205
probabilidad en un período determinado y ver cómo esa probabilidad cambia en diferentes períodos
de tiempo.
Escalada de colinas y regresión lineal
Si encuentra que el cálculo es abrumador al construir el aprendizaje automático desde cero, puede
probar un método más de fuerza bruta. Probemos un algoritmo de escalada de colinas, donde
ajustamos aleatoriamente m y b agregando valores aleatorios para varias iteraciones. Estos valores
aleatorios serán positivos o negativos (lo que hará que la operación de suma sea efectivamente
resta), y solo nos quedaremos con los ajustes que mejoren nuestra suma de cuadrados.
Pero, ¿generamos cualquier número aleatorio como ajuste? Querremos preferir movimientos más
pequeños, pero ocasionalmente podemos permitir movimientos más grandes. De esta manera, en
su mayoría tenemos ajustes finos, pero ocasionalmente haremos grandes saltos si es necesario. La
mejor herramienta para hacer esto es una distribución normal estándar, con una media de 0 y una
desviación estándar de 1. Recuerde del Capítulo 3 que una distribución normal estándar tendrá una
alta densidad de valores cerca de 0, y cuanto más lejos esté el valor desde 0 (tanto en dirección
negativa como positiva), es menos probable que el valor se vuelva como se muestra en la Figura A-
4.

Figura A-4. La mayoría de los valores en una distribución normal estándar son pequeños y
cercanos a 0, mientras que los valores más grandes son menos frecuentes en las colas.

Volviendo a la regresión lineal, comenzaremos m y b en 0 o en algunos otros valores iniciales.


Luego, durante 150 000 iteraciones en un bucle for, ajustaremos aleatoriamente m y b agregando
valores muestreados de la distribución normal estándar. Si un ajuste aleatorio mejora/disminuye la
suma de cuadrados, lo mantenemos. Pero si la suma de cuadrados aumenta, deshacemos ese
ajuste aleatorio. Es decir, solo mantenemos los ajustes que mejoran la suma de cuadrados.
Echemos un vistazo al Ejemplo A-9.
Ejemplo A-9. Uso de la escalada de colinas para la regresión lineal
from numpy.random import normal
import pandas as pd
# Import points from CSV
points = [p for p in pd.read_csv("https://bit.ly/2KF29Bd").itertuples()]
# Building the model
m = 0.0
b = 0.0
# The number of iterations to perform
iterations = 150000
# Number of points
n = float(len(points))
# Initialize with a really large loss
# that we know will get replaced
best_loss = 10000000000000.0
for i in range(iterations):
# Randomly adjust "m" and "b"
m_adjust = normal(0,1)

206
b_adjust = normal(0,1)
m += m_adjust
b += b_adjust
# Calculate loss, which is total sum squared error
new_loss = 0.0
for p in points:
new_loss += (p.y - (m * p.x + b)) ** 2
# If loss has improved, keep new values. Otherwise revert.
if new_loss < best_loss:
print("y = {0}x + {1}".format(m, b))
best_loss = new_loss
else:
m -= m_adjust
b -= b_adjust
print("y = {0}x + {1}".format(m, b))
Verá el progreso del algoritmo, pero finalmente debería obtener una función ajustada de
aproximadamente y = 1.9395722046562853x + 4.731834051245578, más o menos. Validemos
esta respuesta. Cuando usé Excel o Desmos para realizar una regresión lineal, Desmos me dio y =
1.93939x + 4.73333. ¡Nada mal! ¡Me acerqué bastante!
¿Por qué necesitábamos un millón de iteraciones? A través de la experimentación, encontré esto
con suficientes iteraciones donde la solución ya no mejoraba mucho y convergía de cerca a los
valores óptimos para m y b para minimizar la suma de cuadrados. Encontrará que muchas
bibliotecas y algoritmos de aprendizaje automático tienen un parámetro para la cantidad de
iteraciones a realizar, y hace exactamente eso. Debe tener suficiente para que converja en la
respuesta correcta aproximadamente, pero no tanto como para que pierda tiempo de cálculo
cuando ya ha encontrado una solución aceptable.
Otra pregunta que puede tener es por qué comencé best_loss en un número extremadamente alto.
Hice esto para inicializar la mejor pérdida con un valor que sé que se sobrescribirá una vez que
comience la búsqueda, y luego se comparará con la nueva pérdida de cada iteración para ver si
resulta en una mejora. También podría haber usado un flotador infinito positivo ('inf') en lugar de un
número muy grande.

Escalada de colinas y regresión logística


Al igual que en el ejemplo anterior con la regresión lineal, también podemos aplicar la escalada de
colinas a la regresión logística. Nuevamente, use esta técnica si encuentra que el cálculo y las
derivadas parciales son demasiado a la vez.
La metodología de escalada es idéntica: ajuste m y b con valores aleatorios de una distribución
normal. Sin embargo, tenemos una función objetivo diferente, la estimación de máxima
verosimilitud, como se analiza en el Capítulo 6. Por lo tanto, solo tomamos ajustes aleatorios que
aumentan la estimación de probabilidad y, después de suficientes iteraciones, deberíamos
converger en una regresión logística ajustada.
Todo esto se demuestra en el Ejemplo A-10.
Ejemplo A-10. Uso de la escalada para una regresión logística simple
import math
import random
import numpy as np
import pandas as pd
# Desmos graph: https://www.desmos.com/calculator/6cb10atg3l
points = [p for p in pd.read_csv("https://tinyurl.com/y2cocoo7").itertuples()]
best_likelihood = -10_000_000
b0 = .01
b1 = .01
# calculate maximum likelihood
def predict_probability(x):
p = 1.0 / (1.0001 + math.exp(-(b0 + b1 * x)))

207
return p

for i in range(1_000_000):
# Select b0 or b1 randomly, and adjust it randomly
random_b = random.choice(range(2))
random_adjust = np.random.normal()
if random_b == 0:
b0 += random_adjust
elif random_b == 1:
b1 += random_adjust
# Calculate total likelihood
true_estimates = sum(math.log(predict_probability(p.x)) \
for p in points if p.y == 1.0)
false_estimates = sum(math.log(1.0 - predict_probability(p.x)) \
for p in points if p.y == 0.0)
total_likelihood = true_estimates + false_estimates
# If likelihood improves, keep the random adjustment. Otherwise revert.
if best_likelihood < total_likelihood:
best_likelihood = total_likelihood
elif random_b == 0:
b0 -= random_adjust
elif random_b == 1:
b1 -= random_adjust
print("1.0 / (1 + exp(-({0} + {1}*x))".format(b0, b1))
print("BEST LIKELIHOOD: {0}".format(math.exp(best_likelihood)))

Consulte el Capítulo 6 para obtener más detalles sobre la estimación de máxima verosimilitud, la
función logística y la razón por la que usamos la función log().

Una breve introducción a la programación lineal


Una técnica que toda ciencia de datosEl profesional debe estar familiarizado con la programación
lineal, que resuelve un sistema de desigualdades adaptando sistemas de ecuaciones con "variables
flojas". Cuando tiene variables que son números enteros discretos o binarios (0 o 1) en un sistema
de programación lineal, se conoce como programación entera. Cuando se utilizan variables
continuas lineales y enteras, se conoce como programación entera mixta.
Si bien se basa mucho más en algoritmos que en datos, la programación lineal y sus variantes se
pueden usar para resolver una amplia gama de problemas clásicos de IA. Si suena dudoso calificar
los sistemas de programación lineal como IA, es una práctica común de muchos proveedores y
empresas, ya que aumenta el valor percibido.
En la práctica, es mejor usar las muchas bibliotecas de solucionador disponibles para hacer la
programación lineal por usted, pero al final de esta sección se proporcionarán recursos sobre cómo
hacerlo desde cero. Para estos ejemplos usaremos PuLP, aunque Pyomo también es una opción.
También utilizaremos la intuición gráfica, aunque los problemas con más de tres dimensiones no se
pueden visualizar fácilmente.
Aquí está nuestro ejemplo. Tienes dos líneas de productos: el iPac y el iPac Ultra. El iPac obtiene
una ganancia de $200 mientras que el iPac Ultra obtiene una ganancia de $300.
Sin embargo, la línea de ensamblaje puede funcionar solo 20 horas, y se necesita 1 hora para
producir el iPac y 3 horas para producir un iPac Ultra.
Solo se pueden proporcionar 45 kits en un día, y un iPac requiere 6 kits, mientras que iPac Ultra
requiere 2 kits.
Suponiendo que se venderá todo el suministro, ¿cuántos iPac e iPac Ultra deberíamos vender para
maximizar las ganancias?

Notemos primero esa primera restricción y desglosémosla:


…la línea de ensamblaje puede funcionar durante solo 20 horas, y se necesitan 1 hora para
producir el iPac y 3 horas para producir un iPac Ultra.

208
Podemos expresar eso como una desigualdad donde x es el número de unidades iPac e y es el
número de unidades iPac Ultra. Ambos deben ser positivos y la Figura A-5 muestra que podemos
graficar en consecuencia.
x + 3y ≤ 20(x ≥ 0, y ≥ 0)

Figura A-5. Graficando la primera restricción

Ahora veamos la segunda restricción:


Solo se pueden proporcionar 45 kits en un día, y un iPac requiere 6 kits, mientras que iPac Ultra
requiere 2 kits.
También podemos modelar y graficar en la Figura A-6 en consecuencia.
6x + 2y ≤ 45(x ≥ 0, y ≥ 0)

Figura A-6. Graficando la segunda restricción

Observe en la Figura A-6 que ahora tenemos una superposición entre estas dos restricciones.
Nuestra solución está en algún lugar de esa superposición y la llamaremos región factible.
Finalmente, estamos maximizando nuestra ganancia Z, que se expresa a continuación, dadas las
cantidades de ganancias para el iPac y el iPac Ultra, respectivamente.
Z = 200x + 300y

209
Si expresamos esta función como una línea, podemos aumentar Z tanto como sea posible hasta
que la línea ya no esté en la región factible. Luego anotamos los valores x e y como se visualizan
en la Figura A-7.
GRÁFICO DE DESMOS DE LA FUNCIÓN OBJETIVO
Si necesita ver esto visualizado de una manera más interactiva y animada, consulte este gráfico en
Desmos.

Figura A-7. Aumentar nuestra línea objetivo hasta que ya no esté en la región factible

Cuando esa línea "apenas toca" la región factible a medida que aumenta la ganancia Z tanto como
sea posible, aterrizará en un vértice, o esquina, de la región factible. Ese vértice proporciona los
valores de x e y que maximizarán la ganancia, como se muestra en la Figura A-8.
Si bien podríamos usar NumPy y un montón de operaciones matriciales para resolver esto
numéricamente, será más fácil usar PuLP como se muestra en el Ejemplo A-11. Tenga en cuenta
que LpVariable define las variables para resolver. LpProblem es el sistema de programación lineal
que agrega restricciones y funciones objetivo utilizando operadores de Python. Luego, las variables
se resuelven llamando a solve() en LpProblem.

Figura A-8. Objetivo maximizado para nuestro sistema de programación lineal

Ejemplo A-11. Usando Python PuLP para resolver un sistema de programación lineal
# GRAPH" https://www.desmos.com/calculator/iildqi2vt7
from pulp import *
# declare your variables
x = LpVariable("x", 0) # 0<=x

210
y = LpVariable("y", 0) # 0<=y
# defines the problem
prob = LpProblem("factory_problem", LpMaximize)
# defines the constraints
prob += x + 3*y <= 20
prob += 6*x +2*y <= 45
# defines the objective function to maximize
prob += 200*x + 300*y
# solve the problem
status = prob.solve()
print(LpStatus[status])
# print the results x = 5.9375, y = 4.6875
print(value(x))
print(value(y))

Quizás se pregunte si tiene sentido construir 5.9375 y 4.6875 unidades. Los sistemas de
programación lineal son mucho más eficientes si puede tolerar valores continuos en sus variables,
y quizás pueda simplemente redondearlos después. Pero ciertos tipos de problemas requieren
absolutamente que los números enteros y las variables binarias se manejen discretamente.
Para forzar que las variables x e y se traten como números enteros, proporcione un argumento de
categoría cat=LpInteger como se muestra en el Ejemplo A-12.
Ejemplo A-12. Obligar a que las variables se resuelvan como números enteros
# declare your variables
x = LpVariable("x", 0, cat=LpInteger) # 0<=x
y = LpVariable("y", 0, cat=LpInteger) # 0<=y

Gráficamente, esto significa que llenamos nuestra región factible con puntos discretos en lugar de
una región continua. Nuestra solución no aterrizará necesariamente en un vértice, sino en el punto
más cercano al vértice, como se muestra en la Figura A-9.
Hay un par de casos especiales en la programación lineal, como se muestra en la Figura A-10. A
veces puede haber muchas soluciones. A veces, puede que no haya ninguna solución en absoluto.
Este es solo un ejemplo de introducción rápida a la programación lineal y, lamentablemente, no hay
suficiente espacio en este libro para hacer justicia al tema. Se puede usar para problemas
sorprendentes, incluida la programación de recursos limitados (como trabajadores, trabajos de
servidor o salas), la resolución de Sudokus y la optimización de carteras financieras.

211
Figura A-9. Un sistema de programación lineal discreta

Figura A-10. Casos especiales de programación lineal

Si quieres saber más, hay algunos buenos videos de YouTube, incluidos PatrickJMT y Josh
Emmanuel. Si desea profundizar en la optimización discreta, el profesor Pascal Van Hentenryck ha
hecho un tremendo servicio organizando un curso en Coursera.

Clasificador MNIST usando scikit-learn


El ejemplo A-13 muestra cómo usar la red neuronal de scikit-learn para la clasificación de dígitos
escritos a mano.
Ejemplo A-13. Una red neuronal clasificadora de dígitos manuscrita en scikit-learn
import numpy as np
import pandas as pd

212
# load data
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
df = pd.read_csv('https://bit.ly/3ilJc2C', compression='zip', delimiter=",")
# Extract input variables (all rows, all columns but last column)
# Note we should do some linear scaling here
X = (df.values[:, :-1] / 255.0)
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Get a count of each group to ensure samples are equitably balanced
print(df.groupby(["class"]).agg({"class" : [np.size]}))
# Separate training and testing data
# Note that I use the 'stratify' parameter to ensure
# each class is proportionally represented in both sets
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
test_size=.33, random_state=10, stratify=Y)
nn = MLPClassifier(solver='sgd',
hidden_layer_sizes=(100, ),
activation='logistic',
max_iter=480,
learning_rate_init=.1)
nn.fit(X_train, Y_train)
print("Training set score: %f" % nn.score(X_train, Y_train))
print("Test set score: %f" % nn.score(X_test, Y_test))
# Display heat map
import matplotlib.pyplot as plt
fig, axes = plt.subplots(4, 4)
# use global min / max to ensure all weights are shown on the same scale
vmin, vmax = nn.coefs_[0].min(), nn.coefs_[0].max()
for coef, ax in zip(nn.coefs_[0].T, axes.ravel()):
ax.matshow(coef.reshape(28, 28), cmap=plt.cm.gray, vmin=.5 * vmin, vmax=.5 * vmax)
ax.set_xticks(())
ax.set_yticks(())
plt.show()

Apéndice B. Respuestas a los ejercicios

Capítulo 1
1. 62,6738 es racional porque tiene un número finito de decimales y, por lo tanto, se puede
expresar como una fracción 626738 / 10000.
2. 10710-5 = 107+-5 = 102 = 100

3.

4.
5. El monto resultante sería de $1,161.47. El script de Python es el siguiente:
from math import exp
p = 1000
r = .05
t=3
n = 12
a = p * (1 + (r/n))**(n * t)
print(a) # prints 1161.4722313334678
6. El monto resultante sería $1161.83. El script de Python es el siguiente:

213
from math import exp
p = 1000 # principal, starting amount
r = .05 # interest rate, by year
t = 3.0 # time, number of years
a = p * exp(r*t)
print(a) # prints 1161.834242728283

7. La derivada calcula 6 x, lo que haría que la pendiente en x = 3 fuera 18. El código SymPy
es el siguiente:
from sympy import *
# Declare 'x' to SymPy
x = symbols('x')
# Now just use Python syntax to declare function
f = 3*x**2 + 1
# Calculate the derivative of the function
dx_f = diff(f)
print(dx_f) # prints 6*x
print(dx_f.subs(x,3)) # 18
8. El área bajo la curva entre 0 y 2 es 10. El código SymPy es el siguiente:
from sympy import *
# Declare 'x' to SymPy
x = symbols('x')
# Now just use Python syntax to declare function
f = 3*x**2 + 1
# Calculate the integral of the function with respect to x
# for the area between x = 0 and 2
area = integrate(f, (x, 0, 2))
print(area) # prints 10

Capitulo 2
1. 0,3 × 0,4 = 0,12; consulte "Probabilidades conjuntas".
2. (1 – 0,3) + 0,4 – (0,03 × 0,4) = 0,98; consulte las "Probabilidades de unión" y recuerde
que estamos buscando SIN LLUVIA, así que reste esa probabilidad de 1.0.
3. 0,3 × 0,2 = 0,06; consulte “Probabilidad condicional y teorema de Bayes”.
4. El siguiente código de Python calcula una respuesta de 0,822, sumando las
probabilidades de que 50 o más pasajeros no se presenten:
from scipy.stats import binom
n = 137
p = .40
p_50_or_more_noshows = 0.0
for x in range(50,138):
p_50_or_more_noshows += binom.pmf(x, n, p)
print(p_50_or_more_noshows) # 0.822095588147425
5. Usando la distribución beta que se muestra en el siguiente código SciPy, obtenga el área
hasta 0.5 y réstelo de 1.0. El resultado es de aproximadamente 0,98, por lo que es muy
poco probable que esta moneda sea justa.
from scipy.stats import beta
heads = 8
tails = 2
p = 1.0 - beta.cdf(.5, heads, tails)
print(p) # 0.98046875

Capítulo 3
1. La media es 1,752 y la desviación estándar es aproximadamente 0,02135. El código de
Python es el siguiente:

214
from math import sqrt
sample = [1.78, 1.75, 1.72, 1.74, 1.77]

def mean(values):
return sum(values) /len(values)

def variance_sample(values):
mean = sum(values) / len(values)
var = sum((v - mean) ** 2 for v in values) / len(values)
return var

def std_dev_sample(values):
return sqrt(variance_sample(values))
mean = mean(sample)
std_dev = std_dev_sample(sample)
print("MEAN: ", mean) # 1.752
print("STD DEV: ", std_dev) # 0.02135415650406264
2. Use the CDF to get the value between 30 and 20 months, which
is an area of about 0.06. The Python code is as follows:
from scipy.stats import norm
mean = 42
std_dev = 8
x = norm.cdf(30, mean, std_dev) - norm.cdf(20, mean, std_dev)
print(x) # 0.06382743803380352
3. Hay un 99 % de probabilidad de que el diámetro medio del filamento de un rollo esté entre
1,7026 y 1,7285. El código de Python es el siguiente:
from math import sqrt
from scipy.stats import norm
def critical_z_value(p, mean=0.0, std=1.0):
norm_dist = norm(loc=mean, scale=std)
left_area = (1.0 - p) / 2.0
right_area = 1.0 - ((1.0 - p) / 2.0)
return norm_dist.ppf(left_area), norm_dist.ppf(right_area)
def ci_large_sample(p, sample_mean, sample_std, n):
# Sample size must be greater than 30
lower, upper = critical_z_value(p)
lower_ci = lower * (sample_std / sqrt(n))
upper_ci = upper * (sample_std / sqrt(n))
return sample_mean + lower_ci, sample_mean + upper_ci
print(ci_large_sample(p=.99, sample_mean=1.715588,
sample_std=0.029252, n=34))
# (1.7026658973748656, 1.7285101026251342)

4. La campaña de marketing funcionó con un valor p de 0,01888. El código de Python es el


siguiente:
from scipy.stats import norm
mean = 10345
std_dev = 552
p1 = 1.0 - norm.cdf(11641, mean, std_dev)
# Take advantage of symmetry
p2 = p1
# P-value of both tails
# I could have also just multiplied by 2
p_value = p1 + p2
print("Two-tailed P-value", p_value)

215
if p_value <= .05:
print("Passes two-tailed test")
else:
print("Fails two-tailed test")
# Two-tailed P-value 0.01888333596496139
# Passes two-tailed test

Capítulo 4
1. El vector aterriza en [2, 3]. El código de Python es el siguiente:
from numpy import array
v = array([1,2])
i_hat = array([2, 0])
j_hat = array([0, 1.5])
# fix this line
basis = array([i_hat, j_hat])
# transform vector v into w
w = basis.dot(v)
print(w) # [2. 3.]

2. El vector aterriza en [0, -3]. El código de Python es el siguiente:


from numpy import array
v = array([1,2])
i_hat = array([-2, 1])
j_hat = array([1, -2])
# fix this line
basis = array([i_hat, j_hat])
# transform vector v into w
w = basis.dot(v)
print(w) # [ 0, -3]

3. El determinante es 2.0. El código de Python es el siguiente:


import numpy as np
from numpy.linalg import det
i_hat = np.array([1, 0])
j_hat = np.array([2, 2])
basis = np.array([i_hat,j_hat]).transpose()
determinant = det(basis)
print(determinant) # 2.0

4. Sí, porque la multiplicación de matrices nos permite combinar varias matrices en una sola
matriz que representa una transformación consolidada.
5. x = 19,8, y = –5,4, z = –6. El código es el siguiente:
from numpy import array
from numpy.linalg import inv
A = array([
[3, 1, 0],
[2, 4, 1],
[3, 1, 8]
])
B = array([
54,
12,
6
])
X = inv(A).dot(B)
print(X) # [19.8 -5.4 -6. ]

216
6. Sí, es linealmente dependiente. Aunque tenemos cierta imprecisión de punto flotante con
NumPy, el determinante es efectivamente 0:
from numpy.linalg import det
from numpy import array
i_hat = array([2, 6])
j_hat = array([1, 3])
basis = array([i_hat, j_hat]).transpose()
print(basis)
determinant = det(basis)
print(determinant) # -3.330669073875464e-16

Para sortear los problemas de punto flotante, use SymPy y obtendrá 0:


from sympy import *
basis = Matrix([
[2,1],
[6,3]
])
determinant = det(basis)
print(determinant) # 0

Capítulo 5
1. Hay muchas herramientas y enfoques para realizar una regresión lineal como aprendimos
en el Capítulo 5, pero aquí está la solución usando scikit-learn. La pendiente es 1.75919315 y
la intersección es 4.69359655.
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.linear_model import LinearRegression
# Import points
df = pd.read_csv('https://bit.ly/3C8JzrM', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Fit a line to the points
fit = LinearRegression().fit(X, Y)
# m = 1.75919315, b = 4.69359655
m = fit.coef_.flatten()
b = fit.intercept_.flatten()
print("m = {0}".format(m))
print("b = {0}".format(b))
# show in chart
plt.plot(X, Y, 'o') # scatterplot
plt.plot(X, m*X+b) # line
plt.show()

2. Obtenemos una alta correlación de 0.92421 y un valor de prueba de 23.8355 con un rango
estadísticamente significativo de ±1.9844. Esta correlación es definitivamente útil y
estadísticamente significativa. El código es el siguiente:
import pandas as pd
# Read data into Pandas dataframe
df = pd.read_csv('https://bit.ly/3C8JzrM', delimiter=",")
# Print correlations between variables
correlations = df.corr(method='pearson')
print(correlations)
# OUTPUT:
#xy

217
# x 1.00000 0.92421
# y 0.92421 1.00000
# Test for statistical significance
from scipy.stats import t
from math import sqrt
# sample size
n = df.shape[0]
print(n)
lower_cv = t(n - 1).ppf(.025)
upper_cv = t(n - 1).ppf(.975)
# retrieve correlation coefficient
r = correlations["y"]["x"]
# Perform the test
test_value = r / sqrt((1 - r ** 2) / (n - 2))
print("TEST VALUE: {}".format(test_value))
print("CRITICAL RANGE: {}, {}".format(lower_cv, upper_cv))
if test_value < lower_cv or test_value > upper_cv:
print("CORRELATION PROVEN, REJECT H0")
else:
print("CORRELATION NOT PROVEN, FAILED TO REJECT H0 ")
# Calculate p-value
if test_value > 0:
p_value = 1.0 - t(n - 1).cdf(test_value)
else:
p_value = t(n - 1).cdf(test_value)
# Two-tailed, so multiply by 2
p_value = p_value * 2
print("P-VALUE: {}".format(p_value))
"""
TEST VALUE: 23.835515323677328
CRITICAL RANGE: -1.9844674544266925, 1.984467454426692
CORRELATION PROVEN, REJECT H0
P-VALUE: 0.0 (extremely small)
"""
3. En x = 50 , el intervalo de predicción está entre 50,79 y 134,51. El código es el siguiente:
import pandas as pd
from scipy.stats import t
from math import sqrt
# Load the data
points = list(pd.read_csv('https://bit.ly/3C8JzrM', delimiter=",")
\
.itertuples())
n = len(points)
# Linear Regression Line
m = 1.75919315
b = 4.69359655
# Calculate Prediction Interval for x = 50
x_0 = 50
x_mean = sum(p.x for p in points) / len(points)
t_value = t(n - 2).ppf(.975)
standard_error = sqrt(sum((p.y - (m * p.x + b)) ** 2 for p in
points) / \
(n - 2))
margin_of_error = t_value * standard_error * \
sqrt(1 + (1 / n) + (n * (x_0 - x_mean) ** 2) / \
(n * sum(p.x ** 2 for p in points) - \

218
sum(p.x for p in points) ** 2))
predicted_y = m*x_0 + b
# Calculate prediction interval
print(predicted_y - margin_of_error, predicted_y +
margin_of_error)
# 50.792086501055955 134.51442159894404
4. Los conjuntos de datos de prueba funcionan moderadamente bien cuando se dividen en
tercios y se evalúan con k-fold, donde k = 3. Obtendrá una media de aproximadamente 0,83
en MSE y una desviación estándar de 0,03 en los tres conjuntos de datos.
import pandas as pd
from sklearn.linear_model import LinearRegression
from sklearn.model_selection import KFold, cross_val_score
df = pd.read_csv('https://bit.ly/3C8JzrM', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)\
Y = df.values[:, -1]
# Perform a simple linear regression
kfold = KFold(n_splits=3, random_state=7, shuffle=True)
model = LinearRegression()
results = cross_val_score(model, X, Y, cv=kfold)
print(results)
print("MSE: mean=%.3f (stdev-%.3f)" % (results.mean(),
results.std()))
"""
[0.86119665 0.78237719 0.85733887]
MSE: mean=0.834 (stdev-0.036)
"""

Capítulo 6
1. La precisión es extremadamente alta cuando ejecuta esto a través de scikit-learn. Cuando
lo ejecuto, obtengo al menos un 99,9% de precisión en promedio con los pliegues de prueba.
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import KFold, cross_val_score
# Load the data
df = pd.read_csv("https://bit.ly/3imidqa", delimiter=",")
X = df.values[:, :-1]
Y = df.values[:, -1]
kfold = KFold(n_splits=3, shuffle=True)
model = LogisticRegression(penalty='none')
results = cross_val_score(model, X, Y, cv=kfold)
print("Accuracy Mean: %.3f (stdev=%.3f)" % (results.mean(),
results.std()))

2. La matriz de confusión arrojará un número extremadamente alto de trues positivos y trues


negativos, y muy pocos falses positivos y falses negativos. Ejecuta este código y verás:
import pandas as pd
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
# Load the data
df = pd.read_csv("https://bit.ly/3imidqa", delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]

219
# Extract output column (all rows, last column)\
Y = df.values[:, -1]
model = LogisticRegression(solver='liblinear')
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
test_size=.33)
model.fit(X_train, Y_train)
prediction = model.predict(X_test)
"""
The confusion matrix evaluates accuracy within each category.
[[truepositives falsenegatives]
[falsepositives truenegatives]]
The diagonal represents correct predictions,
so we want those to be higher
"""
matrix = confusion_matrix(y_true=Y_test, y_pred=prediction)
print(matrix)
3. A continuación se muestra un caparazón interactivo para probar los colores ingresados por
el usuario. Considere probar negro (0,0,0) y blanco (255,255,255) para ver si las fuentes
oscuras y claras, respectivamente, se predicen correctamente.
import pandas as pd
from sklearn.linear_model import LogisticRegression
import numpy as np
from sklearn.model_selection import train_test_split
# Load the data
df = pd.read_csv("https://bit.ly/3imidqa", delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)
Y = df.values[:, -1]
model = LogisticRegression(solver='liblinear')
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
test_size=.33)
model.fit(X_train, Y_train)
prediction = model.predict(X_test)
# Test a prediction
while True:
n = input("Input a color {red},{green},{blue}: ")
(r, g, b) = n.split(",")
x = model.predict(np.array([[int(r), int(g), int(b)]]))
if model.predict(np.array([[int(r), int(g), int(b)]]))[0] ==0.0:
print("LIGHT")
else:
print("DARK")
5. Sí, la regresión logística es muy efectiva para predecir fuentes claras u oscuras para un color
de fondo determinado. No solo la precisión es extremadamente alta, sino que la matriz de
confusión tiene números altos en la diagonal superior derecha a la inferior izquierda con
números más bajos en las otras celdas.

Capítulo 7
Obviamente, hay mucha experimentación y alquimia que puede probar con diferentes capas
ocultas, funciones de activación, diferentes tamaños de conjuntos de datos de prueba, etc. Traté de
usar una capa oculta con tres nodos con una activación ReLU y luché para obtener buenas
predicciones en mi conjunto de datos de prueba. Las matrices de confusión y la precisión fueron
consistentemente pobres y cualquier cambio de configuración que ejecuté funcionó igual de mal.
Las razones por las que la red neuronal probablemente está fallando son 1) el conjunto de datos de
prueba es demasiado pequeño para una red neuronal (que consume muchos datos) y 2) existen
modelos más simples y efectivos como la regresión logística para este tipo de problema. Eso no
quiere decir que no pueda encontrar una configuración que funcione, pero debe tener cuidado de

220
no piratear su camino hacia un buen resultado que se ajuste demasiado a los pocos datos de
entrenamiento y prueba que tiene.
Aquí está el código scikit-learn que utilicé:
import pandas as pd
# load data
from sklearn.metrics import confusion_matrix
from sklearn.model_selection import train_test_split
from sklearn.neural_network import MLPClassifier
df = pd.read_csv('https://tinyurl.com/y6r7qjrp', delimiter=",")
# Extract input variables (all rows, all columns but last column)
X = df.values[:, :-1]
# Extract output column (all rows, last column)
Y = df.values[:, -1]
# Separate training and testing data
X_train, X_test, Y_train, Y_test = train_test_split(X, Y,
test_size=1/3)
nn = MLPClassifier(solver='sgd',
hidden_layer_sizes=(3, ),
activation='relu',
max_iter=100_000,
learning_rate_init=.05)
nn.fit(X_train, Y_train)
print("Training set score: %f" % nn.score(X_train, Y_train))
print("Test set score: %f" % nn.score(X_test, Y_test))
print("Confusion matrix:")
matrix = confusion_matrix(y_true=Y_test, y_pred=nn.predict(X_test))
print(matrix)

Sobre el Autor
Thomas Nield es el fundador de Nield Consulting Group, así como instructor en O'Reilly
Media y la Universidad del Sur de California. Le gusta hacer que el contenido técnico sea
identificable y relevante para aquellos que no están familiarizados con él o se sienten
intimidados por él. Thomas imparte regularmente clases sobre análisis de datos,
aprendizaje automático, optimización matemática, seguridad del sistema de IA e
inteligencia artificial práctica. Es autor de dos libros, Getting Started with SQL (O'Reilly) y
Learning RxJava (Packt). También es el fundador e inventor de Yawman Flight, una
empresa que desarrolla controles portátiles universales para simulación de vuelo y
vehículos aéreos no tripulados.

Colofón
Los animales de la portada de Essential Math for Data Science son ratones de hierba de
cuatro rayas ( Rhabdomys pumilio ). Estos roedores se encuentran en la mitad sur del
continente africano, en hábitats variados como sabanas, desiertos, tierras de cultivo,
matorrales e incluso ciudades. Como sugiere su nombre común, este animal tiene un
conjunto distintivo de cuatro rayas oscuras que recorren su espalda. Incluso al nacer, estas
rayas son visibles como líneas pigmentadas en la piel sin pelo del cachorro.
La coloración del pelaje del ratón de pasto varía de marrón oscuro a blanco grisáceo, con
lados y vientres más claros. En general, la especie crece entre 18 y 21 centímetros de
largo (sin contar la cola, que es aproximadamente igual a la longitud del cuerpo) y pesa
entre 30 y 55 gramos. El ratón es más activo durante el día y tiene una dieta omnívora de
semillas, plantas e insectos. En los meses de verano, tiende a comer más material vegetal
y de semillas, y mantiene las reservas de grasa para afrontar épocas de escasez de
alimentos.

221
Los ratones de pasto de cuatro rayas son fáciles de observar dada su amplia gama, y se
ha observado que cambian entre estilos de vida solitarios y sociales. Durante la temporada
de reproducción, tienden a permanecer separados (quizás para evitar una competencia
reproductiva excesiva) y las hembras son territoriales en sus madrigueras. Sin embargo,
fuera de eso, los ratones se congregan en grupos para buscar comida, evitar a los
depredadores y acurrucarse para calentarse.
Muchos de los animales de las portadas de O'Reilly están en peligro de extinción; todos
ellos son importantes para el mundo.
La ilustración de la portada es de Karen Montgomery, basada en un grabado antiguo del
Museo de Historia Natural. Las fuentes de la portada son Gilroy Semibold y Guardian
Sans. La fuente del texto es Adobe Minion Pro; la fuente del encabezado es Adobe Myriad
Condensed; y la fuente del código es Ubuntu Mono de Dalton Maag.

222

También podría gustarte