Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.
Ambdós costats versió prèvia Revisió prèvia Següent revisió | Revisió prèvia | ||
opendata_pandas [2023/07/01 14:26] miquel_angel_amoros [Conclusions] |
opendata_pandas [2023/07/04 23:23] (actual) miquel_angel_amoros [Per què triem Pandas ?] |
||
---|---|---|---|
Línia 8: | Línia 8: | ||
En aquesta guia veurem com obtenir dades obertes d'un servei web i guardar-les, | En aquesta guia veurem com obtenir dades obertes d'un servei web i guardar-les, | ||
- | Per aconseguir-ho, | + | Per aconseguir-ho, |
+ | |||
+ | Posteriorment, | ||
+ | |||
+ | <WRAP center round important 90%> | ||
+ | Només s' | ||
+ | </ | ||
======= Per què triem Pandas ? ======= | ======= Per què triem Pandas ? ======= | ||
- | * Ens proporciona una col·lecció molt útil, inexistent a Python, el DataFrame. És una taula bidimensional que podem indexar amb la/les columna/es que més ens interessin en cada monment | + | * Ens proporciona una col·lecció molt útil, inexistent a Python, el DataFrame. És una taula bidimensional que podem indexar amb la/les columna/es que més ens interessin en cada moment |
* Pandas detecta automàticament inconsistències de tipus i contingut en les dades. Aconseguim avantatges similars als llenguatges de tipat fort (C, Java). | * Pandas detecta automàticament inconsistències de tipus i contingut en les dades. Aconseguim avantatges similars als llenguatges de tipat fort (C, Java). | ||
* Ens permet tractar grans volums de dades (superiors a 10.000 lines) amb molts mètodes per filtrar la informació. | * Ens permet tractar grans volums de dades (superiors a 10.000 lines) amb molts mètodes per filtrar la informació. | ||
Línia 18: | Línia 24: | ||
* Si organitzem les dades del Dataframe convenientment podem crear gràfics amb llibreries com Matplotlib o Seaborn, amb menys codi que si el posessim en llistes o diccionaris. | * Si organitzem les dades del Dataframe convenientment podem crear gràfics amb llibreries com Matplotlib o Seaborn, amb menys codi que si el posessim en llistes o diccionaris. | ||
* També facilita la feina si usem llibreries de Machine Learning. | * També facilita la feina si usem llibreries de Machine Learning. | ||
- | * És una molt bona alternativa al llenguatge R, amb una corba d' | ||
- | |||
======= Instal·lació llibreria Pandas ======= | ======= Instal·lació llibreria Pandas ======= | ||
Línia 35: | Línia 39: | ||
Exemple: Volem obtenir el llistat dels equips de la lliga de futbol femení 2022-2023, que hem trobat a: | Exemple: Volem obtenir el llistat dels equips de la lliga de futbol femení 2022-2023, que hem trobat a: | ||
+ | |||
https:// | https:// | ||
En aquest cas potser acabem abans copiant i enganxant en un full de càlcul els resultats; però a la hora de la veritat no sempre funciona. | En aquest cas potser acabem abans copiant i enganxant en un full de càlcul els resultats; però a la hora de la veritat no sempre funciona. | ||
+ | |||
A més a més, ens interessa automatitzar les tasques. | A més a més, ens interessa automatitzar les tasques. | ||
- | Pas 1. Obtenir dades | + | **Exemple codi local, arrencat en un fitxer IPYNB** |
- | < | + | El codi que mostro a continuació el podeu veure arrencat en directe a: |
+ | |||
+ | https:// | ||
+ | |||
+ | [[https:// | ||
+ | en qualsevol IDE, fins i tot llibreries per generar gràfics. Els seus fitxers tenen la extensió **.IPYNB** | ||
+ | |||
+ | **Pas 1. Seleccionar la font de dades.** | ||
+ | |||
+ | En el nostre cas, dins de la pàgina indicada la taula que ens interessa té un atribut HTML " | ||
+ | valor " | ||
+ | El mètode read_html ha de conèixer la pàgina i atributs html per identificar la taula | ||
+ | que volem extreure. | ||
+ | |||
+ | **Pas 2. Obtenir les dades amb Pandas** | ||
+ | |||
+ | < | ||
import pandas as pd | import pandas as pd | ||
from io import StringIO | from io import StringIO | ||
Línia 58: | Línia 80: | ||
</ | </ | ||
- | Pas 2. Filtrar dades i obtenir resultats. | + | **Pas 3. Filtrar dades i obtenir resultats.** |
+ | |||
+ | <code python> | ||
+ | # Seleccionem la llista dels noms dels equips. | ||
+ | classificacio_df[' | ||
+ | list_aux = classificacio_df[' | ||
+ | llista_equips = sum(list_aux, | ||
- | < | ||
- | # Visualitzem informació rellevant de les dades. | ||
def print_data(): | def print_data(): | ||
- | print(classificacio_df) | + | |
print(classificacio_df.dtypes) | print(classificacio_df.dtypes) | ||
- | print(classificacio_df.EQUIPO) | + | print(classificacio_df['EQUIPO']) |
+ | | ||
+ | | ||
print_data() | print_data() | ||
</ | </ | ||
- | ======= Exemple a Jupyter Notebook ======= | ||
- | https:// | + | ======= Codi integrat a la aplicació web amb Django ======= |
- | Pendent millorar. | + | **Pas 4. Inserim el codi que hem comprovat a la aplicació django, dins de l' |
+ | En primer lloc, posem el codi que hem provat abans: | ||
- | ======= Exemple aplicació web ======= | + | <code python> |
+ | def handle(self, | ||
- | Pendent | + | print(" |
+ | # https:// | ||
+ | # Web scrapping: obtenció de dades externes al nostre sistema. | ||
+ | url: str = " | ||
+ | classif: pd.DataFrame = pd.read_html(url, | ||
+ | # Per algún motiu que desconec la informació que m' | ||
+ | # la primera posició d'una llista. | ||
+ | classificacio_df = classif[0] | ||
+ | # Seleccionem la llista dels noms dels equips. | ||
+ | classificacio_df[' | ||
+ | list_aux = classificacio_df[' | ||
+ | llista_equips = sum(list_aux, | ||
+ | print(llista_equips) | ||
+ | print(" | ||
- | ======= Conclusions ======= | + | # |
+ | titol_lliga | ||
+ | ... | ||
+ | </ | ||
- | <WRAP center round important 60%> | + | Després del codi que crea la lliga si no existeix, comento el codi de creació d' |
- | Menys parlar | + | i poso aquest, que crea i guarda els equips pel seu nom: |
- | </WRAP> | + | |
+ | <code python> | ||
+ | for nom_equip in llista_equips: | ||
+ | equip = Equip(nom=nom_equip) | ||
+ | # | ||
+ | equip.save() | ||
+ | lliga.equips.add(equip) | ||
+ | |||
+ | # Seleccionarem algunes jugadores. | ||
+ | print(" | ||
+ | ... | ||
+ | </ | ||
+ | |||
+ | |||
+ | --> Codi complet del seeder i el model # | ||
+ | Aquí podreu veure un exemple del codi de l' | ||
+ | |||
+ | <file python / | ||
+ | from django.db import models | ||
+ | |||
+ | # Observació: | ||
+ | # com a clau primària. Hi ha formes de canviar aquest | ||
+ | # comportament però per ara ens sembla OK. | ||
+ | |||
+ | # Hauria de posar una relació ManyToMany per tal que un mateix equip | ||
+ | # pugui compatir en diverses lligues en un any (Champions) | ||
+ | # equips = models.ManyToManyField(Equip) | ||
+ | class Equip(models.Model): | ||
+ | nom = models.CharField(max_length=100) | ||
+ | ciutat = models.CharField(max_length=100, | ||
+ | estadi = models.CharField(max_length=100, | ||
+ | #lliga = models.ForeignKey(Lliga, | ||
+ | def __str__(self): | ||
+ | return self.nom | ||
+ | |||
+ | |||
+ | class Lliga(models.Model): | ||
+ | nom_temporada = models.CharField(max_length=100) | ||
+ | equips = models.ManyToManyField(Equip) | ||
+ | def __str__(self): | ||
+ | return self.nom_temporada | ||
+ | class Meta: | ||
+ | verbose_name_plural = ' | ||
+ | |||
+ | |||
+ | class Jugadora(models.Model): | ||
+ | nom = models.CharField(max_length=100) | ||
+ | cognom = models.CharField(max_length=100) | ||
+ | dorsal = models.IntegerField() | ||
+ | equip = models.ForeignKey(Equip, | ||
+ | |||
+ | def __str__(self): | ||
+ | return f' | ||
+ | class Meta: | ||
+ | verbose_name_plural = ' | ||
+ | |||
+ | |||
+ | class Partit(models.Model): | ||
+ | class Meta: | ||
+ | unique_together = [" | ||
+ | local = models.ForeignKey(Equip, | ||
+ | related_name=" | ||
+ | visitant = models.ForeignKey(Equip, | ||
+ | related_name=" | ||
+ | lliga = models.ForeignKey(Lliga, | ||
+ | detalls = models.TextField(null=True, | ||
+ | inici = models.DateTimeField(null=True, | ||
+ | def __str__(self): | ||
+ | return "{} - {}" | ||
+ | def gols_local(self): | ||
+ | return self.event_set.filter( | ||
+ | tipus=Event.EventType.GOL, | ||
+ | def gols_visitant(self): | ||
+ | return self.event_set.filter( | ||
+ | tipus=Event.EventType.GOL, | ||
+ | |||
+ | |||
+ | class Event(models.Model): | ||
+ | # Solució subòptima | ||
+ | # tipus_event = models.CharField(max_length=100) | ||
+ | # el tipus d' | ||
+ | class EventType(models.TextChoices): | ||
+ | GOL = " | ||
+ | AUTOGOL = " | ||
+ | FALTA = " | ||
+ | PENALTY = " | ||
+ | MANS = " | ||
+ | CESSIO = " | ||
+ | FORA_DE_JOC = " | ||
+ | ASSISTENCIA = " | ||
+ | TARGETA_GROGA = " | ||
+ | TARGETA_VERMELLA = " | ||
+ | partit = models.ForeignKey(Partit, | ||
+ | temps = models.TimeField() | ||
+ | tipus = models.CharField(max_length=30, | ||
+ | jugador = models.ForeignKey(Jugadora, | ||
+ | on_delete=models.SET_NULL, | ||
+ | related_name=" | ||
+ | equip = models.ForeignKey(Equip, | ||
+ | on_delete=models.SET_NULL) | ||
+ | # per les faltes | ||
+ | jugador2 = models.ForeignKey(Jugadora, | ||
+ | on_delete=models.SET_NULL, | ||
+ | related_name=" | ||
+ | detalls = models.TextField(null=True, | ||
+ | def __str__(self): | ||
+ | return f' | ||
+ | </ | ||
+ | |||
+ | |||
+ | <file python models.py> | ||
+ | from django.db import models | ||
+ | |||
+ | # Observació: | ||
+ | # com a clau primària. Hi ha formes de canviar aquest | ||
+ | # comportament però per ara ens sembla OK. | ||
+ | |||
+ | # Hauria de posar una relació ManyToMany per tal que un mateix equip | ||
+ | # pugui compatir en diverses lligues en un any (Champions) | ||
+ | # equips = models.ManyToManyField(Equip) | ||
+ | class Equip(models.Model): | ||
+ | nom = models.CharField(max_length=100) | ||
+ | ciutat = models.CharField(max_length=100, | ||
+ | estadi = models.CharField(max_length=100, | ||
+ | #lliga = models.ForeignKey(Lliga, | ||
+ | def __str__(self): | ||
+ | return self.nom | ||
+ | |||
+ | |||
+ | class Lliga(models.Model): | ||
+ | nom_temporada = models.CharField(max_length=100) | ||
+ | equips = models.ManyToManyField(Equip) | ||
+ | def __str__(self): | ||
+ | return self.nom_temporada | ||
+ | class Meta: | ||
+ | verbose_name_plural = ' | ||
+ | |||
+ | |||
+ | class Jugadora(models.Model): | ||
+ | nom = models.CharField(max_length=100) | ||
+ | cognom = models.CharField(max_length=100) | ||
+ | dorsal = models.IntegerField() | ||
+ | equip = models.ForeignKey(Equip, | ||
+ | |||
+ | def __str__(self): | ||
+ | return f' | ||
+ | class Meta: | ||
+ | verbose_name_plural = ' | ||
+ | |||
+ | |||
+ | class Partit(models.Model): | ||
+ | class Meta: | ||
+ | unique_together = [" | ||
+ | local = models.ForeignKey(Equip, | ||
+ | related_name=" | ||
+ | visitant = models.ForeignKey(Equip, | ||
+ | related_name=" | ||
+ | lliga = models.ForeignKey(Lliga, | ||
+ | detalls = models.TextField(null=True, | ||
+ | inici = models.DateTimeField(null=True, | ||
+ | def __str__(self): | ||
+ | return "{} - {}" | ||
+ | def gols_local(self): | ||
+ | return self.event_set.filter( | ||
+ | tipus=Event.EventType.GOL, | ||
+ | def gols_visitant(self): | ||
+ | return self.event_set.filter( | ||
+ | tipus=Event.EventType.GOL, | ||
+ | |||
+ | |||
+ | class Event(models.Model): | ||
+ | # Solució subòptima i provisional. | ||
+ | # tipus_event = models.CharField(max_length=100) | ||
+ | # el tipus d' | ||
+ | class EventType(models.TextChoices): | ||
+ | GOL = " | ||
+ | AUTOGOL = " | ||
+ | FALTA = " | ||
+ | PENALTY = " | ||
+ | MANS = " | ||
+ | CESSIO = " | ||
+ | FORA_DE_JOC = " | ||
+ | ASSISTENCIA = " | ||
+ | TARGETA_GROGA = " | ||
+ | TARGETA_VERMELLA = " | ||
+ | partit = models.ForeignKey(Partit, | ||
+ | temps = models.TimeField() | ||
+ | tipus = models.CharField(max_length=30, | ||
+ | jugador = models.ForeignKey(Jugadora, | ||
+ | on_delete=models.SET_NULL, | ||
+ | related_name=" | ||
+ | equip = models.ForeignKey(Equip, | ||
+ | on_delete=models.SET_NULL) | ||
+ | # per les faltes | ||
+ | jugador2 = models.ForeignKey(Jugadora, | ||
+ | on_delete=models.SET_NULL, | ||
+ | related_name=" | ||
+ | detalls = models.TextField(null=True, | ||
+ | def __str__(self): | ||
+ | return f' | ||
+ | </ | ||
+ | |||
+ | <-- | ||
+ | |||
+ | Resultat final, quan arrenquem la aplicació: | ||
+ | |||
+ | Si heu canviat el model, primer executeu: | ||
+ | |||
+ | < | ||
+ | (env) nomusuari@linux: | ||
+ | (env) nomusuari@linux: | ||
+ | </ | ||
+ | |||
+ | Per omplir | ||
+ | |||
+ | < | ||
+ | (env) nomusuari@linux: | ||
+ | (env) nomusuari@linux: | ||
+ | (env) nomusuari@linux: | ||
+ | </code> | ||
+ | |||
+ | Si anem a veure la taula de partits podem comprovar que s'han generat correctament, | ||
+ | dels locals i visitants. | ||
+ | |||
+ | {{: | ||
+ | |||
+ | ======= Conclusions ======= | ||
- | Més info pendent. | + | Publicar i fer ús de dades públiques d' |