xxxxxxxxxx
## Notion de Table
Nous allons dans ce cours nous intéresser aux tables. Elles correspondent à un tableau de p-uplets nommés qui partagent les mêmes descripteurs (dans de rares cas on peut utiliser un tableau de tableaux). Les différents p-uplets nommés - qui correspondent aux différentes lignes de la table – sont aussi appelés *enregistrements*.
En langage python il s'agit donc d'une list de `dict` où tous les `dict` ont les mêmes clés.
Voici un exemple en code python :
Nous allons dans ce cours nous intéresser aux tables. Elles correspondent à un tableau de p-uplets nommés qui partagent les mêmes descripteurs (dans de rares cas on peut utiliser un tableau de tableaux). Les différents p-uplets nommés - qui correspondent aux différentes lignes de la table – sont aussi appelés enregistrements.
En langage python il s'agit donc d'une list de dict
où tous les dict
ont les mêmes clés.
Voici un exemple en code python :
xxxxxxxxxx
notes = [{'Prenom':'Ali', 'Classe':'2D', 'Note':14},
{'Prenom':'Béa', 'Classe':'2F', 'Note':19},
{'Prenom':'Carl', 'Classe':'2A', 'Note':6 },
{'Prenom':'Anton', 'Classe':'2K', 'Note':13},
{'Prenom':'Adeline', 'Classe':'2D', 'Note':20},
{'Prenom':'Antoinette', 'Classe':'2H', 'Note':15}]
xxxxxxxxxx
Et voici la représentation mentale que l'on peut se faire de cet exemple :
| Prenom | Classe | Note |
|:----------:|:------:|:----:|
| Ali | 2D | 14 |
| Béa | 2F | 19 |
| Carl | 2A | 6 |
| Anton | 2K | 13 |
| Adeline | 2D | 20 |
| Antoinette | 2H | 15 |
Voici quelques exemples d'utilisation de cette table où l'on voit que l'accès à un élément de la table se fait grâce à l'instruction :
`table[index_ligne][descripteur]`
Et voici la représentation mentale que l'on peut se faire de cet exemple :
Prenom | Classe | Note |
---|---|---|
Ali | 2D | 14 |
Béa | 2F | 19 |
Carl | 2A | 6 |
Anton | 2K | 13 |
Adeline | 2D | 20 |
Antoinette | 2H | 15 |
Voici quelques exemples d'utilisation de cette table où l'on voit que l'accès à un élément de la table se fait grâce à l'instruction :
table[index_ligne][descripteur]
xxxxxxxxxx
notes[1]
xxxxxxxxxx
notes[0]['Classe']
xxxxxxxxxx
notes[4]['Prenom']
xxxxxxxxxx
[ enregistrement['Note'] for enregistrement in notes ]
xxxxxxxxxx
## Enregistrement dans un fichier
Les tables ont vocation à stocker un grand nombre d'enregistrements. Lorsqu'elles sont utilisées en production (c'est-à-dire dans des applications professionnelles), ces tables doivent pouvoir être sauvegardées dans des fichiers pouvant être utilisés par différentes applications (tableurs, langages de programmation, logiciels de saisie ou de visualisation de données etc.). Deux formats de fichiers texte servant à sauvegarder des tables sont au programme :
- fichiers CSV (Comma-Separated Values) où les champs sont séparés par des virgules (ou des points virgules).
- fichiers TSV (Tab-Separated Values) où les champs sont séparés par des tabulations.
Voici par exemple le contenu du fichier CSV correspondant à la table ci-dessus :
```
Prenom;Classe;Note
Ali;2D;14
Béa;2F;19
Carl;2A;6
Anton;2K;13
Adeline;2D;20
Antoinette;2H;15
```
et le contenu du fichier TSV correspondant (avec une tabulation correspondant à quatre caractères) :
```
Prenom Classe Note
Ali 2D 14
Béa 2F 19
Carl 2A 6
Anton 2K 13
Adeline 2D 20
Antoinette 2H 15
```
Les tables ont vocation à stocker un grand nombre d'enregistrements. Lorsqu'elles sont utilisées en production (c'est-à-dire dans des applications professionnelles), ces tables doivent pouvoir être sauvegardées dans des fichiers pouvant être utilisés par différentes applications (tableurs, langages de programmation, logiciels de saisie ou de visualisation de données etc.). Deux formats de fichiers texte servant à sauvegarder des tables sont au programme :
Voici par exemple le contenu du fichier CSV correspondant à la table ci-dessus :
Prenom;Classe;Note
Ali;2D;14
Béa;2F;19
Carl;2A;6
Anton;2K;13
Adeline;2D;20
Antoinette;2H;15
et le contenu du fichier TSV correspondant (avec une tabulation correspondant à quatre caractères) :
Prenom Classe Note
Ali 2D 14
Béa 2F 19
Carl 2A 6
Anton 2K 13
Adeline 2D 20
Antoinette 2H 15
xxxxxxxxxx
## Import d'un fichier
Lors de l'import d'un fichier CSV ou TSV dans un programme écrit en langage Python, il y a quatre points à vérifier et à indiquer :
- vérifier l'encodage du fichier,
- vérifier le caractère de séparation,
- vérifier que la première ligne du fichier comporte bien les descripteurs des différents champs,
- s'assurer que l'on ferme bien le fichier après lecture (sinon il reste considéré comme ouvert par le système d'exploitation).
Voici un exemple de fonction implémentant un import de fichier csv (qui fonctionne aussi pour les fichiers tsv en remplaçant le delimiter par `'\t'` qui désigne une tabulation). Cette fonction prend en paramètre un chemin d'accès au fichier et retourne la table des données, c'est-à-dire une liste de dictionnaires.
L'import se fait en trois temps :
- On obtient tout d'abord un objet qui correspond au fichier (`fichier_csv`).
- Puis un objet `DictReader` (`lecteur_csv`) correspondant au fichier transformé en enregistrements,
- En parcourant ce `DictReader`, on transvase ces enregistrements (dictionnaires) dans la liste `table_csv`.
Lors de l'import d'un fichier CSV ou TSV dans un programme écrit en langage Python, il y a quatre points à vérifier et à indiquer : - vérifier l'encodage du fichier, - vérifier le caractère de séparation, - vérifier que la première ligne du fichier comporte bien les descripteurs des différents champs, - s'assurer que l'on ferme bien le fichier après lecture (sinon il reste considéré comme ouvert par le système d'exploitation).
Voici un exemple de fonction implémentant un import de fichier csv (qui fonctionne aussi pour les fichiers tsv en remplaçant le delimiter par '\t'
qui désigne une tabulation). Cette fonction prend en paramètre un chemin d'accès au fichier et retourne la table des données, c'est-à-dire une liste de dictionnaires.
L'import se fait en trois temps :
fichier_csv
). DictReader
(lecteur_csv
) correspondant au fichier transformé en enregistrements,DictReader
, on transvase ces enregistrements (dictionnaires) dans la liste table_csv
.xxxxxxxxxx
import csv
def importer_csv(chemin_fichier):
liste_dicos = []
fichier_csv = open(chemin_fichier, 'r', encoding = 'utf-8', newline = '')
lecteur_csv = csv.DictReader(fichier_csv, delimiter = ';')
for element in lecteur_csv :
liste_dicos.append(dict(element))
fichier_csv.close()
return liste_dicos
xxxxxxxxxx
*Remarques concernant la ligne 5 :*
- le `'r'` est là pour indiquer que l'on ouvre le fichier en lecture (`r` pour **r**ead),
- le `newline = ''` est là pour éviter des problèmes au cas où certaines valeurs contiendraient des sauts de ligne.
Voici un exemple d'utilisation (si vous souhaitez télécharger le fichier CSV, vous le trouverez à cette adresse :[https://progalgo.fr/depot/1/22_tables/datas/cours/cours_II.csv](https://progalgo.fr/depot/1/22_tables/datas/cours/cours_II.csv) ) :
Remarques concernant la ligne 5 :
'r'
est là pour indiquer que l'on ouvre le fichier en lecture (r
pour read),newline = ''
est là pour éviter des problèmes au cas où certaines valeurs contiendraient des sauts de ligne.Voici un exemple d'utilisation (si vous souhaitez télécharger le fichier CSV, vous le trouverez à cette adresse :https://progalgo.fr/depot/1/22_tables/datas/cours/cours_II.csv ) :
xxxxxxxxxx
notes = importer_csv('./cours_II.csv')
notes
xxxxxxxxxx
***Point de vigilance :***<br/>
*Observez que ci-dessus les valeurs des notes sont des chaînes de caractères.*<br/>
*En général, lorsqu'on importe un fichier CSV pour en faire une table, le type des valeurs stockées dans la table est `str`. Ainsi les valeurs «numériques» stockées dans la table doivent être converties (grâce aux méthodes `int()` et `float()`) pour être utilisées convenablement.*
Point de vigilance :
Observez que ci-dessus les valeurs des notes sont des chaînes de caractères.
En général, lorsqu'on importe un fichier CSV pour en faire une table, le type des valeurs stockées dans la table est str
. Ainsi les valeurs «numériques» stockées dans la table doivent être converties (grâce aux méthodes int()
et float()
) pour être utilisées convenablement.
xxxxxxxxxx
<hr style="height:1px;"/>
*Remarque : Pour faciliter l'affichage **des tables**, on utilisera la fonction `afficher` utilisant le module `pandas`:*
Remarque : Pour faciliter l'affichage des tables, on utilisera la fonction afficher
utilisant le module pandas
:
xxxxxxxxxx
import pandas
def afficher(table):
f = pandas.DataFrame(table)
return f
xxxxxxxxxx
afficher(notes)
xxxxxxxxxx
<hr style="height:1px;"/>
xxxxxxxxxx
On considère un fichier csv recensant un certain nombre de films (n'ayant chacun qu'un acteur et une actrice !) :
On considère un fichier csv recensant un certain nombre de films (n'ayant chacun qu'un acteur et une actrice !) :
xxxxxxxxxx
table_films = importer_csv('./film_III_bis.csv')
afficher(table_films)
xxxxxxxxxx
Utilisons ce que nous avons déjà vu sur les listes ou dictionnaires définis par compréhension :
- Pour obtenir la **table** des films dont le descripteur 'Subject' a pour valeur 'Horror' :
Utilisons ce que nous avons déjà vu sur les listes ou dictionnaires définis par compréhension :
xxxxxxxxxx
table_horreur = [film for film in table_films if film['Subject'] == 'Horror' ]
afficher(table_horreur)
xxxxxxxxxx
- Pour obtenir la **liste des titres** des films durant moins d'une heure (remarquer la conversion en `int`) :
int
) :xxxxxxxxxx
liste_courts = [film['Title'] for film in table_films if int(film['Length']) <= 30]
liste_courts
xxxxxxxxxx
- Pour obtenir la **liste des actrices** ayant tourné avec John Glen (remarquer la virgule dans la valeur) :
xxxxxxxxxx
liste_actrices_J_G = [film['Actress'] for film in table_films if film['Director'] == 'Glen, John']
liste_actrices_J_G
xxxxxxxxxx
**Nous n'allons pas utiliser les algorithmes de tri par insertion ou par sélection étudiés en cours car il existe des algorithmes beaucoup plus efficaces proposés par Python.**
On considère un fichier csv recensant les scores d'un certain nombre d'adolescents.
Nous n'allons pas utiliser les algorithmes de tri par insertion ou par sélection étudiés en cours car il existe des algorithmes beaucoup plus efficaces proposés par Python.
On considère un fichier csv recensant les scores d'un certain nombre d'adolescents.
xxxxxxxxxx
table_ados = importer_csv('./mockaroo_IV_bis.csv')
afficher(table_ados)
xxxxxxxxxx
Python ne peut pas deviner tout seul sur quel critère effectuer le tri (identifiant ? age ? score ? prénom ? score divisé par l'âge ?).
Pour que python effectue le tri, il faut donc fournir à python une «fonction clef de tri» : c'est une fonction qui :
- prend en argument un enregistrement,
- renvoie, pour cet enregistrement, la valeur que l'on souhaite prendre en compte pour le tri.
*Exemple 1 :*
Si on souhaite **trier selon les scores décroissants**, la *fonction clef de tri* doit renvoyer le score des enregistrements et on indique à python que l'on souhaite un tri en ordre «reverse» :
Python ne peut pas deviner tout seul sur quel critère effectuer le tri (identifiant ? age ? score ? prénom ? score divisé par l'âge ?).
Pour que python effectue le tri, il faut donc fournir à python une «fonction clef de tri» : c'est une fonction qui :
Exemple 1 : Si on souhaite trier selon les scores décroissants, la fonction clef de tri doit renvoyer le score des enregistrements et on indique à python que l'on souhaite un tri en ordre «reverse» :
xxxxxxxxxx
def clef_tri_score(dico):
return int(dico['Score'])
table_scores_decroissants = sorted(table_ados, key = clef_tri_score, reverse = True)
afficher(table_scores_decroissants)
xxxxxxxxxx
*Exemple 2 :*
Si on souhaite **trier selon les prénoms croissants**, la fonction clef de tri doit renvoyer le prénom des enregistrements (inutile de préciser à python que l'on ne souhaite pas un tri en ordre «reverse») :
Exemple 2 : Si on souhaite trier selon les prénoms croissants, la fonction clef de tri doit renvoyer le prénom des enregistrements (inutile de préciser à python que l'on ne souhaite pas un tri en ordre «reverse») :
xxxxxxxxxx
def clef_tri_prenom(dico):
return dico['Prénom']
table_prenoms_croissants = sorted(table_ados, key = clef_tri_prenom)
afficher(table_prenoms_croissants)
xxxxxxxxxx
*Exemple 3 :*
Si on souhaite **trier selon les prénoms croissants puis selon les scores décroissants**, on obtiendra une table triée par scores décroissants et, pour chaque score, triée par prénom croissant :
Exemple 3 : Si on souhaite trier selon les prénoms croissants puis selon les scores décroissants, on obtiendra une table triée par scores décroissants et, pour chaque score, triée par prénom croissant :
xxxxxxxxxx
table_prenoms_croissants = sorted(table_ados, key = clef_tri_prenom)
table_double_tri = sorted(table_prenoms_croissants, key = clef_tri_score, reverse = True)
afficher(table_double_tri)
xxxxxxxxxx
Nous avons désormais deux tables : une table avec les scores des adolescents et une table avec les dates de leur dernière connexion et leurs mots de passe :
Nous avons désormais deux tables : une table avec les scores des adolescents et une table avec les dates de leur dernière connexion et leurs mots de passe :
xxxxxxxxxx
table_scores = importer_csv('./mockaroo_V_bis.csv')
afficher(table_scores)
xxxxxxxxxx
table_connexions = importer_csv('./mockaroo_V_ter.csv')
afficher(table_connexions)
xxxxxxxxxx
On cherche à fusionner les deux tables, c'est à dire à n'en faire qu'une seule qui réunit les informations des deux tables.
Pour cela, il y a une précondition à vérifier concernant le champ `Id` (identifiant) qui est le descripteur commun aux deux tables :
**Deux adolescents différents ne peuvent avoir le même champ `Id` (logique : c'est leur numéro d'identifiant)**
L'algorithme de fusion présenté ici est l'algorithme naïf en langage naturel :
```python
table_fusion = []
Pour chaque dico_score de table_scores :
Pour chaque dico_connex de table_connexions :
Si dico_score['Id'] == dico_connex['Id']:
Faire une copie de dico_ado
Ajouter les champs 'LST_CNX' et 'MDP' à la copie de dico_ado
Ajouter la copie de dico_ado à table_fusion
```
ce qui donne en python :
On cherche à fusionner les deux tables, c'est à dire à n'en faire qu'une seule qui réunit les informations des deux tables.
Pour cela, il y a une précondition à vérifier concernant le champ Id
(identifiant) qui est le descripteur commun aux deux tables :
Deux adolescents différents ne peuvent avoir le même champ Id
(logique : c'est leur numéro d'identifiant)
L'algorithme de fusion présenté ici est l'algorithme naïf en langage naturel :
table_fusion = []
Pour chaque dico_score de table_scores :
Pour chaque dico_connex de table_connexions :
Si dico_score['Id'] == dico_connex['Id']:
Faire une copie de dico_ado
Ajouter les champs 'LST_CNX' et 'MDP' à la copie de dico_ado
Ajouter la copie de dico_ado à table_fusion
ce qui donne en python :
xxxxxxxxxx
import copy
table_fusion = []
for ado in table_scores:
for connex in table_connexions:
if connex['Id'] == ado['Id']:
ado_copie = copy.deepcopy(ado)
ado_copie['LST_CNX'] = connex['LST_CNX']
ado_copie['MDP'] = connex['MDP']
table_fusion.append(ado_copie)
break
afficher(table_fusion)
xxxxxxxxxx
***Point de vigilance :***
Si la table des connexions contenait **toutes** les connexions des joueurs et **pas seulement leur dernière** connexion, un même `'Id'` pourrait être présent plusieurs fois dans la table des connexions. Dans ce cas l'algorithme fonctionne encore à condition de supprimer la ligne `break` : on se force ainsi - pour chaque identifiant - à parcourir toute la table des connexions au lieu de s'arrêter dès qu'on trouve la première connexion correspondant à l'identifiant.
Point de vigilance :
Si la table des connexions contenait toutes les connexions des joueurs et pas seulement leur dernière connexion, un même 'Id'
pourrait être présent plusieurs fois dans la table des connexions. Dans ce cas l'algorithme fonctionne encore à condition de supprimer la ligne break
: on se force ainsi - pour chaque identifiant - à parcourir toute la table des connexions au lieu de s'arrêter dès qu'on trouve la première connexion correspondant à l'identifiant.
xxxxxxxxxx
*Remarque :*
*Ici chaque `'Id'` de la table des scores est présent dans la table des connexions (ce qui est logique car il faut s'être connecté pour jouer et obtenir un score). Néanmoins, si certains scores n'avaient pas été présents dans la table des connexions, l'algorithme aurait tout de même fonctionné.*
Remarque :
Ici chaque 'Id'
de la table des scores est présent dans la table des connexions (ce qui est logique car il faut s'être connecté pour jouer et obtenir un score). Néanmoins, si certains scores n'avaient pas été présents dans la table des connexions, l'algorithme aurait tout de même fonctionné.