Upload
others
View
2
Download
0
Embed Size (px)
Citation preview
Máster en Big Data Deportivo
Módulo 4. Análisis de Datos Deportivos con R y Python
1
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Índice
1.1. Introducción a Python .......................................................................................... 9
1.2. Características del lenguaje .............................................................................. 10
1.2.1. Librerías ......................................................................................................... 11
2.2.1.1. Librerías de gestión de bases de datos o para la adquisición de
datos .................................................................................................................. 12
2.2.1.2. Librerías más importantes para el análisis de datos ....................... 12
2.2.1.3. Librerías más importantes para la visualización de datos ............. 13
2.2.1.4. Librerías más importantes de aprendizaje automático (Machine
Learning) ........................................................................................................... 14
1.2.2. Entornos de desarrollo ................................................................................ 15
1.2.3. Virtual environments ................................................................................... 16
1.2.4. Jupyter Notebook (Anaconda) ................................................................ 19
1.2.4.1. Componentes y requisitos de Anaconda ....................................... 19
1.2.4.2. Primeros pasos con Anaconda ......................................................... 20
1.3. Sintáxis básica ...................................................................................................... 25
1.3.1. Conceptos generales ................................................................................. 25
1.3.2. Función print() .............................................................................................. 25
1.3.3. Comentarios ................................................................................................ 27
1.3.4. Multi-lineas .................................................................................................... 27
1.3.5. Palabras reservadas .................................................................................... 29
1.3.6. Operaciones ................................................................................................ 29
1.3.7. Operadores de comparación ................................................................... 30
1.3.8. Operadores de pertenencia ..................................................................... 32
2
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.3.9. Asignación de Variables ............................................................................ 32
1.4. Tipos y estructuras de datos ............................................................................... 35
1.4.1. Tipos boolean o bool .................................................................................. 35
1.4.2. Estructuras numéricas int, long, float, complex ....................................... 36
1.4.2.1. int ........................................................................................................... 36
1.4.2.3. float ....................................................................................................... 37
1.4.2.5. Funciones para forzar el tipo de un dato ........................................ 37
1.4.3. Fechas (datetime, date, time) .................................................................. 39
1.4.4. Secuencias (str, list, tuple) .......................................................................... 40
1.4.4.1. str ........................................................................................................... 40
1.4.4.2. tuple ...................................................................................................... 43
1.4.4.3. list ........................................................................................................... 44
1.4.4.4. Acceso a los elementos de una secuencia (str, tuple, list) .. 44
1.4.5. Mapeos (dict) .............................................................................................. 45
1.4.6. Conjuntos (set) ............................................................................................. 47
1.5. Funciones .............................................................................................................. 48
1.5.1. Return múltiple ............................................................................................. 49
1.5.2. Funciones y métodos .................................................................................. 49
1.5.3. Los argumentos de las funciones .............................................................. 50
1.5.4. Paso de parámetros ................................................................................... 51
1.5.5. Funciones como argumentos de otras funciones .................................. 53
1.5.6. Funciones lambda ...................................................................................... 53
1.6. Estructuras e instrucciones de control .............................................................. 55
3
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.6.1. if, elif, else ..................................................................................................... 55
1.6.2. Expresiones ternarias ................................................................................... 56
1.6.3. Bucles for y while ......................................................................................... 57
1.7. Definición por compresión o list comprehension ............................................ 61
1.8. Modulos ................................................................................................................ 63
1.9. Excepciones ......................................................................................................... 64
1.10. Ficheros y Entrada/Salida ................................................................................. 69
1.10.1. Impresión por pantalla - print .................................................................. 69
1.10.2. Introducción de datos por teclado – input() ........................................ 69
1.10.3. Apertura y cierre de Ficheros .................................................................. 71
1.10.2. Lectura y escritura de ficheros ................................................................ 75
1.11. Expresiones regulares ........................................................................................ 79
1.12. Array multidimensionales (numpy) .................................................................. 84
1.12.1. Creación de ndarrays .............................................................................. 85
1.12.2. Tipos de datos para ndarray ................................................................... 87
1.12.3. Elementos de un array. Acceso y recorrido .......................................... 88
1.12.4. Operaciones con arrays, matrices y escalares ..................................... 91
1.12.5. Cambiar la forma de un array ................................................................ 94
1.12.6. Copias y vistas ........................................................................................... 96
1.12.7. Procesamiento de datos con Numpy .................................................... 98
1.12.7.1. Función where ................................................................................... 98
1.12.7.2. Métodos matemáticos y estadísticos ............................................. 99
1.13. Pandas (panel data set) ................................................................................ 101
4
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.1. Creación de un objeto de tipo Serie .................................................... 102
1.13.2. Creación de un DataFrame .................................................................. 103
1.13.3. Acceso a los datos (filas y columnas) .................................................. 107
1.13.4. Borrar filas o columnas ............................................................................ 111
1.13.5. Actualización de los datos ..................................................................... 115
1.13.6. Insertar filas o columnas ......................................................................... 118
1.13.6.1. Añadir a un DataFrame una nueva fila ....................................... 118
1.13.6.2. Añadir a un DataFrame una lista de Series ................................. 120
1.13.6.3. Añadir a un DataFrame otro DataFrame .................................... 121
1.13.6.4. Añadir a un DataFrame una fila usando un índice .................... 122
1.13.6.5. Añadir una columna a un DataFrame ......................................... 123
1.13.7.1. Merge ............................................................................................... 125
1.13.8. Indices jerárquicos .................................................................................. 128
1.13.9. Importar y exportar datos ...................................................................... 130
1.13.10. Aplicación de funciones ...................................................................... 136
1.13.11. Funciones y atributos básicos para manejar un DataFrame: ......... 139
1.14. Ejercicios guiados ............................................................................................ 140
1.14.0. Requisitos .................................................................................................. 140
1.14.0.1. Creación del entorno virtual ......................................................... 140
1.14.0.1. Activar el entorno virtual ................................................................ 142
1.14.0.1. Instalar los paquetes necesarios ................................................... 142
1.14.1. Ejercicio 1: Creación de tu propio dataset ......................................... 146
1.14.1.1. Introducción y Objetivo ................................................................. 146
5
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.1.3. Código comentado ....................................................................... 147
1.14.1.4. Código sin comentarios ................................................................. 153
1.14.2. Ejercicio 2: Limpiar el Dataset ................................................................ 155
1.14.2.1. Introducción .................................................................................... 155
1.14.2.2. Objetivo ............................................................................................ 155
1.14.2.3. Código comentado ....................................................................... 156
1.14.2.4. Código sin comentarios ................................................................. 170
1.15.3. Ejercicio 3: Dibujar un campo de fútbol y jugadores ......................... 177
1.15.3.1. Introducción .................................................................................... 177
1.15.3.2. Objetivo ............................................................................................ 177
1.15.3.3. Código comentado ....................................................................... 177
1.15.3.4. Código sin comentarios ................................................................. 184
1.16.4. Ejercicio 4: Análisis y visualización de datos del nacimiento de
jugadores de fútbol. ........................................................................................... 187
1.16.4.1. Introducción .................................................................................... 187
1.16.4.2. Objetivo ............................................................................................ 187
1.16.4.3. Código Comentado ....................................................................... 187
1.16.4.4. Código sin comentarios ................................................................. 207
1.17.1. Ejercicio 5: Captura de tweets .............................................................. 213
1.17.4.1. Introducción .................................................................................... 213
1.17.4.1. Objetivo ............................................................................................ 213
1.17.4.1. Requisitos .......................................................................................... 213
1.17.4.3. Código Comentado ....................................................................... 216
2.1. Introducción a R ................................................................................................ 219
6
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.1.1. Ventajas de R frente a otros lenguajes ............................................... 219
2.2. Características del lenguaje ............................................................................ 221
2.3.1. Entorno de desarrollo ............................................................................. 221
2.2.2. Configuración e instalación de paquetes .......................................... 221
2.2.2.1. Paquetes más importantes para el análisis de datos .................. 223
2.2.2.2. Paquetes desarrollados para deporte ........................................... 225
2.2.2.3. Paquetes desarrollados para fútbol ............................................... 225
2.3. Sintáxis básica .................................................................................................... 226
2.3.1. Operaciones básicas ............................................................................. 226
2.4. Tipos y estructuras de datos ............................................................................. 228
2.4.1. Tipos de datos ......................................................................................... 228
2.4.2. Vectores, matrices y arrays ................................................................... 230
2.4.3. Estructuras de datos. Data.frames y listas ........................................... 241
2.5. Funciones ............................................................................................................ 245
2.6. Ejercicios resueltos ............................................................................................. 246
2.6.0. Requisitos .................................................................................................... 246
2.6.1. Ejercicio 1. Representación polar de varios KPIs de un equipo ....... 247
2.6.1.1. Introducción y Objetivo ................................................................... 247
2.6.1.2. Código Comentado ......................................................................... 247
2.6.1.3. Código sin comentarios ................................................................... 250
2.6.2. Ejercicio 2. Representación de un campo de fútbol con posiciones
de acciones de un jugador, e histogramas como complemento informativo
252
2.6.2.1. Introducción y Objetivo ................................................................... 252
7
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.2.2. Código comentado ......................................................................... 252
2.6.2.3. Código sin comentarios ................................................................... 257
2.6.3. Ejercicio 3. Creación de un mapa de calor para visualización de KPIs
de jugadores de un equipo ............................................................................... 260
2.6.3.1. Introducción y Objetivo ................................................................... 260
2.6.3.2. Código Comentado ......................................................................... 260
2.6.3.3. Código sin comentarios ................................................................... 263
2.6.4. Ejercicio 4. Creación de un gráfico para representar la evolución
temporal de un KPI (puntuación) de un partido ............................................ 265
2.6.4.1. Introducción y Objetivo ................................................................... 265
2.6.4.2. Código comentado ......................................................................... 265
2.6.4.3. Código sin comentarios ................................................................... 271
2.6.5. Ejercicio 5. Simulación de un partido. Calculo de la probabilidad de
un evento en un partido .................................................................................... 274
2.6.5.1. Introducción y Objetivo ................................................................... 274
2.6.5.2. Codigo comentado ......................................................................... 276
2.6.5.3. Codigo sin comentarios ................................................................... 281
2.6.5. Ejercicio 6. Simulación de un partido. Cálculo de la probabilidad de
un evento en un partido .................................................................................... 283
2.6.6.1. Introducción y Objetivo ................................................................... 283
2.6.6.2. Código comentado ......................................................................... 283
2.6.6.3. Código sin comentarios ................................................................... 288
3.1. Creación de un entorno ................................................................................... 290
3.2. Instalación de librerías ...................................................................................... 291
8
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
9
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1. Python
1.1. Introducción a Python
El nombre Python es un tribute de su creador Guido van Rossum al grupo de comediantes
“Monty Python” (británicos). Guido van Rossum nació en enero de 1956 y lanzó la primera
version de python en 1991 buscando y enfatizando el principio de: “Ser fácil de leer y
entender”
Ese principio ha sido, probablemente, el principal éxito de este lenguaje de programación
puesto que precisamente por ser fácilmente comprensible ha conseguido crear una
comunidad muy extensa de colaboradores que han creado una gran cantidad de librerías
para llevar a cabo casi cualquier acción desde el desarrollo de videojuegos, a desarrollos
web, programas de pruebas, monitorización de redes, …
La gran disponibilidad de librerías para realizer casi cualqueir tarea ha hecho que sea un
lenguaje con cada vez mayor número de “seguidores” y/o programadores. En la
actualidad uno de los lenguajes más de moda es Spark por las posibilidades que ofrece de
realizer procesamiento en “streaming” o “al vuelo”, es decir, casi en tiempo real. En este
ámbito Python dispone de la librería pyspark que le permite manejar el tipo de objetos RDD
de spark para el procesamiento en tiempo real.
Esta capacidad es la que sitúa a python en el entorno “Big Data” puesto que puede hacer
uso de las herramientas desarrolladas específicamente para Hadoop (entorno de datos
distribuido).
A través de las diversas librerías, que “conectan a python con el mundo exterior” éste
lenguaje puede llevar a cabo las siguientes funciones:
• Interacturas con el mundo exterior, para lo cuál será necesario leer y escribir datos
en diferentes formatos (csv, xml, excel, json, txt, dat, binario, …
• Preparar los datos a través de limpieza y generando datos estructurados desde
datos no estructurandos.
• Transformación de los datos a través de la aplicacion de operaciones matemáticas
y/o estadísticas a ciertos conjuntos de datos para obtener como resultado nuevos
datos (operaciones de agregación, segregación y filtrado)
• Presentación de los datos y resultados obtenidos hacienda uso de gráficos estáticos
y dinámicos (con javascript), mapas de localización, grafos, …
• Modelos de aprendizaje automático en los que se conectan los datos con
algoritmos de aprendizaje automáticos (supervisado o no) para la obtención de
modelos analíticos que puedan predecir (con mayor o menor g2rado) el futuro.
La principal ventaja de python y por lo que se ha hecho famoso es por la facilidad de su
aprendizaje y por la cantidad de funciones, librerías y módulos ya programados y que
pueden comenzar a utilizarse por otros sin ningún esfuerzo (except el de aprender las
características y funcionalidades de cada librería).
10
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.2. Características del lenguaje
Python es un lenguaje interpretado, multiparadigma, multiplataforma, interactivo, orientado
a objetos, de tipado dinámico y de fácil aprendizaje. Su diseño minimalista para una fácil
lectura se consigue mediante el uso de palabras inglesas y unas construcción sintáctica
sencilla (otros lenguajes hace un mayor uso de signos de puntuación)
• Interpretado, quiere decir que no se debe compilar el código antes de su ejecución.
Lenguajes como C++ o Java requieren de una compilación previa para su
utilización. Esta compilación es una “traducción” del lenguaje a lenguaje máquina
(comprensible por los ordenadores)
• Multiparadigma, porque es un lenguaje imperativos y orientado a objetos pero que
posee características de los lenguajes funcionales de programación
• Multiplataforma, dado que no importa el Sistema operativo utilizado: Unix, Linux,
Mac, Windows, … python se puede ejecutar en cada uno de ellos sin importer en
qué plataforma se ha desarrollado. Por ejemplo se puede desarrollar una aplicación
en un ordenador Windows y usarla en un servidor Linux.
• Interactivo, en el sentido literal de abrir una consola de python y comenzar a escribir
un programa sin necesidad de utilizar herramientas complicadas.
• Orientado a Objetos, un paradigma de programación en el que el código se puede
encapsular en objetos que proporcionan atributos, métodos y funciones con
funcionalidades específicas y determinadas.
• Tipado dinámico, significa que el tipo de los datos se infiere en el tiempo de
ejecución. Esta característica diferencia a python de la mayoría de los lenguajes
compilados. No require definer el tipo de una variable que, además, puede
modificarse en tiempo de ejecución.
Además de las citadas características python tiene otro gran número de características
como son:
• Fácil mantenimiento, derivado de la sencillez de su lectura y comprensión.
• Extensible, se pueden añadir módulos para incrementar su funcionalidad o
mantener scripts sencillos con funcionalidades concretas.
• Fácil conexión a bases de datos, pues tiene drivers para casi todas las bases de
datos conocidas.
• Escalable, puesto que ofrece más funcionalidades que únicamente hacer scripts.
• Se puede compilar, si se desea para mejorar el rendimiento en aplicaciones
grandes.
• Incluye un “garbaje collector” que gestiona la memoria y la va liberando cuando
detecta que hay variables que no existen.
• Se puede integrar fácilmente con C, C++, ActiveX, CORBA y Java.
• El lenguaje distinge entre mayúsculas y minúsculas (es case-sensitive) lo que significa
11
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
que no es lo mismo palabra que Palabra ni PaLaBrA.
Los scripts de Python tienen la extensión .py y, en caso de grandes proyectos que son
compilados .pyc
1.2.1. Librerías
Una de las principales ventajas de Python frente a otros lenguajes son las librerías. Python
cuenta con una base de conocimiento editable por los colaboradores. Hasta hace poco
Guido van Rossum dirigía y gestionaba la evolución de Python, manteniendo éste su
licencia de código libre. Recientemente ha dejado vía libre para que una siguente
generación decida sobre el futuro de Python.
En la página de Python wiki -https://wiki.python.org/moin/FrontPage – se pueden encontrar
la base de conocimiento fundamental para todo desarrollador de Python. En esta página
se pueden encontrar tutoriales, errores comunes, preguntas frequentes, materiales,
descargas, libros, todas las librerías y paquetes así como guías de inicio y, sobretodo, y
fundamental un índice de paquetes (Module Index) - https://docs.python.org/3/py-
modindex.html - que sirve de repositorio para encontrar paquetes que implementen librerías
para casi cualquier acción.
Existen librerías para temas como:
• Análisis de datos
• Aprendizaje automático
• Procesamiento del lenguaje natural
• Deep Learning
• Desarrollo web
• Desarrollo de videojuegos
• Gestión de protocolo http
• Visualización de datos
• Testing de aplicaciones
• Webscraping
• Gestión de redes de comunicaciones y auditoría de las mismas
• Manipulación de imágenes
• Desarrollo de videojuegos en 2D y 3D
• …
En la actualidad existen más de un 1.000.000 de paquetes, cada uno de ellos con una
funcionalidad específica, más de 250.000 usuarios y másd e 150.000 proyectos. Es una
comunidad en continuo crecimiento.
12
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.2.1.1. Librerías de gestión de bases de datos o para la
adquisición de datos
Request
Reduce la complicación de trabajar con http a través de línea de comandos.
Scrapy
Famosa para realizar webscraping y obtener información desde la línea de
comandos
BeautifulSoup
Parsea código de xml y html, lo que permite extraer información de múltiples sitios,
entre otros de páginas web.
SQLAlchemy
Sirve para gestionar el acceso a bases de datos. Existen librerías específicas para
cada base de datos (Oracle, Postgress, …) pero SQLAlchemy gestiona las conexiones de
forma “transparente” para le usuario
2.2.1.2. Librerías más importantes para el análisis de datos
Numpy (Numerical Python)
Es el pilar fundamental de todo el ecosistema numérico en Python. El objeto fundamental
de esta librería es nparray, que es un array multidimensional que permite almacenar datos
homogéneos y heterogéneos. Esta librería proporciona funciones y métodos para operar
con este objeto, entre las que se incluyen la lectura y escritura de datos de disco (ficheros
físicos); operaciones de álgebra lineal, números aleatorios y funciones financieras.
El nparry está pensado para conjuntos de datos de tamaño fijos y aunque permite el
almacenamiento de datos heterogéneos como fechas y números, no está optimizado para
realizar operaciones sobre ellos algo “engorroso” motivo por el cuál se inventaron los pandas
DataFrames. http://www.numpy.org/
Pandas (Panel data sets)
Esta librería está construida sobre NumPy, es decir, utiliza los nparray que proporciona esta
librería. El objeto fundamental de esta librería es el DataFrame. Se trata de una estructura
que permite el almacenamiento de datos que en su origen se representnan en forma
tabular. Un ejemplo claro de este tipo de representación son las hojas de cálculo en las que
13
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
existen unas filas y unas columnas en las que se almacenan los datos.
Pandas incorpora herramientas para leer y escribir datos desde distintas fuentes como
archivos CSV, TXT, documentos XML o JSON y desde bases de datos.
http://pandas.pydata.org/
Scipy (Scientific Python)
Esta librería está formada por un conjunto de sub-librerías y funciones que implementan
funcionalidad estándar útil en el campo de las finanzas y de las ciencias. Un ejemplo son
la interpolación y la integración numérica.
https://www.scipy.org/
Dask
Wes McKinney, el desarrollador principal de la librería pandas se dio cuenta de las
necesidades y mejoras de la librería pandas pero no se dio cuenta de que no era posible
cambiarla (para mejorarla) sin hacer una librería nueva, motivo por el cual surge Dask.
Una librería todavía poco conocida por el público en general pero reconocida por el
mundo del análisis de datos. Es una librería que proporciona diferentes herramientas para
trabajar tanto en una máquina con uno o varios hilos paralelos como en un entorno
distribuido con hilos en paralelo, propiciando un entorno perfecto para el manejo de
grandes cantiades de datos.
Es una librería relativamente nueva (2017) en la que se encuentran trabajando montones
de desarrolladores que, a su vez, reutilizan código para dar soporte a objetos de tipo
dask.array, dask.DataFrame o dask.bag que simulan el funcionamiento de las precedesoras
de esta librería.
2.2.1.3. Librerías más importantes para la visualización de datos
Matplotlib
Es una de las librerías más potentes para hacer gráficos con Python. Es flexible y viene con
algunas construcciones por defecto para visualizar datos. Esa misma flexibilidad hace que
en ocasiones sea necesario dedicar demasiado tiempo a la “personalización” del gráfico.
Es por ello que utilizando Matplotlib se creó Seaborn.
14
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Seaborn
Es una librería de visualización de datos basada en Matplotlib y ofrece un mayor número
de visualizaciones por defecto que son, además, más atractivas y con estilos más
avanzados que los que incluye Matplotlib.
El principal objetivo de esta librería es la visualización de datos estadísticos, cosa que
permite hacerlo en muy pocos pasos.
Bokeh
Es una librería independiente al uso de Matplotlib y está pensada para la visualización de
datos en navegadores web. Generalmente es utilizada para la visualización de datos
complejos porque ofrece visualización interactiva, es decir, el usuario puede explorar los
datos.
Plotly
Es una librería online que se utiliza generalmente para la analítica de datos. No es una
librería completamente descargable sino que es necesario conectarse online a través de
una API (robusta) a través de la cuál los datos se utilizan para generar visualizaciones que
incluyen javascript, lo que aporta una mayor interatividad con el usuario y por tanto más
atractiva.
2.2.1.4. Librerías más importantes de aprendizaje automático
(Machine Learning)
Scikit-learn
Es una librería de aprendizaje automático (machine learning) construida sobre Numpy,
SciPy y Matplotlib. Proporciona herramientas sencillas y eficientes para la minería y el análisis
de datos.
TensorFlow
Librería Open Source que funciona a través de un API que permite realizar cálculos
numéricos mediante diagramas de flujos de datos además de permitir gestionar “redes
neuronales profundas” o Deep Learning.
15
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Pytorch
Es una librería Open Source de instalación en el equipo que, al igual que TensorFlow permite
gestionar “redes neuronales profundas” o Deep Learning.
Existen multitud de librerías para multitud de propósitos. Se recomienda a los usuarios leer y
estudiar qué librerías a utilizar. En algunos casos los desarrolladores de una librería pueden
dejar de dar soporte. En función del tipo de proyecto a desarrollar será necesario tener en
cuenta estas condiciones para decidir sobre la conveniencia o no de utilizar una librería.
Todas las librerías mencionadas en este apartado cuentan con una comunidad de
desarrolladores las mantiene y actualiza no pareciendo probable que dejen de hacerlo a
excep
1.2.2. Entornos de desarrollo
Python está disponible para un gran número de plataformas que incluyen sistemas Linux,
Unix, Windows, DOS, PalmOS, Nokia Mobile phones, Amiga, … Esto implica que cada un
script de Python, sin importar donde sea escrito, debe ser interpretado igual en cualquiera
de estos sistemas.
La escritura de un script de Python puede hacerse desde cualquier editor de texto, desde
los más sencillos como vi, vim, nano, Bloc de notas, … hasta editores más complejos como
NotePad++ o Atom.
La ejecución de un script requiere tener el código fuente de python que se puede conseguir
de la página web: http://python.org e los ficheros necesarios para interpretar y ejecutar
Python.
Es posible utilizar un editor de textos para escribir el script.py y después utilizar la línea de
comandos para ejecutar un programa. Sin embargo para hacer las cosas más sencillas se
inventaron los Integrated Development Environment que son aplicaciones que
proporcionan ambos servicios (y en algunos casos muchos servicios más) para que el
programador pueda centrarse en programar y la gestión de la ejecución, depuración y
otras tareas las realice de forma “inocua” el propio IDE.
16
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Los IDEs principales para Python son:
Pycharm
Visual Studio
Ipython notebook (o jupyter notebook)
Spyder
Atom
Existen mucho más IDEs que permiten escribir, ejecutar, depurar el código y más opciones.
A efectos practicos en este curso utilizaremos Jupyter Notebook de Anaconda, cuya
instalación se verá en un siguiente apartado.
1.2.3. Virtual environments
Los entornos virtuales o virtual environments son la forma que Python ha desarrollado para
permitir que los programas sean fácilmente transportables. Un entorno virtual o virtual
environment encapsula en su interior todos los requisitos de un proyecto (nombres de
librerías, versiones de las librerías, versión de Python y variables de entorno) para que pueda
ser transportable a otra máquina con la misma o distinta versión de sistema operativo.
La forma que tiene el software de evolucionar hace necesaria esta herramienta. Cada
lenguaje de programación tiene su propia forma de implementar herramientas parecidas
17
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
o similares. Un ejemplo práctico de la practicidad de esta herramienta es la evolución del
propio Python.
18
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Con el paso del tiempo se ha desarrollado desde su versión 1.0 a la última versión estable
3.8, dejando por el camino un rastro de errores arreglados y mejoras realizadas. (Este rastro
está en la documentación de python https://docs.python.org/3/) Al igual que ha
evolucionado python, las librerías y módulos a disposición también han avanzado.
Este proceso requiere de la aparición de nuevas funciones y desaparición de otras. Según
avanzan las versiones se van dejando avisos de qué funciones dejarán de existir a través de
mensajes como este:
function deprecated in 1.0, to be removed in 2.0. Use the ‘alt-name-
function’ instead
Con mensajes como este unos programadores (los que mantienen las librerías o el propio
Python) avisan a otros acerca de qué funciones se dejarán de usar y qué función alternativa
pueden usar. Sucesivos cambios en librerías y versiones llevan a que un programa escrito en
Python 2.7 no sea compatible con uno escrito en Python 3.8.
Se ha anunciado que Python 2.7 no dará mantenimiento a esta librería a partir de 2020,
avisando con años de antelación a todos aquellos que tengan proyectos escritos en la
versión 2.7 para que los modifiquen a una versión posterior. La migración de proyectos
grandes no es nada sencilla puesto que y en algunos casos requiere mucho tiempo y
dedicación estudiar cada línea de código para encontrar la mejor alternativa.
Los virtual-environments encapsulan el código para que en una misma máquina puedan
ejecutarse programsa con distintas versiones de Python y/o de librerías salvaguardando así
la seguridad de ejecución del programa.
Los entornos virtuales, por tanto, ofrecen solución para los siguientes problemas:
• Migración de un proyecto a otra máquina sin importar el sistema operativo
• El mantenimiento a lo largo del tiempo de la integridad del proyecto
• La convivencia de proyectos desarrollados en Python 2.7 y en Python 3.0 o posterior.
En resumen, un virtual environment te permite hacer un “clon” de tu sistema para que otras
personas puedan reproducir tu programa o tú puedas ejecutar el programa desarrollado
por otros.
Las herramientas más famosas y utilizadas para la gestión de entornos virtuales son:
• venv
• pipenv
• virtualenv
• conda
Cada una de estas herramientas te permite crear un fichero que normalmente se conoce
como requirements.txt en el que se detallan las librerías, la versión de las librerías y la
versión de Python utilizada.
19
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.2.4. Jupyter Notebook (Anaconda)
Anaconda Distribution es una suite de código libre que incluye un conjunto de aplicaciones,
librerías y objetos diseñados para comenzar de forma rápida y sencilla a ejecutar código
Python. Está especialmente diseñado para el análisis, visualización y aprendizaje
automático de datos y se puede configurar para utilzarse con R, Python 2.7 y Python 3.0+
Anaconda incluye conda como gestor de entornos virtuales y es el único que permite
gestionar los entornos virtuales usando una interfaz gráfica además de la línea de
comandos.
Entre las herramientas incluye como IDEs de desarrollo Jupyter, Jupyter Notebook, Spyder y
RStudio. (Cabe reseñar que un entorno de Python no es compatible con uno de R)
1.2.4.1. Componentes y requisitos de Anaconda
Los componentes de Anaconda Project son:
• Conda, el gestor de paquetes y librerías
• Librerías específicas para el análisis de datos, que vienen preinstaladas.
• Anaconda Project, que encapsula el proyecto a haciendo uso de conda
• Anaconda Navigator, que es el IDE de desarrollo. Permite editar documentos que
tienen código Python y ejecutarlos haciendo uso de las librerías correspondientes.
En el material complementario puedes encontrar los pasos para realizar la instalación.
Los requisitos son:
• 5GB de espacio para la descarga e instalación.
• Sistema Operativo: Windows 7 or newer, 64-bit macOS 10.10+, or Linux, including
Ubuntu, RedHat, CentOS 6+, and others
• Arquitectura: Windows- 64-bit x86, 32-bit x86; MacOS- 64-bit x86; Linux- 64-bit x86, 32-
bit x86, 64-bit Power8/Power9
La instalación tanto de Windows, Mac y Linux se puede seguir en:
https://docs.anaconda.com/anaconda/install/ y es similar a la de Windows, que se
procede a explicar con la ayuda de imágenes.
20
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.2.4.2. Primeros pasos con Anaconda
Una vez instalado Anaconda es necesario iniciar el programa. Este paso será diferente
según el sistema operativo que tengas. Sigue las instrucciones de la página oficial de
Anaconda para inicial el programa. https://docs.anaconda.com/anaconda/user-
guide/getting-started/#
Mientras se abre el programa verás el siguiente icono:
Los pasos siguientes son comunes para todos los sistemas operativos (Mac, Windows y
Linux/Unix). La página de Anaconda es así:
Selecciona la opción de “Launch” Jupiter Notebook.
21
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Esta acción lanzará un proceso por detrás y te abrirá el navegador que tengas
seleccionado por defecto en el sistema operativo. En este caso es Firefox.
Escoge la ruta donde quieras guardar el NoteBook a crear navegando por las carpetas. (Es
posible hacerlo pero requiere ser un usuario avanzado para guardar los notebooks
directamente discos duros extraíbles o similar. En cualquier caso no es necesario porque
después podremos volver a guardarlo donde más nos convenga).
Crea un nuevo fichero pulsando en “New” o “Nuevo” y selecciona la opción de Python 3.
22
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Esta acción abrirá en el navegador una nueva pestaña (tab) en como la siguiente:
Fíjate en que aparece una sección sobremarcada en azul. A esta sección se le conoce
como celda. Un Notebook está compuesto de celdas. En las celdas podemos introducir
código de Python o texto. La selección de qué va a contener la celda se selecciona aquí:
Por defecto viene preestablecido como “Code” que sirve para introducir código a
ejecutar. La opción “Markdown” es la que permite introducir texto y nos permite formatear
el texto introducido usando un “lenguaje” específico para determinar el formateo del texto
que se muestra.
El markdown se utiliza en muchos programas y para lo que vamos a usar en el curso solo
23
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
necesitas saber que introducir un # delante del texto permite crear un título de nivel 1, si se
usan ## el título será de nivel dos y así sucesivamente hasta el 6. Veamos un ejemplo:
Al marcar la celda como de tipo “markdown” y escribir el siguiente texto veremos cómo se
transforma
Este texto pasa a ser:
Además, automáticamente se crea una nueva celda cuyo formato será “code”
24
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si quieres ampliar información al respecto lo mejor es que accedas a algunas de estas webs:
• https://www.markdownguide.org/getting-started
• https://markdown-it.github.io/
• http://www.unexpected-vortices.com/sw/rippledoc/quick-markdown-
example.html
• https://guides.github.com/features/mastering-markdown/
Vayamos directos al código y aprovechemos la celda que se ha creado debajo para
introducir código y ejecutarlo. Para ejecutarlo pulsa sobre el botón que dice “run”
Comencemos a hablar de Python como lenguaje de programación.
25
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.3. Sintáxis básica
1.3.1. Conceptos generales
La sintáxis del lenguaje define la forma en que el lenguaje se debe escribir, para que el
intérprete pueda realizar su labor y traducirlo a lenguaje máquina. Pyhton puede ejecutarse
de forma interactiva desde la línea de comandos o puede guardarse en un script y ejecutar
el script desde la línea de comandos.
Es necesario tener instalado Python, para ello lo mejor es seguir las instrucciones de la
página de oficial de Python https://www.python.org/downloads/, descarga el fichero y
según el sistema operativo que uses haz doble-click y sigue las instrucciones.
Por el momento deberías saber que Python es:
• Sensible a mayúsculas y minúsculas por lo que no es lo mismo print(variable) que Print(“a word”).
• La identación del código es fundamental. Se utiliza en vez de añadir caracteres de
otros lenguajes como pueden ser { } en Java. La identación indica el orden de
ejecución de las l
• La escritura de un programa debe ser como la escritura de un libro o un artículo. No
se solo de que el código funcione sino de que otras personas puedan entenderlo
fácilmente y usarlo motivo por el cuál los programas, nombres de variables,
comentarios, funciones, clases deben estar escritos en inglés.
• Existe una guía de estilo que, si bien no es obligatoria, si recomendable conocer y
utilizar. En ella se detallan específicamente normas de estilo para la escritura de un
programa Python https://www.python.org/dev/peps/, una de las recomendaciones
es la de no escribir líneas de programas con una longitud superior a 79 caracteres,
puesto que esto facilita poder abrir un programa en casi cualquier tamaño de
pantalla y no perder la sencillez de estilo que caracteriza Python.
A partir de ahora vamos a comenzar con código sencillo de Python, te recomiendo que
visualices el video que proporcionamos sobre cómo instalar Anaconda Project y primeros
pasos con Python. Estos ejemplos los puedes encontrar en el fichero “Sintaxis Básica” de tipo
jupyter-notebook que se entrega como parte del curso.
1.3.2. Función print()
La función print() es una de las funciones básica a la hora de utilizar python. Esta función
sirva para forzar la visualización por pantalla (o línea de comandos) de aquellos elementos
que pongamos en medio de los paréntesis. Los elementos pueden ser cadenas de texto,
variables y funciones.
Python necesita que identifiques las cadenas de texto usando comillas simples o dobles de
26
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
la siguiente manera.
La función print() es una función fundamental que nos permite adecuar la salida del
texto a visualizar.
La función print() puede recibir dos argumentos:
sep que indica el separador a utilizar entre los elementos a mostrar. Por defecto es
un espacio
end que indica cómo finalizará la línea. Por defecto es un salto de línea pero se
puede modificar.
Veamos un ejemplo de lo que esto supone:
27
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.3.3. Comentarios
El símbolo # sirve para incluir comentarios de una línea. A partir de este símbolo el texto
que haya en la misma línea no será tenido en cuenta por Python.
1.3.4. Multi-lineas
Si una línea es muy larga o superior a 79 caracteres se debe reducir su tamaño para
28
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
ajustarlo al espacio que tenemos destinado. Lo podemos hacer de la siguiente manera:
En el caso de que sea texto se puede separar con una “coma” y continuar en la siguiente
línea:
Si el problema es el código entonces podemos aplicar un enter para ajustarlo a nuestras
necesidades:
29
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.3.5. Palabras reservadas
Las siguiente lista de palabras son palabras reservadas del lenguaje, es decir, no pueden
ser utilizadas para nombrar una variable, una función, una clase, un objeto. Son palabras
especiales que contienen un significado propio. Anaconda nos indica que son palabras
reservadar marcándolas en verde.
La lista de palabras reservadas es la siguiente:
and, as, assert, break, class, continue, def, del, elif, else, except, exec,
finally, for, from, global, if, import, in, is, lambda, not, or, pass, print,
raise, return, try, while, with, yield
1.3.6. Operaciones
Python permite realizar operaciones ya sea de modo ineractivo o usando un script de
Python. Las operaciones permitidas son:
30
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.3.7. Operadores de comparación
En Python existen los siguientes operadores que sirven para comparar dos valores:
== Comparación entre dos elementos.
Devuelve True cuando son iguales
Devuelve False cuando son distintos
!= Comparación entre dos elementos.
Devuelve True cuando son distintos
Devuelve False cuando son iguales
a > b Si el operando a es mayor que b
Devuelve True, sino devuelve False
31
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
a >= b Si el operando a es mayor o igual que b
Devuelve True, sino devuelve False
a < b Si el operando a es menor que b
Devuelve True, sino devuelve False
a <= b Si el operando a es menor que b
Devuelve True, sino devuelve False
32
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.3.8. Operadores de pertenencia
Los operadores de pertenencia sirven para evaluar si un elemento se encuentra en un una
secuencia.
Las operaciones fundamentales son: in y not in.
1.3.9. Asignación de Variables
33
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Una de las características principales de Python es que el tipado de datos es dinámico. Esto
se traduce en que al crear una variable no es necesario declarar el tipo de la variable, cosa
necesaria en la mayoría de los lenguajes de programación. La variable puede cambiar de
tipo según avanza la ejecución del programa. Este paradigma choca con otros lenguajes
fuertemente tipados en los que las variables no pueden modificar el tipo y tampoco pueden
realizar operaciones con variables de otros tipos.
En Python True equivale al número 1 y False lo que permite hacer cosas como:
Hay que tener en cuenta que en un Notebook nos impiden hacer este tipo de operaciones.
Aún existiendo el tipado dinámico no es recomendable hacer un uso indebido con él y
procurar utilizarlo con sentido común. La ventaja es que permite hacer sumas de enteros
con números reales y obtener un número real
La asignación de variables se realiza Aún existiendo el tipado dinámico no es
recomendable hacer un uso indebido con él. El nombre de las variables no puede ser una
palabra reservada del lenguaje.
Cada variable tiene un nombre y un valor. Los nombres de las variables pueden contener
caracteres alfanuméricos (a-z, A-Z, 0-9) y otros símbolos pero no pueden comenzar con
número.
La asignación de un valor a una variable se realiza a través del símbolo = en ese momento
el valor y el tipo son asignados a la variable. A la izquierda del símbol de asignación = se
sitúa el nombre de la variable y a la derecha el valor de la misma. Es posible realizar
asignaciones múltiples a través del uso del símbolo ,
34
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
35
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.4. Tipos y estructuras de datos
La instalación básica de Python incluye los siguientes tipos de datos
Boolean
True/False # Indican Verdadero o Falso
Números
int # entero
long # entero largo
float # coma flotante
complex # número complejo o real
Secuencias
str # cadena de caractéres
list # lista
tuple # tupla
Mapeos
dict # diccionario
Conjuntos
set # conjunto mutable
frozenset # conjunto inmutable
Adicionalmente y tras instalar las librerías Numpy y Pandas, se añadirán nuevos tipos de
datos como son:
nparry # arrays multidimensionales
pandas # datos tabulados
Cada librería introduce uno o más tipos de datos a través de los cuales se gestionan
determinados atributos y funciones. Puedes ver más información en la sección 3.
Anaconda.
1.4.1. Tipos boolean o bool
El tipo boolean es el tipo más sencillo de todos. Los únicos valores posible son:
36
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Los operadores booleanos más habituales son: and, or, no que se utilizan para la
conjunción, disyunción y negación respectivamente.
1.4.2. Estructuras numéricas int, long, float, complex
Python proporciona, en su nivel más básico cuatro tipos de datos que sirven para que las
variables puedan almacenar número de diferentes características.
1.4.2.1. int
El tipo int almacena valores de tipo entero positivos o negativos. Es un tipo inmutable (no se
puede modificar el valor, la nueva asignación genera un nuevo objeto con el nuevo valor).
37
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.4.2.2. long
Este tipo se utiliza para enteros de tamaño ilimitado. A la hora de mostrarlos por pantalla se
muestran como los enteros pero terminando con una L. Solo existe en python 2.7, en Python
3.0 y posterior queda integrado dentro del tipo int.
468165187L
1.4.2.3. float
Se utiliza para guardar números reales, tanto periódicos como exáctos (en cuyo caso la
fración es 0) Pueden tener notación científica.
1.4.2.4 complex
Se usa para los números complejos que están compuestos por una parte real y una
imaginaria (a + bj)
1.4.2.5. Funciones para forzar el tipo de un dato
Python proporciona funciones que utilizan un constructor para transformar fácilmente un
tipo de números en otro (siempre y cuando sean compatibles)
int(x) # convierte x en un entero
float(x) # convierte x en un float
complex(x) # convierte x en un complex
38
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
complex(x, y) # convierte x en la parte real de un número complejo;
y como parte imaginaria
abs(x)
Las cadenas de texto no se pueden sumar con los números. Si lo intentamos tendremos un
error del tipo “cadena y número no se pueden sumar”
Además temenos la posibilidad de convertir un número o una cadena a un número real
A número complejo
39
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Calcular el valor absoluto de un número
1.4.3. Fechas (datetime, date, time)
El tipo fecha es uno de los cambios importantes de Python 2.7 a Python 3.7. La gestión de
las fechas en Python se puede realizar de diferentes maneras.
datetime
Este tipo de dato encapsula a su vez datos de tipo date y tipo time. Es un tipo que sirve
para almacenar la fecha y la hora. Es necesario importar la librería datetime para poder
hacer uso de este tipo de datos.
Los objetos de tipo datetime es una tupla que contiene año, mes, día, hora, minuto,
segundos, centésimas de segundo.
Proporciona múltiples funciones para convertir objetos de tipo datetime en objetos de tipo
string y viceversa.
40
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
También podemos crear fechas utilizando el constructor de la propia clase
date
Este tipo de dato sirve únicamente para almacenar fecha
time
1.4.4. Secuencias (str, list, tuple)
Las secuencias son tipos de datos que pueden almacenar colecciones de datos de
diversos tipos y se diferencian por su sintaxis y por la forma en la cual los datos pueden ser
manipulados.
1.4.4.1. str
Es uno de los datos básicos más imporantes. Se pueden crear utilizando comillas dobles “
o comillas simples ‘ porque Python maneja ambas nomenclaturas. Es importante recorda
La creación de una cadena es tan sencilla como escribir
41
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
A partir de Python 3.5 el tipo de cadena por defecto es Unicode.
Las cadenas se pueden concaternar usando el operador +
Las cadenas de caracteres muy largas se encierran utilizando triples comillas “””
Existen ciertos caracteres que no se pueden imprimir por pantalla. Están representados por
la barra invertida \ Los caracteres especiales más importantes son:
comillas dobles “
42
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
comillas simples ‘
Barra invertida \
Salto de línea \n
Tabulador \t
Formateo de cadenas “antiguo” %-formatting
Hasta la versíon 3.6 de python el formateo de las cadenas se hacía utilizando el símbolo %,
lo que tenía numerosas limitaciones y errores, motivo por el que se ha creado en nuevo
formateo de cadenas que hace uso de la función str.format().
En la versión anterior se usaba % como sustituo. Ejemplo:
Es possible que encuentres esta nomenclatura en proyectos antiguos. Este tipo de
formateado de texto se ha visto mejorado y modificado.
El principal problema es que cuando tienes que usar varios parámetros de sustitución el
código se hace difícilmente legible. (Sobretodo si quieres sustituirlos por un objeto de tipo
diccionario)
Formateo de cadenas desde python 3.6 str.format()
La nueva manera de formatear cadenas tiene muchas ventajas sobre la anterior ya que
utiliza llamadas a funciones y así los campos se pueden sustituir, lo que permite que el
código sea más fácilmente comprensible.
43
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Al hacer llamadas a funciones se pueden utilizar números que corresponden con la posición
de los elementos en la función o se pueden utilizar vínculos de nombres de variables con
valores.
Formateo de cadenas desde python 3.7 f”cadena”
En la versión 3.7 de Python se introdujo una mejora para el formateo de cadenas. Usando
la letra “f” al principio de una cadena se puede incluir dentro de la misma los valores de las
variables usando el nombre de las mismas.
1.4.4.2. tuple
Una tupla (tuple) es una variable que permite almacenar datos inmutables de tipos
diferentes. Los datos inmutables no se puede modificar el valor, la nueva asignación genera
un nuevo objeto con el nuevo valor.
Las tuplas se cierran con paréntesis ( )
44
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.4.4.3. list
El tipo de dato list se parece a tuple con la diferencia de que la listas puden modificar los
datos una vez creados.
Las listas se cierran con corchetes [ ].
1.4.4.4. Acceso a los elementos de una secuencia (str, tuple, list)
Los elementos de las secuencias se acceden igual sin importar si son de tipo str, tuple o
list. Se utilizan corchetes [indice] con el índice al que se desea acceder.
Es posible seleccionar partes de la lista haciendo “slicing” o particiones de la misma, para
ello usaremos [índice_inicial : índice_final: salto ]
Es posible acceder al último elemento (o elementos desde el final utilizando números
negativos que comienzan en el -1.
45
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Los elementos de las secuencias, tanto list como tuple son heterogéneos, así que es
posible definir listas de listas, listas de tuplas, tuplas de tuplas, tuplas de listas.
Para acceder ellas se concatenan los corchetes porque un corchete maneja cada
secuencia.
Es posible hacer listas, de listas, de listas, … aunque puede ser difícil de manejar
1.4.5. Mapeos (dict)
Los diccionarios dict son una colección no ordenada de pares clave:valor . La clave y el
valor están separados por dos puntos : y cada elemento del diccionario está separado
por comas , y todo ello está cerrado por { }
Las claves son únicas (no se pueden repetir) y deben ser de un tipo inmutable de python
(cadenas, números o tuplas). Los valores del diccionario pueden ser de cualquier tipo.
El acceso a los diccionarios se realiza a través de la clave. Los diccionarios pueden
contener (como valor) otros diccionarios o listas, que a su vez pueden contener otros
diccionarios y listas, …
46
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La identación no es obligatoria, pero ayuda a entender la estructura de este diccionario de
diccionario de listas.
Se pueden hacer consultas para saber si un diccionario tiene o no una clave, ten en cuenta
que es sensible a mayúsculas y minúsculas:
47
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Al ser un diccionario de diccionarios puede ser necesario hacer una consulta con
anidamiento:
1.4.6. Conjuntos (set)
Los conjuntos son colecciones no ordenadas de elementos no repetidos. Los conjuntos
pueden crearse de dos formas diferentes:
• Mediante una lista de elementos entre llaves
• Mediante la función set([])
Los cojuntos, además, permiten las operaciones matemáticas habituales como unión,
intersección, diferencia, …
48
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.5. Funciones
Las funciones son el método principal de organización y reutilización de código. Existen
algunas funciones predefindas como print, len, type, abs, que nos permiten llevar a cabo
acciones sobre los datos. Podemos crear nuestras propias funciones predefindas para
realizar tareas específicas para el proyecto en el que estemos trabajando.
Las funciones se declaran utilizando la palabra reservada def seguida del nombre de la
función, que devolverá un valor utilizando la palabra reservada return. Los nombres de las
funciones no pueden coincidir con palabras reservadas del propio lenguaje. En Python no
es obligatorio que las funciones devuelvan un valor. Si terminan sin return entonces se
devuelve None
No es obligatorio pero se puede, si se desea, indicar el tipo de los valores de entrada y el
valor de salida. Para ello es necesario utilizar dos puntos : seguido del tipo del parámetro
Como puede verse, a diferencia de otros lenguajes Python no utiliza símbolos o llaves para
estructurar el código. Python utiliza espacios en blanco o tabulaciones para dar estructura
a su código.
49
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.5.1. Return múltiple
Las funciones en Python, a diferencia de otros lenguajes, pueden devolver múltiples valores.
Esos valores pueden recogerse en una variable que pasa a ser una tupla, o en múltiples
variables
1.5.2. Funciones y métodos
Python es un lenguaje orientado a objetos y una de las características es que todo número,
cadena, estructura de datos, función, clase y módulo es considerado un objeto.
Los objetos en Python tienen un tipo asociado (ejemplo str o function) y unos atributos y
métodos.
Los atributos son las características del objeto, los datos internos
Los métodos son las funciones asociadas al objeto que tienen acceso a los atributos internos
del objeto.
Por ejemplo, un objeto de tipo str tiene un método asociado format que permite sustituir
elementos de la cadena por otros valores.
50
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.5.3. Los argumentos de las funciones
Las funciones tienen una lista de argumentos:
• Posicionales, estos valores son utilizados conforme a la posición en la que aparecen
en la función.
• Por clave, se usan para indicar valores por defecto y siempre se sitúan después de
los argumentos posicionales. Esto significa que si existen argumetos posicionales y
argumentos clave en la misma función, entonces éstos últimos se sitúan a la derecha
del todo.
• Argumentos agrupados (*args): Los argumentos agrupados se representan
mediante una tupla arbitraria de sus elementos. No es necesario que el argumento
se denomine args
51
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• Diccionario de argumentos accedidos por clave (**kwargs). Representa una lista
arbitraria de elementos. El acceso a los elementos del diccionario se realizará a
través de la clave de los elementos:
o Este tipo de argumentos no se puede definir nunca antes de la definición de
los argumentos agrupados (que pueden no existir en la definición de la
función). Ttampoco es necesario que se denomine el argumento con la
palabra kargs.
1.5.4. Paso de parámetros
El paso de parámetros en Python es siempre por referencia y no por valor. ¿Qué significa
esto? El paso de variables por referencia significa que en una asignación se crea una
referencia al objeto que se encuentra en el lado derecho de la asignación. Esto es muy
importante entenderlo para trabajar con grandes volúmenes de datos. En otros lenguajes
de programación el paso es por valor, pero no en Python.
Veamos un ejemplo:
52
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
En este punto las variables a y b apuntan al mismo objeto y la modificación de una de ellas
modifica el objeto al que referencia, por tanto modifica “involuntariamente” a la otra.
a almacena una referencia al objeto lista b tiene referencia al mismo objeto. Es por ello que
al añadir un elemento en la variable a también se añade en la variable b.
53
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.5.5. Funciones como argumentos de otras funciones
Es mejor explicar con un ejemplo este paso. Imaginemos que tenemos una lista con el
nombre de jugadores de fútbol
La lista no tiene un formato uniforme de nombres y antes de realizar análisis de los mismos o
para mostrar los resultados necesitamoses importante eliminar los espacios en blanco, los
sígnos extraños y otras funciones.
Según el nivel de programador de cada uno lo más sencillo (aunque no lo más eficiente)
sería recorer toda la lista realizando primero una limpieza de caracteres especiales,
quitando espacios extra, y pasando el texto a la primera mayúscula.
El uso de las funciones como argumentos de otras funciones es una característica de los
lenguajes funcionales. La función map() de los lenguajes funcionales también está
habilitada en Python. La función map() devuelve un elemento iterable que evita el uso de
bucles for o while. El objeto iterable podemos transformarlo en un objeto de tipo lista
1.5.6. Funciones lambda
Este tipo de funciones son funciones anónimas, se denominan así porque no tienen nombre.
54
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Se refieren a una única instrucción y se declaran con la palabra reservada labmda.
Generalmente son funciones cortas y muy utilizadas en pandas en funciones de
transformación de datos.
Se utilizan porque el código es corto, claro y hace más fácil entender lo que se está
haciendo.
En el apartado de análisis y limpieza de datos con pandas se ven más usos de esta función.
55
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.6. Estructuras e instrucciones de control
1.6.1. if, elif, else
Esta estructura de control permite seleccionar entre uno o varios caminos.
Al poner dos puntos : al final de una línea del condicional y continuar con un nivel de
sangrado superior, se considera que esa instrucción forma parte del condicional. La
siguiente línea que vuelva a tener el mismo sangrado que la condicional estará fuera del
nivel y habrá cerrado el condicional.
Si la condición no se cumple entonces no ejecuta el código interno
Podemos añadir la estructura else para que cuando no se cumpla la condición realice otra
parte de código
56
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Adicionalmente se pueden incluir más condiciones para ver si se cumplen
Si queremos añadir ramas adicionales al condicional, podemos emplear la instrucción elif
(abreviatura de else if). Para la parte final, que debe ejecutarse si ninguna de las
condiciones anteriores se ha cumplido, usamos la instrucción else.
1.6.2. Expresiones ternarias
Se denominan así porque permiten hacer una asignación distinta según si ocurre o no una
condición.
La definición de las expresiones ternarias es:
57
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.6.3. Bucles for y while
Bucle for
Permite realizar una tarea un número fijo de veces. Se utiliza para recorrer una colección
completa de elementos (una tupla, una lista, un diccionario, etc ) :
Aquí el objeto <iterable_object> puede ser una lista, tupla, array, etc.
El bucle se repite un número fijo de veces, que es la longitud de la colección de elementos.
La instrucción continue permite saltar de una iteración a otra. Así podemos hacer que en
determinados casos no rompa el bucle pero no haga nada.
58
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
59
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Bucle while
Los bucles while repetirán las instrucciones anidadas en él mientras se cumpla una
condición:
El número de iteraciones es variable, depende de la condición. Como en el caso de los
condicionales, los bloques se separan por sangrado sin necesidad de instrucciones del tipo
end. Es importante recordar poner una cláusula que permita finalizar el bucle para evitar
“bucles infinitos”.
Se puede interrumpir el bucle a la mitad con la instrucción break:
La función enumetare()
Las tuplas, las listas y los diccionarios son elementos iterables. La función enumerate()
devuelve una tupla que contiene la información del número i relativo a la secuencia y el
valor.
Es una tupla de tipo (i, valor)
60
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si usamos la función enumerate podemos tener a qué posición corresponde:
Así podemos aprovechar que sabiendo el índice filtrar para solo mostrar los días que
compongan el fin de semana
61
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.7. Definición por compresión o list comprehension
Una definición por compresión es una expresión compacta que sirve para definir listas,
conjuntos y diccionarios. La idea principal es definir cada uno de los elementos sin tener
que nombrar cada uno de ellos. El formato es:
Por ejempo podemos crear una lista que contiene elementos de un conjunto iterable.
Así se puede extraer el valor de las claves de un diccionario, y a su vez podremo utilizar
esta información para acceder a los datos de esos diccionarios:
Podemos usar esa lista que se genera como parámetro de entrada para acceder a los
datos de los jugadores.
62
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Tenemos diferentes formas de acceder a esos datos:
Adicionalmente se pueden anidar este tipo de bucles:
Por ejemplo si solo queremos seleccionar los jugadores del Real Madrid:
63
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.8. Modulos
Los módulos son librerías que te permite organizar de forma lógica el código de Python.
Amplian el lenguaje Python añadiendo clases, funciones y variables para realizar tareas
específicas.
Un ejemplo es el módulo pandas que permite usar objetos de tipo DataFrame o funciones
como la lectura de ficheros csv.
from <modulo> import <nombre_funcion>
import <modulo> as <alias>
Dependerá de cómo hayamos importado el módulo así tendremos que utilizarlo. Se puede
consultar la página de cada módulo para saber qué clases, funciones y variables incluyen
pero también se puede utilizar la función dir para ver las opciones disponibles.
>>> import pandas as pd
>>> dir(pd)
También podemos hacer uso de la función help(modulo) para ver la ayuda del módulo o
de una función específica.
>>> help(pd)
>>> help(pd.DataFrame)
En algunas librerías como pandas la importación del módulo conviene hacerla completa. En
otras librerías como flask es posible que solo se desee cargar una función. Esta técnica
permite mejorar la eficiencia del programa completo dado que no es lo mismo tener en
memoria 1 función que 100.
64
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.9. Excepciones
Las excepciones proporcionan las características fundamentales para gestionar errores
inesperados o errores que pueden ocurrir, además de para añadir capacidades de
depuración al programa.
Es necesario para comprender que una gran mayoría de proyectos de software son
desarrollados para estar funcionando constantemente. Un ejemplo sería una web, que
debe estar disponible en todo momento. En este tipo de proyectos se busca la continuidad
y si surge un problema proponer una solución aunque sea del tipo “hubo un error, no
podemos acceder a la información” pero que el resto del proyecto siga funcionando. En
este sentido las excepciones sirven para tener en cuenta, por ejemplo, que se intente abrir
un archivo y éste no exista, que se intente acceder a la base de datos y no esté disponible,
… es decir, que un problema externo no genere un problema interno, porque un proble
interno hace que el programa termine abruptamente.
La gestión de excepciones se realiza utilizando las palabras reservadas try y except. El
código que hay dentro del bloque try se ejecuta siempre y el código que hay en el bloque
except solo se ejecuta en caso de ocurra una excepción.
Los tipos de excepción más comunes en Python son:
• ModuleNotFound que surge cuando la importación de un módulo no ha sido
correcta bien porque no esté instalado bien porque no ha sido referenciado
65
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• SyntaxError que surge cuando hay un error de sintaxis en el código (por ejemplo
un if mal formado)
• IdentationError surge cuando la identación no es correcta.
• TypeError surge cuando una operación o función que hay que aplicar espera
encontrarse un tipo de datos determinados y encuentra datos diferentes. Por
ejemplo, intentar sumar una cadena y un número entero.
66
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• ValueError surge cuando una operación no función recibe un argumento que
tiene el tipo adecuado pero un valor inadecuado.
• FileNotFoundError surge cuando se intenta acceder a un fichero que no existe en
la ruta referenciada (puede que el fichero exista, pero esté en otra carpeta.
• ZeroDivisionError surge cuando en una división el denominador es 0. Cuando
divides dos variables siempre se corre el riesgo que el denominador tenga valor 0
como resultado de un proceso anterior y que eso provoque la excepción.
67
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si quieres ver un listado más extenso de las execpciones que hay puedes consultar la página
oficial:
https://docs.python.org/3/library/exceptions.html
Podríamos hablar de que existen dos niveles de excepción. Las excepciones esperadas y
las inesperadas. Es posible anticiparse a las excepciones esperadas a continuación planteo
un ejemplo en el que se le pide al usuario que introduzca un nombre de fichero válido.
Si en algún momento durante el master te salta una excepción de tipo FileNotFound prueba
a usar esta función. Lo que hace es solicitar una ruta válida para un fichero hasta que la
encuentra.
Un ejemplo para la apertura de ficheros es solicitarle al usuario que introduza la ruta del
fichero que quiere abrir. Si el usuario introduce una ruta incorrecta puedes aprovechar la
excepción FileNotFoundError para mostrarle un error y que vuelva a introducir la ruta.
En la primera ejecución el nombre del fichero es el correcto y por eso muestra el mensaje
“Nombre y ruta correctos” en el segundo caso como falta la extensión del fichero no da
68
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
por buena la ruta y solicita que se introduzca de nuevo una ruta apropiada.
Este programa sencillo no terminará hasta que no introduzcas un nombre de fichero válido.
Cuando una función se llama así misma dentro de la función se denomina función recursiva
porque de forma reiterada se llama así misma.
Esta función que he puesto de ejemplo también se puede encontrar en el módulo os, que
se carga en memoria a través del comando import os
Otro ejemplo sería tratar de evitar una división entre 0 y detectar que si eso ocurre entonces
lo que quiere hacerse es poner el resultado a 0.
Otros ejemplos:
69
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.10. Ficheros y Entrada/Salida
Las principales formas que tiene Python para interactuar con el “exterior” del programa son:
1. Impresión por pantalla de información
2. Entrada de datos a través de un teclado
3. Lectura y/o escritura en ficheros
4. Lectura y/o escritura en bases de datos
1.10.1. Impresión por pantalla - print
La forma más simple de generar una salida es utilizando la función print, que hemos visto en
el apartado 1.3.2. Función print() recibe un número indeterminado de argumentos
separados por comas. El resultado de la ejecución de esta función es una salida estándar
por pantalla.
1.10.2. Introducción de datos por teclado – input()
La función principal para aceptar la entrada de datos que, por defecto, provienen del
teclado es la función input(). En Python 2.7 coexistían las funciones raw_input() e input()
pero para las versiones de Python 3.+ tan solo existe input(). El funcionamiento es sencillo.
Es necesario asignar la entrada de la función input a una variable. Se puede, de forma
opcional y recomendada, incluir un mensaje que indique que se espera del usuario que
introduzaca valor.
Aparece un cuadro de texto que nos permite introducir datos, por defecto de tipo texto.
Además, podemos incluir un mensaje para orientar al usuario sobre qué tipo de datos se
necesitas.
Entonces al introducir un nombre podemos escribir un mensaje.
70
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Por defecto el tipo de datos que recibe es str (o cadena) pero, como hemos visto en la
sección 1.4. Tipos y estructuras de datos podemos convertir esos datos en otro tipo de
datos.
Esto se puede hacer de dos maneras. La primera, consiste en obligar a que el input sea
transformado en otro dato en el mismo momento en que se solicita.
Uno de los problemas que genera es que si el usuario sin darse cuenta introduce una
cadena cuando el dato que se espera es un entero (y el usuario no sabe que se espera un
tipo entero) entonces el programa se va a romper y no va a ser posible recuperar el control.
71
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La segunda forma es recibir un dato de tipo cadena y tratar de hacer el cambio del tipo
de dato y si no se puede entonces indicar que el dato introducido no es correcto (¿Te suena
que algo así te haya ocurrido en otros programas?)
1.10.3. Apertura y cierre de Ficheros
Las operaciones de apertura y cierre de ficheros se realizan a través de lo que se conoce
como “stream” o flujo de datos. El flujo de datos se inicia con el comando open() y se
cierra con la función .close()
Las operaciones básicas de manipulación de ficheros son:
• Lectura, se indica con la letra ‘r’ y solo permite leer datos
• Escritura, se indica con la letra ’w’ y permite escribir y sobreescribir datos
• Añadir, se indica con la letra ‘a’ y permite añadir datos a un fichero
La indicación de si es apertura, escritura o añadir se realiza cuando se declara el “stream”
en la función open(nombre_archivo, operación). Si al flujo de datos o “stream” se lo
asignamos a una variable que se llame “file” entonces el código será más fácilmente
comprensible.
Una vez finalizadas las operaciones a realizar sobre el archivo entonces se debe cerrar la
conexión con el mismo. Si esto no se hace se puede llegar a generar problemas en el
fichero e incluso en el sistema operativo.
72
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La función open() abrirá el fichero indicado. Si no tiene éxisto se lanzará una excepción. Si
ha abierto el fichero entonces la variable file nos permitirá manipularlo.
El total de las tipo_acceso o tipo_operacion de que dispone Python son:
• r # solo lectura
• rb # solo lectura en modo binario
• r+ # lectura y escritura
• rb+ # lectura y escritura en modo binario
• w # solo escritura
• wb # solo lectura binaria
• w+ # lectura y escritura. Si el fichero existe se sobreescribe y sino se crea.
• wb+ # lectura y escritura en modo binario. Sobreescribe el archivo si existe
• a # abre el archivo para append o añadir al final del mismo
• ab # abre el archvio para añadir en modo binario
• a+ # abre el archivo para añadir y leer.
• ab+ # añadir y leer en modo binario.
Atributos de los objetos de tipo fichero:
• file.closed # Devuelve True si el fichero está cerrado
• file.mode # Devuelve el tipo de acceso
• file.name # Devuele el nombre del fichero
Vamos a comenzar con una operación de escritura para generar un fichero que
posteriormente vamos a leer:
Con este código se va a generar un fichero llamado "mi-primer-fichero.txt" y que se va
a guardar en la misma carpeta en la que tengas el notebook en el que estés trabajando.
Si tratas de leer un fichero que no existe entonces se genera una excepción (que veremos
en el 1.9. Excepciones
73
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Vamos a aprovechar el fichero que acabamos de crear para hablar de la APERTURA y
CIERRE de los ficheros.
La función open() sirve para abrir un fichero que, si no usamos la función close() quedará
abierto y según el tipo de apertura se realice podría quedar bloqueado y que cuando
quieras apagar el ordenador te salga el mensaje del sistema operativo diciendo que “un
fichero está en uso si apaga ahora podría perder el progreso en el mismo” pues bien es lo
que podría pasar.
La función open() se puede utilizar con diferentes opciones para que no sea necesario
añadir la línea de cierre del fichero.
Al hacer uso de la palabra with y de darle el alias “file” al stream lo que ocurre es que el
fichero permanecerá abierto para el código que esté identado dentro del with (es decir la
línea data=file.read() se cerrará una vez que finalice su ámbito y salga de la zona identada.
Al alcanzar el print(data) el fichero se habrá cerrado automáticamente.
ACONSEJO utilizar esta modalidad para que no sea necesario incluir la línea de cierre y que
aún así el fichero se guarde satisfactoramente.
La función close() de un objeto de tipo fichero cierra un fichero y dejan de poder realizarse
operaciones en él. El fichero también se cierra automáticamente si se le asigna a la variable
otro ficheros.
Se considera buenas prácticas hacer uso de la palabra reservada with cuando se trabaja
con ficheros. La ventaja es que no es necesario cerrar el fichero porque las instrucciones a
realizar en él quedan encapsuladas en la cláusula with.
A continuación, vamos a hacer una primera lectura del fichero para ver qué tiene:
Para ello creamos un objeto de tipo fichero al que llamamos fileopen, después usando la
función read(1) que únicamente lee un carácter y a continuación usamos un bucle while
para ir leyenco 1 a uno los caracteres del fichero
74
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Así mismo podríamos leer el fichero usando un bucle for de la siguiente manera:
En este caso creamos un bucle para que recorra cada línea del fichero al mismo tiempo
que lo abre y un nuevo bucle que recorre cada línea. En este caso es el propio bucle for el
que se encarga de cerrar el fichero por nosotros.
75
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.10.2. Lectura y escritura de ficheros
El objeto de tipo FileObjet proporciona dos funciones principales para la lectura y escritura
de datos en los ficheros. Las funciones son:
La función write(string) permite escribir cualquier cadena (que puede ser binaria) en un
archivos que debe estar abierto. Esta función no añade el salto de línea \n al final de la
cadena
Como verás la segunda línea incluye un \n que se usa para indicar un salto de línea para
que pase a la siguiente. Veamos cómo afecta esto a la lectura del fichero aprovechando
para ver cómo un ejemplo de read(), readline(), readlines().
read(size) Lee una cantidad de datos especificados por el valor de tamaño y los
devuelve como cadena o binario en función del modo especificado. Cuando no se
especifica el tamaña entonces se lee todo el fichero, lo cual se desaconseja porque cargar
en memoria todo el contenido del fichero (sin saber su tamaño) es arriesgado y python se
puede quedar sin memoria para procesarlo. La primera lectura hemos usado solo 1
carácter y la segunda solo los 10 primeros caracteres. Ten encuenta que ficheros que
ocupen 15GB no se pueden leer completos, sino que es necesario ir procesando los datos
poca a poco, lo que se conoce como “chunks”.
El tipo de la variable que se genera es de tipo str
76
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
readline() Lee una línea del fichero (hasta que encuentra un sálto de line \n de forma que
permite procesar el fichero línea a línea. Recuerda incluir \n en los ficheros que escribas allí
donde corresponda para que la lectura se pueda realizar línea a línea y no desvirtuar el
texto del fichero
readlines() Lee todo el fichero y lo almacena en una variable que posteriormente se
puede procesar por partes. El tipo de salida de esta función es una lista de str, es importante
saber el para saber cómo analizar la información posteriormente.
Veamos cómo nos enfrentaríamos al mismo problema según cómo se maneje la lectura
de datos en un ejemplo en el que queramos contar las veces que la letra a está presente
en cada linea del fichero:
Usando readline()
77
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Usando realines()
Por último, tenemos el método ‘a’ para hacer “append” o añadir datos a los que ya había.
En el siguiente ejemplo hecho lo siguiente: Primero, escribir una línea con usando append.
Segundo, leer el contenido del fichero con la nueva línea. Tercero, añadir otra línea nueva.
Cuarto, volver a leer el contenido para que se vea cómo se ha añadido otra línea más.
78
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si ahora volvemos a ejecutar el siguiente código:
Y vuelves a leer el fichero verás que ha borrado todo lo que tenía y a escrito de nuevo solo
3 líneas en el, que son con las que habíamos empezado.
79
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.11. Expresiones regulares
Las expresiones regulares son secuencias especiales de caracteres que ayudan a encontrar
otras cadenas o grupos de cadenas dentro de una cadena. (Imagina que quieres dentro
de un documento quieres buscar direcciones de email o teléfonos).
Esto se realiza importando el módulo re:
Las expresiones regulares no son algo nuevo de Python, lo que es nuevo es proporcionar
funciones específicas para el tratamiento de cadaenas utilizando ciertos patrones. Los
métodos más utilizados son:
• split()
• strip()
• in()
• find()
• count()
• replace()
• split(sep) # Parte una cadena cada vez que encuentra el separador sep y
devuelve una lista de cadenas.
• strip([caracteres]) # Elimina cualquier combinación de caraceres de una
cadena al comienzo y al final. Por defecto elimina espacios en blanco.
80
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• in # Sirve para buscar una subcadena en otra cadena
• find # Busca la posición de una cadena en una subcadena. El resultado es -1
cuando no existe en el texto
• count # Cuenta el número de ocurrencias de una subcadena en una cadena
81
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• replace(origen, destino) # sustituye la cadena origen por la cadena destino
Un ejemplo más completo
El bucle for del final podría también escribirse de otra forma:
82
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Crear expresiones regulares propias:
import re
El módulo re es el que nos permite definir expresiones regulares. Las expresiones regulares
son, en sí mismo, un lenguaje a través del cuál se definie las denominadas redex.
Require tres pasos:
• Definición de la expresión regular
• Compilar la expresión regular
• Usar la expresión regular
Rangos
Si queremos encontrar un número podemos utilizar la expresión regular [0123456789] o
podemos utilizar un rango. Un rango es una exprexión regular abreviada que se crea
escribiendo el primer carácter del rango, un guión y el último carácter del rango. Múltiples
rangos puden definirse de la misma clase de caracteres
Los ejemplos de rangos más comunes son: [0-9] para indicar que es un número, [a-z] para
indicar que es una letra minúscula y [A-Z] para indicar que es una mayúscula. También
puede definirse el rango [a-Z] que incluye todas las letras mayúsculas o minúsculas
>>> mayuscula = r'[A-Z]'
83
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Cuantificadores
Los cuantificadores se utilizan para buscar cero o más elementos. Por ejemplo 7 dígitos (útil
para buscar números de teléfono) o un @nombre para buscar identificadores de redes
sociales.
Los cuantificadores son:
? coincide con cero o con una ocurrencia del patrón. Es decir, hace que el patrón sea
opcional.
+ coincide con una o más ocurrencias del patrón.
* coincide con cero o más ocurrencias del patrón.
{x} coincide con exactamente x ocurrencias del patrón.
{x , y} coincide con al al menos x ocurrencias y no más de y ocurrencias del patrón. Si se
omite x el mínimo es cero y si se omite y no hay máximo.
84
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.12. Array multidimensionales (numpy)
El módulo numpy (Numerical Python) y Scipy proporcionan funciones y rutinas matemáticas
para la manipulación de array y matrices de datos numéricos de forma eficiente. El módulo
Scipy extiende la funcionalidad de numpy con una colección de algoritmos matemáticos
(minimización, transformada de Fourier, regresión, …)
El objeto principal del módulo numpy es ndarray (N-dimensional Array).
ndarray es un array multidimensional que permite realizar operaciones aritméticas sobre
vectores muy eficientes. Es una tabla de elementos (normalmente números), todos del
mismo tipo indexados por una tupla de enteros positivos. Las dimensiones se denominan
ejes o axes.
Numpy ofrece igualmente una colección de funciones matemáticas muy eficientes que
operan sobre vecotres (ndarrays) sin necesidad de escribir bucles for o while. Las
operaciones sobre los vectores son más eficientes y rápidas que las operaciones sobre listas.
Es buena práctica hacer uso de este módulo así:
El alias o namespace np nos permite utilizar las funciones del módulo utilizando np en lugar
de numpy.
Realizar operaciones sobre todos los elementos del array es tan fácil como utilizar el array
entero:
Propiedades de los ndarray:
ndarray.shape # Tupla con el tamaño en formato (filas, columnas)
ndarray.size # Numero total de elementos del array: filas * columnas
ndarray.dtype # Tipo de los elemensot del array.
ndarray.itemsize # Tamaño en bytes de cada elemento del array
ndarray.data # Buffer indicando dónde están los datos
85
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.12.1. Creación de ndarrays
La forma más sencilla de crare un array es utilizar la función array y una lista de objetos, que
pueden ser otros arrays.
Dado que todos los elementos de un array son el mismo tipo se garantiza que la eficacia
en las operaciones que se vayan a realizar con ellos.
Se puden crear arrays declarando el tipo de los elementos:
86
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Existen dos funciones llamadas zeros() y ones() que nos permiten crear arrays de ceros y
unos respectivamente. Tan solo hay que indicar el tamaño de las dimensiones del array
mediante una tupla o lista
Las funciones zeros_like y ones_like son análogas a zeros y ones pero no se indica la
dimensión, lo que se indica es el array del cual queremos copiar las dimensiones.
arange y linspace son funciones que también sirven para crear arrays mediante criterios
de secuencias de números. La función arange utiliza argumentos de tipo float y la
predicción del número total de elementos no es directa.
lispace, lo que precisamente hace es acotar el número de elementos totales, para lo
cual no se puede indicar el paso
87
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
rand, función para crear un nparry con números aleatorios. Es necesario importar el módulo
random, pues es en éste módulo en el que se encuentra la función rand. rand devuelve un
número aleatorio procedente de una distribución uniforme en el intervalo [0, 1]
1.12.2. Tipos de datos para ndarray
El módulo ndarray tiene tipos de datos especiales, creados para optimizas las operaciones.
El tipo de datos se puede determinar al crear un array o se puede modificar con
posterioridad.
Los tipos de datos incluidos en el módulo numpy son:
• int8 # byte (-128 a 127)
• int16 # entero (-32768 a 32767)
• int32 # entero (-2147483648 a 2147483647)
• int64 # entero (-9223372036854775808 a 9223372036854775807)
• uint8 # entero sin signo (0 a 255)
• uint16 # entero sin signo (0 a 65535)
• uint32 # entero sin signo (0 a 4294967295)
• uint64 # entero sin signo (0 a 18446744073709551615)
• float16 # float de precisión media, 1 bit signo, 5 bits exponente, 10 mantisa
• float32 # float de precisión sencilla, 1 bit signo, 8 bits exponente, 23 mantisa
• float64 # float de precisión doble, 1 bit signo, 11 bits exponente, 52 mantisa
Es importante escoger el tipo adecuado para los datos porque el tiempo de ejecución
puede variar en varios segundos (lo que en computación como millones).
88
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.12.3. Elementos de un array. Acceso y recorrido
Al trabajar con arrays es importante tener en cuenta la dimensión. El acceso a los elementos
se realiza de forma parecida al cómo se accede a los elementos de tipo secuencia (list,
tuple, str)
Es importante recordar que los índices en Python comienzan en 0, y que podemos acceder
al último índice usando -1, o al penúltimo usando -2 (así sucecisamente).
Es posible seleccionar partes de la haciendo “slicing” o particiones del array, tal y como se
hace en las listas y tuplas.
Importante destacar que existe una diferencia con el acceso a listas. En el acceso a las
particiones de un ndarry mediante la notación mencionada, hay que recordar que son
vistas del array original por lo tanto todo cambio hecho en una vista mediante asignación
modifica el array original.
Ejemplo
Este comportamiento evita problemas de memoria y numpy ha sido diseñado con la
intención de manejar grandes cantidades de datos.
Si el array tiene más de una dimensión el acceso se realiza indicando los índices separados
por comas.
89
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Es posible, pero no necesario recorrer los elementos de un nparry. Existen funciones que
permiten ejecutar operaciones en o con cada uno (o algunos) elementos del array. No
obstante, si fuera necesario utilizar un bucle for, ser haría así:
90
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
También se puede utilizar el atributo flat, que devuelve un objeto iterable con cada uno de
los elementos.
Uso de máscaras para la selección de partes de un array.
Otra forma de acceso a un array es mediante el uso de una máscara, que es un ndarray
de bool que actua como clasificador de los elementos que queremos seleccionar.
91
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Otra forma de seleccionar elementos consiste en aplicar condiciones al array.
1.12.4. Operaciones con arrays, matrices y escalares
Es posible aplicar operadores aritméticos a un array completo y que éstos se apliquen sobre
cada uno de los elementos. Eso si, para que la operación sea exitosa los arrays implicados
deben tener la misma dimensión. El resultado será un nuevo array cuyos datos dependen
de la operación realizada.
92
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
En el caso de arrays multidimensionales las operaciones se realizan elemento a elemento y
no es una multiplicación de matrices.
El producto de matrices se consigue usando la función np.dot() o creando objetos de tipo
matrix en lugar de nparray.
93
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Las matrices se crean de forma parecida da los arrays: np.matrix()
Funciones universales
Se pueden visualizar todas las operaciones incluidas en el módulo numpy haciendo uso del
comando dir(numpy) o dir(np) si se ha importado con un alias. Entre las funciones más
útiles y destacadas de este módulo destacan las siguientes:
• np.abs()
• np.maximum()
• np.eye(dim) #Devuelve un array 2-D de dimensión dim con ceros y la diagonal con
unos
94
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• np.greater_equal() #Compara dos arrays y devuelve un array de bool
Upcasting: Cuando dos arrays de distinto tipo operan entre sí, el array resultante de la
operación es del tipo con mayor precisión.
1.12.5. Cambiar la forma de un array
Es posible que debamos cambiar la forma de un array, ya sea para operar o para realizar
otro tipo de cálculo. El módulo numpy incluye las siguientes funciones que nos permite
manejar la disposición de los elementos y trabajar con las dimensiones:
• reshape # Sirve para redimensionar un array
95
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• ravel #Sirve para aplanar un array
• transpose(T) # Transpone un array
• vstack # Concatena arrays por filas
96
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• hstack # Concatena arrays por columnas
1.12.6. Copias y vistas
En el manejo de los arrays los valores de los mismos, por defecto, se comparten, no se
copian. Si se desea hacer una copia de los datos es necesario especificarlo. Es el mismo
concepto explicado en el paso de valores por referencia en las funciones.
a y b comparten la referencia a la localización de los datos. La modificación en b afecta a
a.
La función view permite crear un array cuyos datos son compartidos con otro, pero cuya
forma y acceso a los datos puede ser diferente.
97
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Como los datos son compartidos, la modificación de los datos afectará a los dos arrays
Si queremos evitar que esto ocurra podemos hacer una copia completa del array usando
la función np.copy()
98
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.12.7. Procesamiento de datos con Numpy
Los arrays son un objeto mucho más eficiente para el procesamiento de datos que las listas
porque utilizan vectorización, que es un tipo de procesado que evita los costosos bucles
(costosos en términos de uso de memoria ra). Las funciones de numpy están igualmente
optimizadas para utilizar vectorización.
1.12.7.1. Función where
Esta función es una versión vectorizada de la expresión ternaria v = x if cond else y que
hemos visto anteriormente.
Con esta función podemos asignar un valor si se comple la condición cond o un valor y si
no se cumple. Esta función se utiliza mucho para crear nuevos arrays a partir de datos de
otros.
Un ejemplo es dado un vector de números aleatorios poner a 0 los números negativos.
Al poner v como valor en caso de que no se cumpla la condición lo que se está indicando
es que tome el valor que ya tiene.
99
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.12.7.2. Métodos matemáticos y estadísticos
Entre la lista de funciones de numpy y scipy se pueden destacar las siguientes con fines
estadísticos (recuerda que escribiendo dir(numpy) o dir(scipy) puedes ver la lista
completa de atributos, funciones y variables que proporciona el módulo. Recuerda
importar el módulo para poder consultar esta lista
Funciones destacas:
• sum, suma de elementos
• cumsum, acumulado de la suma
• max y min, máximo y mínimo
• mean, media
• var y std, varianza y desviación estándar
Ejemplo del uso de las funciones
100
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
101
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13. Pandas (panel data set)
El nombre de pandas proviene de la abreviación de “PANel DAta Set”. En el apartado
anterior hemos visto el funcionamiento y manejo del módulo numpy para arrays y matrices
de datos numéricos. La libería pandas de Python es una estructura de datos de mayor nivel
y tiene herramientas diseñadas específicamente para conseguir hacer que el análisis de los
datos sea rápido y sencillo. Pandas está construido sobre numpy, esto significa que utiliza los
arrays de numpy.
Los objetos principales de esta librería son Series y DataFrame, que es una estructura que
permite el alamacenamiento de datos que en su origen se representa en forma tabular, (el
ejemplo que todos conocemos es una hoja de Excel o una tabla de una base de datos).
Si numpy está especialmente diseñado para trabajar con datos numéricos pandas está
especialmente diseñado para trabajar con:
• Datos heterogéneos
• Series Temporales
• Matrices
Otra de las características de pandas es que permite el tratamiento de datos perdidos o
nulos (missing data), operciones aritméticas y álgebra relacional.
Anaconda tiene definidos unos parámetros para la visualización de DataFrame con el
objetivo de hacerlos más visibles al ojo humano. De ahí que si se usa la función print() se
pierdan esos atributos.
102
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.1. Creación de un objeto de tipo Serie
El objeto Series es un tipo de array unidimensional que tiene asociado un array de índices
y que puede contener cualquier tipo de datos.
Imagen extraida de “Python for data science cheat sheets” de www.datacamp.com
Un objeto de tipo pandas.Series se crea así:
En el momento de la creación de un objeto de tipo series podemos especificar:
• data # Los datos a almacenar
• index # Sirve para establecer el índice de la serie y deben ser tipos que tengan
valores hash y no cambien durante su ciclo de vida. La longitud del array de índices
debe ser la misma que la longitud de los datos. Es un valor que se puede dejar vacío
y automáticamente pondrá índices con número enteros empezando por el 0
103
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
• dtype # Establece el tipo de los datos. Si se deja vacío el objeto lo infiere de los datos
• copy # cuando la entrada de datos provenga de otra serie copy=True indica que se
debe hacer una copia de los datos, sino los datos se pasarán por referencia.
Creación de una serie:
Creación de una Serie usando otra Serie:
1.13.2. Creación de un DataFrame
Existen múltiples formas de crear un DataFrame, entre otras cosas porque pandas
proporciona muchas funciones que generan un DataFrame a partir de diccionario, json,
csv, Excel, bases de datos, … (A continuación muestro una imagen extraida de
Datacamp.com)
104
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Imagen extraida de “Python for data science cheat sheets” de www.datacamp.com
La forma estándar es:
La documentación se encuentra en la web pandas
Adicionalmente se puede utilizar una de las siguientes funciones para crear un DataFrame:
• Desde un diccionario: DataFrame.from_dict
• Desde tuplas o arrays de datos: DataFrame.from_records
• Desde una secuencia: DataFrame.from_items
• Desde un csv: pandas.read_csv
Lo mejor es leer la documentación porque en ella está explicado y se incluyen ejemplos.
He aquí algunos ejemplos:
Se pueden crear desde listas de elementos, en este caso tuplas, y añadir información sobre
el nombre de las columnas
105
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si se establece el nombre de las columnas estas aparecerán nombradas. La longitud de la
lista de nombre de las columnas debe ser igual a la longitud del número de atributos de los
datos.
También se pueden crear desde diccionarios:
Si queremos indexar el DataFrame de forma personalizada podemos hacerlo agregando
información al atributo índice. Por ejemplo, el dni.
106
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Atributos importantes en un DataFrame:
• Índice
• Columnas
• Valores
107
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
El acceso a los atributos se hace utilizando un .<nombre_atributo> si fuera una función
llevaría paréntesis: .<nombre_función>()
1.13.3. Acceso a los datos (filas y columnas)
Una vez que tenemos un DataFrame podemos acceder a las columnas asi:
Si queremos acceder a más de una columna tendremos que usar notación de tipo lista. Es
decir, serán necesarios [] y dentro de los mismos un objeto tipo lista, que requiere de
corchetes si no se pasan en una variable
108
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
En el caso anterior la lista se define en el momento de hacer la selección, pero la lista con
el nombre de columnas a las que se desea acceder podría ser declarada en un paso
anterior y almacenada en una variable.
Accedes a las filas se puede utilizar diferentes métodos. Uno de ellos consiste en utilizar el
número de fila como si fuese una lista, pudiendo hacer uso de las características de acceso
a secuencias:
109
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
A continuación, hacemos uso de los números correspondientes a cada fila
.loc permite acceder a las filas utilizando el índice y se puede pasar también el nombre de
la columna
110
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
.iloc permite acceder a los datos de la fila cuyo que correspondería numéricament con
el índice especificado.
Adicionalmente se pueden utilizar también para el acceso del índice enteros como len(df)
que permite acceder a la última fila
Así el acceso a una celda concreta se puede hacer utilizando la nomenclatura
.loc[num_fila, num_col]
111
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.4. Borrar filas o columnas
La librerías pandas proporciona dos métodos distintos para borrar columnas
Método .pop(<nom_columna>) lo que hace es hacer “saltar” una columna fuera,
eliminándola del DataFrame que la contenía.
112
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
El método .drop() que permite elminar tanto filas como columnas. En el caso de querer
eliminar filas es necesario acceder a través del índice.
El argumento inplace=bool es muy importante. No es obligatorio usarlo, lo que hace que
haya tres casos especiales:
• Si se hace un drop sin utilizar el atributo inplace (significa que inplace= False) y no
se indica nada entonces la operación se ejecuta pero en el momento siguiente el
objeto recupera su estado inicial.
• Si se hace drop sin utilizar el atributo inplace (significa que inplace= False) y se
desea borrar una columna entonces es necesario asignar a un objeto el resultado
de quitar un elemento a un DataFrame.
• Si se hace un drop() pasando como argumento inplace = True entonces la
operación se realiza sobre el mismo objeto que la llama.
Veamos un ejemplo de su uso:
113
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Como ves hemos quitado un elemento usando drop() pero no ha sido borrado del
DataFrame de forma definitiva. Si queremos borrarlo de forma definitiva tenemos que hacer
una asignación de el DataFrame va a ser igual que sí mismo (DataFrame) pero sin la fila que
queremos quitar y para la que usamos .drop()
La otra opción para no tener que hacer esta reasignación es utilizar el parámetro inplace=
True, que justamente identifica como que lo que se quiere hacer el modificar el DataFrame
que se está manipulando.
114
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Como se podrá comprobar el atributo inplace se puede utilizar en muchas otras funciones
de pandas.
Del mismo modo se pueden borrar columnas:
115
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.5. Actualización de los datos
La actualización supone la modificación de los datos de una fila, una columna o una celda
concreta. El requisito es seleccionar la fila, columna o celda y asignarle el nuevo valor:
Volvemos a crear el DataFrame para ver la evolución:
Modificación del valor de una columna
116
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Modificación del valor de una fila
Modificación del valor de una celda
A través de la selección podemos realizar operaciones sobre las columnas, por ejemplo
calcular la media usando .mean(), el máximo usando .max(), el mínimo usando .min(). Las
funciones que podamos hacer sobre la columna dependerán el tipo de dato que contenga.
117
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Las operaciones en los DataFrames son vectorizadas, al igual que ocurria con las
operaciones en numpy. Esto significa que siempre será mucho más eficaz realizar una de
estas operaciones que realizar un bucle for para iterar por los valores de las filas y columnas.
118
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.6. Insertar filas o columnas
La librería de pandas incuye una función que es append() para este tipo de cosas
“other” es un parámetro puede ser de tipo DataFrame, Series o Diccionario o una lista de
alguno de los anteriores. El uso de ignore_index = True es para mantener la consistencia
de los índice en el DataFrame.
1.13.6.1. Añadir a un DataFrame una nueva fila
119
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si a este DataFrame le podemos añadir una nueva fila usando .append() con un diccionario
que tiene clave : valor en el que la clave debe corresponder con el nombre de la columna
y el valor el dato a insertar en la columna nueva:
En el caso de que una de las claves no exista en el DataFrame lo que sucederá es que
añadirá una nueva columna con el valor indicado y al resto le asignará valor nulo.
120
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.6.2. Añadir a un DataFrame una lista de Series
Es posible añadir una lista de Series en un DataFrame usando también la función append().
Como vemos el resultado es el muy parecido al caso anterior pero nos permite añadir más
de un dato al DataFrame.
121
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.6.3. Añadir a un DataFrame otro DataFrame
Esta función también se puede realizar usando un merge pero la hemos separado porque
el append() permite hacer añadir un DataFrame a otro siempre y cuando tengan la misma
estructura. En el caso del merge(), que veremos más adelante, las opciones son distintas.
122
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.6.4. Añadir a un DataFrame una fila usando un índice
Se puede insertar una nueva fila usando un índice que no exista en el DataFrame y
asignándole el valor que queramos añadir.
123
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.6.5. Añadir una columna a un DataFrame
Insertar una fila o una columna es tan sencillo como hacer una selección de una columna
que no exista en el DataFrame y asignarle valores. Es decir, buscar un índice que no esté en
el DataFrame y utilizar las funciones de Actualización de datos.
Ahora creamos una nueva columna y le damos valores correspondientes con los índices:
Es posible crear una nueva columna con un valor por defecto para todos los elementos.
En este caso importamos la librería numpy para utilizar el tipo de dato np.nan que
equivale a nulo.
124
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
125
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.7.1. Merge
La función merge permite combinar filas de dos o más DataFrames basándose en una o
varias claves (índices o columnas). Trabaja de forma muy eficiente y análogamente a las
bases de datos de tipo SQL. Existen tres tipos de merge:
• Interno (inner)
• Externo (outer)
• Cruzado (left, right)
La mejor manera de explicarlos es con una imagen:
Consulta la página con la documentación oficial para ampliar información al respecto:
https://pandas.pydata.org/pandas-docs/stable/merging.html
126
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
INNER JOIN:
Cada fila de la tabla df1 se combina con otro de la tabla df2 que cumpla con las
condiciones (igualdad o varias columnas)
El resultado de hacer un inner join es seleccionar aquellos elementos que coinciden en
ambos DataFrame
127
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
OUTER JOIN:
En este caso se seleccionan todos los elementos de ambos DataFrame pero se evita que
haya duplicados. En caso de haber duplicados selecciona solo un elemento.
LEFT JOIN:
Este tipo de unión busca coincidencias de los elementos del DataFrame de la izquierda (left
o el primero en el merge) para rellenar datos con los que coincidan en el DataFrame de la
derecha (right o segundo el merge)
128
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.8. Indices jerárquicos
Pandas permite tener varios niveles de índices (o índicer jerárquicos) en cualquiera de los
ejes. Los índices jerárquicos sirve como agrupaciones de elementos que guardan
información en común.
A continuación, se muestra un ejemplo en el que:
129
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La ventaja es que podemos hacer selección por múltiples índices para encontrar por años
y número de dorsal el número de goles:
Podemos crear y deshacer los índices utilizando la función stack() y unstack().
unstack() hace que el índice más interno pase a ser columna
stack() proporciona una representación de los datos de forma que los índices de la tabla
original pasan a ser índices de primer nivel. Las columans pasan a ser índices de segundo
nivel y los datos se representan en una única columna
130
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.9. Importar y exportar datos
El análisis de datos requiere leer fuentes externas, ya sean más grandes o más pequeñas es
necesario tener listos los datos para poder empezar a trabajar con ellos. Sin importar si se va
a proceder a limpiar las cadenas, poner fechas en el formato apropiado o hacer cálculos
los datos deben venir de alguna fuente de datos.
La librería pandas incorpora funciones para leer datos de diferentes formatos: csv, txt, Excel,
HDFS, sql, json, html, …
Si vamos a la documentación de pandas para algunas de estas librerías podemos ver lo
siguiente:
pandas.read_csv Lee ficheros con campos generalmente separados por comas,
pandas.read_excel lee documentos de Excel
131
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
pandas.read_table Lee ficheros cuyos atributos están generalmente separados
por tabuladores (\t)
La lista de argumentos es muy larga y leyendo la documentación suele quedar bastante
explicado, no obstante los argumentos más importantes son:
path
Este argumento es el que sirve para indicar dónde se encuentra el archivo. Se ha
establecido como una buena práctica que los ficheros de análisis de datos estén
organizados de la siguiente manera
/carpeta_principal
----/data
--------/source.csv
----/file1.py
----/file2.py
…
Esto significa que cada carpeta de proyecto tiene, a su vez, una carpeta con los ficheros
que contienen las fuentes de datos que pueden ser ficheros csv, txt, .. para separ el análisis
del almacenamiento de datos.
Teniendo en cuenta la notación tanto de Windows como de Unix en el que el directorio
donde se encuentra un archivo se puede denominar con un . generalmente la asignación
será:
132
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Ejemplo:
Esta es mi carpeta con los diferentes notebooks:
Así que en la carpeta campus_big_data tengo un fichero que se llama
“my_players_info_2.csv” que tiene información de jugadores.
En la carpeta llamada “data” que está en la misma ruta tengo otro archivo que se llama
“my_players_info_1.csv” que tiene datos diferentes.
133
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Sep
Este argumento sirve para especificar cuál es el separador (si no es el por defecto) de los
datos contenidos en el fichero especificado:
sep=”;” sep=’,’ sep=’,\t’
chunk_size
Cuando hay archivos muy grandes no es posible cargarlos todos en memoria, puesto esto
causaría fallos de memoria en el ordenador y el proceso en ejecución se pararía.
Este argumento recibe un número entero que identifica el tamaño del “trozo” del fichero
que va a recuperar.
chunksize : int, default None
Return TextFileReader object for iteration. See the IO Tools docs for more
information on iterator and chunksize.
134
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Importando datos al entorno de trabajo:
Usando la estructura de carpetas anteriormente mencionada ahora puedo leer ambos
ficheros usando, por ejemplo, pd.read_csv
Con esta función abre, lee el fichero, lo carga en memoria y cierra el fichero para que
puedas manejarlo en memoria.
135
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Exportar datos
Al igual que se pueden leer datos con las funciones mencioandas, también se pueden
guardar datos con funciones similares: to_csv, to_excel, to_json, …
Ejemplo:
136
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.10. Aplicación de funciones
La librería pandas está construida sobre la librería Numpy e incorpora, análogamente,
funciones para aplicar a todas las filas de un DataFrame o una Serie sin necesidad de utilizar
bucles.
Las opciones que ofrece pandas son:
• apply: Es una función aplicable a Series (se aplica a filas o columnas de un
DataFrame)
• applymap Función que se aplica elemento a elemento de un DataFrame
• map, función que se aplica elemento a elemento de un DataFrame.
Por ejemplo dado un DataFrame con una columna País y teniendo un diccionario,
podemos crear una nueva columna con nacionalidad.
137
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La función map va recorriendo todas las filas de la columna Pais, que es la seleccionada, y
en base al la clave devuelve un valor.
Podemos añadir una columna que sea la edad más 10
138
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La función map recorre todas las filas, que están representadas por la variable x, devuelve
la suma de x +10 que es lo que se almacena en la columna ‘edad+10’
Podemos modificar una misma columna pasando todas las letas a minúsculas
El recorrido de las columnas se simplifica gracias al uso de estas funciones.
139
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.13.11. Funciones y atributos básicos para manejar un
DataFrame:
df = pd.read_csv('file.csv', header=None, sep=',') # carga en un df la info de un
archivo
df.to_csv("savemydataframe.csv") # guarda un df en un archivo csv
df = pd.read_excel('myfile.xlsx') # carga en un df los datos de un excel
df.to_excel("savemyexcel.xlsx", sheet_name="Hoja1") # guarda un df en un
excel
df.drop('columnname', inplace=True) # elimina una fila o columna
df.shape # describe el tamaño altoxancho de un DataFrame
df.index # describe los indeces de un DataFrame
df.columns # describe las columnas de un DataFrame
df.info # Muestra información básica de un DataFrame
df.count() # Cuenta en número de valores no nulos
df.sum() # Suma los valores
df.cumsum() # Guarda valor acumulado
df.min() / df.max() # Valore smínimos y máximo
df.describe() # Genera información estadística básica
df.mean() # Calcula la media
df.median() # Calcula la mediana
df.apply(f) # aplica la función f a todas las filas
df.applymap(f) # aplica una función elemento a elemento (filas y columnas)
Se recomienda buscar en internet el término “Pandas Cheat Sheet” porque contiene un
resumen más detallado de las funciones más utilizadas.
140
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14. Ejercicios guiados
1.14.0. Requisitos
En Python las librerías cambian y avanzan rápidamente. Es necesario mantener una
consistencia en las versiones de las mismas para asegurar la estabilidad y la vida de un
proyecto. En este sentido vamos a proceder a crear el entorno virtual necesario para
ejecutar los diferentes ejercicios. Es necesario haber instalado conda en el ordenador (En el
material complementario puedes encontrar los pasos para realizar la instalación. )
1.14.0.1. Creación del entorno virtual
En Windows abre el programa “cmd”, en Linux o Mac abre el programa “Terminal”.
Ambos casos abren los programas por defecto para ejecutar acciones a travé de línea
de comandos.
Al abrir el programa debería salir algo así, indicando la ruta donde estás.
A continuación ejecuta
C:\Users\jaime.lazcano> conda create --name venvcampusbigdata python==3.6.6
para crear el entorno virtual. Te hará la siguiente pregunta (a la que debes contestar que
si)
Te preguntará lo siguiente:
Solving environment: done
## Package Plan ##
environment location: C:\ProgramData\Anaconda2\envs\venvcampusbigdata
added / updated specs:
- python==3.6.6
The following packages will be downloaded:
package | build
---------------------------|-----------------
setuptools-40.6.3 | py36_0 585 KB conda-forge
141
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
142
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
The following NEW packages will be INSTALLED:
certifi: 2018.11.29-py36_1000 conda-forge
pip: 18.1-py36_1000 conda-forge
python: 3.6.6-he025d50_0 conda-forge
setuptools: 40.6.3-py36_0 conda-forge
vc: 14-0 conda-forge
vs2015_runtime: 14.0.25420-0 conda-forge
wheel: 0.32.3-py36_0 conda-forge
wincertstore: 0.2-py36_1002 conda-forge
Proceed ([y]/n)? y
Pasa al siguiente punto para activar el entorno virtual
1.14.0.1. Activar el entorno virtual
En este momento tienes el entorno virtual creado pero no estas haciendo uso de las
librerías que hay en él, lo cual se consigue activándolo.
C:\Users\jaime.lazcano> conda activate venvcampusbigdata
Ahora si ejecutas las siguientes ordenes podrás ver los diferentes módulos y librerías
instalados: (venvcampusbigdata) C:\Users\jaime.lazcano> conda list
(venvcampusbigdata) C:\Users\jaime.lazcano> pip freeze
Conda y pip tienen diferencias que poco a poco se van resolviendo. Estas diferencias
provienen de la fuente de los repositorios de las librerías. Generalente las líbrerías y módulos
se instala con conda install <nombremodulo> y en otras ocasiones se usará pip install
<nombremodulo> según corresponda.
1.14.0.1. Instalar los paquetes necesarios
El objetivo de los entornos virtuales es mantener un índice de los paquetes a actualizar. Los
utilizados en los ejericios son los siguientes (se encuentran en el fichero
requirementsejercicios.txt y también en el fichero environmentejercicios.yml
asn1crypto==0.24.0
attrs==18.2.0
backports.functools-lru-cache==1.5
beautifulsoup4==4.6.3
bokeh==1.0.1
certifi==2018.10.15
cffi==1.11.5
chardet==3.0.4
cryptography==2.3.1
cryptography-vectors==2.3.1
cycler==0.10.0
decorator==4.3.0
html5lib==1.0.1
httplib2==0.12.0
143
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
idna==2.7
ipython-genutils==0.2.0
Jinja2==2.10
jsonschema==3.0.0a3
jupyter-core==4.4.0
kiwisolver==1.0.1
lxml==4.2.3
MarkupSafe==1.1.0
matplotlib==2.1.0
mkl-fft==1.0.6
mkl-random==1.0.2
nbformat==4.4.0
numpy==1.15.4
oauth2==1.9.0.post1
olefile==0.46
packaging==18.0
pandas==0.23.4
patsy==0.5.1
Pillow==4.3.0
plotly==3.4.2
pycparser==2.19
pymongo==3.7.1
pyOpenSSL==18.0.0
pyparsing==2.3.0
pyrsistent==0.14.7
PySocks==1.6.8
python-dateutil==2.7.5
pytz==2018.7
PyYAML==3.13
requests==2.20.1
retrying==1.3.3
scikit-learn==0.20.0
scipy==1.1.0
seaborn==0.9.0
six==1.11.0
statsmodels==0.9.0
tornado==5.1.1
traitlets==4.3.2
urllib3==1.23
webencodings==0.5.1
win-inet-pton==1.0.1
wincertstore==0.2
Se pueden instalar de dos formas: Usando pip o usando conda.
Instalación mediante Pip
El archivo requirements se puede utilizar para instalar los paquetes necesarios. Para ello
ejecuta:
(venvcampusbigdata) C:\Users\jaime.lazcano> pip install –r requirementsejercicios.txt
Este proceso irá instalando cada uno de los paquetes. Si alguna falla prueba a utilizar:
(venvcampusbigdata) C:\Users\jaime.lazcano> pip install <nombremodulo>==<versión>
(venvcampusbigdata) C:\Users\jaime.lazcano> pip install pandas==0.23.4
144
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
145
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Instalación mediante conda
Esta instalación suele dar más problemas pero si funciona es más cómoda.
Abre el archivo environmentejercicios.yml, en la última fila podrás encontrar la ruta en la que
se va a instalar. Asegúrate de que no existe la ruta. En el archivo proporcionado la ruta es:
prefix: C:\ProgramData\Anaconda2\envs\venvcampusbigdata
Ejecuta ahora el comando que te crea un clon del entorno virtual utilizando el archivo.
Asegurate de estar situado en la misma carpeta en la que está el archivo.
(venvcampusbigdata) C:\Users\jaime.lazcano> conda env créate –f environmentejercicios.yml
146
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.1. Ejercicio 1: Creación de tu propio dataset
1.14.1.1. Introducción y Objetivo
Este módulo no consiste en la obtención de datos pero ayuda a comprender algunos
procedimientos y sobretodo a practicar en el uso de listas, diccionarios y listas de
diccionarios, cuyo manejo es fundamental para el análisis de datos.
El análisis, por definición, está limitado a los datos que se pueden conseguir. Es vital poder
construirse un dataset puesto que de lo contrario se está limitado a medir, analizar y
cuantificar lo que otros te permitan de la información que te dejen usar. Es verdad que a la
hora de enfrentarse a un conjunto de datos todo el mundo tiene una forma distinta de
hacerlo pero siempre será mejor poder construir las herramientas que necesitas a medida
que utilizar las de otros, entre otras cosas porque tendrás la posibilidad de decidir qué datos
quieres o incluso añadir datos posteriormente.
Acceder a las páginas de Wikipedia de algunos jugadores de la liga española, obtener la
información que tenga Wikipedia de ellos y almacenar esa información en un csv.
El ejercicio hace lo siguiente:
• Abrir un fichero txt que contiene urls de jugadores de la liga española de fútbol.
• Crear una lista de urls de Wikipedia sobre jugadores de futbol.
• Crear una lista de diccionarios que servirá para ir guardando la información de cada
jugador.
• Acceder a cada una de estas urls de jugadores (almacenadas en el archivo)
utilizando request para descargar la información.
• Se utilizan la caputura de excepciones.
• Utilizar Beautifulsoup para “parsear”, es decir, organizar jerárquicamente la
información lo que permite extraer partes de la misma fácilmente.
• De entre toda la información descargada se selecciona la relativa a un jugador de
futbol y se guarda en un diccionario.
• Se actualiza la información en la lista de diccionarios de jugadores de futbol
• Se crea un pandas.DataFrame que con la infomación recuperada de los jugadores
• Se guarda el DataFrame en un archivo () para su posterior limpieza y análisis. Que se
realizará en ejercicios posteriores.
147
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.1.3. Código comentado
El primer paso en todo script de python es comenzar con la importación de las librerías y
módulos necesarios para la ejecución del script. El lenguaje permite hacer la importación
de los datos en cualquier momento pero una de las "buenas" prácticas de python
(redactadas en la guía de estilo de python) indica que la importación de las librerías o
módulos se realizará siempre en la cabecera del documento y antes de ningúna
instrucción.
Nos permite hacer solicitudes http y traer la información de una url a nuestro ordenador
import requests
La información descargada de una web viene en formato web, es decir, incluye todos los
elementos del código html como son <header>, <table>, <link>, <p>, ... esta librería nos
permite "parsear" u organizar esa información para que podamos acceder a ella más
fácilmente.
from bs4 import BeautifulSoup
Librería básica que almacena la información de forma tabular. Es una de las librerías básicas
de python para manipular y analizar la información.
import pandas as pd
# Estos parámetros nos permiten selecionar cuántas filas y columnas visualizar
# pd.set_option('display.max_rows', 1000)
# pd.set_option('display.max_columns', 12)
Esta librería, ya preinstalada, nos permite hacer "dormir"o hacer esperar al programa.
from time import sleep
Librería utilizada para "dormir" o hacer esperar al programa. Si se realizan muchas solicitudes
en el mismo segundo a un servidor éste puede detectar que estás tratando de dañarlo y
bloquear preventivamente tu ip. Si se espera un segundo cada vez que haces una solicitud
no deberías tener problemas.
Nota: No todas las páginas "aceptan" webscrapping o scrapping. Lee las condicionesde
uso de cada página antes de recabar su información con esta técnica.
Con motivo de realizar el ejemplo vamos a utilizar el fichero url_demo.txt que contiene una
muestra pequeña. Si lo deseas puedes probar a utilizar el fichero
urljugadoresprimeradivision.txt que contiene una lista más detallada y que puede tener
algunos fallos.
Ejecuta el programa usando url_demo.txt al menos una vez antes de cambiar de fichero.
148
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Establecemos la ruta y el nombre del fichero.
path = "./data/url_demo.txt"
# OJO si utilizas el siguiente archivo ten en cuenta que la ejecución puede
# durar entre 5 y 10 minutos. Te recomiendo que primero ejecutes el demo y
# después, si quieres y funciona correctamente ejecutes el completo
# path = "./data/urljugadoresligaespañola.txt"
Creamos una lista vacía en la que almacenar la información que vamos a extraer.
lineas_fichero = [ ] # Son los corchetes los que indican que es una lista
A modo de ejemplo, usa la función type() para ver el tipo de una variable.
print("La variable lineas_fichero es de tipo "+
"{0}".format(type(lineas_fichero)))
Abrimos y leemos el fichero en modo solo lectura
with open(path,'r') as file:
# Leemos el fichero y lo cargamos en memoria
lineas_fichero = file.readlines()
El resultado debería ser algo así:
El resultado debería ser algo así:
['https://es.wikipedia.org/wiki/Aritz_Aduriz, Athletic Club',
'https://es.wikipedia.org/wiki/Sergio_%C3%81lvarez_Conde, Real Celta Vigo',
'https://es.wikipedia.org/wiki/Nordin_Amrabat, C.D.Leganes',
'https://es.wikipedia.org/wiki/Pau_L%C3%B3pez, R.C.D. Español'
]
Como puedes ver el fichero contiene una url seguida del equipo del jugador. En este
ejercicio el equipo lo obtendremos directamente de la wikipedia, por eso solo utilizaremos
la url.
Antes de continuar es importante que accedas a una de estas urls para que veas cómo
está dispuesto el contenido de la misma. Haciendo click derecho en la foto del jugador y
seleccionando: En Firefox "Inspeccionar elemento",en Chrome “Inspeccionar” puedes ver
el código html que hay detrás de la página. Mueve el ratón por el código hasta que
encuentres la línea:
149
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
<table class="infobox" style="width:22.7em; line-height: 1.4em; text-align:left;
padding:.23em;">
En el interior de este elemento denominado "infobox" se encuentra toda la información del
jugador repartida en filas (<tr>) y dentro de las filas en celdas (<td>) No todas las filas tienen
dos celdas. en este ejercicio solo nos quedaremos con las filas de cuyo número de celdas
sea igual o mayor a 2
Creamos una lista vacía para almacenar la información de todos los jugadores cuyas url
vamos a leer
lista_jugadores = []
Vamos a recorrer cada linea del fichero (ya en memoria) para extraer la info.
for linea in lineas_fichero:
Creamos un diccionario vacío en el que vamos a almacenar la información parcial del
jugador.
jugador = {}
Las líneas del fichero utilizan una coma , para separar el link de la url del nombre del equipo.
Si utilizamos esa coma para separar cada línea el resultado es que el primer elemento (en
python elemento 0) es la url y el segundo elemento, con índice 1 el nombre del equipo. En
nuestro caso solo nos interesa la url
url = linea.split(',')[0]
# Solicitamos la información de esta url
req = requests.get(url)
El acceso a una url puede fallar así que confirmamos si ha ido bien antes de continuar. De
lo contrario podríamos encontrarnos con una excepción.
150
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
if req.ok: # Si es True es que el acceso ha ido bien
151
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Prepararnos para continuar el proceso si una url no funciona encapsulando el código en un try: <instrucciones> exception : <instrucciones>
try:
Si ha ido bien entonces le decimos a BeautifulSoup que parsee la info utilizando lxml como
método de parseo
soup = BeautifulSoup(req.text, "lxml")
En soup está la información de toda la página. El nombre del jugador en el html tiene como
característica que aparece como firstHeading así que vamos a pedirle a soup que lo
busque.
jugador['nombre'] = soup.find(class_='firstHeading').text
Hacemos la misma búsqueda para la tabla infobox cuyas características más importantes
son que: es una tabla con class='infobox'
table_info = soup.find('table', class_='infobox')
A continuación buscamos dentro de la tabla_infobox todas las filas y recorremos buscando
las filas con longitud = 2, que son las que tienen dos celdas una con la descripcion de la
información y otra con a propia información.
for row in table_info.find_all('tr'):
# Si la fila tiene dos celdas
if len(row) == 2:
Podría haber algún error en la adquisición de atributos, para no quedarnos sin toda la
información del jugador añadimos un nuevo try que permita almacenar los datos que no
hayan dado.
try:
Separamos y limpiamos datos de las celdas. La información está en la celda th y en la celda
td, de cada una extraemos el texto que limpiamos de forma apropiada. La salida de el
campo text la introducimos en la siguiente función: replace para que sustituya los saltos de
carácter “\n” por espacios en blanco. La salida de ésta función se la pasamos a strip que
elimina los caracteres en blanco de ambos lados.
celda_descrip = row.th.text.replace("\n", " ").strip()
celda_datos = row.td.text.replace("\n", " ").strip()
Volvemos a realizar las mimas operaciones pero con caracteres no convencionales y que
se usan a menudo en las páginas web.
celda_descrip = celda_descrip.replace(u'\xa0', u' ').strip()
celda_datos = celda_datos.replace(u'\xa0',u' ').strip()
celda_descrip = celda_descrip.replace(u'\xc0',u' ').strip()
celda_datos = celda_datos.replace(u'\xc0', u' ').strip()
La información la almacenamos en el diccionario jugador, que tiene como clave la celda
152
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
descripción y como valor la celda con los datos.
Recuerda que un diccionario es un objeto (clave, valor) al que se accede mediante el
nombre_diccionario[clave] (si se añade un = entonces se le asigna un valor)
jugador[celda_descrip] = celda_datos
Cerramos el try de Atributos que pudieron dar error:
except AttributeError:
Si alguno de los atributos surge algún error inesperado lo dejamos y pasamos al siguiente
atributo pass
Es el momento de añadir el jugador a la lista de jugadores, que es, a su vez, una lista de
diccionarios.
lista_jugadores.append(jugador)
Cerramos la excepción más grande de errores, que nos haría no poder almacenar los datos
de un jugador
except Exception:
# Si en algún paso algo fue mal sacamos el error por pantalla y
# seguimos la ejecución del programa
print("Hubo un problema con esta url {0}, pero he continuado con el "
"proceso de extracción de datos ".format(url))
Pausamos durante 0.8 segundos la ejecución del programa
sleep(0.8) # Usado para no hacer demasiadas peticiones seguidas
Podemos utilizar la lista de diccionarios para crear un DataFrame
df = pd.DataFrame.from_dict(lista_jugadores)
Guardamos los datos del DataFrame en un archivo seleccionando como separador el
símbolo de ; e indicando que no hay un índice predefinido.
OJO el siguiente paso está puesto para crear de cero el archivo. Si ya existe entonces se
borra y se vuelve a crear. Pon atención y decide si cambiar el nombre del archivo para
evitar la sobreescitura.
df.to_csv('./data/my_players_info_demo.csv', sep=";", index=False)
En el siguiente ejercicio haremos uso de la información recopilada en un proceso de
limpieza de los datos.
153
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.1.4. Código sin comentarios
import requests
from bs4 import BeautifulSoup
import pandas as pd
pd.set_option('display.max_rows', 1000)
pd.set_option('display.max_columns', 12)
from time import sleep
# Establecemos la ruta y el nombre del fichero
path = "./data/url_demo.txt"
# opcional
# path = os.path.join(".","data","urljugadoresligaespañola.txt")
lineas_fichero = [ ]
with open(path,'r') as file:
# Leemos el fichero y lo cargamos en memoria
lineas_fichero = file.readlines()
lista_jugadores = []
for linea in lineas_fichero:
jugador = {}
url = linea.split(',')[0]
print(url)
req = requests.get(url)
if req.ok: # El acceso a una url puede fallar.
try:
soup = BeautifulSoup(req.text, "lxml")
jugador['nombre'] = soup.find(class_='firstHeading').get_text()
table_info = soup.find('table', class_='infobox')
for row in table_info.find_all('tr'):
if len(row) == 2:
try:
celda_descrip = row.th.text.replace("\n", " ").strip()
celda_datos = row.td.text.replace("\n", " ").strip()
celda_descrip = celda_descrip.replace(u'\xa0', u' ').strip()
celda_datos = celda_datos.replace(u'\xa0', u' ').strip()
celda_descrip = celda_descrip.replace(u'\xc0',u' ').strip()
celda_datos = celda_datos.replace(u'\xc0',u' ').strip()
jugador[str(celda_descrip)] = str(celda_datos)
except AttributeError:
# Si alguno de los atributos surge algún error inesperado
# lo dejamos y pasamos al siguiente atributo
pass
print(jugador)
lista_jugadores.append(jugador)
except Exception:
print("Hubo un problema con esta url {0}, pero he continuado con el "
"proceso de extracción de datos ".format(url))
sleep(0.8) # Usado para no hacer demasiadas peticiones seguidas
df = pd.DataFrame.from_dict(lista_jugadores)
154
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
print(df.info())
print(df.sample(3))
# OJO el siguiente paso está puesto para crear de cero el archivo. Si ya existe
# entonces se borra y se vuelve a crear. Pon atención y decide si cambiar el
# nombre del archivo para evitar la sobreescitura
df.to_csv('./data/my_players_info_demo.csv', sep=";", index=False)
155
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.2. Ejercicio 2: Limpiar el Dataset
En el ejercicio anterior hemos generado un dataset a partir de información de internet, en
este caso Wikipedia.
1.14.2.1. Introducción
En el ejercicio anterior hemos generado un dataset a partir de información de internet, en
este caso Wikipedia. Los datos obtenidos a través de internet incluyen caracteres “extraños”
o no convencionales que se usan en las páginas web para mostrar elementos caracteres
con tíldes, y otros signos de puntuación. Los datos “no estructurados” se denominan así
porque no todos tienen la misma forma, formato ni están en las mismas posiciones. El paso
de datos “no estructurados” a “estructurados” requiere esfuerzo y muchas iteraciones sobre
los datos, que es precisamente lo que se propone este ejercicio.
Utilizando el archivo de información del ejercicio anterior los datos se manipulan y se
gestionan para conseguir darles una forma que se pueda analizar fácilmente, una forma
comprensible y estructurada.
1.14.2.2. Objetivo
Cargar en memoria la información de un conjunto de datos y aprender a manejar los
DataFrames para poder crear nuevos datos y mejorar los actuales
El ejercicio hace lo siguiente:
• Carga un fichero con datos de jugadores de futbol
• Analiza la estructura de cada atributo (o columna) y le proporciona un formato
estándar y común.
• Crear columnas en un DataFrame, ya sea vacías o a partir de información de otras
columnas.
• Utilizar la función apply sobre columnas.
• Usar la función map en una columna del DataFrame.
• Manejar expresiones regulares sencillas.
• Entender el funcionamiento y utilidad de funciones básicas como son: .info(), .describe(), .head(), .sample(), .tail()
• Filtrar DataFrames conforme a condiciones.
• Aprender a aplica modificaciones de tipos de datos usando pd.to_numeric().
156
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.2.3. Código comentado
El primer paso es cargar las librerías utilizadas en el durante el ejercicio.
import re
import pandas as pd
# Determinar el número de filas que se visualizan al hacer print
pd.set_option('display.max_rows', 1000)
# Determinar el número de columnas que se visualizan al hacer print
pd.set_option('display.max_columns', 12)
Establecemos una variable que sirva para almacenar la ruta y nombre del archivo:
path = './data/my_players_info.csv'
En este caso vamos a nombrar las columnas a la vez que abrimos el archivo. Podemos
hacerlo creando una lista de nombres o asignando a la variable names de la función
read_csv la lista con el nombre a asignar a cada columna. Vamos a utilizar una lista.
nombre_columnas = ['GOLES','ALTURA','APODO','CLUB','DEBUT','DEBUTDEPORTIVO',
'DEPORTES','DORSAL','ENTRENADOR','GOLESCLUBES','LIGA',
'NACIMIENTO','NACIONALIDAD','NOMBRENACIMIENTO',
'NOMBRECOMPLETO', 'PAREJA','PARTIDOS','PARTIDOGOLES','PAIS',
'PESO','POSICION','RETIRADADEPORTIVA','SELECCION','NOMBRE'
]
df = pd.read_csv(path, sep=";", names=nombre_columnas, skiprows =1)
Veamos algunos datos que describan al DataFrame, datos que nos permitan saber cuánta
información hay o cómo podemos leerla.
print("El DataFrame tiene {0} filas y {1} columnas\n".format(len(df),
len(df.columns)))
# El DataFrame tiene 478 filas y 24 columnas
Si queremos ver el detalle de la información de cada columna lo más fácil es utilizar la
función pandas.info()
print("Información de cada columna:", df.info())
# Revisemos esta información detalladamente.
# GOLES 2 non-null object
# ALTURA 468 non-null object
# APODO 157 non-null object
# CLUB 473 non-null object
# DEBUT 148 non-null object
# DEBUTDEPORTIVO 471 non-null object
# DEPORTES 478 non-null object
# DORSAL 310 non-null object
# ENTRENADOR 11 non-null object
# GOLESCLUBES 215 non-null object
157
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# LIGA 400 non-null object
# NACIMIENTO 478 non-null object
# NACIONALIDAD 375 non-null object
# NOMBRENACIMIENTO 30 non-null object
# NOMBRECOMPLETO 390 non-null object
# PAREJA 13 non-null object
# PARTIDOS 33 non-null object
# PARTIDOGOLES 205 non-null object
# PAIS 179 non-null object
# PESO 274 non-null object
# POSICION 478 non-null object
# RETIRADADEPORTIVA 4 non-null object
# SELECCION 249 non-null object
# NOMBRE 478 non-null object
El resultado de esta función es una lista con el nombre de cada columna, el número de
campos rellenos para esa columna y el tipo de datos que tiene. Se puede ver que ningún
dato tiene ningún tipo específico. Iremos poco a poco poniendo el tipo a los atributos.
El primer paso que vamos a tomar es eliminar las columnas o atributos de los datos que no
aporte información (precisamente porque casi no tienen información almacenada). Así el
campo GOLES, que solo tiene rellenos dos datos frente al total de 478 jugadores será uno
de los que eliminemos. Otro campo a eliminar es la RETIRADADEPORTIVA, que contiene
información de 4 jugadores.
Eliminar una columna se puede realizar de dos formas:
df = df.drop(columns='GOLES')
df.drop(columns='ENTRENADOR', inplace=True)
La primera lo que hace es asignar a un DataFrame el resultado de quitar a un DataFrame
una columna. Podría hacerse asignarse a un DataFrame distinto pero al asignárselo al
mismo DataFrame lo que hacemos es “borrar” la versión anterior y dejarle sin una
columna.
La segunda forma es utilizar la variable inplace=True, que lo que hace es indicar al
DataFrame que debe ejecutar la operación “sobre sí mismo”. El resultado de ambas
operaciones es el mismo, un DataFrame con una columna menos.
Adicionalmente vamos a eliminar columnas, unas porque no aportan valor y otras para
dejarte a ti mismo descubrir e investigar cómo llevar a cabo las operaciones sobre cada
una de ellas.
df.drop(columns='NOMBRENACIMIENTO', inplace=True)
df.drop(columns='PAREJA', inplace=True)
df.drop(columns='PARTIDOS', inplace=True)
df.drop(columns='RETIRADADEPORTIVA', inplace=True)
df.drop(columns='APODO', inplace=True)
df.drop(columns='NOMBRECOMPLETO', inplace=True)
df.drop(columns='GOLESCLUBES', inplace=True)
df.drop(columns='PARTIDOGOLES', inplace=True)
df.drop(columns='SELECCION', inplace=True)
158
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
df.drop(columns='DEPORTES', inplace=True)
df.drop(columns='LIGA', inplace=True)
159
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Así la información disponible es:
print(df.info())
# Data columns (total 11 columns):
# ALTURA 467 non-null object
# CLUB 472 non-null object
# DEBUT 147 non-null object
# DEBUTDEPORTIVO 470 non-null object
# DORSAL 309 non-null object
# NACIMIENTO 478 non-null object
# NACIONALIDAD 374 non-null object
# PAIS 178 non-null object
# PESO 273 non-null object
# POSICION 477 non-null object
# NOMBRE 478 non-null object
# dtypes: object(11)
# memory usage: 41.2+ KB
Veamos distintas formas de visualizar contenido del DataFrame.
# Ver las primeras filas
print(df.head(5))
# Ver las últimas n filas
# print(df.tail(4))
# Ver un número aleatorio de filas
# print(df.sample(3))
También podemos ver una sola columna, para ello filtramos el DataFrame usando [ ] o se
puede utilizar el . seguido de el nombre de la columna
print(df['ALTURA'].head())
print(df.ALTURA.tail(2))
El segundo paso va a ser localizar las columnas cuyo tipo debería ser numérico (Altura,
Dorsal y Peso) y asignarles el tipo correspondiente.
Veamos una muestra de estás columnas haciendo uso del filtrado múltiple:
print(df[['ALTURA','PESO','DORSAL']].head(4))
ALTURA PESO DORSAL
# 0 1,89 m (6 ft 2 in) 84 kg (185 lb) 13
# 1 1,87 m (6 ft 2 in) 89 kg (196 lb) 13
# 2 1,90 m (6 ft 3 in) 79 kg (174 lb) 25
# 3 1,81 m (5 ft 11 in) 77 kg (169 lb) 4
Como se puede apreciar altura y peso están en medidas de metros y pies, kilos y libras. Esto
require una transformación mientras que dorsal se puede transformar a entero fácilmente
usando la función pd.to_numeric(DataFrame)
df['DORSAL'] = pd.to_numeric(df['DORSAL'])
Al ejecutar esta función nos avisa de que ha habido un error:
ValueError: Unable to parse string "-" at position 83
160
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
161
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Así que para ver que ha pasado utilizamos la función pd.loc para encontrar la fila 83 y ver
qué valor tiene el nombre y dorsal: print(df[['DORSAL', 'NOMBRE']].loc[83])
# DORSAL -
# NOMBRE Gerard Gumbau
Lo que podemos hacer entonces es recorrer toda la columna de DORSAL y si encuentra un
carácter que no sea un número entonces que devuelva 0. Para saber si un carácter es es
de tipo numérico existe una función: isinstance(variable, tipo_buscado) que devuelve
verdadero cuando variable es del tipo_buscado y falso cuando no.
Esta función podemos usarla en if lineal del tipo:
<accion_si_verdadero> if <condición> else <accion_si_falso>
La función sería
Int(x) if isinstance(x, int) else 0
Con esto devolvemos x transformado en entero si x es un número y sino devolvemos 0
Para recorrer todos las filas de una atributo o columna necesitaremos usar la función
df.apply que ejecuta una función sobre cada elemento de la columna.
df.apply(nombre_funcion)
Para poder acceder al elemento de la columna se usa una función lambda, o función en
línea que declaramos en el mismo momento. La función lambda, como se explicaba antes
es un tipo de función si nombre que se crea generalmente en la misma línea
lamba x: int(x) if isinstance(x, int) else 0
Esta función devuelve x transformado en entero si x es un número y sino devuelve 0
Ahora bien, una función lambda utilizada dentro de una función df.apply se ejecuta para
todos los elementos.
df.apply recorre todos registros o filas de una columna y lambda aplica la función sobre
cada uno de ellos
Si lo juntamos todo tenemos:
df['DORSAL'] = df['DORSAL'].apply(lambda x: int(x) if isinstance(x, int) else 0)
162
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Esta línea de código lo que hace es asignar en df[‘DORSAL’] la salida del resultado de
aplicar la parte derecha del =
df['DORSAL'].apply recorre todas las filas y aplica una función
lambda x: int(x) if isinstance(x, int) else 0 es la función que se aplica sobre cada
registro o fila del DataFrame.
Resulta entonces que:
df['DORSAL'] = df['DORSAL'].apply(lambda x: int(x) if isinstance(x, int) else 0)
Recorre todos las filas de la columna DORSAL y los convierte a enteros si puede, si no puede
devuelve 0.
Esta es una de las mayores ventajas de los DataFrames. En una sola línea de código se
pueden ejecutar funciones que realizan cálculos o conversiones y asignarlos a nuevos
elementos.
La cosa se puede complicar un poco más pero es mejor que sigamos el ejercicio.
df['DORSAL'] = df['DORSAL'].apply(lambda x: int(x) if isinstance(x, int) else 0)
Hemos transformado la columna Dorsal a entero, para comprobarlo podemos hacerlo
accediendo al atributo dtypes de la columna
print("Tipo de la fila es",df['DORSAL'].dtypes)
# Tipo de la fila es int64
Es momento de trabajar sobre ALTURA y PESO, recordemos cómo son las columnas:
print(df[['ALTURA','PESO']].head(4))
ALTURA PESO
# 0 1,89 m (6 ft 2 in) 84 kg (185 lb)
A la vista de cómo se representan los resultado podemos extraer el peso si extraemos los
primeros 2 caracteres de la cadena. Las funciones de cadenas nos permiten escoger los
primeros 2 elementos usando el formato cadena[inicio:fin:paso]
Para poder recorrer todos los registros de una columna es necesario que la columna esté
completa, es decir, no puede tener filas sin rellenar. Podemos rellenar una columna con un
dato específico o uno calculado utilizando la función df.fillna(valor) para rellenar los
datos nulos con el valor deseado.
Con el objetivo de recorrer la columna de PESO y extraer el valor usaremos la siguiente
instrucción:
df['PESO'].fillna("00", inplace=True)
163
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
164
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
A continuación extraemos los dos primeros caracteres y los convertimos a entero:
df['PESO'] = df['PESO'].apply(lambda x: int(x[0:2]))
Con esto hemos conseguido convertir la columna PESO en una columna con datos de tipo
entero.
El atributo ALTURA se puede hacer de forma análoga. Primero rellenamos los valores que
faltan y posteriormente vamos a sustituir las comas por puntos para que al traducirlo a float
entienda que hay una parte entera y una parte fraccionada
df['ALTURA'].fillna("00", inplace=True)
df['ALTURA'] = df['ALTURA'].apply(lambda x: x.replace(",",".").replace("'","."))
df['ALTURA'] = df['ALTURA'].apply(lambda x: float(x[0:4]))
Al final terminamos extrayendo los 4 primeros caracteres y convieréndolos en un float.
Hasta aquí hemos modificado los tipos de 3 columnas, veamos el resultado utilizando para
ello la función pd.describe(). Esta función nos aporta la siguiente información: el total de
elementos, la media, la desviación estándar, el valor máximo, el valor mínimos y el
porcentaje de elementos que están en cada cuartil
print(df[['ALTURA','PESO','DORSAL']].describe())
# ALTURA PESO DORSAL
# count 478.000000 478.000000 478.0
# mean 1.764603 42.667364 0.0
# std 0.283056 37.527184 0.0
# min 0.000000 0.000000 0.0
# 25% 1.760000 0.000000 0.0
# 50% 1.810000 67.000000 0.0
# 75% 1.850000 76.000000 0.0
# max 2.030000 93.000000 0.0
El tercer paso va a ser extraer la información del año en el que debutó el jugador. Vemamos
un ejemplo de cómo están los datos:
print(df['DEBUTDEPORTIVO'].head(7))
# 0 NaN
# 1 2006(C. D. Basconia)
# 2 2014(C. D. Basconia)
# 3 2000(Athletic Club)
# 4 2010( Club Deportivo Basconia)
# 5 28 de noviembre de 2012(Athletic Club)
# 6 (Bilbao Athletic)
La lectura de estos resultados nos permite extraer el año de debut del jugador. Para ello
vamos a utilizar una expresión regular que detecte 4 dígitos seguidos, que serán el año de
debut. Si no hubiera 4 dígitos entonces devolverá un 0.
165
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La expresión regular es:
re.search('\d{4}', x)
search busca todas las ocurrencias de \d{4} en la cadena x. \d significa número y {4}
busca exactamente 4 ocurrencias. Search aunque encuentre uno va a seguir buscando y
es por eso que necesitamos agrupar los número de la primera vez que encuentre el grupo.
Ello se consigue con el método .group(). Lo mejor es crear una función que busque el año
en una cadena.
def find_year(x):
print(x)
año = re.search('\d{4}', x)
return int(año.group(0)) if año else 0
Con esta función podemos utilizar la función map para recorrer todos los elementos de la
columna y aplicar la función. No es necesario pasarle los parámetros a la función find_year
porque los extrae de la función map.
Antes es necesario rellenar los valores nulos para poder recorrer todos los datos.
df['DEBUTDEPORTIVO'].fillna("0000", inplace=True)
df['AÑODEBUT'] = df['DEBUTDEPORTIVO'].map(find_year)
Tras lo cual podemos eliminar las columnas DEBUT y DEBUTDEPORTIVO
El cuarto paso va a consistir en trabajar con la columna NACIMIENTO. Veamos primero un
ejemplo de los datos.
print(df['NACIMIENTO'].tail(4))
# Name: DEBUTDEPORTIVO, dtype: object
# 474 Puerto Colombia (Atlántico)8 de septiembre de ...
# 475 Cartagena, Colombia23 de junio de 1994 (24 años)
# 476 Múnich, Alemania10 de septiembre de 1991 (27 a...
# 477 Bursa10 de mayo de 1997 (21 años)
# Name: NACIMIENTO, dtype: object
Se puede ver la fecha de nacimiento que está pegada a la ciudad y al país de nacimiento
(aunque no en todos los casos) y seguida de la edad del jugador.
Vamos a extraer el mes de nacimiento y lo vamos a representar como un número enero: 1,
febrero: 2, … diciembre:12 y la vamos a guardar en una nueva columna MESNACIMIENTO.
Crear una nueva columna es fácil:
df['MESNACIMIENTO'] = 0 #también se puede rellenar con np.nan
A continuación vamos a realizar el filtrado utilizando la función df.loc(<condicoin>) que
localiza los índices para los que se cumple la condición <condición>. Si aplicamos
df[‘nom_col’].loc(<cond>) podremos además asignar valores a la columna nom_col solo a
los índices que cumplan la condición <cond>
La condición que vamos a buscar es: df['NACIMIENTO'].str.contains("enero")==True lo
que significa que si la columna NACIMIENTO tiene la subcadena enero entonces es True y
166
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
sino False
Para asegurarnos el éxito vamos a hacer que tolas las letras de la columna NACIMIENTO
sean minúsculas. Python es sensible a las mayúsculas y Enero ES DISTINTO que enero.
df['NACIMIENTO'] = df['NACIMIENTO'].apply(lambda x: x.lower())
Una vez pasadas a minúsculas todas las letras podemos buscar si contienen las subcadenas
de los meses y si la contienen asignar el valor correspondiente a la columna MESNACIMIENTO
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("enero") == True] = 1
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("febrero") == True] = 2
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("marzo") == True] = 3
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("abril") == True] = 4
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("mayo") == True] = 5
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("junio") == True] = 6
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("julio") == True] = 7
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("agosto") == True] = 8
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("septiemb") == True] = 9
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("octubre") == True] = 10
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("noviembre")== True] = 11
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("diciembre")== True] = 12
Además podemos extraer y almacenar el año de nacimiento utilizando la función creada
con anterioridad find_year.
df['AÑONACIMIENTO'] = df['NACIMIENTO'].map(find_year)
El quinto paso va a consistir en trabajar con la columna POSICION. Veamos primero un
ejemplo de los datos.
print(df.POSICION.head())
# 0 Portero
# 1 Portero
# 2 Portero
# 3 Lateral derechoDefensa central derecho
# 4 Defensa
Puesto que vamos a trabajar con cadenas y dado que no parece que haya un “formato”
exacto en todas voy a utilizar el método Series.value_counts() que devuelve una lista
ordenada de los valores existentes incluyendo el número de apariciones del mismo:
print(df['POSICION'].value_counts().head(12))
# Centrocampista 93
# Delantero 68
# Defensa 64
# Portero 34
# Defensa central 24
# Lateral izquierdo 22
# Lateral derecho 18
# Extremo 16
# Guardameta 14
# Mediocentro 13
# Mediocampista 8
# Extremo izquierdo 5
167
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# Lateral Izquierdo 5
# Delantero centro 5
# Mediapunta 4
# Centrocampista defensivo 4
# Mediocentro defensivo 4
# Lateral 4
# Defensor 3
# Pivote 3
# Central 3
# Extremo derecho 3
# Arquero 3
# Centrodelantero 2
# Defensor central 2
# Interior izquierdo 2
# Centrocampista ofensivo 2
# Volante 2
# mediocentro 2
# Lateral derecho. 1
# Defensa central Mediocentro defensivo 1
# carilero 1
# Defensa central/Lateral izquierdo 1
# Volante de marca 1
# Mediocentro o defensa 1
# Centrocampista / Extremo 1
# Mediapunta, Delantero 1
# Delantero / Mediapunta 1
# Delantero y centrocampista 1
# MediapuntaInterior izquierdo 1
# Centrocampista/Lateral derecho 1
# Delantero extremo izquierdo 1
# DefensaCentrocampista 1
# Lateral izquierdo - Centrocampista 1
# Delantero Extremo 1
# defensa 1
# MediapuntaInterior derecho 1
# delantero 1
# Lateral derechoExtremo derecho 1
# Defensa lateral derecho 1
# Medio centro, Medio centro defensivo 1
# Extremo Izquierdo|Mediapunta 1
# Defensa centralLateral 1
# Lateral derechoMediocentro defensivo 1
# Defensor Central 1
# Extremo derechoSegundo delantero 1
# Mediocampista ofensivo 1
# Interior derecho 1
# lateral derecho 1
# Lateral derecho , Extremo derecho , Mediapunta 1
# delantero centro 1
# Delantero, centrocampista 1
# Interior derecho Interior izquierdo 1
# Lateral izquierdo/Interior izquierdo 1
# Medio 1
# Defensa (lateral izquierdo o central) 1
# ExtremoMediapunta 1
# medio centro ofensivo/interior derecho 1
# extremo derecho 1
168
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# Lateral derechoDefensa central derecho 1
# Interior o Lateral derecho 1
# Defensa lateral izquierdo 1
# Lateral derecho Interior derecho 1
# Interior/Extremo Izquierdo 1
Es interesante ver cómo no hay un criterio sobre la forma de llamar a la posición. Portero,
Guardameta y Arquero son sinónimos, Defensa y Defensor son lo mismo. También ocurre
que hay jugadores que tienen más de una posición asignada.
Es necesario aplicar algún tipo de reglas para definir las posiciones. Antes de lo cual es
importante eliminar posibles fallos de mayúscula y minúsuclas. Así que vamos a realizar la
misma operación pero con todo minúsculas:
df['POSICION'] = df['POSICION'].apply(lambda x: str(x).lower())
Leyedo la lista anterior podemos encontrar lo siguiente:
Portero = guardameta, arquero
Centrocampista = mediocentro, mediocampista, medio
Defensa = defensor
Así que podemos recorrer el la columna buscando ocurrencias para asignar el valor
correspondiente.
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("guardamenta",'portero'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("arquero",'portero'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("defensor",'defensa'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("mediocentro",'centrocampista'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("mediocampista",'centrocampista'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("medio",'centrocampista'))
169
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Prueba a seguir mejorando la afinidad en este campo.
Recordemos cómo es el DataFrame:
print(df.head())
ALTURA CLUB DORSAL NACIONALIDAD PAIS
0 1.89 Chelsea F. C. 0 Española NaN
1 1.87 Athletic Club 0 NaN NaN
2 1.90 Athletic Club 0 Española España
3 1.81 Deportivo de La Coruña 0 NaN NaN
4 1.87 Maccabi Tel Aviv Football Club 0 Española España España
PESO POSICION NOMBRE AÑODEBUT
0 84 Portero Kepa Arrizabalaga 0
1 89 Portero Iago Herrerín 2006
2 79 Portero Unai Simón 2014
3 77 Lateral derechoDefensa central derecho Eneko Bóveda 2000
4 73 Defensa Enric Saborit 2010
MESNACIMIENTO AÑONACIMIENTO
0 10 1994
1 1 1988
2 6 1997
3 12 1988
4 4 1992
print(df.info())
# ALTURA 478 non-null float64
# CLUB 472 non-null object
# DORSAL 478 non-null int64
# NACIONALIDAD 374 non-null object
# PAIS 178 non-null object
# PESO 478 non-null int64
# POSICION 477 non-null object
# NOMBRE 478 non-null object
# AÑODEBUT 478 non-null int64
# MESNACIMIENTO 478 non-null int64
# AÑONACIMIENTO 478 non-null int64
# dtypes: float64(1), int64(5), object(5)
Hemos trabajado sobre las columnas: ALTURA, DORSAL, PESO, POSICIÓN y creado las columnas
MESNACIMIENTO, AÑONACIMIENTO.
Podemos guardar todas estas mejoras en un nuevo documento:
df.to_csv("./data/my_players_info_cleaner.csv")
170
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.14.2.4. Código sin comentarios
import re
import pandas as pd
# Determinar el número de filas que se visualizan al hacer print
pd.set_option('display.max_rows', 1000)
# Determinar el número de columnas que se visualizan al hacer print
pd.set_option('display.max_columns', 12)
path = './data/my_players_info.csv'
nombre_columnas = ['GOLES','ALTURA','APODO','CLUB','DEBUT','DEBUTDEPORTIVO',
'DEPORTES','DORSAL','ENTRENADOR','GOLESCLUBES','LIGA',
'NACIMIENTO','NACIONALIDAD','NOMBRENACIMIENTO',
'NOMBRECOMPLETO', 'PAREJA','PARTIDOS','PARTIDOGOLES','PAIS',
'PESO','POSICION','RETIRADADEPORTIVA','SELECCION','NOMBRE'
]
df = pd.read_csv(path, sep=";", names=nombre_columnas, skiprows =1)
# Comencemos descripción de lo que hay en el DataFrame
print("El DataFrame tiene {0} filas y {1} columnas\n".format(len(df),
len(df.columns)))
# Pandas incorpora la función describe para ver los datos más relevantes
# de cada columna
print("Información de cada columna:", df.info())
# Eliminación de columnas
df = df.drop(columns='GOLES')
df.drop(columns='ENTRENADOR', inplace=True)
df.drop(columns='NOMBRENACIMIENTO', inplace=True)
df.drop(columns='PAREJA', inplace=True)
df.drop(columns='PARTIDOS', inplace=True)
df.drop(columns='RETIRADADEPORTIVA', inplace=True)
df.drop(columns='APODO', inplace=True)
df.drop(columns='NOMBRECOMPLETO', inplace=True)
df.drop(columns='GOLESCLUBES', inplace=True)
df.drop(columns='PARTIDOGOLES', inplace=True)
df.drop(columns='SELECCION', inplace=True)
df.drop(columns='DEPORTES', inplace=True)
df.drop(columns='LIGA', inplace=True)
print(df.info())
# Data columns (total 11 columns):
# ALTURA 467 non-null object
# CLUB 472 non-null object
# DEBUT 147 non-null object
# DEBUTDEPORTIVO 470 non-null object
# DORSAL 309 non-null object
# NACIMIENTO 478 non-null object
# NACIONALIDAD 374 non-null object
# PAIS 178 non-null object
# PESO 273 non-null object
# POSICION 477 non-null object
# NOMBRE 478 non-null object
# dtypes: object(11)
# memory usage: 41.2+ KB
171
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# El segundo paso va a ser localizar las columnas cuyo tipo debería ser
# numérico: Altura, Dorsal y Peso.
# Ver las primeras filas
print(df.head(5))
# Ver las últimas n filas
print(df.tail(4))
# Ver un número aleatorio de filas
print(df.sample(3))
print(df['ALTURA'].head())
print(df.ALTURA.tail(2))
print(df[['ALTURA','PESO','DORSAL']].head(4))
# ALTURA PESO DORSAL
# 0 1,89 m (6 ft 2 in) 84 kg (185 lb) 13
# 1 1,87 m (6 ft 2 in) 89 kg (196 lb) 13
# 2 1,90 m (6 ft 3 in) 79 kg (174 lb) 25
# 3 1,81 m (5 ft 11 in) 77 kg (169 lb) 4
# df['DORSAL'] = pd.to_numeric(df['DORSAL'])
print(df[['DORSAL', 'NOMBRE']].loc[83])
# DORSAL -
# NOMBRE Gerard Gumbau
df['DORSAL'] = df['DORSAL'].apply(lambda x: int(x) if isinstance(x, int) else 0)
print("Tipo de la fila es",df['DORSAL'].dtypes)
# Tipo de la fila es int64
df['PESO'].fillna("00", inplace=True)
df['PESO'] = df['PESO'].apply(lambda x: int(x[0:2]))
df['ALTURA'].fillna("00", inplace=True)
df['ALTURA'] = df['ALTURA'].apply(lambda x: x.replace(",",".").replace("'","."))
df['ALTURA'] = df['ALTURA'].apply(lambda x: float(x[0:4]))
print(df[['ALTURA','PESO','DORSAL']].head())
# ALTURA PESO DORSAL
# 0 1.89 84 0
# 1 1.87 89 0
# 2 1.90 79 0
# 3 1.81 77 0
# 4 1.87 73 0
print(df[['ALTURA','PESO','DORSAL']].describe())
# ALTURA PESO DORSAL
# count 478.000000 478.000000 478.0
# mean 1.764603 42.667364 0.0
# std 0.283056 37.527184 0.0
# min 0.000000 0.000000 0.0
# 25% 1.760000 0.000000 0.0
# 50% 1.810000 67.000000 0.0
# 75% 1.850000 76.000000 0.0
# max 2.030000 93.000000 0.0
172
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
print(df['DEBUTDEPORTIVO'].head(7))
# 0 NaN
# 1 2006(C. D. Basconia)
# 2 2014(C. D. Basconia)
# 3 2000(Athletic Club)
# 4 2010( Club Deportivo Basconia)
# 5 28 de noviembre de 2012(Athletic Club)
# 6 (Bilbao Athletic)
df['DEBUTDEPORTIVO'].fillna("0000", inplace=True)
def find_year(x):
# print(x)
año = re.search('\d{4}', x)
return int(año.group(0)) if año else 0
df['AÑODEBUT'] = df['DEBUTDEPORTIVO'].map(find_year)
# Con el año debut añadido podemos proceder a eliminar las columnas
df.drop(columns='DEBUT', inplace=True)
df.drop(columns='DEBUTDEPORTIVO', inplace=True)
print(df['NACIMIENTO'].tail(4))
# Name: DEBUTDEPORTIVO, dtype: object
# 474 Puerto Colombia (Atlántico)8 de septiembre de ...
# 475 Cartagena, Colombia23 de junio de 1994 (24 años)
# 476 Múnich, Alemania10 de septiembre de 1991 (27 a...
# 477 Bursa10 de mayo de 1997 (21 años)
# Name: NACIMIENTO, dtype: object
df['NACIMIENTO'] = df['NACIMIENTO'].apply(lambda x: x.lower())
df['MESNACIMIENTO'] = 0
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("enero") == True] = 1
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("febrero") == True] = 2
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("marzo") == True] = 3
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("abril") == True] = 4
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("mayo") == True] = 5
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("junio") == True] = 6
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("julio") == True] = 7
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("agosto") == True] = 8
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("septiemb") == True] = 9
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("octubre") == True] = 10
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("noviembre")== True] = 11
df['MESNACIMIENTO'].loc[df['NACIMIENTO'].str.contains("diciembre")== True] = 12
df['AÑONACIMIENTO'] = df['NACIMIENTO'].map(find_year)
df.drop(columns='NACIMIENTO', inplace=True)
print(df.head())
print(df.info())
# ALTURA 478 non-null float64
# CLUB 472 non-null object
# DORSAL 478 non-null int64
173
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# NACIONALIDAD 374 non-null object
# PAIS 178 non-null object
# PESO 478 non-null int64
# POSICION 477 non-null object
# NOMBRE 478 non-null object
# AÑODEBUT 478 non-null int64
# MESNACIMIENTO 478 non-null int64
# AÑONACIMIENTO 478 non-null int64
# dtypes: float64(1), int64(5), object(5)
print(df.POSICION.head())
# 0 Portero
# 1 Portero
# 2 Portero
# 3 Lateral derechoDefensa central derecho
# 4 Defensa
print(df['POSICION'].value_counts())
# Centrocampista 93
# Delantero 68
# Defensa 64
# Portero 34
# Defensa central 24
# Lateral izquierdo 22
# Lateral derecho 18
# Extremo 16
# Guardameta 14
# Mediocentro 13
# Mediocampista 8
# Extremo izquierdo 5
# Lateral Izquierdo 5
# Delantero centro 5
# Mediapunta 4
# Centrocampista defensivo 4
# Mediocentro defensivo 4
# Lateral 4
# Defensor 3
# Pivote 3
# Central 3
# Extremo derecho 3
# Arquero 3
# Centrodelantero 2
# Defensor central 2
# Interior izquierdo 2
# Centrocampista ofensivo 2
# Volante 2
# mediocentro 2
# Lateral derecho. 1
# Defensa central Mediocentro defensivo 1
# carilero 1
# Defensa central/Lateral izquierdo 1
# Volante de marca 1
# Mediocentro o defensa 1
# Centrocampista / Extremo 1
# Mediapunta, Delantero 1
# Delantero / Mediapunta 1
# Delantero y centrocampista 1
174
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# MediapuntaInterior izquierdo 1
# Centrocampista/Lateral derecho 1
# Delantero extremo izquierdo 1
# DefensaCentrocampista 1
# Lateral izquierdo - Centrocampista 1
# Delantero Extremo 1
# defensa 1
# MediapuntaInterior derecho 1
# delantero 1
# Lateral derechoExtremo derecho 1
# Defensa lateral derecho 1
# Medio centro, Medio centro defensivo 1
# Extremo Izquierdo|Mediapunta 1
# Defensa centralLateral 1
# Lateral derechoMediocentro defensivo 1
# Defensor Central 1
# Extremo derechoSegundo delantero 1
# Mediocampista ofensivo 1
# Interior derecho 1
# lateral derecho 1
# Lateral derecho , Extremo derecho , Mediapunta 1
# delantero centro 1
# Delantero, centrocampista 1
# Interior derecho Interior izquierdo 1
# Lateral izquierdo/Interior izquierdo 1
# Medio 1
# Defensa (lateral izquierdo o central) 1
# ExtremoMediapunta 1
# medio centro ofensivo/interior derecho 1
# extremo derecho 1
# Lateral derechoDefensa central derecho 1
# Interior o Lateral derecho 1
# Defensa lateral izquierdo 1
# Lateral derecho Interior derecho 1
# Interior/Extremo Izquierdo 1
df['POSICION'] = df['POSICION'].apply(lambda x: str(x).lower())
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("guardamenta",'portero'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("arquero",'portero'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("defensor",'defensa'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("mediocentro",'centrocampista'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("mediocampista",'centrocampista'))
df['POSICION'] = df['POSICION'].apply(
lambda x: x.replace("medio",'centrocampista'))
print(df['POSICION'].value_counts())
# centrocampista 117
# delantero 69
# defensa 68
# portero 37
# defensa central 27
175
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# lateral izquierdo 27
# lateral derecho 19
# extremo 16
# guardameta 14
# centrocampista defensivo 8
# delantero centro 6
# extremo izquierdo 5
# lateral 4
# mediapunta 4
# extremo derecho 4
# centrocampista ofensivo 3
# pivote 3
# central 3
# volante 2
# interior izquierdo 2
# centrodelantero 2
# defensa central/lateral izquierdo 1
# defensa (lateral izquierdo o central) 1
# centrocampista o defensa 1
# mediapunta, delantero 1
# lateral derechocentrocampista defensivo 1
# mediapuntainterior derecho 1
# lateral derechoextremo derecho 1
# delantero extremo 1
# delantero, centrocampista 1
# centrocampista/lateral derecho 1
# lateral derecho , extremo derecho , mediapunta 1
# nan 1
# delantero extremo izquierdo 1
# interior o lateral derecho 1
# lateral izquierdo - centrocampista 1
# delantero / mediapunta 1
# defensacentrocampista 1
# defensa central centrocampista defensivo 1
# carilero 1
# defensa lateral derecho 1
# volante de marca 1
# defensa lateral izquierdo 1
# extremo derechosegundo delantero 1
# delantero y centrocampista 1
# extremo izquierdo|mediapunta 1
# defensa centrallateral 1
# centrocampista centro, centrocampista centro defensivo 1
# lateral derecho interior derecho 1
# interior/extremo izquierdo 1
# centrocampista centro ofensivo/interior derecho 1
# mediapuntainterior izquierdo 1
# extremomediapunta 1
# interior derecho interior izquierdo 1
# centrocampista / extremo 1
# interior derecho 1
# lateral derechodefensa central derecho 1
# lateral izquierdo/interior izquierdo 1
# lateral derecho. 1
df.to_csv("./data/my_players_info_cleaner.csv")
176
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si tienes tiempo prueba por ti mismo a preparar los datos de columnas que no se hayan
modificado en este ejemplo.
177
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.15.3. Ejercicio 3: Dibujar un campo de fútbol y jugadores
1.15.3.1. Introducción
Este es un ejercicio sencillo que sirve para demostrar cómo la librería matplotlib se puede
utilizar para pintar un campo de fútbol y, posteriormente, añadir jugadores al terreno de
juego. Es un ejercicio de pericia y precisión cuyo requisito principal es saber ubicar punto (x,
y) en un plano, con la característica que los puntos x e y estarán en variables de datos
distintas.
1.15.3.2. Objetivo
El objetivo principal es obtener la soltura suficiente como para poder respresentar cualquier
elemento, incluso si hay que prepararlo ad hoc o desde cero.
El ejercicio hace lo siguiente:
• Dibuja líneas rectas en una imagen para dibujar un campo de fútbol.
• Añade a la imagen círculos que simulan ser jugadores de fútbol.
• Aprender a manejar listas por compresión
1.15.3.3. Código comentado
Se comienza importanto las librerías necesarias asignándoles, a su vez un álias que permita
usarlas más fácilmente y se escoge un color para el terreno de juego (en este caso azul
oscuro). El colo se utilizará en las líneas que forman el campo.
import matplotlib.pyplot as plt
color_campo = '#0a59bc'
Es importante saber que en matplotlib y la mayoría de librerías de visualización los elementos
a dibujar y/o pintar no se hacen efectivos hasta que no se ejecuta el comando plt.show()
o el comando plt.save(“image.jpg”). Los sucesivos elementos se van sucediendo y
añadiendo a los anteriores hasta que se hace plt.show(), motivo por el cuál el código está
acompañado de múltiples de estos comandos para que los puedas descomentar mientras
los ejecutas y veas la evolución de la imagen. Ver cómo se van dibujando los distintos
elementos es lo que hace más sencillo entender el ejercicio.
Es importante tenerlo en cuenta a la hora de ejecutar y seguir el ejericicio.
178
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Comencemos dibujando una línea. Las líneas se dibujan indicando dos puntos (que son los
que se unen con la línea. Cada punto tiene una coordenada x y una coordenada y. punto
A(x1, y1), punto B(x2, y2). Como veremos más adelante las líneas a dibujar se pueden llevar
a cabo poniendo todos los puntos a unir, digamos A-B-C-D-E, … pero en este primer caso
uniremos dos puntos usando la función:
# plt.plot( *x, *y, color)
con la característica de que todas las coordenadas de x se pasan como primer parámetro
y las coordenadas de y como segundo parámetro. Algo así:
# plt.plot( (x1,x2), (y1, y2), color)
Así que si queremos dibujar una línea horizontal del punto (0,0) al punto (0,100) los
parámetros de entrada serán [0, 0], [0,100]
# Linea inferior los puntos (0,0) a (100, 0)
# plt.plot( *x, *y, color)
# plt.plot( (x1,x2), (y1, y2), color)
coord_x = [0, 100]
coord_y = [0, 0]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
Hemos dibujado la línea interior del campo, para dibujar una línea de gol izquierda
empezaremos con una línea vertical:
# Linea gol-izq los puntos (0,0) a (0, 65)
coord_x = [0, 0]
coord_y = [0, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
179
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Pintemos ahora el las otras dos líneas exteriores del campo siguiendo el mismo modo de
operar:
# Linea superior los puntos (x,y) a(0,65) , b(100, 65)
coord_x = [0, 100]
coord_y = [65, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
# Linea gol-dcha los puntos (100, 0) a (100, 65)
coord_x = [100, 100]
coord_y = [0, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
El resto de líneas del campo son sencillas, así que continuemos con la línea de medio
campo, y las áreas grande y pequeña del lado izquierdo del campo.
# Linea area GRANDE izq son tres líneas, esto requiere unir 4 puntos (x, y)
# requiere de 4 puntos a ir conectando, el formato (x, y) de los puntos sería
# A = (0, 12.34)
# B = (16.5, 12.34)
# C = (16.5, 52.66)
# D = (0, 52.66)
coord_areagrande_izq_x = [0, 16.5, 16.5, 0]
coord_areagrande_izq_y = [12.34, 12.34, 52.66, 52.66]
plt.plot(coord_areagrande_izq_x, coord_areagrande_izq_y, color_campo)
# plt.show()
# Linea area PEQUEÑA izq son tres líneas, esto requiere unir 4 puntos (x, y)
# requiere de 4 puntos a ir conectando, el formato (x, y) de los puntos sería
# A = (0, 23.34)
# B = (5.5, 23.34)
# C = (5.5, 41.66)
# D = (0, 41.66)
coord_pequeña_izq_x = [0, 5.5, 5.5, 0]
coord_pequeña_izq_y = [23.34, 23.34, 41.66, 41.66]
plt.plot(coord_pequeña_izq_x, coord_pequeña_izq_y, color_campo)
# plt.show()
180
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Hasta aquí todo ha sido bastante sencillo. Vamos a aprovechar para poner en uso las listas
de compresión que se explicaban anteriormente. La definición por compresión es una
expresión compacta que sirve para definir listas, conjuntos y diccionarios.
Normalmente se definen como list_variable = [x for x in iterable]
¿Cómo las vamos a utilizar? Teniendo en cuenta que el campo aquí representado mide 100
metros y que las líneas de las áreas son reflejas unas de otras, los puntos a representar para
las áreas del lado derecho son abs(coordenada_x – 100), es decir, el número absoluto
(positivo) de restarle 100 a la coordenada x.
Dados los puntos: A(0, 12.34) y el punto B(16.5, 12,34) dibujar el espejo de esta línea por dos
puntos sería dibujas la línea entre los puntos A2(100, 12.34) y B1(83.5, 12.34) o lo que es lo
mismo abs(coord._x – 100, y)
Si queremos realizar la operación para todos los puntos de las coordenadas x de lo puntos
podemos hacer lo siguiente:
coord_areagrande_dcha_x = [abs(c -100) for c in coord_areagrande_izq_x]
# coord_areagrande_dcha_x = [100, 83.5, 83.5, 100]
coord_areagrande_dcha_y = coord_areagrande_izq_y
# plt.plot(coord_areagrande_dcha_x, coord_areagrande_dcha_y, color_campo)
Así en el contenido de las coord._areagrande_dcha_x tenenos la lista de coordenadas x
de los puntos a dibujar, mientras que la coordenada y no se modifica.
Lo mismo podemos hacer con el otro área:
coord_pequeña_dcha_x = [abs(c -100) for c in coord_pequeña_izq_x]
coord_pequeña_dcha_y = coord_pequeña_izq_y
plt.plot(coord_pequeña_dcha_x, coord_pequeña_dcha_y, color_campo)
El resultado obtenido (teniendo en cuenta que hasta este punto solo he ejecutado un
plt.plot() para ir añadiendo elementos a la imagen.
181
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
En la imagen se puede ver el campo, en el que falta dibujarel círculo central círculo.
cicle1 = plt.Circle((50,32.5), radius=9.15, fill= False, color = color_campo)
plt.gca().add_patch(cicle1)
Con la función plt.Circle usando las coordenadas (x, y) del centro y el tamaño del radio
podemos dibujar el círculo. La función nos devuelve un objeto y debemos indicar al
matplotlib que queremos incluirlo en la imagen.
Podemos añadirle las porterías utilizando las coordenadas negativas.
182
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# Portería izquierda
port_izq_x = [0,-2.44,-2.44,0]
port_izq_y = [28.84,28.84,36.16,36.16]
plt.plot(port_izq_x, port_izq_y,
color_campo)
# Portería derecha
port_dcha_x = [100,102.44,102.44,100]
port_dcha_y = [28.84,28.84,36.16,36.16]
plt.plot(port_dcha_x, port_dcha_y,
color_campo)
# plt.show()
#Le podemos añadir un titular.
plt.text(0,-11,'Como pintar un campo de'\
' fútbol y jugadores en él'\
'', fontsize=10, color= color_campo)
La representación de los jugadores la vamos a hacer utilizando círculos pequeños y rellenos
que contengan un dorsar posible.
Con el fin de pintar más fácilmente a los jugadores en el campo vamos a crear una función
que los pinte.
def pintar_jugador(coor_x: int, coord_y: int, dorsal: int, tamaño: int, color:
str):
""" Esta función permite pintar a un jugador, representado como un círculo
con un radio y una posición. En el círculo se escribe el dorsal del jugador
"""
icon_player = plt.Circle((coor_x, coord_y), tamaño, fill=True, color=color)
plt.gca().add_patch(icon_player)
plt.text(coor_x, coord_y - 0.9, dorsal, fontsize=11, ha='center', color='w')
Esta función pinta un círculo relleno en las coordinadas seleccionadas y del tamaño
indicado. A continuación escribe en él el número de dosar.
Una llamada a esta función podría ser así:
pintar_jugador(51.01356, 65-11.5290, "NACHO", 5, '#aaaaaa' )
No obstante vamos a crear un diccionario de jugadores para pintarlos a todos utilizando un
bucle. La definición del diccionario de jugadores sería:
color_jugador = '#aaaaaa'
equipo = {'Nacho': {
'dorsal': 5,
'pos_x': 12,
'pos_y': 54,
},
'Fran': {
'dorsal': 12,
'pos_x': 12,
'pos_y': 10,
},
'Javi': {
'dorsal': 9,
183
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
'pos_x': 80.5,
'pos_y': 35.0
},
'Fer': {
'dorsal': 4,
'pos_x': 45,
'pos_y': 50
},
'Sergio': {
'dorsal': 8,
'pos_x': 35,
'pos_y': 15
},
}
Recorrer un diccionario requiere de un bucle for que utiliza dos variables, la clave (que
identifica el objeto y el valor. En este caso el valor es, a su vez, la clave de otro diccionario.
for key, value in equipo.items():
print("El jugador se llama {0} y sus datos son: {1}".format(key, value))
pintar_jugador(value['pos_x'], value['pos_y'], value['dorsal'],
tamaño=3, color=color_jugador)
plt.show()
Con este bucle pintamos a los jugadores del diccionario. Prueba a añadir jugadores y a
modifcar las posiciones para que veas cómo funciona.
184
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.15.3.4. Código sin comentarios
import matplotlib.pyplot as plt
import numpy as np
color_campo = '#0a59bc'
# Linea inferior los puntos (0,0) a (100, 0)
# plt.plot( *x, *y, color)
# plt.plot( (x1,x2), (y1, y2), color)
coord_x = [0, 100]
coord_y = [0, 0]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
# Linea gol-izq los puntos (0,0) a (0, 65)
coord_x = [0, 0]
coord_y = [0, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
# Linea superior los puntos (x,y) a(0,65) , b(100, 65)
coord_x = [0, 100]
coord_y = [65, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
# Linea gol-dcha los puntos (100, 0) a (100, 65)
coord_x = [100, 100]
coord_y = [0, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
# Linea medio campo los puntos (50, 0) a (50, 65)
coord_x = [50, 50]
coord_y = [0, 65]
plt.plot(coord_x, coord_y, color_campo)
# plt.show()
# Linea area GRANDE izq son tres líneas, esto requiere unir 4 puntos (x, y)
# requiere de 4 puntos a ir conectando, el formato (x, y) de los puntos sería
# A = (0, 12.34)
# B = (16.5, 12.34)
# C = (16.5, 52.66)
# D = (0, 52.66)
coord_areagrande_izq_x = [0, 16.5, 16.5, 0]
coord_areagrande_izq_y = [12.34, 12.34, 52.66, 52.66]
plt.plot(coord_areagrande_izq_x, coord_areagrande_izq_y, color_campo)
# plt.show()
# Linea area PEQUEÑA izq son tres líneas, esto requiere unir 4 puntos (x, y)
# requiere de 4 puntos a ir conectando, el formato (x, y) de los puntos sería
# A = (0, 23.34)
# B = (5.5, 23.34)
# C = (5.5, 41.66)
# D = (0, 41.66)
coord_pequeña_izq_x = [0, 5.5, 5.5, 0]
185
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
coord_pequeña_izq_y = [23.34, 23.34, 41.66, 41.66]
plt.plot(coord_pequeña_izq_x, coord_pequeña_izq_y, color_campo)
# plt.show()
# Del mismo modo podemos ahora dibujar las líneas de área pequeña y grande
# del lateral derecho
coord_areagrande_dcha_x = [abs(c -100) for c in coord_areagrande_izq_x]
# coord_areagrande_dcha_x = [100, 83.5, 83.5, 100 ]
coord_areagrande_dcha_y = coord_areagrande_izq_y
plt.plot(coord_areagrande_dcha_x, coord_areagrande_dcha_y, color_campo)
#
coord_pequeña_dcha_x = [abs(c -100) for c in coord_pequeña_izq_x]
coord_pequeña_dcha_y = coord_pequeña_izq_y
plt.plot(coord_pequeña_dcha_x, coord_pequeña_dcha_y, color_campo)
# plt.show()
# object = plt.Circle( (x,y), radius, fill= , color = )
cicle1 = plt.Circle((50,32.5), radius=9.15, fill= False, color = color_campo)
plt.gca().add_patch(cicle1)
# plt.show()
# Portería izquierda
port_izq_x = [0,-2.44,-2.44,0]
port_izq_y = [28.84,28.84,36.16,36.16]
plt.plot(port_izq_x, port_izq_y, color_campo)
# Portería derecha
port_dcha_x = [100,102.44,102.44,100]
port_dcha_y = [28.84,28.84,36.16,36.16]
plt.plot(port_dcha_x, port_dcha_y, color_campo)
# plt.show()
plt.text(0,-11,'Como pintar un campo de'\
' fútbol y jugadores en él'\
'', fontsize=10, color= color_campo)
# plt.show()
print("Fin de la impresión del campo")
def pintar_jugador(coor_x: int, coord_y: int, dorsal: int, tamaño: int, color:
str):
""" Esta función permite pintar a un jugador, representado como un círculo
con un radio y una posición. En el círculo se escribe el dorsal del jugador
"""
icon_player = plt.Circle((coor_x, coord_y), tamaño, fill=True, color=color)
plt.gca().add_patch(icon_player)
plt.text(coor_x, coord_y - 0.9, dorsal, fontsize=11, ha='center', color='w')
# exito = pintar_jugador(51.01356, 65-11.5290, "NACHO", 5, '#aaaaaa' )
color_jugador = '#aaaaaa'
equipo = {'Nacho': {
186
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
'dorsal': 5,
'pos_x': 12,
'pos_y': 54,
},
'Fran': {
'dorsal': 12,
'pos_x': 12,
'pos_y': 10,
},
'Javi': {
'dorsal': 9,
'pos_x': 80.5,
'pos_y': 35.0
},
'Fer': {
'dorsal': 4,
'pos_x': 45,
'pos_y': 50
},
'Sergio': {
'dorsal': 8,
'pos_x': 35,
'pos_y': 15
},
}
for key, value in equipo.items():
print("El jugador se llama {0} y sus datos son: {1}".format(key, value))
pintar_jugador(value['pos_x'], value['pos_y'], value['dorsal'],
tamaño=3, color=color_jugador)
plt.show()
187
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.16.4. Ejercicio 4: Análisis y visualización de datos del nacimiento
de jugadores de fútbol.
1.16.4.1. Introducción
¿Es relevante cuándo ha nacido una persona para saber si podrá ser jugador de fútbol?
¿Hay alguna coincidencia entre el mes de nacimiento y la posición en la que se juega?
Usando este objetivo como la forma principal para el análisis de datos, este ejercicio utiliza
un dataset de los jugadores de futbol del juego Fifa’18
1.16.4.2. Objetivo
Los datos de tipo pandas.DataFrames y pandas.Series facilitan mucho la tarea del análisis
de datos. El objetivo principal del ejercicio es aprender a manejar los DataFrames de
pandas, la información que proporcionan y sus funciones, a la vez que se aprende a
visualizar la información de los DataFrames usando seaborn y matplotlib.
El ejercicio hace lo siguiente:
• Establece un objetivo o hipótesis para el análisis. (El análisis se realiza con una
finalidad, que es necesario definir para saber si se consigue obtener la información
a cambio o no)
• Carga los datos en un DataFrame.
• Prepara los datos.
• Gestiona los “missing values” de un dataset.
• Visualiza los resultados
• Proporciona unas conclusiones
1.16.4.3. Código Comentado
Se comienza cargando las librerías a utilizar y estableciendo los parámetros de
visualización de las librerías pandas y seaborn.
# Cargas las librerías e ignorar los warnings
import warnings; warnings.simplefilter('ignore')
import numpy as np
import pandas as pd
# Librerías para la situalizacion
import seaborn as sns #
import matplotlib.pyplot as plt
import matplotlib; matplotlib.style.use('ggplot')
# carga de la librería datetime
from datetime import datetime
188
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# Configuración de pandas
pd.set_option('display.max_columns', 100)
pd.set_option('display.max_rows', 100)
# Configuración de Seaborn
sns.set_context("notebook")
sns.set_palette('husl')
Cargamos los datos del documento fifa18-player-dataset.csv
df = pd.read_csv('./data/fifa18-player-dataset.csv', encoding='utf_8')
Visualizar los primeros elementos (por defecto 10) del DataFrame podemos ejecutar:
print(df.head()) # Se puede indicar un número
Visualizar los últimos elementos (por defecto 10)
print(df.tail(8))
Visualizar n elementos al azar
print(df.sample(7))
Visualizar el tamaño de la muestra de datos:
print(df.shape)
(17994, 185) 17.7994 filas y 185 atributos o columnas
Podemos enumerar y ver todas las columnas del DataFrame usando un bucle. Esto nos
puede ayudar a descartar qué campos utilizar y cuáles no. Además al imprimir el número
de columna es más fácil hacer esa selección.
for e, col in enumerate(df.columns):
print(e,"->",col)
La lista de los 185 es largo.En este ejercicio usaremos solo las siguientes columnas:
• 0 -> ID
• 2 -> full_name
• 3 -> club
• 6 -> age
• 7 -> league
• 8 -> birth_date
• 9 -> height_cm
• 10 -> weight_kg
• 14 -> nationality
• 19 -> overall
189
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Podríamos eliminar todas las columnas restantes pero pandas nos ofrece seleccionar qué
columnas queremos leer del fichero.
selectedColumns = [0,2,3,6,7,8,9,10,14,19]
# cargar los datos seleccionados
df = pd.read_csv('./data/ fifa18-player-dataset.csv', encoding='utf_8',
usecols=selectedColumns
Esto sería lo mismo que hacer:
# Sería lo mismo que hacer
df = pd.read_csv('./data/ fifa18-player-dataset.csv',
usecols=[0,2,3,6,7,8,9,10,14,19])
Comprobamos que solo se han cargado las columnas seleccionadas:
print(df.shape)
# (17994, 10
El índice por defecto es un índice autonumérico de 0..n, para hacer que el índide sea el ID
del jugador ejecutamos:
df = df.set_index('ID')
Si queremos ver la información de cada columna lo mejor es usar la función info
print(df.info())
Esta función nos proporciona información acerca del número de elementos que tienen
datos en cada columna y el tipo de datos de cada columna
Data columns (total 9 columns):
full_name 17994 non-null object
club 17741 non-null object
age 17994 non-null int64
league 17741 non-null object
birth_date 17994 non-null object
height_cm 17994 non-null float64
weight_kg 17994 non-null float64
nationality 17994 non-null object
overall 17994 non-null int64
dtypes: float64(2), int64(2), object(5)
memory usage: 1.4+ MB
190
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Análisis de datos duplicados
A continuación, y tras ver los datos básicos lo siguiente es analizar si hay datos duplicados
y decidir qué hacer si los hay. Por un lado, no nos quedaríamos mas que con un juego de
daos de un jugador (si estuviese duplicado). Por otro lado, lo normal es que haya clubs
repetidos y por tanto su existencia es normal.
La función a utilizar es pd.duplicated que podemos aplicar sobre un datafram completo
print(df.duplicated())
Esta función nos devuelve un DataFrame booleano indicando qué registros están
duplicados y cuáles no. Esto es útil para seleccionar DataFrames cuando quieres que
cumplan una condición. Si lo que queremos ver es si hay duplicados lo mejor es utilizar la
función value_counts() a la salida, así obtenemos un resumen de cuántos duplicados hay.
Adicionalmente podemos aplicar la búsqueda de duplicados en las columnas full_name y
club para ver si los datos que tenemos “tienen sentido”
print(df['club'].duplicated().value_counts())
print(df['full_name'].duplicated().value_counts())
El resultado es el esperado para los clubs
True 17346
False 648
Name: club, dtype: int64
No es el resultado esperado para los nombres:
False 17891
True 103
Name: full_name, dtype: int64
Parece que hay 103 repetidos. Es ahora cuando es útil aprovechar el DataFrame que
devuelve la función .duplicated para seleccionar a aquellos que están repetidos.
print(df[df['full_name'].duplicated() == True])
Aunque la visualización de los resultados tal cuál no es fácil porque salen muchos nombres
seguidos. Como la salida de esta función es un DataFrame, podemos seleccionar la
columna full_name para que solo nos muestre los nombres duplicados:
print(df[df['full_name'].duplicated() == True]['full_name'])
Con la ejecución de esta línea es fácil identificar a los jugadores que parecen duplicados.
Si queremos filtrar aún más la vista podemos ejecutar la función .value_counts sobre la salida
y así clasifica el número de repeticiones:
print(df[df['full_name'].duplicated() == True]['full_name'].value_counts())
191
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Los primeros resultados de este filtrado son:
Ben Davies 2
Jordan Williams 2
Luis Martínez 2
Scott Brown 2
Santiago García 2
Nathan Smith 2
Danny Rose 2
Liam Kelly 2
Luis Caicedo 1
Graham Kelly 1
…
Se puede comprobar que son nombres “repetibles” y que el número de repeticiones no es
alto. Adicionalmente y dado que la salida de .values_counts es una Serie, podemos
seleccionar, por ejemplo, los primeros cinco elementos. Para ello lo mejor sería hacer lo
siguiente:
print(df[df['full_name'].duplicated() == True]['full_name'].value_counts()
.head(5))
Análisis de valores vacíos
Encontrar valores vacíos en una fuente de datos es algo de lo más común. La tendencia
general es rellenar los datos que sí existen y según el caso no tener datos de algún atributo
puede no afectar al análisis. Veamos si hay datos vacíos, para ello es necesario llamar a la
función pd.isnull(<objeto>) que nos devuelve un objeto de tipo DataFrame de booleanos
que apuntan a los registros vacíos. Adicionalmente la salida de esta función la introducimos
en .sum y nos cuenta el número de ocurrencias.
print(pd.isnull(df).sum())
full_name 0
club 253
age 0
league 253
birth_date 0
height_cm 0
weight_kg 0
nationality 0
overall 0
dtype: int64
192
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La salida nos permite ver cómo hay 253 jugadores sin equipo ni liga asociadas. Si queremos
ver quienes son entonces tendremos que, sobre el df hacer la selección de aquellos cuyo
club sea nulo y filtrar la salida para que nos muestre datos que nos permitan saber quiénes
y así poder razonar el posible motivo.
print(df[pd.isnull(df['club'])][['full_name','age','nationality']].head(6))
full_name age nationality
ID
188152 Oscar dos Santos Emboaba 25 Brazil
184826 Adrien S. Perruchet Silva 28 Portugal
177413 Axel Witsel 28 Belgium
176733 Marcus Berg 30 Sweden
169195 Renato Augusto 29 Brazil
170733 Gervais Yao Kouassi 30 Ivory Coast
Viendo que es posible localizar el motivo podemos filtrar únicamente por país y seleccionar
los 10 primeros países cuyos jugadores no tienen club ni liga asociada.
print(df[pd.isnull(df['club'])]['nationality'].value_counts().head(10))
India 30
Bolivia 28
China PR 25
Hungary 14
South Africa 14
Ecuador 13
Bulgaria 13
Paraguay 12
Egypt 12
Venezuela 11
Esto significa que hay 30 jugadores de la india cuyo equipo no está introducido y cuya liga
tampoco está registrada. Podemos ver qué porcentaje de datos son con respecto del total
de la muestra utilizando la función len(df).
Podemos aplicarla sobre el total
print(df.club.isnull().value_counts() / len(df))
False 0.98594
True 0.01406
193
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Con lo que podemos comprobar que tan tolo hay un 0.01% de los jugadores sin asignación
de equipo o liga. Adicionalmente podemos utilizar esta misma función para ver qué
nacionalidades de jugadores han generado el mayor número de datos no rellenos. (De
estos seleccionamos solo los 10 primeros)
print(((df[pd.isnull(df['club'])]['nationality'].value_counts()/
len(df))).head(10))
India 0.001667
Bolivia 0.001556
China PR 0.001389
Hungary 0.000778
South Africa 0.000778
Bulgaria 0.000722
Ecuador 0.000722
Paraguay 0.000667
Egypt 0.000667
Venezuela 0.000611
Name: nationality, dtype: float64
A la vista de estos resultados y para no eliminar jugadores, que sería una opción, vamos a
rellenar los datos de club y liga que faltan utilizando la palabra “unkown” de manea que
podamos saber si la fecha de nacimiento afecta a dichos jugadores o no.
Para rellenar con valor unknown lo haremos así:
df.club.fillna("Unknown", inplace=True)
df.league.fillna("Unknown", inplace=True)
Recuerda que para acceder a una columna podemos hacerlo utilizando corchetes o
utilizando . y el nombre columna. Finalmente comprobamos que ahora todos los jugadores
tienen club y liga asignados.
print(df.club.isnull().value_counts() / len(df))
False 1.0
Name: club, dtype: float64
Pasemos a trabajar con la fecha de nacimiento. Lo primero es explorar cómo está
construida, para ello lo mejor es ver unos pocos ejemplos.
print(df['birth_date'].head(5))
20801 1985-02-05
158023 1987-06-24
190871 1992-02-05
176580 1987-01-24
167495 1986-03-27
Name: birth_date, dtype: object
194
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La columna es de tipo object, transformemos la columna en tipo date utilizando la función
proporcionada por pandas to_datetime:
df['birth_date'] = pd.to_datetime(df['birth_date'])
print(df['birth_date'].head(5))
20801 1985-02-05
158023 1987-06-24
190871 1992-02-05
176580 1987-01-24
167495 1986-03-27
Name: birth_date, dtype: datetime64[ns]
Si aún no has manejado mucho el formato fecha puede parecer un cambio inocuo pero
que tiene mucha utilidad en la visualización de timeseries.
df['birth_date'] = df['birth_date'].apply(lambda x: datetime.strftime(x,'%d-%m-%Y'))
20801 05-02-1985
158023 24-06-1987
190871 05-02-1992
176580 24-01-1987
167495 27-03-1986
Adicionalmente podemos extraer el dia, mes y año del nacimiento.
df['day'] = pd.DatetimeIndex(df['birth_date']).day
df['month'] = pd.DatetimeIndex(df['birth_date']).month
df['year'] = pd.DatetimeIndex(df['birth_date']).year
La visualización la dejamos para el final No obstante podemos aplicar las siguientes
funciones para hacernos una idea de los resultados.
meses = df['month'].value_counts()
print(meses / len(df))
2 0.122430
1 0.098033
3 0.091197
5 0.085084
8 0.079749
4 0.079415
9 0.079193
6 0.077859
7 0.076692
10 0.074469
12 0.068467
11 0.067411
Con lo que podemos observar la distribución de nacimiento por meses, ordenada de mayor
a menor.
195
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Dejando esto en pausa antes de las visualizaciones pasemos a manejar la columna overall,
que contiene la información de la calidad que la empresa a asignado a cada jugarodor.
Utilizando una vez más la función describe podemos hacernos una idea de los quantiles de
jugadores que hay conforme a su calidad estimada.
print(df.overall.describe())
count 17994.000000
mean 66.253029
std 6.946729
min 46.000000
25% 62.000000
50% 66.000000
75% 71.000000
max 94.000000
Name: overall, dtype: float64
Vamos a crear un conjunto de categorías conforme al overall. Así creamos una nueva
columna, cuyo valor establecemos a nulo inicialmente y que iremos rellenando conforme
a distintas categorías. Como hemos visto al utilizar la función describe el valor mínimo es 46,
con lo cual podemos hacer categorías únicamente desde el 40 hasta el 100
Esta vez, para hacer categorías utilizaremos la función loc. Esta función lo que hace es
seleccionar por índice (Al inicio del ejercicio se establece el índice como el ID del jugador)
Esta vez queremos seleccionar un rango con lo cual son necesarias dos condiciones una
que mire que el valor es mayor que y otra que mire que el valor es menor que.
df['overallcat'] = np.nan
df['overallcat'].loc[(df['overall'] > 40) & (df['overall'] <=50 )] = 4
df['overallcat'].loc[(df['overall'] > 50) & (df['overall'] <=60 )] = 5
df['overallcat'].loc[(df['overall'] > 60) & (df['overall'] <=70 )] = 6
df['overallcat'].loc[(df['overall'] > 70) & (df['overall'] <=80 )] = 7
df['overallcat'].loc[(df['overall'] > 80) & (df['overall'] <=90 )] = 8
df['overallcat'].loc[(df['overall'] > 90) & (df['overall'] <=100 )] = 9
A continuación vemos cómo ha quedado la muestra de los jugadores por categorías.
overall_categories = df.overallcat.value_counts()
print(overall_categories/len(df))
6.0 0.532233
7.0 0.246415
5.0 0.188341
8.0 0.021396
4.0 0.011282
9.0 0.000333
Name: overallcat, dtype: float64
196
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La categoría dominante es la 6, es decir los que tiene calidad 60 a 70 de overall.
1. Visualización de la información general sobre la distribución del mes de nacimiento en
los jugadores de fútbol.
Lo primero será crear el gráfico que llamaremos sns_plot y que se obtiene de utilizar la
función sns.factorplot, que básicamente muestra los datos en un diagrama de barras.
sns_plot = sns.catplot(x='month', data=df, kind="count", height=5,
aspect=3, edgecolor='black');
Se podría guardar esta figura pero aprovechamos para añadirle valores extra que ayuden
a entender la imagen. Añadimos un título
sns_plot.fig.subplots_adjust(top=.9)
Preparamos la lista de meses y modificamos el parámetro xticklabels para que muestre el
nombre abreviado de los meses.
monthList = ['Ene','Feb','Mar','Abr',
'May','Jun','Jul','Ago',
'Sep','Oct','Nov','Dic']
sns_plot.set_xticklabels(monthList)
Añadimos un subtítulo y modificamos las etiquetas del eje x y del eje y
sns_plot.fig.suptitle("Nacimiento de jugadores de fútbol por mes")
sns_plot.set_ylabels("Número de nacimientos")
sns_plot.set_xlabels("Mes de nacimiento")
Adicionalmente a cada columna de datos le añadimos el valor de la cuenta total de
nacimientos. Para ello tenemos que utilizar el eje ax de la imagen y añadirle texto para
cada una de las columnas
for p in ax.patches:
ax.text(p.get_x() + p.get_width()/2., p.get_height(),
'{0}'.format(int(p.get_height())),
fontsize=10, color='black', ha='center', va='bottom')
Finalmente guardamos la imagen:
sns_plot.savefig("1_Distribucion_general_mes_nacimiento.png")
197
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Al terminar de pintar la imagen es necesario “cerrarla”, como si de un fichero se tratase
para hacer saber a Python que debe comentar una nueva. De lo contrario no se realizarán
los cambios.
El “cierre” de una imagen compuesta se consige ejecutando:
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
198
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2. Visualización de la densidad de nacimientos por mes.
Seaborn nos proporciona el gráfico de tipo sns.kdeplot con la densidad por número de
ocurrencias.
sns_plot2 = sns.kdeplot(df['month'], label='Month of birth', shade=True)
sns_plot.savefig("2_densidad_nacimientos.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
199
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
3. Visualización del efecto del mes de nacimiento en la “calidad” u “overall” de un
jugador.
En otras palabras, es visualizar la relación que hay entre calidad y mes de nacimiento.
El cálculo de la media podemos hacer usando la función mean()
df_overall = df.groupby(['month'])['overall'].mean()
La librería pandas trae un conjunto de visualizaciones por defecto. Si aislamos
la muestra a visualizar podemos utilizar .plot() para que nos muestre los datos.
ax3 = df_overall.plot()
ax3.set_title("Overall de un jugador respecto del mes de nacimiento");
ax3.figure.savefig("3_relacion_calidad_mes_nacimiento.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
200
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
4. Visualización del mes de nacimiento con respecto al año
Si queremos ver varias representaciones de datos en la misma imagen utiliznado como filtro
una de las variables, podemos usar un sns.FacetGrid, especificamos el filtro a realizar y el
número de columnas (col_wrap). Posteriormente escogemos la información a pintar en
cada una de las imágenes del grid utilizando la función map
sns_plot = sns.FacetGrid(df, col="year",col_wrap=5)
sns_plot.map(sns.kdeplot, "month");
sns_plot.savefig("4_nacimiento_por_años.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
Este tipo de gráficas nos permiten realizar una visualización rápida de los elementos y se
puede destacar que una mayoría importante de los jugadores de 1989, 1993 y 1997
nacieron en determinados meses mientras que aquellos nacidos en el año 1996 tienen una
distribución diferente.
201
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
5. Visualización de la densidad de nacimiento en el año 1997 y 2000 concretos
Es importante recordar que todas lo que se va pintando se pinta sobre el mismo lienzo, salvo
que decidamos comenzar con uno nuevo. Sabiendo esto superponer dos vistas es tan
sencillo como realizar dos visualizaciones.
Podemos comparar dos años realizando dos visualizaciones
print(df[df['year'] == 1997]['month'].describe())
print(df[df['year'] == 2000]['month'].describe())
label_1997 = "1997, {0} jugadores".format(len(df[df.year == 1997]))
label_2000 = "2000, {0} jugadores".format(len(df[df.year == 2000]))
ax5= sns.kdeplot(df[df['year'] == 1997]['month'],
label=label_1997, shade=True)
202
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
ax5= sns.kdeplot(df[df['year'] == 2000]['month'],
label=label_2000,shade=True)
print(df['year'].value_counts())
ax5.set_title("Comparativa de mes de nacimientos");
ax.figure.savefig("5_comparativa_densidad.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
203
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
6. Visualización de la densidad de nacimiento según la liga en la que juega.
El dataset contiene mucha información de jugadores, clubs y ligas. Si queremos hacer una
comparación conforme a la liga debemos primer ver las ligas que tenemos (y que tengan
el suficiente número de jugadores para que sean relevantes). Lo primero es acceder a la
página de la IFFHS (International Federation of Football History & Statistics) cuyo ranking de
ligas es: Española, Inglesa, Brasileña, Italiana, Francesa, Colombiana, Argentina, …
Con esta lista vamos a buscar la denominación de las mismas en el dataset.
print(df['league'].value_counts().headh(15))
A continuación creamos una lista con los nombres de las ligas que queremos comparar
entre sí:
top6leagues = ["Spanish Primera División", "English Premier League",
"Italian Serie A", "French Ligue 1",
"Colombian Primera A", "Argentinian Superliga"]
Vamos a crear una copia del dataset que contenga solo los datos que queramos
visualizar, es decir, los de las ligas mencionadas.
df_plot = df[df['league'].isin(top6leagues)].copy()
Hacemos uso del método isin que comprueba si una cadena está en una secuencia, en
este caso una lista. Aquellos en los que coincida serán los seleccionados y posteriomente
copiados en el nuevo DataFrame.
Utilizando la información del nuevo DataFrame vamos a crear un diagrama de barras con
los meses de nacimiento. A sustituir las etiquetas del eje x por el nombre de los meses y a
añadir nombres a los ejes x, y; finalmente añadir título a la imagen y la guardamos.
sns_plot6 = sns.factorplot(x='month', data=df_plot,kind="count",
hue='league', height=8, aspect=2, edgecolor='black');
sns_plot6.fig.subplots_adjust(top=.9)
monthList = ['Ene','Feb','Mar','Abr','May','Jun','Jul','Ago',
'Sep','Oct','Nov','Dic']
sns_plot6.set_xticklabels(monthList)
sns_plot6.fig.suptitle('Nacimiento mensual comparativo por liga en la que juega')
sns_plot6.set_ylabels("Cantidad de nacimientos")
sns_plot6.set_xlabels("Mes de nacimiento");
sns_plot6.savefig("6_nacimientoporliga.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
204
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
205
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
7. Visualizacion de la distribución de mes de nacimiento por equipo
En este caso vamos a utilizar un bucle para que vaya dibujando sobre la misma imagen las
distintas distribuciones.
Antes de eso debemos hacer una selección de los equipos a mostrar, en este caso hay
equipos de ligas europeas y de sur américa.
topclub = ["Real Madrid CF", "Grêmio", "Manchester United", "FC Barcelona",
"Paris Saint-Germain", "Flamengo","Juventus", "FC Bayern Munich",
"Manchester City", "FC Red Bull Salzburg"
]
Con la lista creada podemos recorrer la lista y crear un gráfico de densidad para cada uno
de los equipos seleccionados
for club in topclub:
ax8 = sns.kdeplot(df_plot[df_plot['club']==club]['month'],
label=club, legend=True)
Finalmente añadimos el título, guardamos la imagen y cerramos.
ax8.set_title("Densidad de nacimiento en equipos de fubol",fontsize=10);
ax8.figure.savefig("7_club.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
206
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
8. Visualizacion de la distribución de mes de nacimiento por equipo (cuartiles)
En este caso vamos a mostrar la misma información que en el caso anterior pero de
diferente manera. Vamos a mostrar la distribución en quartiles de los jugadores de distintos
equipos según el mes de nacimiento.
df_plot = df[df['club'].isin(topclub)]
g = sns.catplot(x="month", y="club", data=df_plot, kind='box',
height=4, aspect=2, palette='bright')
Posteriormente terminamos de personalizar la imagen con in titulo y poniendo nombre a los
ejes x, y.
g.fig.subplots_adjust(top=.9)
g.fig.suptitle('Distribución del mes de nacimiento de las plantillas')
g.set_ylabels("Nombre del equipo")
g.set_xlabels("Mes de nacimiento");
g.fig.savefig("8_club_cuartiles.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
207
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.16.4.4. Código sin comentarios
# Cargas las librerías e ignorar los warnings
import warnings; warnings.simplefilter('ignore')
import numpy as np
import pandas as pd
# Librerías de visualización
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib; matplotlib.style.use('ggplot')
# carga de la librería datetime
from datetime import datetime
# Configuración de pandas
pd.set_option('display.max_columns', 100)
pd.set_option('display.max_rows', 100)
# Configuración de Seaborn
sns.set_context("notebook")
sns.set_palette('husl')
# Cargamos los datos
df = pd.read_csv('./data/fifa18-player-dataset.csv', encoding='utf_8')
# Visualización de los primeros elementos del DataFrame
print(df.head()) # Se puede indicar un número
# Visualización de los últimos elementos del df
print(df.tail(8))
# Visualización de n elementos al azar
print(df.sample(7))
# Visualización del tamaño del DataFrame
print(df.shape)
# (17994, 185) 17.7994 filas y 185 atributos o columnas
# Podemos enumerar y ver todas las columnas del DataFrame usando un bucle.
# Esto nos puede ayudar a descartar qué campos utilizar y cuáles no. Además
# al imprimir el número de columna es más fácil hacer esa selección.
for e, col in enumerate(df.columns):
print(e,"->",col)
# La lista de los 185 es largo.En este ejercicio usaremos solo las
# siguientes columnas:
# • 0 -> ID
# • 2 -> full_name
# • 3 -> club
# • 6 -> age
# • 7 -> league
# • 8 -> birth_date
# • 9 -> height_cm
208
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# • 10 -> weight_kg
# • 14 -> nationality
# • 19 -> overall
# Podríamos eliminar todas las columnas restantes pero pandas nos ofrece
# seleccionar qué columnas queremos leer del fichero.
selectedColumns = [0,2,3,6,7,8,9,10,14,19]
# cargar los datos seleccionados
df = pd.read_csv('./data/fifa18-player-dataset.csv', encoding='utf_8',
usecols=selectedColumns)
# Sería lo mismo que hacer
# df = pd.read_csv('../input/complete.csv', encoding='utf_8',
# usecols=[0,2,3,6,7,8,9,10,14,19])
# Comprobamos que solo se han cargado las columnas seleccionadas:
print(df.shape)
# (17994, 10)
# El índice por defecto es un índice autonumérico de 0..n, para hacer que el
# índide sea el ID del jugador ejecutamos:
df = df.set_index('ID')
# Información de las columnas del DataFrame
print(df.info())
# A continuación, y tras ver los datos del data set vamos a confirmar que
# no hay duplicados, si los hubiera, habría que eliminarlos.
# print(df.duplicated().value_counts())
print(df['club'].duplicated().value_counts())
print(df['full_name'].duplicated().value_counts())
print(df[df['full_name'].duplicated() ==
True]['full_name'].value_counts().head(5))
print(type(pd.isnull(df).sum()))
print(pd.isnull(df).sum())
print(df[pd.isnull(df['club'])][['full_name','age','nationality']].head(6))
print(df[pd.isnull(df['club'])]['nationality'].value_counts().head(10))
print(df.club.isnull().value_counts() / len(df))
print(((df[pd.isnull(df['club'])]['nationality'].value_counts()/
len(df))).head(10))
df.club.fillna("Unknown", inplace=True)
df.league.fillna("Unknown", inplace=True)
print(df.club.isnull().value_counts() / len(df))
print(df['birth_date'].head(5))
df['birth_date'] = pd.to_datetime(df['birth_date'])
print(df['birth_date'].head(5))
209
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
df['birth_date'] = df['birth_date'].apply(lambda x: datetime.strftime(x,'%d-%m-%Y'))
df['day'] = pd.DatetimeIndex(df['birth_date']).day
df['month'] = pd.DatetimeIndex(df['birth_date']).month
df['year'] = pd.DatetimeIndex(df['birth_date']).year
df.day = df.day.astype(int)
df.month = df.month.astype(int)
df.year = df.year.astype(int)
meses = df['month'].value_counts()
print(meses / len(df))
df['overallcat'] = np.nan
df['overallcat'].loc[(df['overall'] > 40) & (df['overall'] <=50 )] = 4
df['overallcat'].loc[(df['overall'] > 50) & (df['overall'] <=60 )] = 5
df['overallcat'].loc[(df['overall'] > 60) & (df['overall'] <=70 )] = 6
df['overallcat'].loc[(df['overall'] > 70) & (df['overall'] <=80 )] = 7
df['overallcat'].loc[(df['overall'] > 80) & (df['overall'] <=90 )] = 8
df['overallcat'].loc[(df['overall'] > 90) & (df['overall'] <=100 )] = 9
overall_categories = df.overallcat.value_counts()
print(overall_categories/len(df))
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 1 . Visualización de la información general sobre la distribución
# del mes de nacimiento en los jugadores de fútbol.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
sns_plot = sns.catplot(x='month', data=df, kind="count", height=5,
aspect=3, edgecolor='black');
# titulo
sns_plot.fig.subplots_adjust(top=.9)
monthList = ['Ene','Feb','Mar','Abr',
'May','Jun','Jul','Ago',
'Sep','Oct','Nov','Dic']
sns_plot.set_xticklabels(monthList)
sns_plot.fig.suptitle("Nacimiento de jugadores de fútbol por mes")
sns_plot.set_ylabels("Número de nacimientos")
sns_plot.set_xlabels("Mes de nacimiento")
# Extraer el eje actual de la imagen
ax = plt.gca()
# Añadir texto a cada columna
for p in ax.patches:
ax.text(p.get_x() + p.get_width()/2., p.get_height(),
'{0}'.format(int(p.get_height())),
fontsize=10, color='black', ha='center', va='bottom')
210
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
sns_plot.savefig("1_Distribucion_general_mes_nacimiento.png")
sns_plot.fig.suptitle("")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 2. Visualización de la densidad de nacimientos por mes.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
ax= sns.kdeplot(df['month'], label='Mes de nacimiento', shade=True)
ax.figure.savefig("2_densidad_mes_nacimiento.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 3. Visualización del efecto del mes de nacimiento en la “calidad” u
# “overall” de un jugador.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
df_overall = df.groupby(['month'])['overall'].mean()
ax3 = df_overall.plot()
ax3.set_title("Overall de un jugador respecto del mes de nacimiento");
ax3.figure.savefig("3_relacion_calidad_mes_nacimiento.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 4. Densidad del mes de nacimiento y el año
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
sns_plot = sns.FacetGrid(df, col="year",col_wrap=5)
sns_plot.map(sns.kdeplot, "month");
sns_plot.savefig("4_nacimiento_por_años.png")
# sns_plot.fig.clf()
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# plt.cla()
# plt.close()
# plt.clf()
# plt.close("all")
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 5. Visualización de la densidad de nacimiento en el año 1997 y 2000
# concretos
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
print(df[df['year'] == 1997]['month'].describe())
print(df[df['year'] == 2000]['month'].describe())
211
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
label_1997 = "1997, {0} jugadores".format(len(df[df.year == 1997]))
label_2000 = "2000, {0} jugadores".format(len(df[df.year == 2000]))
ax5= sns.kdeplot(df[df['year'] == 1997]['month'],
label=label_1997, shade=True)
ax5= sns.kdeplot(df[df['year'] == 2000]['month'],
label=label_2000,shade=True)
print(df['year'].value_counts())
ax5.set_title("Comparativa de mes de nacimientos");
ax5.figure.savefig("5_comparativa_densidad.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 6. Visualización de la densidad de nacimiento por liga.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
print(df['league'].value_counts().head(15))
top6leagues = ["Spanish Primera División", "English Premier League",
"Italian Serie A", "French Ligue 1",
"Colombian Primera A", "Argentinian Superliga"]
df_plot = df[df['league'].isin(top6leagues)].copy()
print(df_plot.head())
sns_plot6 = sns.catplot(x='month', data=df_plot,kind="count",
hue='league', height=8, aspect=2, edgecolor='black');
sns_plot6.fig.subplots_adjust(top=.9)
monthList = ['Ene','Feb','Mar','Abr',
'May','Jun','Jul','Ago',
'Sep','Oct','Nov','Dic']
sns_plot6.set_xticklabels(monthList)
sns_plot6.fig.suptitle('Nacimiento mensual comparativo por liga en la que juega')
sns_plot6.set_ylabels("Cantidad de nacimientos")
sns_plot6.set_xlabels("Mes de nacimiento");
sns_plot6.savefig("6_nacimientoporliga.png")
# plt.show()
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 7. Visualización de la distribución de mes de nacimiento por equipo.
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
topclub = ["Real Madrid CF", "Grêmio", "Manchester United", "FC Barcelona",
"Paris Saint-Germain", "Flamengo","Juventus", "FC Bayern Munich",
"Manchester City", "FC Red Bull Salzburg"
]
212
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
for club in topclub:
ax8 = sns.kdeplot(df_plot[df_plot['club']==club]['month'],
label=club, legend=True)
ax8.set_title("Densidad de nacimiento en equipos de fubol",fontsize=10);
ax8.figure.savefig("7_club.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
# 8. Visualización
# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
df_plot = df[df['club'].isin(topclub)]
g = sns.catplot(x="month", y="club", data=df_plot, kind='box',
height=4, aspect=2, palette='bright')
g.fig.subplots_adjust(top=.9)
g.fig.suptitle('Distribución del mes de nacimiento de las plantillas')
g.set_ylabels("Nombre del equipo")
g.set_xlabels("Mes de nacimiento");
g.fig.savefig("8_club_cuartiles.png")
plt.cla() # Cierra el ‘axis’ o eje de la imagen
plt.clf() # Limpia la figura completamente
plt.close() # cierra la venta actual de funcionamiento
213
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.17.1. Ejercicio 5: Captura de tweets
1.17.4.1. Introducción
Twitter es una fuente continua de datos que se puede incorporar (con cuidado) al proceso
analítico de datos. Este ejercicio te ayudará a acceder al API en tiempo real de twitter. Ten
en cuenta que al ser gratuito es posible que no puedas capturar todos los tweets
1.17.4.1. Objetivo
El objetivo principal es conocer cómo se ejecuta un script de Python y utilizar su salida para
introducir datos en una base de datos (en este caso la base de los datos será un archivo
json)
El ejercicio hace lo siguiente:
• Ayuda a crear una aplicación en twitter
• Obtiene resultados de twitter streaming API
• Almacena los resultados en un json
1.17.4.1. Requisitos
Este ejercicio requiere que registres tu cuenta de twitter una aplicación. Accede a la
página: https://apps.twitter.com/ con tu cuenta de twitter y una vez logeado pulsa “Create
New APP”
214
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
A continuación crea una aplicación.
Los atributos podrían ser algo así:
Name =MyFirstTwitterApp
Description = This is a test aplication
Website = https://www.campusbigdata.com
Marca la casilla de “Developer Agreement” una vez que hayas leído y aceptado el
acuerdo.
215
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Accede a la pestaña “Keys and Access Tokens” para obtener los datos que serán
necesarios introducir en el archivo:
216
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1.17.4.3. Código Comentado
Los siguientes pasos son sencillos. Lo primero es importar las librerías e introducir los
parámetros anteriores en las variables correspondientes:
import oauth2 as oauth
import urllib.request
# Parámetros de configuración del script
consumer_key = ""
consumer_secret = ""
access_token = ""
access_token_secret = ""
_debug = 0
oauth_token = oauth.Token(key=access_token, secret=access_token_secret)
oauth_consumer = oauth.Consumer(key=consumer_key, secret=consumer_secret)
signature_method_hmac_sha1 = oauth.SignatureMethod_HMAC_SHA1()
http_method = "GET"
http_handler = urllib.request.HTTPHandler(debuglevel=_debug)
https_handler = urllib.request.HTTPSHandler(debuglevel=_debug)
Con los parámetros de entrada establecidos creamos una función para que solicite
información del streaming API de twitter
def twitterreq(url, method, parameters):
# Creación del objeto request
req = oauth.Request.from_consumer_and_token(oauth_consumer,
token=oauth_token,
http_method=http_method,
http_url=url,
parameters=parameters)
# Acreditación
req.sign_request(signature_method_hmac_sha1, oauth_consumer, oauth_token)
# Inclusión de las cabeceras
headers = req.to_header()
if http_method == "POST":
encoded_post_data = req.to_postdata()
else:
encoded_post_data = None
url = req.to_url()
opener = urllib.request.OpenerDirector()
opener.add_handler(http_handler)
217
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
opener.add_handler(https_handler)
# Captura de información
response = opener.open(url, encoded_post_data)
return response
Una función extra nos ayudará a establecer una url distinta en función del tipo de
búsquedas que queramos hacer. El API gratuita está limitada a no utilizar ningún filtro o
utilizar filtros de palabras a buscar o localizaciones.
def fetchsamples():
# Captura de tweets si filtros
# url = "https://stream.twitter.com/1.1/statuses/sample.json"
# Utiliza track para buscar seguir palabras
# url = "https://stream.twitter.com/1.1/statuses/filter.json?track=Madrid,Gol"
# Usar el parámetro location para determinar la zona. Requiere usar track
# En este caso Madrid.
latitud, longitud = str(40.4165000), str(-3.7025600)
url =
"https://stream.twitter.com/1.1/statuses/filter.json?track=Marcelo&locations =
"+latitud+", "+longitud
print(url)
parameters = []
response = twitterreq(url, "GET", parameters)
# Visualizacíon
for line in response:
print(line.strip().decode('utf-8'))
En este ejercicio se han encapsulado las funciones. Establecemos el parámetro __name__
como principal para que solo se ejecute el código que haya a continuación y que será
nuestra función principal:
if __name__ == '__main__':
fetchsamples()
A partir de este momento si quieres ejecutar el script y almacenar la información que
genera debes ir a la línea de comandos (aplicación cmd o Powershell en Windows;
Aplicación Terminal en Linux/Mac)
Ejecuta los siguientes comandos:
C:\Users\myuser> conda info –envs
218
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Deberían aparecer todos los entornos virtuales de tu equipo. En el apartado de los entornos
virtuales hemos creado uno para todos los ejercicios. El nombre escogido para el entorno
virtual es venvcampusbigdata. A continuación vamos a proceder a activarlo
C:\Users\myuser> conda activate venvcampusbigdata
Al activarlo podrás ver lo siguiente:
(venvcampusbigdata) C:\Users\myuser>
Utiliza la línea de comandos para situarte en la carpeta en la que tengas almacenado el
fichero. (En Windows la separación de carpetas se hace con \ y en Linux-mac con / )
(venvcampusbigdata) C:\Users\myuser> cd Documents\ejercicios
(venvcampusbigdata) C:\Users\myuser\Documents\ejercicios>
En este punto puedes ejecutar el comando Python y el nombre del ejercicio. Si deseas
cancelar puedes usar Cntrl+c o cntrl+z (venvcampusbigdata) C:\Users\myuser\Documents\ejercicios>python twitter.py
Podrás comprobar la salida de todos los prints en tu pantalla. Ahora vamos a dirigir esos
prints hacia un archivo:
(venvcampusbigdata) C:\Users\myuser\Documents\ejercicios>python twitter.py >>
capturatweets.json
Las flechas >> indican que deseas pasar la salida del primer comando como entrada para
el siguiente comando.
El archivo generado se puede leer desde un script de python usando el comando pandas.DataFrame.from_json(filename)
219
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2. R
2.1. Introducción a R
Si tenemos que definir R, diríamos que se trata de un lenguaje y entorno de programación
con un claro enfoque al análisis estadístico. No obstante, a pesar de que ese era su
planteamiento inicial, en la actualidad, dada la aportación de muchos académicos e
investigadores, se ha convertido en un lenguaje muy completo que le hace muy popular
en el campo de Data Mining, investigación analítica, bioinformática o matemáticas
financieras.
Inicialmente desarrollado por Robert Gentleman y Ross Ihaka del Departamento de
Estadística de la Universidad de Auckland en 1993, R es un programa en continuo proceso
de evolución. En la actualidad, es el R Development Core Team quien se responsabiliza de
su desarrollo. R es parte del sistema GNU, y se distribuje bajo la licencia GNU GPL. Se
encuentra disponible para los sistemas operativos Windows, Mac OS, Unix y GNU/Linux.
Así, a modo de resumen, podemos decir que por R nos podemos referir no sólo al lenguaje
sino al intérprete que ejecuta el código escrito, el sistema que es capaz de representar
visualmente lo que hemos programado y la aplicación que engloba a los anteriores.
2.1.1. Ventajas de R frente a otros lenguajes
Cuando una persona se plantea aprender un lenguaje de programación, en nuestro caso
aplicado a la ciencia o análisis de datos, la pregunta que surge es si la elección es acertada
o qué ventajas e inconvenientes presenta dicho lenguaje frente a otras alternativas. Siendo
conscientes de la velocidad a la que evoluciona este campo, los lenguajes dominantes son
susceptibles también de dichos cambios, pudiendo alternar sus posiciones en función de
qué funcionalidades (se) desarrollen. En esta sección, tratamos de describir las ventajas de
R frente a otras alternativas como SAS, SPSS o Python.
SAS ha sido el líder del mercado como software comercial para el análisis de datos. Como
alternativa directa a SAS, por su naturaleza abierta, destaca R, muy ampliamente utilizada
por académicos e investigadores. Al ser el equivalente en código abierto a SAS, presenta
un muy amplio abanico de funciones y funcionalidades, así como estar en continuo
desarrollo. Efectivamente, la desventaja de SAS (y SPSS) es que, al no ser libres, la velocidad
con la cual se adaptan o evolucionan es menor que la de R o Python.
Comparando R con Python, el primero pierde frente al segundo si se comparan como
lenguajes de programación propiamente dicho. R no es un verdadero lenguaje de
programación y, por tanto, Python destaca como una herramienta de desarrollo o
construcción de código. Esto es debido a algo que siempre se ha destacado de Python, la
versatilidad y la facilidad de lenguaje o sintáxis. Sin embargo, en visualización, se podría
afirmar que R sigue por delante, con paquetes como ggplot2, rCharts o googleVis. De
hecho, librerías de Python para visualización, como Plot.ly, también tienen cabida en R. Y
220
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
no sólo en su postprocesado final, sino en el propio análisis de los datos. Aunque Python ya
cuenta con librerías destinadas al análisis estadístico de datos, R sigue igualmente por
delante en este aspecto.
Si enumeramos algunas de las ventajas (no exclusivas) de R:
• Elevado número de funciones o paquetes para análisis estadístico.
• Excelente herramienta para procesado y tratamiento de imágenes.
• Numerosas funciones específicas para postprocesado y visualización de resultados,
generando gráficos de alta calidad.
• Puedes utilizar Python desde R usando rPython
• Gratuito, código libre y abierto. No requiere de licencia, se puede extender por
tener acceso al código fuente y puedes corregir, modificar o ampliar el código sin
depender del proveedor.
• Independiente de plataforma, funcionando en los sistemas operativos Windows,
Mac OS, Unix y GNU/Linux.
• Acceso a una amplia documentación, tanto en comunidad (foro o blog) como a
nivel académico (artículos de investigación revisados por pares).
Podemos concluir que la elección de R o Python atiende más a las necesidades específicas
de cada uno, y entendidas dichas necesidades, en la identificación de las capacidades
de cada opción para resolver el problema. Generalmente, si se trabaja en aplicaciones de
investigación, estadística o análisis de datos, R será la opción dominante. Si se trata de
aplicaciones más de ingeniería o programación, Python será la primera. R no requiere que
seas programador; de hecho, no es un lenguaje para programadores sino más para
estadísticos. Python sí es un lenguaje más vinculado a la programación y, por ello, que su
sintáxis sea tan legible.
221
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.2. Características del lenguaje
2.3.1. Entorno de desarrollo
Una vez instalado R en nuestro ordenador, nos ponemos en situación de utilizarlo. Si bien
cabe la opción de ejecutar R desde terminal o línea de comandos (Console Mode), aquí
consideramos como opción por defecto el trabajar con un IDE (Integrated Development
Environment) o entorno de desarrollo.
Existen numerosas opciones de IDE para trabajar con R, pudiendo destacar a Bluefish,
Eclipse, Emacs, jEdit, Vim, notepad++, Visual Studio o RStudio. Es este último editor el que
propondremos como herramienta de desarrollo en este curso. RStudio se encuentra
disponible para cualquiera de los sistemas operativos indicados en la sección 1.1. Incluye
una consola, un editor con marcado de síntesis de programacación, así como herramientas
de representación gráfica y visualización, historial de acciones, debugging y gestión de
trabajo.
2.2.2. Configuración e instalación de paquetes
Como se ha comentado, R surgió y se desarrolló en un entorno colaborativo, de modo que
su crecimiento es constante con las aportaciones de todos aquellos que trabajan o
necesitan de nuevas capacidades de R. Aunque la instalación básica o por defecto de R
ya incluye numerosas funciones para las distintas tareas de un científico de datos, desde la
importación, transformación, actuación sobre el dato y posterior análisis o post-proceso, la
fortaleza de R radica precisamente en esa disponibilidad de nuevas funciones que ayudan
a las ya presentes.
La organización de las funciones se realiza mediante paquetes. Por lo tanto, entendemos
por paquete a un conjunto o colección de funciones, y en algunos casos incluso datos, que
se recogen en una carpeta con una estructura manejable por R. Los paquetes son lo
equivalente a las librerías en C/C++ o Python, o las clases en Java. Los paquetes se
encuentran en un repositorio público oficial llamado CRAN (Comprehensive R Archive
Network). En la actualidad (noviembre de 2018), en CRAN se almacenan hasta 13468
paquetes, pudiéndose consultar por fecha de publicación o por tema:
http://cran.r-project.org/web/packages/available_packages_by_date.html
https://cran.r-project.org/web/views/
Listado con información de paquetes instalados installed.packages()
Listado de paquetes disponibles en repositorio available.packages()
Conjunto de paquetes a descargar download.packages("x")
Conjunto de paquetes a instalar install.packages("x")
222
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
223
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Sin embargo, no todos los paquetes que existen se encuentran en CRAN. Así, el paquete
devtools() permite instalar paquetes de otros repositorios como GitHub. Dentro del
paquete devtools() se encuentra para ello la función install_github().
Para poder utilizar un paquete que no se encuentre instalado, previamente es necesario
instalarlo, ya sea mediante la función install.packages() o en RStudio pulsando en el
botón Install Packages (ventana izquierda-inferior, sección Packages/) o bien en la barra
de herramientas, en Tools/Install Packages. Una vez instalado, hay que cargarlo mediante
el comando library() para permitir la llamada a cualquiera de las funciones recogidas en
el paquete.
2.2.2.1. Paquetes más importantes para el análisis de datos
plyr
Paquete utilizado para la agregación de datos y la aplicación de funciones por grupos, de
modo que se puede trabajar sobre subgrupos de un conjunto de datos más amplio. Este
paquete es de los más utilizados y contiene algunas funciones para operar sobre los datos
ddply(), daply(), dlply(), adply(), ldply().
lubridate:
Paquete utilizado para el tratamiento de fechas y series temporales así como para
operaciones aritméticas sobre ajuste de tiempo. Contiene funciones que permiten
modificar formato de fechas.
reshape2:
Paquete utilizado para la transformación del formato de los datos así como para su
agregación. Generalmente se utiliza con matrices o data.frame donde se quiere la
transformación de formato wide a long. Los datos en formato wide tienen una columna por
cada variable mientras que el formato long tiene una columna para cada uno de los tipos
de variables y otra para los valores de esas variables. Las funciones melt() y cast() son las
utilizadas para dichos cambios.
stringr:
Paquete desarrollado para trabajar con texto. Permite procesar factores y caracteres de la
misma forma, simplificar operaciones de procesamiento de cadenas de caracteres, e
incorporar funciones de procesamiento de texto.
ggplot2:
A pesar de que R ya incluye por defecto algunas funciones básicas para la representación
gráfica de resultados, este paquete es el más completo y óptimo para cualquier
visualización, con una amplísima variedad de opciones y gráficos.
224
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
rgl:
Paquete para la generación de gráficos interactivos en 3D y en tiempo real.
foreign:
Paquete que permite la carga directa de datos extraídos de otro software como SAS o SAP.
SQLdf, RODBC, RPostgresSQL, RSQLite (entre otros):
Paquetes para cargar datos de una base de datos y poder realizar consultas o diversas
acciones sobre los datos.
caret:
Paquete que incluye sencillas herramientas para analizar la calidad de los datos, selección
de características y construcción de modelos predictivos. Los resultados que proporciona
son especialmente completos.
car:
Paquete que permite realizar análisis de varianza (ANOVA) para determinar la importancia
(relativa) de diferentes variables de un conjunto de datos.
randomforest:
Como su nombre indica, paquete que permite trabajar con randomforest. Éste es un
método de clasificación mediane el uso de árboles de decisión aplicado a grandes
volúmenes de datos, pudiéndose utilizar para el aprendizaje tanto supervisado como no
supervisado. Es bastante popular por su sencillez y buenos resultados.
zoo y forecast:
Paquetes que realizan el formateo de datos y creación de modelos de predicción para
series temporales.
shiny:
Paquete utilizado para la representación de resultados, mostrándolos mediante gráficos
interactivos que se pueden publicar en cualquier web.
xtable:
Paquete utilizado para exportar tablas desde DataFrames a HTML o LaTeX.
225
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.2.2.2. Paquetes desarrollados para deporte
Sin entrar en detalle en los diferentes y muy diversos paquetes que se han desarrollado para
el análisis de datos deportivos, aquí enumeramos unos cuantos. Dado que en Estados
Unidos se cuenta con un entorno analítico mucho más maduro, la gran mayoría de estos
paquetes se enfocan a los deportes más populares del país. Así, en baloncesto o NBA
encontramos paquetes como ballR o bbscrapeR; en beisbol, origen de Moneyball,
encontramos a Lahman, pitchRx u openWAR; y en hockey hielo, nhlscrapr o nhl-pbp. El
atletismo, o al menos el running, también tiene cabida en R. El paquete strava, disponible
en GitHub, permite visualizar datos de la App Strava. Mientras, el paquete decathlon recoge
datos de la prueba olímpica desde 1985 a 2006. Finalmente, también podemos incluir un
paquete destinado a la gestión de datos para apuestas deportivas, como el paquete que
trabaja con la API de betfair, betfair. Más generalistas son el paquete sport o
PlayerRatings.
2.2.2.3. Paquetes desarrollados para fútbol
engsoccerdata:
Repositorio de bases de datos de partidos completos de las principales competiciones
inglesas (Premier League, FA Cup) así como ligas europeas. Incluye igualmente algunas
funciones útiles para el procesado de estos datos.
soccermatics:
Paquete que incluye diferentes funciones o herramientas para la visualización de datos
asociados a eventos realizados por jugadores o información espacial y de seguimiento de
movimientos. Representa, en otros, posiciones de disparos, posiciones medias, redes de
pases o mapas de calor sectoriales.
SportAnalytics:
Aunque dispone de varias funciones relacionadas con otros deportes, incluye dos ligadas
al fútbol y, específicamente, a la Bundesliga. No obstante, también incorpora funciones
generalistas útiles para el análisis de datos.
regista:
Paquete desarrollado para realizar algunas de las operaciones más populares en análisis
de datos deportivos. En particular, permite diseñar un modelo de Dixon-Coles para estimar
la fortaleza de un equipo y poder predecir resultados de partidos de fútbol.
goalmodel:
Paquete que permite construir modelos Gaussianos para predecir resultaods (goles
marcados) en partidos de fútbol.
226
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.3. Sintáxis básica
Siendo conscientes de la dificultad de comenzar a trabajar con un lenguaje nuevo,
estructuramos esta primera etapa de trabajo con R con una descripción de la sintáxis
básica para familiarizarse con el entorno. Sin entrar en los formalismos de la tipología o
naturaleza de un objeto en R, comenzaremos con operaciones básicas aplicadas
únicamente a valores numéricos. Posteriormente, ya ubicados en la práctica con R,
introduciremos los tipos más básicos de datos; y extenderemos estos conceptos a conjuntos
de valores numéricos unidimensionales (vectores) o bidimensionales (matrices) para, a
continuación, ampliarlo a estructuras de datos (dataframes).
2.3.1. Operaciones básicas
Las operaciones matemáticas básicas son inmediatas y no requieren más que su escritura
y ejecución. Cabe recordar que las propiedades asociativa, conmutativa y distributiva de
la adición y multiplicación son tenidas en cuenta en R, de modo que se deben respetar
en su escritura.
1
2
3
4
5
6
7
8
9
10
> 2 + 3
[1] 5
> (3 + 2)*(4 – 1)
[1] 15
> 9850/20
[1] 492.5
> 4^3
[1] 64
20 < 5
[1] FALSE
El operador de asignación puede ser =, -> o <-, siendo preferible el uso de éste último
debido a que el signo igual puede tener connotaciones lógicas y el segundo menos
práctico que el tercero.
1
2
3
4
5
6
7
8
9
> goles_local = 12;
> goles_visitante <- 8;
> 0.80 -> goles_local_p90;
> goles_local
[1] 12
> goles_visitante
[1] 8
> goles_local_p90
[1] 0.80
227
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Nótese que en este ejemplo hemos utilizado el signo ; para incluir varias instrucciones en
una misma línea de modo que al pulsar la tecla Enter no ha supuesto una salida por pantalla
del valor correspondiente. No es hasta que se hace llamada a la variable cuando sale el
resultado correspondiente. En este caso, hemos hecho uso de los tres métodos de
asignación. El operador de asignación resulta interesante cuando se va a utilizar de forma
reiterada un cierto valor, actuando la variable como una constante.
1
2
3
4
5
6
> goles_local + goles_visitante
[1] 20
> diferenciagoles <- goles_local – goles_visitante
[1] 4
> partidos_local <- goles_local/goles_local_p90
[1] 15
Algunos de los operadores más básicos para el cálculo numérico son los siguientes,
agrupados en operadores aritméticos, comparativos o lógicos:
Operadores aritméticos Operadores comparativos Operadores lógicos
Suma + Igualdad == x Y z x & z
Resta - Diferente != x Y z x && z
Multiplicación * Menor que < x O z x | z
División / Mayor que > x O z x || z
Potencia ^ Menor o igual <= No x !x
División entera %/% Mayor o igual >= No es x o z xor(x,z)
228
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.4. Tipos y estructuras de datos
2.4.1. Tipos de datos
Cuando trabajamos en R, podemos encontrarnos una amplia variedad de tipos de datos.
Desde el nivel más básico, los datos se pueden clasificar en:
- Lógico
- Numérico
- Carácter(es)
Lógico
Este tipo de dato es el más básico y sencillo de todos, al permitir sólo dos únicos valores:
TRUE o FALSE. El valor TRUE corresponde con el valor numérico y entero 1, mientras que FALSE
equivale a 0.
Numérico
Dentro del conjunto de valores numéricos, podemos identificar valores enteros (integer),
valores reales con doble precisión (double) y valores complejos (complex). Si bien en muchas
ocasiones los valores enteros serán suficiente (sobre todo cuando cuantifiquemos acciones
realizadas por un jugador, o en una temporada), cualquier número real podrá venir dado
como tipo float. Por defecto, cualquier valor numérico será clasificado como tipo numeric
(o double).
1
2
3
> x <- 10
> is.numeric(x)
[1] TRUE
Sin embargo, cabe la posibilidad de transformar dicho valor a otro tipo de dato, tanto
numérico como diferente a numérico:
1
2
3
4
5
6
> x <- 10
> is.integer(x)
[1] FALSE
> x <- as.integer(x)
> is.integer(x)
[1] TRUE
En el ejemplo anterior vemos cómo la variable x, a la cual se le asigna un valor de 10, no es
un entero por defecto (sino numérico, simplemente). Observamos que el comando
is.integer() permite preguntar y ver si acaso la variable es de ese tipo de dato. Con el
comando as.integer() podemos transformar el tipo de dato. Efectivamente, los
comandos is.[tipodedato]() y as.[tipodedato]() son fundamentales para el manejo y
transformación de tipos de datos.
229
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Carácter
Los caracteres son cualquier tipo de dato (número o letra) introducido como texto.
Típicamente, los caracteres aparecerán como cadenas de caracteres. En ese caso, se
darán entre comillas. Resulta muy común la transformación de (cadena de) caracteres a
numérico.
1
2
3
4
5
6
7
8
> x <- 10
> is.numeric(x)
[1] TRUE
> x <- as.character(x)
> x
[1] “10”
> is.character(x)
[1] TRUE
Otros valores
Caben mención especial los siguientes tipos de datos o valores. NULL y NA son dos de ellos.
El primero es un objeto que se utiliza para indicar que la variable no contiene ningún objeto.
Aunque el concepto de objeto se introduce a continuación, dejamos como válida dicha
definición. En la práctica, generalmente se utiliza para inicializar una variable, asignarle un
espacio antes de que, en un proceso iterativo o después de alguna operación, se vaya
almancenando datos o información dentro de él.
Por el contrario, NA es un valor que indica que no hay datos en ese lugar. Cuando se importa
información de una tabla, puede ocurrir que haya celdas de la tabla que se encuentren
vacías. En esos casos, el valor correspondiente es NA.
230
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.4.2. Vectores, matrices y arrays
Una vez introducidos los tipos de datos más básicos, pasamos a introducir el concepto de
objeto, en sus muy diversas formas en R. Todas las entidades que manipula R son objetos.
Así, vectores de cualquier tipo, matrices o arrays, y sucesivos, son objetos. Los objetos están
definidos con una serie de atributos, entendidos como unos adjetivos o apellidos que
describen el objeto. Tipo, nombre, longitud, dimensión o clase son algunos de dichos
atributos.
Atributos de un objeto attributes(x)
Tipo de dato de un objeto typeof(x)
Clase de un objeto class(x)
Longitud de un objeto length(x)
Dimensión de un objeto dim(x)
Vector
Un vector se construye siguiendo la misma sintáxis que la utilizada para una constante, es
decir, haciendo uso del signo de asignación. En primer lugar se asigna un nombre a la
variable vector, luego se utiliza el signo de asignación y finalmente se construye el vector
concatenando los diferentes valores recogidos, separados por comas. Es por esto que que
se utilice la letra c para construir un vector:
1
2
3
> disparos_a_puerta_p90 <- c(2,4,0,0,1,2,1)
> disparos_a_puerta_p90
[1] 2 4 0 0 1 2 1
Otra opción sería construir un vector de datos que siguieran una distribución determinada,
por ejemplo una distribución Normal (estándar) de 20 componentes (equipos de La Liga)
con un valor medio de los goles por partido de 1.5 y una desviación típica de 0.45:
1
2
3
4
5
6
> goles_p90 <- rnorm(20, 1.5, 0.45)
> goles_p90
[1] 1.8184343 1.9177216 1.1302944 0.9223009 2.0645012
[6] 1.5650661 1.0578041 2.0718095 1.0289928 2.5905102
[11]1.4721856 0.8606167 1.2534015 2.1199665 2.1463868
[16]2.0638716 0.6568868 1.8167876 1.4875798 1.1490517
Si se quiere trabajar con una componente determinada de un vector, basta con indicar el
nombre de la variable vector y el número de la componente en cuestión dentro de
corchetes.
1
2
3
4
5
> jornada <- 3
> disparos_a_puerta_p90[jornada]
[1] 0
> disparos_a_puerta_p90[jornada + 3]
[1] 2
231
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
232
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
En otras ocasiones, no se conoce a priori el índice del elemento al cual se quiere acceder
o, por el contrario, el número de elementos que cumplen una determinada condición es
mayor que el que no lo cumple, queriendo en ese caso realizar una selección negativa.
1
2
3
4
5
6
7
8
9
10
> which(disparos_a_puerta_p90>=2)
[1] 1 2 6
> disparos_a_puerta_p90[which(disparos_a_puerta_p90>=2)]
[1] 2 4 2
> disparos_a_puerta_p90[disparos_a_puerta_p90>=2]
[1] 2 4 2
> disparos_a_puerta_p90[-1]
[1] 4 0 0 1 2 1
> disparos_a_puerta_p90[-length(disparos_a_puerta_p90)]
[1] 2 4 0 0 1 2
Vemos cómo la primera sentencia devuelve los índices de los elementos que satisfacen la
condición, mientras que en la segunda se devuelve el valor de los elementos
correspondientes a dicha condición. La segunda y tercera sentencia son equivalentes.
Una operación muy típica es la de construir un vector cuyos elementos son equidistantes,
ya sea a modo de contadores dentro de un bucle o para definir una determinada
secuencia:
1
2
3
4
> partidos_temporada <- seq(1,38)
> intervalos_partido <- seq(0,90,15)
> intervalos_partido
[1] 0 15 30 45 60 75 90
Las operaciones y funciones vistas anteriormente para variables escalares también son
válidas para vectores, teniendo en cuenta que la operación se aplicará a cada
componente del vector:
1
2
3
4
5
6
> disparos_fuera_p90 <- 1
> disparos_p90 <- disparos_a_puerta_p90+disparos_fuera_p90
> disparos_p90
[1] 3 5 1 1 2 3 2
> disparos_p90 >=3
[1] TRUE TRUE FALSE FALSE FALSE TRUE FALSE
Cabe mencionar qué ocurre cuando se suman o se opera sobre dos vectores de tamaño
diferente (a pesar de que en este ejemplo en particular no tenga sentido su suma):
1
2
3
4
> faltas_cometidas_01 <- c(10,5)
> faltas_cometidas_02 <- c(10,5,3)
> disparos_01 <- c(4,5,3)
> disparos_02 <- c(4,5,3,2,1,2)
Si combinamos faltas_cometidas_01 y disparos_01, veremos que nos sale un mensaje de
error en la consola. Lo mismo ocurrirá si combinamos faltas_cometidas_02 con disparos_02.
Esto se debe a que las dimensiones de los dos vectores en cuestión no son múltiplo.
Efectivamente, cuando tratamos de operar sobre vectores de diferentes longitudes, el
233
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
resultado es la operación (suma o producto) por el mínimo común múltiplo:
1
2
3
4
> faltas_cometidas_01 + disparos_02
[1] 14 10 13 7 11 7
> faltas_cometidas_02 * disparos_02
[1] 40 25 9 20 5 6
En el primer caso, vemos que suma uno con uno por parejas, repitiendo valores del primer
vector en sucesivos pasos. En el segundo caso, se realiza el producto en dos pasos de tres
productos.
Algunas de las funciones básicas para utilizar con vectores son:
Número de elementos de un vector length(x)
Suma de los elementos del vector sum(x)
Valores máximo y mínimo del vector range(x)
Ordenación sort(x)
Ordenación inversa sort(x,decreasing = TRUE)
Resumen estadístico del vector summary(x)
Mostrar valores del vector cat(x); print(x)
Una de las situaciones más frecuentes, e interesantes, de trabajo en estadística es la de
encontrarse con un vector en el cual falte algún elemento o no se tenga información de
algún elemento. Por ejemplo, pongamos que estamos trabajando con la variable minutos
jugados por el jugador A, el cual no ha estado disponible, por lesión o decisión técnica, en
varios partidos. Así:
1
2
3
> minutos_jugados_a <- c(90, 90, 67, NA, NA, 0, 15, 70)
> minutos_jugados_a
[1] 90 90 67 NA NA 0 15 70
Vemos que el jugador A comenzó como titular y jugó los primeros partidos completos, pero
en la jornada 3 se pudo lesionar y fue sustituido en el minuto 67. Las siguientes jornadas se
las perdió sin estar convocado y en la jornada 6 fue convocado pero no llegó a disputar un
solo minuto. No volvió a jugar hasta la jornada 7, donde entró a falta de 15 minutos. La
siguiente jornada la jugó entera y la última en la que se tienen datos jugó sólo 70 minutos.
Aquellos partidos en los que no jugó, bien se podría incluir un 0, pero para poder diferenciar
de aquellos partidos en los que no jugó ni tan siquiera fue convocado, se utilizaría como
valor NA (Non available).
234
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si lo que queremos es que R nos diga en qué partidos no jugó, cuántos no jugó, cuántos
minutos jugó o cuántos minutos se ha perdido por no estar convocado:
1
2
3
4
5
6
7
8
9
10
> is.na(minutos)
[1] FALSE FALSE FALSE TRUE TRUE FALSE FALSE FALSE
> sum(minutos)
[1] NA
> sum(minutos, na.rm=TRUE)
[1] 332
> sum(is.na(minutos))
[1] 2
> 90*sum(is.na(minutos))
[1] 180
Podemos ver que si le pedimos a R que efectúe una operación sobre un vector que
contiene elementos NA y queremos que los ignore o que no los tenga en cuenta, debemos
incluir dentro del parénteis el atributo na.rm=TRUE (NA remove = TRUE).
Nota: aunque se deja para más adelante la introducción de funciones en R, el estudiante
habrá podido observar cómo se han utilizado dos conceptos diferentes: función y atributo.
Mientras que el primero realizac una operación, el segundo se encarga de definir las
características de cómo se realiza la instrucción, ajustando detalles que no se tienen en
cuenta en la función por defecto.
Por último, cabe indicar que un vector puede ser no sólo de valores numéricos sino también
cadenas de caracteres.
1
2
3
> equipos <- c("Deportivo Alaves", "Atletico de Madrid",
"FC Barcelona")
[1] "Deportivo Alaves" "Atletico de Madrid" "FC Barcelona"
Nota: existen más formas de definir un vector, aunque la más frecuente sea la anteriormente
citada. Sin embargo, para permitir al alumno estar familiarziado con otras opciones,
generalmente utilizadas para inicializar vectores cuando se conoce a priori su tamaño:
1
2
3
4
5
6
> lesiones_euro2008_por_partido <- numeric(6)
> lesiones_euro2008_por_partido <- vector(mode='integer',
length = 6)
> lesiones_euro2008_por_partido <- rep(0,6)
> lesiones_euro2008_por_partido
[1] 0 0 0 0 0 0
Cualquiera de las asignaciones anteriores da como resultado el mismo vector.
235
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Matrices
Si lo que queremos es extender la dimensión de los datos de nuestro vector a varias filas,
construiremos una matriz. Una primera manera de construir una matriz es con la instrucción
array, indicándose todos los elementos de la matriz como si fuera un vector único, e
incluyendo las dimensiones de la matriz. Así, si se quiere construir una matriz de 3x5 para
poder ver cuántos puntos ha conseguido en cada partido de las 5 primeras jornadas los tres
primeros equipos:
1
2
3
4
5
6
7
> puntos_por_partido <-
array(c(1,1,0,3,0,3,3,3,3,1,0,1,3,1,0), dim=c(3,5))
> puntos_por_partido
[0,] [,1] [,2] [,3] [,4] [,5]
[1,] 1 3 3 1 3
[2,] 1 0 3 0 1
[3,] 0 3 3 1 0
Nótese que los valores se introducen por columnas para construir la matriz. A diferencia del
vector, en el caso de una matriz se incluye el argumento dimensión para especificar el
tamaño de la matriz. Para acceder a un elemento determinado de la matriz, al igual que
con los vectores, se utilizan los corchetes:
1
2
3
4
> puntos_por_partido[2,3]
[1] 3
> puntos_por_partido[3, c(1,3,5)]
[1] 0 3 0
Si lo que se quiere es obtener todos los datos de un equipo (es decir, de una fila), o todos
los datos de una jornada (es decir, de una columna):
1
2
3
4
5
6
7
8
> puntos_atm <- puntos_por_partido[2,]
> puntos_atm
[1] 1 0 3 0 1
> sum(puntos_atm)
[1] 5
> puntos_j03 <- puntos_por_partido[,3]
> puntos_j03
[1] 3 3 3
Para sustituir valores dentro de la matriz:
1
2
3
4
5
6
> puntos_por_partido[2,c(1,2)] = c(3,1)
> puntos_por_partido
[0,] [,1] [,2] [,3] [,4] [,5]
[1,] 1 3 3 1 3
[2,] 3 1 3 0 1
[3,] 0 3 3 1 0
Al igual que con los vectores, es posible realizar operaciones sobre la matriz, actuando sobre
cada elemento de la matriz:
236
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
> pases_acertados <- array(c(45,20,40,45,4,10,15,13,33),
dim=c(3,3))
> pases_acertados
[0,] [,1] [,2] [,3]
[1,] 45 45 15
[2,] 20 4 13
[3,] 40 10 33
> pases_acertados+10
[0,] [,1] [,2] [,3]
[1,] 55 55 25
[2,] 30 14 23
[3,] 50 20 43
> pases_acertados*2
[0,] [,1] [,2] [,3]
[1,] 90 90 30
[2,] 40 8 26
[3,] 80 20 66
Si lo que queremos es operar sobre matrices, realizando suma, producto, traspuesta o
inversa de una matriz, podemos ver cómo la operación x*y en R implica el producto
elemento a elemento entre los que ocupan las mismas posiciones (i,j) en la matriz, mientras
que la operación x%*%y realiza el producto matricial.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
> pases_fallados <- array(c(5,10,0,10,26,15,5,30,5),
dim=c(3,3))
> pases_fallados
[0,] [,1] [,2] [,3]
[1,] 5 10 5
[2,] 10 26 30
[3,] 0 15 5
> pases_acertados+pases_fallados
[0,] [,1] [,2] [,3]
[1,] 50 55 30
[2,] 30 30 43
[3,] 40 25 38
> pases_acertados*pases_fallados
[0,] [,1] [,2] [,3]
[1,] 225 450 75
[2,] 200 104 390
[3,] 0 150 165
> pases_acertados%*%pases_fallados
[0,] [,1] [,2] [,3]
[1,] 675 1845 1650
[2,] 140 499 285
[3,] 300 1155 665
> t(pases_acertados)
[0,] [,1] [,2] [,3]
[1,] 45 20 40
[2,] 45 4 10
[3,] 15 13 33
237
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
238
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Desde el inicio de esta subsección, hemos considerado la instrucción array para construir
una matriz. Sin embargo, hay otras maneras de definir una matriz.
1
2
3
4
5
6
7
> pases_acertados <- matrix(c(45,45,15,20,4,13,40,10,33),
nrow = 3, ncol = 3, byrow = TRUE)
> pases_acertados
[0,] [,1] [,2] [,3]
[1,] 45 45 15
[2,] 20 4 13
[3,] 40 10 33
En este caso, los datos son introducidos por filas, a diferencia de antes donde se introducían
por columnas. Vemos que es el atributo byrow el que nos permite cambiar el modo. Otra
opción de crear matrices es mediante combinación de varias matrices, uniéndolas por filas
o por columnas de acuerdo con la compatibilidad de dimensiones. En el caso de los
ejemplos que estamos considerando, al trabajar con matrices cuadradas, cualquier unión
es válida:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> pases_totales <- cbind(pases_acertados, pases_fallados)
> pases_totales
[0,] [,1] [,2] [,3] [,4] [,5] [,6]
[1,] 45 45 15 5 10 5
[2,] 20 4 13 10 26 30
[3,] 40 10 33 0 15 5
> pases_totales <- rbind(pases_acertados, pases_fallados)
> pases_totales
[0,] [,1] [,2] [,3]
[1,] 45 45 15
[2,] 20 4 13
[3,] 40 10 33
[4,] 5 10 5
[5,] 10 26 30
[6,] 0 15 5
Vemos cómo la función cbind une columnas y, por lo tanto, la matriz crece horizontalmente,
mientras que la función rbind une filas (rows) y, consecuentemente, crece verticalmente.
Alguna de las funciones más útiles para realizar operaciones por filas o columnas son las
siguientes:
Vector de medias de cada fila rowMeans(x)
Vector de medias de cada columna colMeans(x)
Vector de sumas por fila rowSums(x)
Vector de sumas por columna colSums(x)
239
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Arrays
Si, al igual que el paso de vector a matriz, ampliamos la dimensión de una matriz,
obtenemos un array. Efectivamente, hemos visto cómo crear una matriz con la instrucción
array, dado que una matriz es un caso particular de array, donde la tercera dimensión es
1. Si queremos construir un cubo, o matriz de 3x3x2:
1
2
3
4
5
6
7
8
9
10
11
12
13
> pases_totales <- array(c(45,20,40,45,4,10,15,13,33,
5,10,0,10,26,15,5,30,5), dim =c(3,3,2))
> pases_totales
, , 1
[0,] [,1] [,2] [,3]
[1,] 45 45 15
[2,] 20 4 13
[3,] 40 10 33
, , 2
[0,] [,1] [,2] [,3]
[1,] 5 10 5
[2,] 10 26 30
[3,] 0 15 5
Factores
Aunque dimensionalmente los factores tienen más relación con los vectores que con los
arrays, ordenamos este objeto aquí por la continuidad conceptual que identificamos entre
vectores, matrices y arrays. Los factores son vectores unidimensionales de valores
categóricos u ordinales. Por lo tanto, podemos hablar de factores de niveles nominales y
factores de niveles ordinales. Su importancia es notable en estudios estadísticos, donde
muchas funciones de R los manejan de forma particular en uno y otro caso. Igualmente, en
la visualización de datos en R, el paquete ggplot2 trabaja con factores.
Para entender su uso, consideremos la plantilla de la selección española de baloncesto en
el Mundial de 2006, donde los 12 jugadores son ordenados por dorsal. Si creamos un vector
que contenga las posiciones de cada uno de ellos (dados con acrónimos, simplificando
dicha clasificación a base, escolta, alero, ala-pivot y pivot (‘bas’,’esc’,’ale’,’alp’,’piv’):
1
2
3
4
5
6
> posiciones <- c("piv", "esc", "bas", "esc", "bas",
"piv", "ale", "bas", "esc", "piv", "ale", "alp")
> factor_posiciones <- factor(posiciones)
> factor_posiciones
[1] piv esc bas esc bas piv ale bas esc piv ale alp
Levels: ale alp bas esc piv
Si ahora queremos ver, por posiciones, cuál es el promedio de altura, utilizando un vector
en el que recojamos los datos de la altura de cada jugador:
240
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1
2
3
4
5
6
> altura <- c(215, 196, 187, 191, 190, 205, 205, 189, 197,
212, 202, 204)
> media_altura <- tapply(altura, factor_posiciones, mean)
> media_altura
ale alp bas esc piv
203.5000 204.0000 188.6667 194.6667 210.6667
La función tapply() se utiliza para aplicar una función, en este caso mean() para cada
grupo de componentes del primer argumento, definidos por los niveles de la segunda
componente, en este caso, factor_posiciones. Igualmente, podemos ver un resumen de
los niveles de factores con el comando summary para observar cómo estaba construido el
equipo por posiciones:
1
2
3
> summary(factor_posiciones)
ale alp bas esc piv
2 1 3 3 3
Las posiciones en el campo no tienen de por sí un orden. Sin embargo, si consideramos
como orden la altura media de los jugadores, podemos aplicar un orden a los factores:
1
2
3
4
5
6
7
8
> índices_ordenados_altura <- order(media_altura)
> índices_ordenados_altura
[1] 3 4 1 2 5
> factor_posiciones_altura <- ordered(factor_posiciones,
levels(factor_posiciones)[índices_ordenados_altura])
> factor_posiciones_altura
[1] piv esc bas esc bas piv ale bas esc piv ale alp
Levels: bas < esc < ale < alp < piv
En este caso, primero vemos qué índice ordenado ocuparía cada posición, de menor a
mayor. Esta información queda recogida en índices_ordenados_altura. Aplicando esta
información a los niveles de factor_posiciones podemos ordenar dicho factor. El orden de
altura, aun de forma artificial, permite ubicar a los jugadores en el campo y determinar su
“implicación” en la construcción o finalización de la jugada (siendo evidente el
reconocimiento de tal simplificación sólo con propósitos académicos). Si queremos saber
qué jugadores participan más en la construcción que un alero:
1
2
3
4
5
6
7
8
> factor_posiciones_altura < "ale"
[1] FALSE TRUE TRUE TRUE TRUE FALSE FALSE TRUE TRUE FALSE
[14] FALSE FALSE
> factor_posiciones < "ale"
[1] NA NA NA NA NA NA NA NA NA NA NA NA
Warning message:
In Ops.factor(factor_posiciones, "ale") : ‘<’ not
meaningful for factors
Vemos cómo con factor_posiciones_altura sí tiene sentido una comparación ordinal
mientras en el primer caso no, al no haberse aplicado ni entenderse ninguna ordenación.
241
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.4.3. Estructuras de datos. Data.frames y listas
Data.frame
La forma más habitual de almacenar datos es mediante tablas (data.frames en R). Un
data.frame es una matriz en la cual cada columna puede ser una variable de un tipo
diferente. Así, pueden aparecer columnas con información numérica, entera o decimal,
otras con información cualitativa en cadenas de caracteres o variables lógicas. Para
construir una estructura de tipo data.frame, se utilza la función data.frame().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> nombre <- c("Iker Casillas","Sergio Ramos","Carles
Puyol","Carlos Marchena","Joan Capdevila");
> edad <- c(27,22,30,28,30);
> club <- c("Real Madrid","Real Madrid","FC
Barcelona","Valencia CF","Villareal")
> faltas_cometidas <- c(0,3,2,0,1)
> espana_euro2008_j01 <-
data.frame(nombre,edad,club,faltas_cometidas)
> espana_euro2008_j01
nombre edad club faltas_cometidas
1 Iker Casillas 27 Real Madrid 0
2 Sergio Ramos 22 Real Madrid 3
3 Carles Puyol 30 FC Barcelona 2
4 Carlos Marchena 28 Valencia CF 0
5 Joan Capdevila 30 Villarreal 1
El nombre que se asocia a cada columna dentro de la estructura es el nombre
correspondiente al vector utilizado para construir el data.frame. Si se desea cambiar el
bombre de alguna columna:
1
2
3
4
5
6
> espana_euro2008_j01 <-
data.frame(jugador=nombre,edad,club,faltas_cometidas)
> espana_euro2008_j01$jugador
[1] Iker Casillas Sergio Ramos Carles Puyol
[4] Carlos Marchena Joan Capdevila
5 Levels: Carlos Marchena Carles Puyol ... Sergio Ramos
Vemos que para acceder a una variable determinada de la estructura data.frame, se utiliza
el símbolo $. Igualmente a como hacíamos con las matrices, se puede operar sobre los
datos y acceder a algún dato en cuestión.
1
2
3
4
5
6
7
8
9
> espana_euro2008_j01$jugador[4]
[1] Carlos Marchena
>
sum(espana_euro2008_j01$edad)/length(espana_euro2008_j01$nomb
re)
[1] 27.4
> summary(espana_euro2008_j01[,4])
Min. 1st Qu. Median Mean 3rd Qu. Max.
0.0 0.0 1.0 1.2 2.0 0.0
242
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si bien resulta muy intuitivo la llamada a alguna variable del data.frame, puede resultar
relativamente engorroso cuando el nombre del data.frame es largo. Para ello, los
comandos attach y detach pueden ser de ayuda. Su objetivo es el de enganchar el
contenido del data.frame al entorno donde R busca los nombres de variables. Así, se
puede acceder directamente a las variables del data.frame por su nombre sin encabezar
con el propio nombre del data.frame. Una vez finalizadas las acciones a realizar con dichas
variables, se procede a desenganchar el data.frame con el comando detach.
1
2
3
4
5
6
7
8
9
10
> espana_euro2008_j01 <-
data.frame(jugador=nombre,edad,club,faltas_cometidas)
> attach(espana_euro2008_j01)
> jugador
[1] Iker Casillas Sergio Ramos Carles Puyol
[4] Carlos Marchena Joan Capdevila
5 Levels: Carlos Marchena Carles Puyol ... Sergio Ramos
> detach(espana_euro2008_j01)
> jugador
Error: object ‘jugador’ not found
Podemos ver cómo al enganchar el data.frame espana_euro2008_j01, donde en su
construcción hemos cambiado el nombre de la variable nombre por jugador, la llamada
a la variable jugador da la información de los jugadores. Cuando desenganchamos, si
volvemos a llamar a la variable jugador, recibimos un mensaje de error, al no existir dicha
variable fuera del data.frame. Cabe indicar que es muy importante tener cuidado de
cuándo se engancha y desengancha el data.frame para no interferir con variables fuera
del mismo con el mismo nombre que alguna dentro.
Dada la importancia de los data.frame, existen numerosas funciones o comandos
aplicados a éstos. Por brevedad, no se analizaran todos en detalle, dejando como ejercicio
practicar con algunos de ellos, según se indique.
243
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Listas
Las listas representan el siguiente nivel de complejidad en las estructuras de datos dentro
de R. A diferencia de los vectores, donde se recogen o contienen valores, en las listas se
incluyen objetos, de modo que éstos pueden ser de muy diferente naturaleza o clase,
desde valores numéricos a vectores, matrices, data.frame o hasta listas. Dado que dichos
elementos son independientes en naturaleza, también pueden serlo en dimensiones. Por
ello, su extensión puede ser arbitraria. En el ejemplo siguiente creamos una lista de nuestros
datos de la Euro 2008, recogiendo nuestro data.frame, el array de pases_totales, la matriz
de pases_acertados y el vector de lesiones del campeonato.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
> datos_euro2008 <- list(espana_euro_2008_j01,
pases_totales, pases_acertados,
lesiones_euro2008_por_partido)
> datos_euro2008
[[1]]
jugador edad club faltas_cometidas
1 Iker Casillas 27 Real Madrid 0
2 Sergio Ramos 22 Real Madrid 3
3 Carles Puyol 30 FC Barcelona 2
4 Carlos Marchena 28 Valencia CF 0
5 Joan Capdevila 30 Villarreal 1
[[2]]
, , 1
[0,] [,1] [,2] [,3]
[1,] 45 45 15
[2,] 20 4 13
[3,] 40 10 33
, , 2
[0,] [,1] [,2] [,3]
[1,] 5 10 5
[2,] 10 26 30
[3,] 0 15 5
[[3]]
[0,] [,1] [,2] [,3]
[1,] 45 45 15
[2,] 20 4 13
[3,] 40 10 33
[[4]]
[1] 0 0 0 0 0 0
244
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Observamos que, a pesar de construir nuestra lista con distintos objetos, cada uno con su
nombre, en la lista aparecen como objetos enumerados (de 1 a 4), por lo que al llamarlos
por su nombre no podremos acceder a ellos. Para eso, deberíamos crear la lista con sus
nombres:
1
2
3
4
5
6
7
8
9
10
11
> datos_euro2008$lesiones_euro2008_por_partido
NULL
> datos_euro2008 <- list(espana_euro_2008_j01 =
espana_euro_2008_j01, pases_totales = pases_totales,
pases_acertados = pases_acertados,
lesiones_euro2008_por_partido =
lesiones_euro2008_por_partido)
> datos_euro2008$lesiones_euro2008_por_partido
[1] 0 0 0 0 0 0
> datos_euro2008[[4]]
[1] 0 0 0 0 0 0
Cuando se trabaja con listas y es necesario indexar algún elemento u objeto recogido
dentro de la lista es preferible utilizar $ o [[]] y no []. Esta última opción crea una nueva
lista en vez de devolver el objeto en cuestión.
1
2
3
4
5
6
> dummy01 <- datos_euro2008[[4]]
> is.list(dummy01)
[1] FALSE
> dummy02 <- datos_euro2008[4]
> is.list(dummy01)
[1] TRUE
Si se quiere ampliar el tamaño de la lista a fin de que ésta contenga nuevos objetos:
1
2
3
4
5
6
7
8
9
> datos_euro2008[[6]] <- 'Luis Aragones'
> datos_euro2008[[6]]
[1] "Luis Aragones"
> names(datos_euro2008)
[1] "espana_euro2008_j01" "pases_totales"
[3] "pases_acertados" "lesiones_euro2008_por_partido"
[5] "" ""
> names(datos_euro2008)[c(1,5,6)] <- c("Jornada
1","Vacio","Seleccionador")
Así hemos creado dos nuevos objetos (vacíos) en nuestra lista, ocupando las posiciones 5 y
6, donde vemos que, por crear hasta 6, implícitamente hemos creado espacio también
para 5. En la sexta posición hemos introducido la cadena de caracteres Luis Aragones y, si
vemos los nombres de cada elemento de la lista, vemos que los nuevos (5 y 6) no tienen
nombre. SI queremos cambiar los nombres de varios de esos objetos dentro de la lista,
utilizamos el comando names(). Como comentario final, se recomienda utilizar las funciones
apply() para aplicar una función a cada elemento de una lista.
245
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.5. Funciones
Aunque R dispone de suficientes paquetes con sus funciones para resolver de por sí
prácticamente cualquier necesidad, cabe la posibilidad también de construir funciones ad
hoc. En R, como en cualquier otro lenguaje, las funciones son objetos que evalúan un
conjunto de argumentos de entrada y devuelven una salida. Ya hemos visto que los
argumentos en cada caso pueden ser de muy diversa naturaleza, pero básicamente son
los valores sobre los que operar en la función, o las características que particularizan cómo
actúa la función.
En realidad, cualquier sentencia en R se puede escribir como una función. Como podemos
observar, desde la más básica asignación, una función toma un argumento o entrada y da
una salida. Si convertimos en función cualquiera de las operaciones matemáticas
anteriores, veremos que, además de los argumentos, se deben indicar las instrucciones a
ejecutar por parte de la función:
1
2
3
4
5
> operacion_producto <- function(x,y){
x*y
}
> operacion_producto(2,5)
[1] 10
Si la función no consta de una única instrucción, sino de varias, la salida de la función es la
última operación realizada:
1
2
3
4
5
6
7
8
> operacion_exponente <- function(x,y,z){
exponente = y + z
x^exponente
}
> operacion_exponente(2,3,2)
[1] 32
> operacion_exponente(y=3,x=2,z=2)
[1] 32
Vemos cómo la función se construye con tres argumentos, x, y, z. La función sabe cómo
actuar con los argumentos, ya sea por orden o por nombre. Si se introducen en el orden en
el cual se define la función, no hace falta indicar el nombre de las variables argumento.
246
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6. Ejercicios resueltos
2.6.0. Requisitos
Para instalar paquetes en R utiliza Rstudio. Ve a “Tools”, “Install Packages…” e instala los
siguientes paquetes (Marca la casilla que dice “Install dependencies” para que instale los
paquete necesarios”
readr , gridExtra, ggforce, ggExtra, ggplot2, plyr, reshape2, scales, lubridate,
lattice
247
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.1. Ejercicio 1. Representación polar de varios KPIs de un
equipo
2.6.1.1. Introducción y Objetivo
Este ejercicio se inspira en uno de los gráficos que recientemente ha propuesto STATS para
visualizar diferentes KPIs de jugadores y equipos, comparando el rendimiento de uno u otro
con la media de la liga o de un subconjunto deseado. La Fig. F muestra un ejemplo. El
objetivo de esta práctica no es tanto el tratamiento de los datos para preparar el input del
gráfico sino, directamente, trabajando sobre un vector de KPIs, trabajar sobre el gráfico en
sí.
Fig. F. Ejemplo de representación polar de varios KPIs. En este caso, imagen extraída de
https://www.stats.com/industry-analysis-articles/salah-out-of-form-or-out-of-position/
2.6.1.2. Código Comentado
El único paquete que utilizaremos en este ejercicio es el de ggplot2(). Ahí encontraremos
las funciones necesarias para una representación semejante a la presentada en la Fig. F.
1 > library(ggplot2)
248
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Queda fuera del objetivo del ejercicio en explicar más en profundidad el significado y cómo
se definen cada uno de los KPIs elegidos para el gráfico. De hecho, hay libertad para elegir
cualquiera. En este caso, hemos decidido incluir 7 estadísticas, dadas porcentualmente
para que sean equivalentes, que pueden describir el rendimiento de un equipo de fútbol.
En primer lugar elegimos la posesión, dada porcentualmente como comparación con la
media de la Liga. Valores positivos indicaran una mayor posesión que la media,
contextualizando así los valores que pueden frecuentar un equipo de fútbol. En segundo
lugar, se elige los tiros por gol a favor, dando una idea del rendimiento o acierto ofensivo al
presentar un ratio entre los disparos totales y los disparos que realmente acaban en gol.
Equivalentemente, la tercera variable es idéntica pero en contra, para dar una idea, a su
vez, del rendimiento defensivo o del portero. La cuarta variable, llamada Juego directo,
cuantifica el porcentaje de pases que son en largo frente al total, y contextualiza el valor
en comparación con el resto de equipos de la Liga. La quinta variable, centros indica el
porcentaje de acierto de los centros realizados (a favor). Con la variable agresividad se
trata de cuantificar qué porcentaje de faltas acaban en tarjeta amarilla o roja. Finalmente,
la variable Inicio de juego (Portero) representa el porcentaje de pases realizados por el
portero que son en corto.
Estos KPIs son recogidos en la variable vector kpis que posteriormente será utilizada para
la representación gráfica. La variable percentagedata es un vector numérico con los
valores de cada KPI. Finalmente, la variable clubname recoge el nombre del equipo que
estamos considerando.
1
2
3
4
5
6
> kpis = c("Posesion", "Tiros por gol\n a favor", "Tiros por
gol \n en contra", "Juego directo", "Centros", "Agresividad",
"Inicio \n de juego (Portero)")
> percentagedata = c(18.03, -6.27, 11.67, -40.04, 6.19, -9.30,
95.98)
> clubname = "Atletico Villalpando"
Para poder hacer la representación polar, necesitamos crear una estructura de tal manera
que asocie los nombres de los KPIs y los valores porcentuales de cada uno.
1
2
3
4
5
6
7
8
9
10
> mydata <- structure(
list(Category = structure(1:7,
.Label = kpis,
class = "factor"),
Percentage = percentagedata
),
.Names = c("Category", "Percentage"),
row.names = c(NA, 7L),
class = "data.frame"
)
249
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Postproceso
Para construir nuestro diagrama polar, lo que realmente hacemos es construir un diagrama
de barras al cual, posteriormente, aplicaremos una transformación de coordenadas, para
conseguir nuestro diagrama polar. Por ello, con la función geom_bar() construimos nuestro
diagrama de barras, al que iremos editando y, posteriormente transformando con la
función coord_polar().
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
> ggplot(mydata) +
geom_bar(aes(x = Category, y = pmin(200, 100 + Percentage)),
fill = "#004da8", stat = "identity", width = 1) +
geom_hline(yintercept = seq(0,200,by = 25), linetype =
"dashed", color = "#e9e9e9", size = 0.5) +
geom_vline(xintercept = seq(0.5, 7.5, by = 1), color =
"#c9c9c9", size = 0.5) +
geom_hline(yintercept = 100, color = "#a9a9a9", size = 0.75)
+
geom_hline(yintercept = 200, color = "#a9a9a9", size = 0.75)
+
coord_polar() +
theme_minimal() +
labs(x = NULL, y = NULL) +
labs(title = clubname) +
theme(plot.title = element_text(hjust = 0.5, size = 20,
color = "#a9a9a9"),
plot.subtitle = element_text(vjust = 0, hjust = 0.5,
size = 12, color = "#a9a9a9"),
axis.text.y = element_blank(),
legend.position = "none",
panel.grid = element_blank(),
axis.text.x = element_blank()) +
geom_text(aes(x = Category, y = 290, label = sprintf("%s \n
%1.2f%%", Category, Percentage)), size = 4, color = "#a9a9a9")
250
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.1.3. Código sin comentarios
# -------------
# Preproceso
# -------------
# Instalar paquetes si aun no se tienen instalados en la distribución de R
#install.packages("ggplot2");
# Cargar los paquetes que utilizaremos en el ejercicio
library(ggplot2)
# -------------
# Proceso
# -------------
# Definir los KPIs que queremos representar en nuestro diagrama polar
kpis = c("Posesion", "Tiros por gol\n a favor",
"Tiros por gol \n en contra",
"Juego directo", "Centros", "Agresividad",
"Inicio \n de juego (Portero)")
percentagedata = c(18.03, -6.27, 11.67, -40.04, 6.19, -9.30, 95.98)
clubname = "Atletico Villalpando"
# Para poder trabajar posteriormente con la transformación polar,
# necesitamos convertir nuestros datos en una estructura que asocie
# los nombres de los KPIs y los valores porcentuales
mydata <- structure(
list(Category = structure(1:7,
.Label = kpis
, class = "factor"),
Percentage = percentagedata
),
.Names = c("Category", "Percentage"),
row.names = c(NA, 7L),
class = "data.frame"
)
# -------------
# Postproceso
# -------------
# Construir el gráfico de barras y aplicar transformación polar
ggplot(mydata) +
geom_bar(aes(x = Category, y = pmin(200, 100 + Percentage)),
fill =
"#004da8",
stat =
"identity", width = 1) +
geom_hline(yintercept = seq(0,200,by = 25), linetype = "dashed",
color = "#e9e9e9", size =
0.5) +
geom_vline(xintercept = seq(0.5, 7.5, by = 1), color = "#c9c9c9",
size = 0.5) +
geom_hline(yintercept = 100, color = "#a9a9a9", size = 0.75) +
geom_hline(yintercept = 200, color = "#a9a9a9", size = 0.75) +
coord_polar() +
theme_minimal() +
labs(x = NULL, y = NULL) +
251
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
labs(title = clubname) +
theme(plot.title = element_text(hjust = 0.5, size = 20, color = "#a9a9a9"),
plot.subtitle = element_text(vjust = 0, hjust = 0.5, size = 12, color =
"#a9a9a9"),
axis.text.y = element_blank(),
legend.position = "none",
panel.grid = element_blank(),
axis.text.x = element_blank()) +
geom_text(aes(x = Category, y = 290, label = sprintf("%s \n %1.2f%%", Category,
Percentage)), size = 4,
color = "#a9a9a9")
252
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.2. Ejercicio 2. Representación de un campo de fútbol con
posiciones de acciones de un jugador, e histogramas como
complemento informativo
2.6.2.1. Introducción y Objetivo
En este ejercicio abordaremos diferentes aspectos de las capacidades gráficas de R para
representar un campo de fútbol y sobre él las posiciones en las que tiene lugar un
determinado evento o acción de nuestro interés. Para hacer más completa la aplicación
del ejercicio, consideraremos en primer lugar la opción de elegir qué jugador y qué partido
se desea visualizar.
Como complemento informativo a dicha visualización, crearemos histogramas en los
laterales del campo, de modo que se pueda identificar rápidamente cuáles son las zonas
del campo donde mayor actividad se ha observado de acuerdo con el evento elegido.
2.6.2.2. Código comentado
Comenzamos cargando los paquetes que necesitaremos para este ejercicio.
Fundamentalmente, éstas serán paquetes que nos permitan cargar los datos, y diferentes
paquetes que usaremos para la representación gráfica.
1
2
3
4
5
> library(ggplot2)
> library(readr)
> library(gridExtra)
> library(ggforce)
> library(ggExtra)
A continuación, cargamos los datos que usaremos en este ejercicio:
1
2
3
> full_data <- read_delim("full_data.txt", ";", locale =
locale(decimal_mark = ","), trim_ws = TRUE)
> View(full_data)
Si visualizamos estos datos, veremos que se tratan de acciones de dos partidos del Real
Madrid (vs FC Barcelona y vs Málaga CF), donde se disponen de las coordenadas (x,y)
tanto de origen o localización (faltas, pérdidas…) como de destino para estadísticas cuyo
final difiere de su origen, como por ejemplo pases o disparos. Igualmente se dispone
información de qué jugador es el responsable del evento, tiempo en el que tiene lugar,
resultado del evento…
253
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Proceso
Supongamos que deseamos ver la información sobre un jugador en particular. Hayamos
elegido, por ejemplo, a Toni Kroos, en el partido contra el FC Barcelona, jugando como
local, y supongamos que queremos analizar todos los pases realizados:
1
2
3
4
5
6
7
> jugador_elegido <- c("Kroos")
> rival_elegido <- c("Barcelona")
> donde <- c("1")
> evento_elegido <- ("Pass All")
> data_player <- subset(full_data, nombre_jugador ==
jugador_elegido & Rival == rival_elegido & Local ==
partido_elegido &Sección == evento_elegido)
De acuerdo con ese filtro, podemos crear un subconjunto de datos a partir de la base de
datos inicial, donde se recojan todos los datos de los pases de Kroos contra el FC Barcelona
en el partido en el Santiago Bernabeu. Dicho subconjunto es data_player.
Postproceso
Ya podemos empezar a preparar el gráfico una vez hecha la selección de datos que nos
es interesante. El gráfico se puede dividir en tres elementos. Por un lado, procederemos a
representar el campo de acuerdo con unas dimensiones acordes a la fuente de datos. En
segundo lugar, podremos representar mediante puntos los pases realizados por Kroos,
donde el color de cada punto se basa en una clasificación de los pases según su resultado.
Finalmente, completamos el gráfico con los histogramas laterales.
Comenzamos con las dos primeras partes. Si llamamos player_scatter_plot al gráfico que
incluye la dispersión de puntos correspondiente a los eventos elegidos (pases) y el campo
de fútbol, incluiríamos en primer lugar con la función geom_point() los puntos de las
acciones. Vemos que la función geom_point tiene una serie de atributos. En primer lugar,
indicamos la base de datos que usamos para representar los puntos. Esta base de datos es
data_player, la que habíamos construido como filtro de la base de datos inicial. A
continuación, necesitamos indicar qué coordenadas x e y se utilizan para los puntos,
haciendo una corrección de coordenadas (x) de acuerdo a la fuente de datos. Luego
indicamos cómo coloreamos dichos puntos. En este caso, se rellenan de acuerdo con los
niveles del factor Resultado. Estos tres datos se adjuntan con la función aes. Finalmente,
indicamos el tamaño y forma de los puntos. Como complemento, se incluye una sentencia
que retira el título de la leyenda para los diferentes resultados de los pases.
1
2
3
4
5
6
> player_scatter_plot <- ggplot() +
geom_point(data_player, mapping = aes(x = x1 - 58.015,y = y1,
fill = factor(data_player$Resultado)),
shape = 21,
size = 5) +
guides(fill = guide_legend(title = NULL)) +
Hemos dividido artificialmente el código para su explicación, aunque el símbolo + debe
254
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
dejar claro que las sentencias se continúan como parte de la definición de los gráficos. En
esta segunda parte nos quedamos con la construcción del terreno de juego. Las
dimensiones se disponen a partir de la fuente de datos. Podemos ver cómo la combinación
de sucesivos rectángulos contruidos con geom_rect, línea para dividir el campo con
geom_linerange, puntos para indicar la posición de los puntos de penalti y un círculo para
representar el centro del campo permite tener una visualización sencilla y básica de un
campo de fútbol.
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
geom_rect(mapping = aes(xmin = 0.0, xmax = 596.97, ymin =
50.5, ymax = 446.5), color ="#00529f", fill = NA, alpha = 0.1)
+
geom_rect(mapping = aes(xmin = 0.0, xmax = 91.935, ymin =
128.975, ymax = 368.025), color ="#00529f", fill = NA, alpha =
0.1) +
geom_rect(mapping = aes(xmin = 505.035, xmax = 596.97, ymin =
128.975, ymax = 368.025), color ="#00529f", fill = NA, alpha =
0.1) +
geom_rect(mapping = aes(xmin = 0.0, xmax = 29.858, ymin =
195, ymax = 302.0), color ="#00529f", fill = NA, alpha = 0.1) +
geom_rect(mapping = aes(xmin = 567.112, xmax = 596.97, ymin =
195, ymax = 302.0), color ="#00529f", fill = NA, alpha = 0.1) +
geom_linerange(aes(x = 298.485, ymin = 50.5, ymax = 446.5),
color = "#00529f") +
geom_point(mapping = aes(x = 66.33, y = 248.5), size = 1,
color = "#00529f") +
geom_point(mapping = aes(x = 530.64, y = 248.5), size = 1,
color = "#00529f") +
geom_circle(mapping = aes(x0 = 298.485, y0 = 248.5, r = 52),
color = "#00529f") +
Finalmente, editamos el gráfico para hacerlo más limpio, eliminando ejes, bordes y
cualquier elemento a fin de que sólo se visualice el campo de fútbol y la leyenda de colores
utilizado para visualizar el resultado de cada pase.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
coord_fixed() +
theme_no_axes(base.theme = theme_bw()) +
theme(legend.position = c(0.5, 0.04),
legend.box = "horizontal",
legend.direction = "horizontal",
legend.box.background = element_rect(fill =
"transparent", colour = "transparent"),
legend.text = element_text(size = 14),
panel.border = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank()) +
scale_x_continuous(limits = c(0,647.47), expand = c(0,0)) +
scale_y_continuous(limits = c(0,497), expand = c(0,0))
255
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
El resultado de esta primera parte del gráfico es el siguiente:
Resultado de la primera parte del ejercicio con edición final.
La última parte del postproceso es, como decíamos, la adición de histogramas laterales
para ver distribuciones espaciales de los pases. Para ello utilizamos la función ggMarginal,
incluída en ggExtra.
1
2
3
4
5
6
7
8
9
> ggExtra::ggMarginal(player_scatter_plot,
x = x1 - 258.015,
y = y1,
type = "histogram",
xparams = list(breaks = seq(0,600,50),
colour = "#00529f"),
yparams = list(breaks = seq(50,450,50),
colour = "#00529f")
)
Vemos que los atributos de ggMarginal incluye qué gráfico es la base sobre la cual se
construye el histograma, qué datos se representan en cada eje, qué tipo de visualización
se utiliza (hay diferentes opciones como histograma, gráficos de densidad o diagramas de
violín) y, finalmente, parámetros específicos de cada eje, donde se puede personalizar la
forma del histograma.
256
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Así, el resultado final del ejercicio es:
Resultado del ejercicio con edición final.
257
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.2.3. Código sin comentarios
# -------------
# Preproceso
# -------------
# Instalar paquetes si aun no se tienen instalados en la distribución de R
#install.packages("readr");
#install.packages("ggplot2");
#install.packages("gridExtra");
#install.packages("ggforce");
#install.packages("ggExtra");
# Cargar los paquetes que utilizaremos en el ejercicio
library(readr)
library(ggplot2)
library(gridExtra)
library(ggforce)
library(ggExtra)
# Fijar directorio de trabajo
# Cambiar el directorio de trabajo donde hemos guardado el archivo
# full_data.txt, sustituyendo ... por la ruta correspondiente
setwd("...")
# Cargar datos de trabajo y visualizar tabla de datos
full_data <- read_delim("full_data.txt", ";",
locale = locale(decimal_mark = ","),
trim_ws = TRUE)
View(full_data)
# -------------
# Proceso
# -------------
# Elegir jugador a analizar
jugador_elegido <- c("Kroos")
# Elegir rival
rival_elegido <- c("Barcelona")
# Elegir partido (1 = Real Madrid local, 0 = Real Madrid visitante)
partido_elegido <- c("1")
# Elegir seccion, ver full_data para identificar qué es sección
evento_elegido <- c("Passes_All")
data_player <- subset(full_data, nombre_jugador == jugador_elegido &
Rival == rival_elegido &
Local == partido_elegido &
Sección == evento_elegido)
#realmadrid_colors <-c("#00529f", "#8cc1f3", "blue")
258
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# -------------
# Postproceso
# -------------
# Crear campo de fútbol con distribución de puntos correspondientes
# a la posición (x,y) de cada evento
player_scatter_plot <- ggplot() +
# Crear nueve de puntos, corrigiendo coordenada x (debido a fuente de datos)
geom_point(data_player, mapping = aes(x = x1 - 58.015,
y = y1,
fill =
factor(data_player$Resultado)),
shape = 21,
size = 5) +
# Activar, si se desea, de modo que los eventos tengan color corporativo,
# de acuerdo a cómo se ha definido variable realmadrid_colors
#scale_fill_manual(values = realmadrid_colors) +
guides(fill = guide_legend(title = NULL)) +
# Comenzar a representar campo de fútbol como combinación de sucesivos
# rectángulos. Las dimensiones del campo
# vienen marcadas por la fuente de los datos
geom_rect(mapping = aes(xmin = 0.0, xmax = 596.97,
ymin = 50.5, ymax = 446.5),
color ="#00529f", fill = NA, alpha =
0.1) +
geom_rect(mapping = aes(xmin = 0.0, xmax = 91.935,
ymin = 128.975, ymax = 368.025),
color ="#00529f", fill = NA, alpha =
0.1) +
geom_rect(mapping = aes(xmin = 505.035, xmax = 596.97,
ymin = 128.975, ymax = 368.025),
color ="#00529f", fill = NA, alpha =
0.1) +
geom_rect(mapping = aes(xmin = 0.0, xmax = 29.858,
ymin = 195, ymax = 302.0),
color ="#00529f", fill = NA, alpha
= 0.1) +
geom_rect(mapping = aes(xmin = 567.112, xmax = 596.97,
ymin = 195, ymax = 302.0),
color ="#00529f", fill = NA, alpha = 0.1)
+
# Continuación de la representación del campo, con línea de medio campo,
# circulo del centro y puntos de penalti
geom_linerange(aes(x = 298.485, ymin = 50.5,
ymax = 446.5),
color = "#00529f") +
geom_point(mapping = aes(x = 66.33, y = 248.5),
size = 1, color = "#00529f") +
geom_point(mapping = aes(x = 530.64, y = 248.5),
size = 1, color = "#00529f") +
geom_circle(mapping = aes(x0 = 298.485,
y0 = 248.5, r = 52),
color = "#00529f") +
coord_fixed() +
# Limpiar representación gráfica para que quede sólo el terreno de juego
theme_no_axes(base.theme = theme_bw()) +
259
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
theme(legend.position = c(0.5, 0.04),
legend.box = "horizontal",
legend.direction = "horizontal",
legend.box.background = element_rect(fill = "transparent",
colour =
"transparent"),
legend.text = element_text(size = 14),
panel.border = element_blank(),
axis.title = element_blank(),
axis.text = element_blank(),
axis.ticks = element_blank()) +
# plot.margin=unit(c(-0.05,-0.05,-0.05,-0.1),"in")) +
scale_x_continuous(limits = c(0,647.47), expand = c(0,0)) +
scale_y_continuous(limits = c(0,497), expand = c(0,0))
# Visualizar campo de fútbol con información representada
player_scatter_plot
# Completar gráfico con información marginal, donde se muestra
# histograma en x e y del evento elegido.
ggExtra::ggMarginal(player_scatter_plot,
x = x1 - 258.015,
y = y1,
type = "histogram",
xparams = list(breaks = seq(0,600,50),
colour = "#00529f"),
yparams = list(breaks = seq(50,450,50),
colour = "#00529f")
)
260
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.3. Ejercicio 3. Creación de un mapa de calor para
visualización de KPIs de jugadores de un equipo
2.6.3.1. Introducción y Objetivo
Cuando manejamos una base de datos, recogiendo información de los jugadores de un
equipo o de una competición matricialmente, resulta más cómodo identificar aquellos
jugadores que destacan, positiva o negativamente en el conjunto, en alguna de las
variables o KPIs recogidos en la matriz. Para ello, en este ejercicio vamos a transformar la
información numérica de una matriz o base de datos en una representación gráfica a
modo de mapa de calor que permita reconocer visualmente las fortalezas y debilidades
de cada jugador. Adjuntamos el archivo data-nba-points-per-game-2008.csv, donde
se incluyen a los 50 mejores jugadores de la historia de la NBA en puntuación por partido.
2.6.3.2. Código Comentado
Cargamos los paquetes necesarios para esta práctica (si aún no están cargados).
Principalmente, estos son ggplot2() y plyr() para la representación gráfica y la
manipulación de datos; y los paquetes reshape() y scales() para poder modificar la escala
de los valores de los KPIs y facilitar una representación homogénea de la información. El
paquete readr() nos permitirá abrir el archivo .csv.
1
2
3
4
5
> library(ggplot2)
> library(plyr)
> library(reshape2)
> library(scales)
> library(readr)
Dependiendo entonces de dónde se encuentre el archivo .csv que queremos usar, será
necesario o no cambiar o fijar el directorio de trabajo. Consideremos el caso más general
en el cual el archivo se encuentra ubicado en una carpeta diferente. Sea esta carpeta
(C:/Users/my-home-station/Desktop/master/r/create-heat-map/)
1
2
3
> setwd("C:/Users/my-home-station/Desktop/master/r/create-heat-
map/")
> mydata <- read_csv("data-nba-points-per-game-2008.csv")
261
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Proceso
Los 50 jugadores recogidos en la base de datos se encuentran ordenados por puntos
anotados por partido. Si se observa la naturaleza de la variable mydata$Name, vemos que se
trata de cadenas de caracteres. Lo que nos interesa a continuación es transformarlo en
factores, para posteriormente facilitarnos la representación del mapa. Así, la variable $Name
es el factor que ordena de manera conveniente cada parcela del mapa.
1 > mydata$Name <- with(mydata, reorder(Name, PTS))
Las variables recogidas son muy diversas, incluyendo desde porcentaje de tiros libres a
bloqueos o minutos, de modo que queda en evidencia la diferencia de escala entre una
variable y otra. Para facilitar su tratamiento en un mismo mapa, resulta necesario un
escalado. Previamente, procedemos a conjuntar toda la información, de modo que las 50
observaciones de las 21 variables diferentes (incluyendo nombre), se transforma con la
función melt() en 1000 observaciones de 3 variables distintas (nombre, KPI y valor del KPI).
1
2
3
> mydata_melted <- melt(mydata)
> mydata_melted <- ddply(mydata_melted, "variable", transform,
rescale = scale(value))
Postproceso
El paquete ggplot2() no dispone explícitamente de una función para representar mapas
de calor. Sin embargo, poder construir un mapa de calor con la función geom_tile() y un
relleno de color con degradado.
1
2
3
> myplot <- ggplot(mydata_melted, aes(variable, Name)) +
geom_tile(aes(fill = rescale), colour = "white") +
scale_fill_gradient(low = "white", high = "red"
Finalmente, queda a libertad del alumno jugar con la apariencia del gráfico, jugando con
los tamaños de fuente y color, posición de la leyenda o cualquier otro aspecto que se desee
modificar. En particular, aquí editamos la imagen inicial, eliminando los títulos de los ejes,
extendiendo la imagen en ambos ejes a fin de eliminar bordes grises, retirando del gráfico
las marcas de divisiones y eliminando la leyenda del gráfico, siendo el resultado final el
mostrado en la Fig. F.
1
2
3
> myplot + labs(x = "", y = "") + scale_x_discrete(expand =
c(0,0)) + scale_y_discrete(expand = c(0,0)) + theme(axis.ticks
= element_blank(), legend.position = "none")
262
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Resultado del ejercicio con edición final.
263
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.3.3. Código sin comentarios
# -------------
# Preproceso
# -------------
# Instalar paquetes si aun no se tienen instalados en la distribución de R
#install.packages("ggplot2");
#install.packages("reshape2");
#install.packages("plyr")
#install.packages("scales")
#install.packages("readr")
# Cargar los paquetes que utilizaremos en el ejercicio
library(ggplot2)
library(reshape2)
library(plyr)
library(scales)
library(readr)
# Fijar directorio de trabajo
# Cambiar el directorio de trabajo donde hemos guardado el archivo
# data-nba-points-per-game-2008.csv, sustituyendo ... por la ruta correspondiente
setwd("...")
# Cargar el archivo .csv
mydata <- read_csv("data-nba-points-per-game-2008.csv")
# Mostrar el dataframe y los datos
# View(mydata)
# print(mydata)
# -------------
# Proceso
# -------------
# Reordenar jugadores por nombre y convertir la variable en factor para asegurar
# ordenado adecuado en el gráfico
mydata$Name <- with(mydata, reorder(Name, PTS))
# Agrupar todas las columnas de las distintas estadísticas en una unica columna
mydata_melted <- melt(mydata)
# Para hacer comparable las distintas estadisticas, escalar las variables
mydata_melted <- ddply(mydata_melted, .(variable), transform, rescale =
scale(value))
# -------------
# Postproceso
# -------------
# ggplot() con la funcion geom_tile y un relleno de degradado permite crear mapa
de calor
myplot <- ggplot(mydata_melted, aes(variable, Name)) +
geom_tile(aes(fill = rescale), colour = "white") +
scale_fill_gradient(low = "white", high = "red")
264
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# Editar al gusto el grafico obtenido
myplot + labs(x = "", y = "") +
scale_x_discrete(expand = c(0, 0)) +
scale_y_discrete(expand = c(0, 0)) +
theme(legend.position = "none", axis.ticks = element_blank())
265
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.4. Ejercicio 4. Creación de un gráfico para representar la
evolución temporal de un KPI (puntuación) de un partido
2.6.4.1. Introducción y Objetivo
Un gráfico interesante es el que permite representar información temporal de un KPI a largo
de un periodo de tiempo. Un ejemplo sería el mostrar cómo evoluciona la puntuación de
un partido de baloncesto, o cómo evolucionan los goles esperados acumulados de un
equipo de fútbol en un partido, o los puntos conseguidos en un campeonato liguero.
2.6.4.2. Código comentado
Dentro del paquete lubridate() se encuentra el conjunto de datos lakers. Este conjunto
de datos recoge información estadística, jugada a jugada, de cada partido del equipo de
baloncesto de la NBA Los Ángeles Lakers en la temporada 2008-2009. Estos datos incluyen
fecha, rival y si el partido se jugó como local o visitante. Cada jugada se describe por el
instante de tiempo en el que comienza la jugada, el periodo o cuarto de partido, el tipo de
jugada, el jugador y el equipo que hizo la jugada, el resultado de la misma y la posición del
campo en el que cada jugada tuvo lugar. Todos estos datos se encuentran disponibles en
www.basketballgeek.com/data/, y los autores del paquete incluyeron esta información al
tratarse el paquete de un conjunto de herramientas y funciones diseñado específicamente
para trabajar con series temporales.
1
2
3
> library(lubridate)
> library(ggplot2)
> library(plyr)
Cuando se desea representar más de un gráfico generado con ggplot2(), disponemos de
diversas opciones para ubicar posteriormente en una cuadrícula cada uno de los subplots
que necesitemos. En la tabla adjunta, listamos algunas de las alternativas disponibles
Paquete Función(es) ggsave compat. Alineamiento grid viewport, grid.layout No No gridExtra grid.arrange Sí No gtable multiplot Sí Sí cowplot rbind, cbind Sí Sí multipanelfigure plot_grid Sí Sí egg multi_panel_figure Sí Sí patchwork plot_layout Sí Sí
266
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La base de todos los paquetes mencionados, los cuales están ordenados
cronológicamente, es grid(), incluido por defecto en la distribución de R. Este paquete
proporciona funciones a bajo nivel para dibujar y ubicar objetos en un soporte. El concepto
clave para posicionar un objeto (entiéndase un gráfico) es el de viewport, el cual
representa una subregión rectangular del display. Por defecto, el viewport toma una página
entera (o ventana), y personalizando la posición, espacio e incluso orientación, es posible
ordenar un conjunto de gráficos arbitrariamente. El paquete grid() contiene las funciones
viewport y grid.layout, que las utilizaremos para ajustar los márgenes del gráfico y para
representar conjuntamente los gráficos que iremos construyendo.
1
2 > vplayout <-function(x,y) +
viewport(layout.pos.row=x, layout.pos.col=y)
Proceso
Podemos buscar y recordar qué equipos participaron en la temporada 2008-2009 en la NBA;
y dado que la variable lakers$opponent es un acrónimo con tres letras de cada equipo,
construimos dos variables, team_code_2008 y team_name_2008, para tener recogido en un
vector de cadenas tanto el acrónimo como el equipo correspondiente. Para ello,
registramos cada equipo ordenadamente en ambos vectores:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
> team_code_2008 = c("ATL", "BOS", "CHA", "CHI", "CLE", "DAL",
"DEN", "DET", "GSW", "HOU", "IND", "LAC", "LAL", "MEM", "MIA",
"MIL", "MIN", "NJN", "NOH", "NYK", "OKC", "ORL", "PHI", "PHX",
"POR", "SAC", "SAS", "TOR", "UTA", "WAS")
> team_name_2008 = c("Atlanta Hawks", "Boston Celtics",
"Charlotte Hornets", "Chicago Bulls", "Cleveland Cavaliers",
"Dallas Mavericks", "Denver Nuggets", "Detroit Pistons",
"Golden State Warriors", "Houston Rockets", "Indiana Pacers",
"Los Angeles Clippers", "Los Angeles Lakers", "Memphis
Grizzlies", "Miami Heat", "Milwaukkee Bucks", "Minnesota
Timberwolves", "New Jersey Nets", "New Orleans Hornets", "New
York Knicks", "Oklahoma City Thunder", "Orlando Magic",
"Philadelphia 76ers", "Phoenix Suns", "Portland Trail Blazers",
"Sacramento Kings", "San Antonio Spurs", "Toronto Raptors",
"Utah Jazz", "Washington Wizards")
La fecha de los partidos viene dado como un texto de formato AñoMesDía, que
transformamos en fecha con la función ymd(). Igualmente, transformamos la información
del tiempo en el que tiene lugar la jugada del formato original “XX:XX” en “XM XS” mediante
la función ms(). Así, podemos transformar finalmente la información contenida en la
variable tiempo en cuánto tiempo queda del cuarto por jugar. Esto es posible con la función as.duration().
1
2
3
> lakers$date <-ymd(lakers$date)
> lakers$time <- ms(lakers$time)
> lakers$time <- as.duration(lakers$time)
267
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
La variable lakers$period recoge el cuarto en el cual se incluye la jugada. Recordamos
que los cuartos en la NBA no son de 10 minutos como en torneos FIBA, sino de 12 minutos,
mientras que las prórrogas son de 5 minutos. Por lo tanto, el código siguiente consigue
transformar el instante en el que se realiza la jugada (medido en tiempo que quedaba hasta
fin del cuarto) en tiempo de juego transcurrido desde el inicio del partido. La última
sentencia del código permite transformar el tiempo de juego de segundos a minutos,
habiendo transformado previamente en número la cadena de cada elemento de
lakers$gametime.
1
2
3
> lakers$gametime <- dminutes(c(12,24,36,48,53)[lakers$period])
> lakers$gametime <- lakers$gametime – as.duration(lakers$time)
> lakers$minutes <- as.numeric(seconds(lakers$gametime))/60
Entre las jugadas o acciones recogidas en la base de dato, también figuran las luchas por
balón (jump ball) o cuando ninguno de los equipos interviene (team OFF). Por ello, resulta
necesario filtrar las filas de la base de datos que correspondan a ese caso, pasando de
34624 a 34342 observaciones. La segunda sentencia hace referencia a las diferentes fechas
disponibles. Dado que se recogen todas las jugadas de todos los partidos de la temporada,
resulta evidente entender que, en toda la base de datos, habrá fechas repetidas, al
poderse referir al mismo partido (misma fecha) diferentes jugadas o acciones. Si lo que
queremos es cuantificar el número de partidos y asignarle un índice a cada uno para, en
bucle, hacer las mismas acciones sobre los datos, la función unique() identifica todos los
valores diferentes de la variable lakers_games$date. Podremos ver que hay 78 partidos en
total.
1
2
> lakers_games <- lakers[(lakers$team !="OFF"),]
> gamedate <- unique(lakers_games$date)
A continuación, procederemos a tratar iterativamente cada partido o fecha registrada en
la base de datos. Para ello, utilizamos un bucle for que haga lo mismo para cada índice.
Hemos decidido separar el código para poder explicar y entender qué se va haciendo
sucesivamente, dejando en el código siguiente sólo el inicio y final (cierre de llave en línea
68) del bucle.
1
…
68
> for (igame in seq_along(gamedate)){
#Acciones a realizar explicadas a continuación
}
268
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Dado que hasta que no se cierre el bucle no se genera una nueva sentencia, nótese que
cada línea dentro de las llaves, indicadas en los subcódigos siguientes, no empiezan con el
símbolo >. Para más aclaración, la sangría introducida deja entender que forma parte de
código dentro del bucle. Sea la variable this_game el partido de la base de datos
correspondiente al índice igame dentro del bucle.
2
3
4
5
this_game <- lakers_games[lakers_games$date ==
gamedate[igame],]
this_game_scores <- ddply(this_game, "team", transform,
score = cumsum(points))
En la variable this_game_scores, creamos una nueva columna que da el resultado del
partido, jugada a jugada, como suma acumulada de los puntos que se van consiguiendo
progresivamente, sumándose para cada equipo. A continuación, correlacionamos los
acrónimos de los equipos involucrados en los partidos, donde siempre estará Los Ángeles
Lakers y donde el rival vendrá dado en la variable $opponent, con los nombres que
habíamos registrado en la variable team_name_2008. Igualmente, determinamos el resultado
final, siendo éste el valor máximo de la puntuación acumulada a lo largo del partido para
equipo, calculada con la función max().
6
7
8
9
10
11
12
13
14
15
first_team_name <- team_name_2008[which(team_code_2008 ==
"LAL")]
second_team_name <- team_name_2008[which(team_code_2008 ==
this_game_scores$opponent[1])]
first_team_score <-
max(this_game_scores[(this_game_scores$team == "LAL"),
"score"])
second_team_score <-
max(this_game_scores[(this_game_scores$team ==
this_game_scores$opponent[1]), "score"])
Esta información, equipos involucrados con su nombre completo y resultado del partido, así
como la fecha del encuentro, serán datos que se incorporarán al gráfico.
16
17
18
19
20
this_game_summary_text <- paste(gsub(" UTC", "",
ymd(this_game_scores$date)[1]), " ", first_team_name, " ",
this_game_scores$game_type[1], " (", first_team_score, ")
vs ", second_team_name, " ", "(", second_team_score, ")",
sep = "")
Postproceso
Finalmente, sólo queda construir el gráfico que muestre la evolución de puntuación a lo
largo del partido. A pesar de haberlo separado en una etapa diferente (postproceso), cabe
indicar que el código siguiente quedaría dentro del bucle for que todavía no se ha cerrado.
El gráfico contendrá las líneas de evolución temporal de la puntuación de cada equipo a
lo largo del partido. Para ello, hacemos uso de la función geom_step(). El resto de
sentencias hacen referencia a modificaciones del gráfico, ya sea para añadir información
269
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
de leyenda, con los colores y nombre de cada equipo, resultado final al final de cada recta
escalonada, cabecera o título con la información incluida en this_game_summary-text,
títulos de los ejes y formato de cada título, o color del gráfico y de las líneas.
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
myplot <-
ggplot() +
geom_step(data = subset(this_game_scores, team ==
"LAL"), aes(x = minutes, y = score), size = 0.75, colour =
"purple") +
geom_step(data = subset(this_game_scores, team ==
this_game_scores$opponent[1]), aes(x = minutes, y =
score), size = 0.75, colour = "darkgrey") +
geom_segment(x = 1.0, xend = 3.0, y =
max(this_game_scores$score) - 5, yend =
max(this_game_scores$score) - 5, colour = "purple", size =
0.75) +
annotate("text", x = max(this_game$minutes), y =
first_team_score, colour = "purple", size = 5, label =
first_team_score, hjust = 0) +
annotate("text", x = max(this_game$minutes), y =
second_team_score, colour = "darkgrey", size = 5, label =
second_team_score, hjust = 0) +
annotate("text", x = 4, y = max(this_game_scores$score)
- 5, colour = "#a9a9a9", size = 5, label =
first_team_name, hjust = 0) +
annotate("text", x = 4, y = max(this_game_scores$score)
- 12, colour = "#a9a9a9", size = 5, label =
second_team_name, hjust = 0) +
geom_rect(aes(xmin = 1.0, xmax = 3.0, ymin =
max(this_game_scores$score) - 5, ymax =
max(this_game_scores$score) - 5), color = "purple", size =
0.75) +
geom_rect(aes(xmin = 1.0, xmax = 3.0, ymin =
max(this_game_scores$score) - 12, ymax =
max(this_game_scores$score) - 12), color = "darkgrey",
size = 0.75) +
ggtitle(this_game_summary_text) +
xlab("Minutos del partido") +
ylab("Resultado") +
theme_bw() +
theme(axis.ticks = element_blank(),
axis.title.x = element_text(size = 16, color =
"#a9a9a9"),
axis.title.y = element_text(size = 16, color =
"#a9a9a9"),
axis.text.x = element_text(size = 12, color =
"#a9a9a9"),
axis.text.y = element_text(size = 12, color =
"#a9a9a9"),
axis.line = element_line(colour = "#a9a9a9")
)
270
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Fig. F. Resultado del ejercicio con edición final
271
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.4.3. Código sin comentarios
# -------------
# Preproceso
# -------------
# Instalar paquetes si aun no se tienen instalados en la distribución de R
#install.packages("ggplot2");
#install.packages("lubridate");
#install.packages("plyr")
# Cargar los paquetes que utilizaremos en el ejercicio
library(ggplot2)
library(lubridate)
library(plyr)
# Definir funcion que se usara en la representacion grafica para dividir la
region de
# plotting y anadir varios graficos simultaneamente
vplayout <-function(x,y) +
viewport(layout.pos.row=x, layout.pos.col=y)
# -------------
# Proceso + Postproceso
# -------------
# Crear vectores que contengan acronimos y nombres de todos los equipos de la NBA
team_code_2008 = c("ATL", "BOS", "CHA", "CHI", "CLE",
"DAL", "DEN", "DET", "GSW", "HOU",
"IND", "LAC", "LAL", "MEM", "MIA",
"MIL", "MIN", "NJN", "NOH", "NYK",
"OKC", "ORL", "PHI", "PHX", "POR",
"SAC", "SAS", "TOR", "UTA", "WAS")
team_name_2008 = c("Atlanta Hawks", "Boston Celtics",
"Charlotte Hornets", "Chicago Bulls",
"Cleveland Cavaliers", "Dallas Mavericks",
"Denver Nuggets", "Detroit Pistons",
"Golden State Warriors", "Houston Rockets",
"Indiana Pacers", "Los Angeles Clippers",
"Los Angeles Lakers", "Memphis Grizzlies",
"Miami Heat", "Milwaukkee Bucks",
"Minnesota Timberwolves", "New Jersey Nets",
"New Orleans Hornets", "New York Knicks",
"Oklahoma City Thunder", "Orlando Magic",
"Philadelphia 76ers", "Phoenix Suns",
"Portland Trail Blazers", "Sacramento Kings",
"San Antonio Spurs", "Toronto Raptors",
"Utah Jazz", "Washington Wizards")
# Crear variables de fecha y tiempo del partido en formato Año-Mes-Dia
# y Minutos Segundos, respectivamente
lakers$date <-ymd(lakers$date)
lakers$time <- ms(lakers$time)
# Convertir el tiempo en duración del partido, transformando
# Minutos Segundos en Segundos
lakers$time <- as.duration(lakers$time)
# En función del periodo correspondiente, crear variable gametime
# que recoge duración acumulada de cada periodo
272
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
# de acuerdo a cómo se define un periodo en la NBA de 12 minutos
lakers$gametime <- dminutes(c(12,24,36,48,53)[lakers$period])
# Restar duración restante a duración total del periodo para determinar
#tiempo acumulado desde 0 de la acción
lakers$gametime <- lakers$gametime - as.duration(lakers$time)
# Crar variable minutos correspondiente a los segundos de la acción
lakers$minutes <- as.numeric(seconds(lakers$gametime))/60
# Filtrar acciones o jugadas donde no este definido equipo que posee balon
lakers_games <- lakers[(lakers$team !="OFF"),]
# Contar partidos de la temporada
gamedate <- unique(lakers_games$date)
# Bucle for de acciones a aplicar a cada partido
for (igame in seq_along(gamedate))
{
# Cargar el partido correspondiente al indice igame
this_game <- lakers_games[lakers_games$date == gamedate[igame],]
# Calcular el resultado en cada jugada como suma acumulada de
# puntos hasta la jugada
this_game_scores <- ddply(this_game, "team", transform,
score = cumsum(points))
# Identificar equipo 1 (siempre Los Angeles Lakers) y equipo 2 (oponente)
first_team_name <- team_name_2008[which(team_code_2008 == "LAL")]
second_team_name <- team_name_2008[which(team_code_2008 ==
this_game_scores$opponent[1])]
# Calcular resultado final como valor maximo de resultados a lo largo del
partido
first_team_score <- max(this_game_scores[(this_game_scores$team == "LAL"),
"score"])
second_team_score <- max(this_game_scores[(this_game_scores$team ==
this_game_scores$opponent[1]),
"score"])
# Crear resumen informativo del partido, que sera utilizado en titulo del
grafico
this_game_summary_text <- paste(gsub(" UTC", "", ymd(this_game_scores$date)[1]),
". ", first_team_name, " ",
this_game_scores$game_type[1],
" (", first_team_score, ") vs ",
second_team_name, " ",
"(", second_team_score, ")", sep = "")
# Crear visualizacion
myplot <- ggplot() +
geom_step(data = subset(this_game_scores, team == "LAL"),
aes(x = minutes, y = score),
size = 0.75, colour = "purple") +
geom_step(data = subset(this_game_scores,
team ==
this_game_scores$opponent[1]),
aes(x = minutes, y = score), size = 0.75, colour = "darkgrey") +
geom_segment(x = 1.0, xend = 3.0, y = max(this_game_scores$score) - 5,
yend = max(this_game_scores$score) - 5,
colour = "purple", size = 0.75) +
273
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
annotate("text", x = max(this_game$minutes),
y = first_team_score,
colour = "purple", size = 5,
label = first_team_score, hjust = 0) +
annotate("text", x = max(this_game$minutes),
y = second_team_score,
colour = "darkgrey", size = 5,
label = second_team_score, hjust = 0) +
annotate("text", x = 4,
y = max(this_game_scores$score) - 5,
colour = "#a9a9a9", size = 5,
label = first_team_name, hjust = 0) +
annotate("text", x = 4,
y = max(this_game_scores$score) - 12,
colour = "#a9a9a9", size = 5,
label = second_team_name, hjust = 0) +
geom_rect(aes(xmin = 1.0, xmax = 3.0,
ymin = max(this_game_scores$score) - 5,
ymax = max(this_game_scores$score) - 5),
color = "purple", size = 0.75) +
geom_rect(aes(xmin = 1.0, xmax = 3.0,
ymin = max(this_game_scores$score) - 12,
ymax = max(this_game_scores$score) - 12),
color = "darkgrey", size = 0.75) +
ggtitle(this_game_summary_text) +
xlab("Minutos del partido") +
ylab("Resultado") +
theme_bw() +
theme(axis.ticks = element_blank(),
axis.title.x = element_text(size = 16, color = "#a9a9a9"),
axis.title.y = element_text(size = 16, color = "#a9a9a9"),
axis.text.x = element_text(size = 12, color = "#a9a9a9"),
axis.text.y = element_text(size = 12, color = "#a9a9a9"),
axis.line = element_line(colour = "#a9a9a9")
)
}
Myplot
274
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.5. Ejercicio 5. Simulación de un partido. Calculo de la
probabilidad de un evento en un partido
2.6.5.1. Introducción y Objetivo
Este ejercicio está inspirado y se guía por la propuesta de Thomas W. Miller en su libro Sports
Analytics and Data Science. Con el objetivo de extender la generalización de los conceptos
aplicados en este módulo a otros deportes, incluimos un ejemplo relacionado con un
deporte diferente como es el béisbol. Como se puede observar, adjuntamos también el
código en Python para que los alumnos puedan comparar cómo afrontar un mismo
ejercicio con dos códigos diferentes pero semejantes.
El objetivo es el de realizar una simulación para determinar las probabilidades de victoria
de uno u otro equipo, o las probabilidades, en el caso que consideramos aquí, de realizar
tantas carreras en un partido. Recordamos que en el béisbol se entiende por carrera a la
anotación que se consigue cuando el jugador consigue avanzar sobre la primera, segunda
y tercera base, y regresar al home plate, tocando las bases en ese orden, antes de que se
registren tres outs en la pizarra. ¿Cuántas carreras se pueden esperar que el equipo A (local)
haga? ¿Y cuántas el equipo B (visitante)? Y, consecuentemente, ¿qué equipo se espera
que gane el partido?
Para predecir las carreras, y por extensión cualquier otra variable de otro deporte, que se
marcará en el futuro, comenzamos a analizar las carreras logradas en el pasado. Las
simulaciones del resultado (o carreras) de un partido se basan en históricos. Para aproximar
a la realidad que se puede afrontar, donde la incertidumbre (mayor o menor) es parte
indiscutible del juego, se introduce una cierta aleatoriedad mediante generadores de
números aleatorios, de modo que jugar (simular) un mismo partido una y otra vez puede
dar resultados diferentes.
275
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Carreras
conseguidas por
equipo A
6
4
10
11
3
2
8
0
11
3
6
1
9
5
6
1
4
4
…
Carreras
conseguidas
por equipo B
9
6
4
10
4
10
9
8
0
4
3
4
11
8
5
2
5
8
…
Elección
aleatoria
→ 11
Elección
aleatoria
→ 5
Elección
aleatoria
→ 3
Elección
aleatoria
→ 6
Elección
aleatoria
→ 1
…
Gana A
Gana B
Gana A
Empate
(descartada)
Gana B
…
Elección
aleatoria
7 ←
Elección
aleatoria
9 ←
Elección
aleatoria
0 ←
Elección
aleatoria
6 ←
Elección
aleatoria
2 ←
…
Resultados de 50000 simulaciones
- Gana A: 19945 → 39.89% P(victoria)
- Gana B: 30055 → 60.11% P(victoria)
Podemos ver cómo a partir del histórico de cada equipo, podemos tener información de
cuántas carreras han conseguido en un partido. Si se simula una elección aleatoria de las
carreras que cada equipo podría hacer, descartando los casos en los que el resultado sea
el mismo (en béisbol no tienen cabida los empates), tendríamos del total de simulaciones
realizadas cuántas veces ganaría el equipo A y cuántas el equipo B. De este modo,
podemos determinar la probabilidad de victoria de cada equipo.
En este caso sólo se (pseudo-)simulan los puntos o carreras conseguidas, pero no los puntos
o carreras permitidas o recibidas en un partido. Una simulación equilibrada contendría
información no sólo de la parte ofensiva sino también de la defensiva, de modo que en vez
de comparar CarrerasConseguidas(A) vs CarrerasConseguidas(B), lo que haríamos sería
0.5*CarrerasConseguidas(A) + 0.5*CarrerasPermitidas(A) vs 0.5*CarrerasConseguidas(B) +
0.5*CarrerasPermitidas(B).
276
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Si en vez de simular directamente el resultado lo que queremos es simular el número de
carreras (o goles en un partido de fútbol) para, de forma indirecta, simular la probabilidad
de victoria de un partido, utilizaremos la distribución de Poisson o la distribución binomial
negativa. Queda fuera del alcance de este curso el análisis de estas distribuciones. Para
una lectura más en profundidad de estos conceptos se recomienda el libro de Statistics, de
David Freeman, o Fundamentos de Estadística, de Daniel Peña. Aquí simplemente
indicaremos que Keller, en 1994, comprobó que una distribución de Poisson aproximaba las
puntuaciones (carreras) conseguidas en un partido de fútbol. La distribución de Poisson
viene dada como
𝑃(𝑥) = 𝑒−𝜆𝜆𝑥
𝑥!
donde P(x) es la probabilidad de conseguirse x carreras, e es la constante matemática e =
2.71828, y λ es el parámetro de la distribución, cuyo valor es la media y la varianza de la
distribución. Sin perdernos en los detalles, se observa que una distribución de Poisson de
media 4.68 aproxima significativamente la distribución de frecuencia relativa de las carreras
conseguidas en un partido.
Equivalente o inversa a la distribución de Poisson, tenemos la distribución binomial negativa.
Mientras que la distribución binomial indica el número de sucesos en n intentos, la binomial
negativa da el número de intentos hasta que observamos un determinado número de
éxitos. Así, la probabilidad de observar x carreras en un partido:
𝑃(𝑥) = (1 +𝜇
𝑘)
−𝑘 (𝑘 + 𝑥 − 1)!
𝑥! (𝑘 − 1)!(
𝜇
𝑢 + 𝑘)
𝑥
En este ejercicio trataremos de construir una matriz de probabilidades basada en la
distribución binomial negativa para determinar la probabilidad de victoria de un equipo
(equipo local) de acuerdo con las carreras esperadas de éste y del rival (equipo visitante).
2.6.5.2. Codigo comentado
Comenzamos cargando la librería lattice(), que incluye funciones gráficas específicas
para matrices de probabilidades.
1 > library(lattice)
277
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Proceso
Para construir nuestro modelo, primero definimos una función que, en función de los valores
medios de carreras del equipo local y visitante, determinará la probabilidad de victoria en
cada caso. La función es simulator, y los argumentos son home_mean, away_mean y el número
de iteraciones. En el código vemos cómo, una vez inicializada la semilla para asegurar
reproductibilidad de los resultados, inicializamos tres variables con un tamaño o longitud
igual al número de iteraciones que consideremos. Esas variables son away_game_score,
home_game_score y home_win.
Poniendo el contador a 1, arrancamos un bucle while que se ejecutará hasta que se
cumpla el total de iteraciones consideradas. En el bucle, asignamos valores a las variables
anteriores (away_game_score y home_game_score), recogiendo el resultado correspondiente a
cada partido simulado (tantos como iteraciones), de acuerdo con una distribución
binomial negativa de media igual a la media de puntuación de cada equipo, y tamaño 4.
La variable home_win toma el valor 1 cuando efectivamente la puntuación simulada para
el equipo local es mayor que la del equipo visitante.
Hacemos un pequeño inciso relativo a los operadores lógicos que ya introdujimos en la
teoría pero que hasta ahora no habíamos puesto en práctica. Los operadores lógicos AND
y OR se representan en R como & y |, respectivamente. Sin embargo, en vez de en su forma
corta, estos operadores suelen aparecer en su forma extendida como && y ||,
respectivamente. La forma corta realiza una comparación elemento a elemento, en un
modo semejante a los operadores aritméticos. Mientras, la forma extendida evalúa de
izquierda a derecha, examinando sólo el primer elemento de cada vector, y dura la
evaluación sólo hasta que el resultado es determinado, pudiendo ahorrar coste
computacional frente a la primera opción. Es esta forma extendida la más apropiada para
programación de flujos de control y típicamente preferida en bucles o condiciones IF. En
este caso, vemos que utilizamos el operador ||para sumar un paso más al bucle.
La suma de todos los contadores de home_win permite finalmente calcular la probabilidad
de victoria del equipo local después de n_iterations simulaciones.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> simulator <- function(home_mean, away_mean, niterations){
set.seed(1234)
away_game_score <- numeric(niterations)
home_game_score <- numeric(niterations)
home_win <- numeric(niterations)
i <- 1
while (i < niterations + 1){
away_game_score[i] <- rnbinom(1, mu = away_mean, size = 4)
home_game_score[i] <- rnbinom(1, mu = home_mean, size = 4)
if(away_game_score[i] > home_game_score[i])
home_win[i] <- i
if(away_game_score[i] > home_game_score[i] ||
away_game_score[i] < home_game_score[i]) i <- i + 1
}
myprob <- sum(home_win)/niterations
}
278
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
17
Construida la función, definimos el número de iteraciones. Aunque el número de iteraciones
debería ser órdenes superior al propuesto, por reducir el coste computacional para este
test, fijamos el valor en 100000.
1 > niterations <- 100000
Y a continuación, creamos la matriz donde recogeremos las probabilidades de que se den
diversos resultados, donde en las filas consideraremos al equipo local, y en las columnas al
visitante. Creamos la matriz probability_matrix, de 9x9, fijando este valor arbitrariamente
como máximo número de carreras de cada equipo; y en cada dirección (filas y columnas),
indicamos el índice correspondiente. El valor de cada elemento de la matriz es la
probabilidad de victoria del equipo local cuando para cada uno de los dos se espera un
número determinado de carreras dadas por los índices i y j.
1
2
3
4
5
6
7
8
> probability_matrix <- array(NA, dim = c(9,9), dimnames =
list(c(as.character(1:9)), c(as.character(1:9))))
> for (index_home in 1:9)
for (index_away in 1:9)
if (index_home != index_away){
probability_matrix[index_home, index_away] <-
simulator(index_home, index_away, niterations)
}
Postproceso
Comenzamos con el postproceso. Para ello, vamos a considerar que el gráfico que
generemos se presentará en un pdf al que llamaremos fig_sports_analytics_prob_matrix.pdf.
1
2
> pdf(file = "fig_sports_analytics_prob_matrix.pdf", width =
8.5, height = 8.5)
A continuación, definimos qué escribiremos en el pdf. Cada elemento [i,j] será un término
[x,y]. Por ello, x es un vector de enteros del número de filas por el número de columnas, es
decir, 81 elementos. Inicializando y como elemento vacío, comenzamos a asignar valor a y
de modo que recorremos para cada columna (índice i) todas las filas. Así conseguimos
generar los índices que permitirán posteriormente escribir cada elemento de la matriz de
probabilidades.
1
2
3
4
5
> x <- rep(1:nrow(probability_matrix), times =
ncol(probability_matrix))
> y <- NULL
> for (i in 1:ncol(probability_matrix)) y <- c(y, rep(i, times
= nrow(probability_matrix)))
El texto se escribirá como valor numérico de dos decimales.
279
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
1
2
> matrix_text <- sprintf("%0.2f",
as.numeric(probability_matrix))
Creamos el data.frame text_data_frame sobre el cual convertimos en texto (caracteres)
los resultados obtenidos en la matriz de probabilidades:
1
2
3
4
5
6
7
> text_data_frame <- data.frame(x,y,matrix_text)
> text_data_frame$matrix_text <-
as.character(text_data_frame$matrix_text)
> text_data_frame$matrix_text <-
ifelse((text_data_frame$matrix_text == "NA"), NA,
text_data_frame$matrix_text)
> text_data_frame <- na.omit(text_data_frame)
A continuación, definimos cómo representaremos la matriz de probabilidades. Cómo se
colorearan cada una de las celdas de la matriz, qué título tendrá cada eje…
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
> print(levelplot(probability_matrix,
cuts = 25,
tick.number = 10,
col.regions = colorRampPalette(c("violet",
"white", "light blue")),
xlab = "Carreras esperadas equipo visitante",
ylab = "Carreras esperadas equipo local",
panel = function(...){
panel.levelplot(...)
panel.text(text_data_frame$x,
text_data_frame$y,
labels =
text_data_frame$matrix_text)
}
)
)
Finalmente, para liberar el dispositivo sobre el que se trabaja (el .pdf creado), lo cerramos
con el commando dev.off().
1 > dev.off()
280
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Fig. F. Resultado del ejercicio con edición final
281
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.5.3. Codigo sin comentarios
# -------------
# Preproceso
# -------------
# Instalar paquetes si aun no se tienen instalados en la distribución de R
#install.packages("lattice");
#install.packages("ggplot2");
# Cargar los paquetes que utilizaremos en el ejercicio
library(lattice)
# -------------
# Proceso
# -------------
# Crear función que calcula probabilidad de victoria basada en
# simulación niterations veces con
# distribuciones binomiales negativas
simulator <- function(home_mean, away_mean, niterations){
# Para asegurar repetitibilidad, inicializar simulación con semilla 1234
set.seed(1234)
# Inicializar variables away_game_score, home_game_score y home_win,
# así como contador i
away_game_score <- numeric(niterations)
home_game_score <- numeric(niterations)
home_win <- numeric(niterations)
i <- 1
# Comenzar bucle que calcula carreras probables del equipo
# visitante y local
# de acuerdo con distribución binomial negativa de media 4.
while (i < niterations + 1){
away_game_score[i] <- rnbinom(1, mu = away_mean, size = 4)
home_game_score[i] <- rnbinom(1, mu = home_mean, size = 4)
# En función de las carreras simuladas en la iteración,
# se suma victoria y sigue el bucle con contador +1
# o sólo se sigue el bucle con contador +1
if(away_game_score[i] > home_game_score[i])
home_win[i] <- 1
if(away_game_score[i] > home_game_score[i] ||
away_game_score[i] < home_game_score[i]) i <- i + 1
}
# Calcular probabilidad de victoria como cociente de
# victorias totales en la simulación
myprob <- sum(home_win)/niterations
}
# Fijar el valor de numero de iteraciones para reducir el
# coste computacional en este test. Se puede jugar con diferentes ordenes
# de magnitud para ver su efecto
niterations <- 10000
# Crear matriz de probabilidad, dejando vacía la diagonal
# principal y asignando valores a cada elemento
# de la matriz de acuerdo con valor i,j de fila y columna.
probability_matrix <- matrix(data = NA, nrow = 9, ncol = 9,
dimnames =
list(c(as.character(1:9)),
282
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
c(as.character(1:9))))
for (index_home in 1:9)
for(index_away in 1:9)
if (index_home != index_away){
probability_matrix[index_home, index_away] <- simulator(index_home,
index_away, niterations)
}
# -------------
# Postproceso
# -------------
# Fijar directorio de trabajo
# Cambiar el directorio de trabajo donde hemos queremos
# guardar el .pdf de salida,
# sustituyendo ... por la ruta correspondiente
#setwd("...")
setwd("G:/ix-blog/xx-work/master/modulo-04/r/simulate-team-win-prob")
# Definir .pdf en el que se guardará la información generada tras simulación
pdf(file = "fig_sports_analytics_prob_matrix.pdf", width = 8.5, height = 8.5)
# Crear variables x e y para recorrer toda la matriz de probabilidad
x <- rep(1:nrow(probability_matrix), times = ncol(probability_matrix))
y <- NULL
for (i in 1:ncol(probability_matrix)) y <- c(y,
rep(i, times =
nrow(probability_matrix)))
# Construir matriz a mostrar en .pdf, girada con respecto a la matriz de
probabilidades
matrix_text <- sprintf("%0.2f",
as.numeric(probability_matrix))
text_data_frame <- data.frame(x, y, matrix_text)
text_data_frame$matrix_text <- as.character(text_data_frame$matrix_text)
text_data_frame$matrix_text <- ifelse((text_data_frame$matrix_text == "NA"),
NA,
text_data_frame$matrix_text)
text_data_frame <- na.omit(text_data_frame)
print(levelplot(probability_matrix, cuts = 25, tick.number = 10,
col.regions = colorRampPalette(c("violet", "white", "light
blue")),
xlab = "Carreras esperadas por equipo visitante",
ylab = "Carreras esperadas por equipo local",
panel = function(...){
panel.levelplot(...)
panel.text(text_data_frame$x, text_data_frame$y,
labels = text_data_frame$matrix_text)
}))
# Desactivar archivo para poder ser abierto
dev.off()
283
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.5. Ejercicio 6. Simulación de un partido. Cálculo de la
probabilidad de un evento en un partido
2.6.6.1. Introducción y Objetivo
El objetivo de este ejercicio es el de tratar de predecir si un jugador va a estar en el All Star
en función del número de puntos anotados.
2.6.6.2. Código comentado
Cargamos la base de datos basketballData.csv, guardando la información en la variable basket_data.
1
2
3
> basket_data <- read.csv("basketballData.csv", sep = ";",
header = TRUE, stringsAsFactors = FALSE)
> str(basket_data)
Como se ha indicado en la teoría, con el comando attach podemos evitar llamar a
cualquier variable del data.frame mediante el símbolo $ después del nombre del
data.frame, y así ser sólo necesario llamar a la variable en cuestión.
1 > attach(basket_data)
Vamos a crear dos conjuntos de datos, uno para entrenar y otro para testear el modelo
predictivo. Estos dos subconjuntos serán train_set y test_set. Para asegurar la trazabilidad de
los resultados, inicializamos una semilla para la generalización de números aleatorios:
1
2
3
4
5
> set.seed(2)
> index_train <- sample(1:nrow(basket_data),
as.integer(nrow(basket_data)*0.70), replace = FALSE)
> train_set <- basket_data[index_train,]
> test_set <- basket_data[-index_train,]
Vemos que, efectivamente, el subconjunto test_set es la parte de basket_data que no se
recoge en train_set.
A continuación, comenzamos a construir nuestro modelo. En particular, y por sencillez,
vamos a considerar un modelo lineal de regresión logística. En R, podemos construir un
modelo de este tipo con la función glm, especificando como familia de modelos de tipo
binomial. Recordamos que los modelos de regresión logística son útiles cuando queremos
predecir un resultado binario (aunque también se puede utilizar para casos multiples). En
este caso, el resultado binario es 1 o 0 en función de si el jugador es elegido o no para el All
Star.
284
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Como hemos indicado, nuestro modelo de predicción se basará sólo en los puntos
anotados. Por lo tanto, la elección para el All Star es función únicamente de dicha variable
independiente. Dicha relación queda explícita en la construcción de nuestro modelo con
la sentencia AS_games_played ~ points. Para ajustar los coeficientes del modelo de
regresión logística (entrenamiento del modelo), utilizamos el subconjunto train_set. Así:
1
2
> my_model <- glm(AS_games_played ~ points, family = binomial,
data = train_set)
El comando summary() nos permite ver cómo está construido el modelo:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
> summary(my_model)
Call:
glm(formula = AS_games_played ~ points, family = binomial, data
= train_set)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.7393 -0.2118 -0.0943 -0.0553 3.6751
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -6.7520032 0.1380006 -48.93 <2e-16 ***
points 0.0041836 0.0001021 40.98 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 7685.4 on 14922 degrees of freedom
Residual deviance: 4021.3 on 14921 degrees of freedom
AIC: 4025.3
Number of Fisher Scoring iterations: 7
Construido el modelo, y siguiendo aún sólo con el subconjunto de entrenamiento, podemos
ver qué predice el modelo, en tanto por uno (mostrando sólo los seis primeros valores del
total con la función head()):
1
2
3
4
5
6
7
> prediction_train_set <- predict(my_model, train_set, type =
"response")
> head(prediction_train_set)
4046 5338 12491 1930 185
8341
0.002193036 0.001610076 0.002211422 0.001211903 0.242769716 0.0
01414511
285
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Una matriz de confusión nos permitirá ver la calidad de nuestro modelo, al mostrar los
aciertos positivos y negativos, así como los falsos positivos y falsos negativos. Entendemos
como acierto positivo aquel que se predice como un 1 y es un 1 (es decir, se predice que
asiste al All Star y así fue). Entendemos como falso positivo a una predicción de 1 resultando
en 0.
1
2
3
4
5
> probabilities <- ifelse(prediction_train_set > 0.5, 1, 0)
> table(probabilities, train_set$AS_games_played)
probabilities 0 1
0 13649 609
1 207 458
Podemos ver cómo de los 14923 datos incluidos en el subconjunto train_set, el modelo ha
acertado con 13649 como negativo (no asiste a All Star) y con 458 como positivo (asiste a
All Star). Así, el porcentaje de acierto es de 94.532%:
1
2
3
4
> accuracy_my_model <- mean(probabilities ==
train_set$AS_games_played)
> accuracy_my_model
[1] 0.9453193
Los resultados de predicción relativos al conjunto con el que se entrena el modelo suelen
ser de por sí altos. Es evidente que si el modelo se construye basado en un conjunto de
datos, cabe esperar que el resultado de predicción sobre esos datos sea alto. De hecho,
puede ocurrir que en algunos casos el entrenamiento sea tan bueno basado en los datos
utilizados que la capacidad de predicción roce el 100%. Si bien este resultado puede
conducir a pensar que el modelo es muy bueno o incluso perfecto en el caso de valores
más altos, la realidad es que el modelo se encuentra sobre entrenado. Es decir, el modelo
en vez de entrenarse para desarrollar una capacidad predictiva, se ha construido
ajustando sus coeficientes para interpolar los datos utilizados.
Por ello, para determinar cuál es la capacidad real de predicción del modelo, es necesario
utilizar un conjunto de datos no utilizado para el entrenamiento o ajuste del modelo.
1
2
3
4
5
6
7
8
9
10
11
> prediction_test_set <- predict(model, test_set, type =
"response")
> head(prediction_test_set)
1 7 8 12 16 20
0.002051334 0.983836981 0.993658245 0.940798658 0.852899658 0.6
06186938
> predictions <- ifelse(prediction_test_set > 0.5, 1, 0)
> table(predictions, test_set$AS_games_played)
predictions 0 1
0 5846 261
1 85 204
Podemos ver cómo con este segundo conjunto de datos, el modelo predice
correctamente el valor correspondiente a 5846 (negativo) y 204 (positivo) de 6396 datos.
Esto supone un total de 94.590%. Por lo tanto, podemos concluir que el modelo es bueno no
sólo con el conjunto utilizado para construirlo sino también con un conjunto independiente
de validación.
286
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
El modelo construido se basa sólo en una variable, los puntos anotados. Si decidimos
ampliar la complejidad del modelo, de modo que no sólo incluya esa variable, sino también
las asistencias y rebotes:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
> my_model_advanced <- glm(AS_games_played ~ points + assists +
rebounds, family = binomial, data = train_set)
> summary(my_model_advanced)
Call:
glm(formula = AS_games_played ~ points + assists + rebounds,
family = binomial, data = trainSet)
Deviance Residuals:
Min 1Q Median 3Q Max
-2.7977 -0.1830 -0.0670 -0.0335 3.9547
Coefficients:
Estimate Std. Error z value Pr(>|z|)
(Intercept) -7.8195212 0.1763996 -44.33 <2e-16 ***
points 0.0033140 0.0001176 28.18 <2e-16 ***
assists 0.0030020 0.0002740 10.96 <2e-16 ***
rebounds 0.0028268 0.0001776 15.92 <2e-16 ***
---
Signif. codes: 0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1
(Dispersion parameter for binomial family taken to be 1)
Null deviance: 7685.4 on 14922 degrees of freedom
Residual deviance: 3720.7 on 14919 degrees of freedom
AIC: 3728.7
Number of Fisher Scoring iterations: 8
Vemos en el resumen del modelo que todas las variables involucradas son significativas, con
p-valores inferiores a 0.001. Si repetimos los pasos anteriores con el nuevo modelo:
1
2
3
4
5
6
7
8
9
10
11
> prediction_train_set <- predict(my_model_advanced, train_set,
type = "response")
> probabilities <- ifelse(prediction_train_set > 0.5, 1, 0)
> table(probabilities, train_set$AS_games_played)
probabilities 0 1
0 13648 566
1 208 501
> accuracy_my_model_advanced <- mean(probabilities ==
train_set$AS_games_played)
> accuracy_my_model_advanced
[1] 0.94581338
Ahora, la predicción es de un 94.581%, tan sólo un 0.049% mejor que el anterior. Comparado
con el modelo inicial, los aciertos negativos prácticamente son iguales (sólo -1). Sin
embargo, ha subido el acierto positivo, mientras que se ha reducido el falso negativo y se
ha mantenido el falso positivo (+1).
287
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
Analizando la capacidad predictiva del modelo para el conjunto de validación o test:
1
2
3
4
5
6
7
8
9
10
11
> prediction_test_set <- predict(my_model_advanced, test_set,
type = "response")
> predictions <- ifelse(prediction_test_set > 0.5, 1, 0)
> table(predictions, test_set$AS_games_played)
predictions 0 1
0 5853 224
1 78 241
> accuracy_my_model_advanced <- mean(predictions ==
test_set$AS_games_played)
> accuracy_my_model_advanced
[1] 0.952783
288
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
2.6.6.3. Código sin comentarios
# -------------
# Preproceso
# -------------
# Instalar paquetes si aun no se tienen instalados en la distribución de R
#install.packages("lattice");
#install.packages("ggplot2");
# Cargar los paquetes que utilizaremos en el ejercicio
library(lattice)
# -------------
# Proceso
# -------------
# Crear función que calcula probabilidad de victoria basada en
# simulación niterations veces con
# distribuciones binomiales negativas
simulator <- function(home_mean, away_mean, niterations){
# Para asegurar repetitibilidad, inicializar simulación con semilla 1234
set.seed(1234)
# Inicializar variables away_game_score, home_game_score y home_win,
# así como contador i
away_game_score <- numeric(niterations)
home_game_score <- numeric(niterations)
home_win <- numeric(niterations)
i <- 1
# Comenzar bucle que calcula carreras probables del equipo
# visitante y local
# de acuerdo con distribución binomial negativa de media 4.
while (i < niterations + 1){
away_game_score[i] <- rnbinom(1, mu = away_mean, size = 4)
home_game_score[i] <- rnbinom(1, mu = home_mean, size = 4)
# En función de las carreras simuladas en la iteración,
# se suma victoria y sigue el bucle con contador +1
# o sólo se sigue el bucle con contador +1
if(away_game_score[i] > home_game_score[i])
home_win[i] <- 1
if(away_game_score[i] > home_game_score[i] ||
away_game_score[i] < home_game_score[i]) i <- i + 1
}
# Calcular probabilidad de victoria como cociente de
# victorias totales en la simulación
myprob <- sum(home_win)/niterations
}
# Fijar el valor de numero de iteraciones para reducir el
# coste computacional en este test. Se puede jugar con diferentes ordenes
# de magnitud para ver su efecto
niterations <- 10000
# Crear matriz de probabilidad, dejando vacía la diagonal
# principal y asignando valores a cada elemento
# de la matriz de acuerdo con valor i,j de fila y columna.
probability_matrix <- matrix(data = NA, nrow = 9, ncol = 9,
dimnames =
list(c(as.character(1:9)),
289
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
c(as.character(1:9))))
for (index_home in 1:9)
for(index_away in 1:9)
if (index_home != index_away){
probability_matrix[index_home, index_away] <- simulator(index_home,
index_away, niterations)
}
# -------------
# Postproceso
# -------------
# Fijar directorio de trabajo
# Cambiar el directorio de trabajo donde hemos queremos
# guardar el .pdf de salida,
# sustituyendo ... por la ruta correspondiente
#setwd("...")
setwd("G:/ix-blog/xx-work/master/modulo-04/r/simulate-team-win-prob")
# Definir .pdf en el que se guardará la información generada tras simulación
pdf(file = "fig_sports_analytics_prob_matrix.pdf", width = 8.5, height = 8.5)
# Crear variables x e y para recorrer toda la matriz de probabilidad
x <- rep(1:nrow(probability_matrix), times = ncol(probability_matrix))
y <- NULL
for (i in 1:ncol(probability_matrix)) y <- c(y,
rep(i, times =
nrow(probability_matrix)))
# Construir matriz a mostrar en .pdf, girada con respecto a la matriz de
probabilidades
matrix_text <- sprintf("%0.2f",
as.numeric(probability_matrix))
text_data_frame <- data.frame(x, y, matrix_text)
text_data_frame$matrix_text <- as.character(text_data_frame$matrix_text)
text_data_frame$matrix_text <- ifelse((text_data_frame$matrix_text == "NA"),
NA,
text_data_frame$matrix_text)
text_data_frame <- na.omit(text_data_frame)
print(levelplot(probability_matrix, cuts = 25, tick.number = 10,
col.regions = colorRampPalette(c("violet", "white", "light
blue")),
xlab = "Carreras esperadas por equipo visitante",
ylab = "Carreras esperadas por equipo local",
panel = function(...){
panel.levelplot(...)
panel.text(text_data_frame$x, text_data_frame$y,
labels = text_data_frame$matrix_text)
}))
# Desactivar archivo para poder ser abierto
dev.off()
290
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
3. Anaconda
3.1. Creación de un entorno
Crea un entorno virtual pulsando sobre “Environments”, a continuación en la parte inferior
encontrarás le botón para crear uno nuevo. Pon un nombre al entorno virtual y selecciona
la versión 3.7 de Python.
Verás que tengo varios entornos virtuales creados. Esto sirve para tener diferentes versiones
de Python o de librarías de Python.
291
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
3.2. Instalación de librerías
La instalación de librerías requiere que selecciones un entorno virtual y que pulses sobre las
librerías que tienes a tu disposición y aún no han sido instaladas:
A continuación busca, la librerías pandas usando el cuadro de texto, pulsa en el botón
inferior derecho para “Apply” o instalar la librería seleccionada.
292
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
293
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
4. Referencias
http://www.numpy.org/
http://pandas.pydata.org/
https://www.scipy.org/
https://matplotlib.org/
https://plot.ly/
https://seaborn.pydata.org/
https://bokeh.pydata.org/en/latest/
http://scikit-learn.org/stable/
https://pytorch.org/
https://www.tensorflow.org/
https://markdown.es/
https://wikipedia.com/
https://www.dataschool.io/python-pandas-updates/
T. W. Miller, Sport Analytics and Data Science. Winning the Game with Methods and Models,
Ed. Pearson Education, 2016
N. Zumel y J. Mount, Practical Data Science with R, Ed. Manning Publications, 2014
G. Grolemund, R for Data Science, Ed. O'Reilly Media, 2016
G. James, D. Witten, T. Hastie, R. Tibshirani, An Introduction to Statistical Learning, 2013
D. A. Freeman, Statistics, Ed. W. W. Norton & Co., 2007
D. Peña, Fundamentos de Estadística, Alianza Editorial, 2008
https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.Series.html
https://pandas.pydata.org/pandas-docs/stable/dsintro.html
http://shop.oreilly.com/product/0636920023784.do
https://www.tutorialspoint.com/python_pandas/index.htm
294
Máster en Big Data Deportivo
Módulo 4. Análisis de datos Deportivos con R y Python
© Jaime Lazcano Bello - 2018
Máster en Big Data Deportivo
https://realpython.com/
https://matplotlib.org/
https://docs.python.org/3/library/json.html
https://pandas.pydata.org/pandas-
docs/stable/generated/pandas.DataFrame.to_json.html
https://pandas.pydata.org/pandas-docs/stable/merging.html
https://pandas.pydata.org/pandas-docs/version/0.23.4/generated/pandas.Series.html
https://pandas.pydata.org/