<jupyter_start><jupyter_text>M2.851 - Tipología y ciclo de vida de los datos aula 1 · Práctica 12018 · Máster universitario en Ciencia de datos (Data science)Prof. Colaboradora: <NAME>éAlumno: <NAME> - <EMAIL>&nbsp;  DatasetHistorial de eventos del UFC (*Ultimate Fighting Championship*) DescripciónUn dataset completo con todos los eventos deportivos de MMA (*mixed martial arts*) más famoso del mundo, los deportistas, resultados, entre otros. Imagen identificativaFigura 1: Resultados y card de peleas de un evento de UFC.  ContextoEl conjunto de datos se trata de todos los eventos deportivos de MMA realizados desde la creación del UFC (primer evento en el **12 de Noviembre de 1993**) hasta el último que ocurrió en el **27 de Octubre de 2018**, o sea, **454 eventos**, bien como el resultado de cada una de las peleas que ocurrieron en cada evento - precisamente **4869 luchas**. ContenidoEl dataset tiene un contenido bastante sencillo que consiste en:* [String] *event_name:* Nombre del evento* [String] *weight_class:* Categoría de peso de la pelea* [String] *fighter_1:* Nombre del competidor 1* [String] *action:* Acción que ejecutó el competidor 1 sobre el oponente / resultado* [String] *fighter_2:* Nombre del oponente* [Integer] *round:* *Round* en que acabó la lucha* [String] *time:* Tiempo en el *round* que acabó la lucha* [String] *method:* Como ha sido el método utilizado para ganarEl intervalo de tiempo fuera mencionado arriba, vale resaltar que en cada evento hay una media de 10.7 luchas. La estrategia utilizada para recoger los datos es el resultado de iteraciones en listas:* Inicialmente, pillamos la [lista de todos los eventos del UFC](https://en.wikipedia.org/wiki/List_of_UFC_events)* Hacemos un `for` loop en la lista completa y extraemos (con uso de BeautifulSoup) las URLs individuales de cada evento* Finalmente también haremos una lectura de tabla para finalmente recolectar los datos. AgradecimientosEn análisis se realizó entre **17 y 20 de Octubre** y específicamente el enfoque era encontrar puntos donde pudiera haber ilegalidad en la extracción de información de las fuentes de datos. Para ello, estuve mirando especialmente los ficheros de [robots.txt de Wikipedia](https://en.wikipedia.org/robots.txt), que dicho, es nuestra fuente de información, al cual dejamos el agradecimiento y sugiero donaciones para la iniciativa.Las URLs de lectura no estaban *Disallowed* en el fichero de Robots, por lo tanto, no habría problemas explorarlas. Aun así, he aplicado técnicas como sleep recomienda **[4] <NAME>. (2017)** para evitar la sobrecarga (*throttling*) de la webpage.  InspiraciónDesde mi punto de vista, el conjunto de datos es interesante porque el ámbito de su aplicación es bastante amplio, para comprobar, voy a describir escenarios de su aplicación:1. Primeramente, una aplicación podría ser para uso en periodismo deportivo - para enseñar datos y patrones del deporte.2. Un deportista, que compete o no en el evento, podría sacar informaciones de métodos más comúnmente utilizados para encerrar una lucha y, de esa manera, prepararse para evitar que hicieran con él o mismo practicar las técnicas para intentar aplicarlas cuando esté competiendo.3. La preparación física en un deporte es un punto clave. Entender donde suele pasar la mayor parte de fines de luchas puede también ayudar los profesionales de preparación física a entrenar sus atletas para que en cansancio no les quite la oportunidad de victoria.4. Podríamos identificar patrones de acuerdo con el peso (categoría) de los atletas, es decir, puede que en una categoría más ligera estén acostumbrados a pelearse más de pie, mientras en otras categorías más pasadas suele ocurrir grappling (lucha de suelo). Seguramente hay otras numerosas posibilidades de aplicación. LicenciaHaciendo un breve estudio de las licencias presentadas, creo que la que se aplicaría más ampliamente a mi estudio sería **CC BY-NC-SA 4.0**, me explico: la licencia en cuestión permite:* *Compartir*: copiar y redistribuir el material* *Adaptar*: transformar y cambiar el materialSin embargo, no permite el uso comercial del mismo - el que, siendo un trabajo de máster, tiene fines más académicos.Abajo, una imagen de que trata la licencia elegida:Figura 2: CC BY-NC-SA 4.0. P.D.: Como el los repositorios de Github no había disponibilidad de utilizar la dicha licencia, por allí he definido el uso de **BSD 3-Clause** que básicamente define que las redistribuciones de generadas con base en el proyecto en cuestión deben ser hechas con notificación a priori. Ademas, garantiza que los nombres de los creadores del proyecto inicial no pueden ser usados para promover productos derivados del proyecto inicial. CódigoEn ese apartado, tendremos el código utilizado para la extracción de los datos y al final para la generación del CSV.<jupyter_code>import sys
print(sys.version)
# Not necessary at all, but to demonstrate that I'm aware that BeautifulSoup4 must be installed
!{sys.executable} -m pip install --upgrade pip
!{sys.executable} -m pip install BeautifulSoup4
from bs4 import BeautifulSoup
from IPython.core.display import display, HTML
from time import sleep
import requests
import pandas as pd
import os
Events = []
base_url = 'https://en.wikipedia.org'
main_url = base_url + '/wiki/List_of_UFC_events'
def perform_http_get(url):
    """
    Note:
        This is a simple function that performs an http_get and if the result code is 200 proceed the return.  

    Args:
        url (str): A string.

    Returns:
        BeautifulSoup: a version parsed of the request content
    """
    
    
    r = requests.get(url)
    if r.status_code == 200:
        return BeautifulSoup(r.content, 'html.parser')
        
def extract_cell(cells, id_td):
    """
    Note:
        This method is aimed for returning the content of a given cell (td) decoded and without 
        additional blank spaces. 

    Args:
        cells (list): A list representing the table row.
        id_td (int): The index of the wanted cell

    Returns:
        String: the real content of the cell.
    """
    
    return cells[id_td].renderContents().decode().strip()
def append_fighter_names(cells_event, info):
    """
    Note:
        This method presents some logic that will be briefly explained here. It turns out that some
        fighters don't have their own wikipedia page, in these cases, there is no link (<a>) within
        their names. Therefore, returning just the content of the cell where this info is present 
        is enough. In other cases, where the link is there, we must extract to update our dictionary.
    Args:
        cells_event (list): A list representing the table row.
        info (dict): The dictionary to be updated
    """
    
    
    
    fighter1 = ''
    fighter2 = ''
    if len(cells_event[1].findAll('a')) == 0:
        fighter1 = extract_cell(cells_event, 1)
    else:
        fighter1 = cells_event[1].find('a').renderContents().decode().strip()

    if len(cells_event[3].findAll('a')) == 0:
        fighter2 = extract_cell(cells_event, 3)
    else:
        fighter2 = cells_event[3].find('a').renderContents().decode().strip()
    
    info.update({"fighter_1" : fighter1})
    info.update({"fighter_2" : fighter2})
def extract_row(cells_event, link):
    """
    Note:
        The goal here is to create a dictionary for the given events and also
        to update in our events list (Events.append). We realize that within
        the method we are also invoking the append_fighter_names that will call
        the aforementioned method to treat the fighters' name.

    Args:
        cells_event (list): A list representing the table row.
        link (str): Basically the event name
    """   
    info = {
        "event_name": link.contents[0],
        "weight_class": extract_cell(cells_event, 0),
        "action": extract_cell(cells_event, 2),
        "method": extract_cell(cells_event, 4),
        "round": extract_cell(cells_event, 5),
        "time": extract_cell(cells_event, 6)
    }
    
    append_fighter_names(cells_event, info)
    Events.append(info)
def download_event_image(individual_event, link):
    """
    Note:
        The method's name is pretty clear here, however, the objective is to 
        download the images of each event in order to present them at the bottom
        of this current document. In a nutshell, the behaviour expected here
        is to create all the recovered images in a folder called pictures
        which, by the way, we can observe that will be created.

    Args:
        individual_event (BeautifulSoup): A BeautifulSoup representing the page of a single event.
    """  
    
    event_images = individual_event.select('table.infobox a.image img[src]')
    if len(event_images) > 0:
        for img in event_images:
            img_url = 'http:' + img['src']
            r = requests.get(img_url)
            with open('pictures/' + link.contents[0], "wb") as code:
                code.write(r.content)
            
def extract_info_individual_event(link):
    """
    Note:
        As you will see, this is the second part of a for loop that I will summarize here:
        First we iterate over the list of UFC events presented in the main web-page (
        https://en.wikipedia.org/wiki/List_of_UFC_events). From the data gathered there
        each individual event will be accessed and we'll collect data from these events.
        
        Needless to say that I'm not iterating over a single web-page, but instead, more than
        450 different web pages, being the first of them the "master one", and this individual
        ones.

    Args:
        link (url): The URL for the individual web-pages of a given list.
    """  
    individual_event = perform_http_get(base_url + link.get('href'))
    table = individual_event.find('table',{'class': 'toccolours'})

    download_event_image(individual_event, link)
   
    if table is not None:
        rows_event = table.findAll('tr')

        for row_event in rows_event:
            cells_event = row_event.findAll('td')
            if len(cells_event) > 0 :
                extract_row(cells_event, link)
                        
"""
From my perspective this is a key part of the program and it will trigger 
the execution and the invocation of the previous methods.
Basically we are collecting the "Past Events" of a table in one page and
for each event in this table (currently 454), we will read another 
information as previously explained in different web pages.
By reading another information, I mean: download the event image, read
the card and the results of the event and so on.


Apart from the behaviour expected, in this part of the code, I also tried
to avoid throtling the Wikipedia source by adding some sleeps within each
iteration - it will slow down the process and avoid some common problems.
"""


Events = []
soup = perform_http_get(main_url)
table_past_events = soup.find('table', {'id': 'Past_events'})

rows = table_past_events.findAll('tr')

for row in rows:
    #sleep(10) # Wait 10 sec, recommendations explained by [4] <NAME>. (2017)
    cells = row.findAll('td')
    if len(cells) > 0 :
        links = cells[1].findAll('a')
        for link in links:        
            extract_info_individual_event(link)
"""
Once we have a list of dict in Events attributes, it's high time we defined
a panda dataframe to properly store the info.
It is done here and we present a glimpse of the data with the df.head() below.
"""



print(len(Events), ' eventos fueron añadidos')

df = pd.DataFrame(Events)
df = df[['event_name', 'weight_class', 'fighter_1', 'action', 'fighter_2', 'round', 'time', 'method' ]]

df.head(15)
"""
This is particularly a visual part of the presentation of the data.
For each event, I'm presenting the folder advertising it.
Remembering that we download each of these pictures in a method 
explained before
"""


df_imgs = df['event_name'].drop_duplicates()

print('Imagenes: ', len(df_imgs))
display(HTML('<table style="width:100%; border: 1px solid black;"><tr>'))
i = 0
row = ''
for img in df_imgs:
    img_src = 'pictures/' + img
    if i == 20:
        row = '{}<td><img src=\'{}\' alt=\'{}\' /></td></tr>'.format(row, img_src, img)
        display(HTML(row))
        row = '<tr>'
        i = 0
    else:
        row = '{}<td><img src=\'{}\' /></td>'.format(row, img_src)
     
    i += 1

display(HTML('</tr></table>'))<jupyter_output>Imagenes:  454<jupyter_text>Dataset: Dataset en formato CSVPor aquí generamos el dataset que podrá ser consultado en el repositorio.<jupyter_code>"""
Last but not least, we are storing the dataframe in a CSV file
"""

file_name = 'ufc-events.csv'
df.to_csv(file_name)<jupyter_output><empty_output>
StarcoderdataJupyterStructuredCleanDedup