11. TP - Traitements de données
11.1. Introduction
Manipuler des données et en extraire de l'information est une compétence primordiale dans les
domaines tels que l'Apprentissage, la Fouille de Données (ce que l'on qualifie en anglais de
Machine Learning, Data Mining ou de Big Data).
Python offre certaines facilités de traitement des données. Nous allons en étudier quelques unes.
11.2. La fonction zip
La fonction zip prend en entrée plusieurs itérables (listes , dictionnaires) ayant généralement la même longueur et les regroupe en
tuples. On peut alors itérer (parcourir) sur ces tuples.
Si les itérables ont des tailles différentes, zip s'arrête à la fin du plus petit itérable.
Voici un exemple avec deux listes pour lequel on veut associer chaque élément de la liste_1 avec un élément
de la liste_2 en suivant l'ordre de parcours des listes :
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/fonction_zip.py
# Données initiales sous forme de deux tableaux
liste_1 = [4, 7, 9, 1]
liste_2 = ["rouge", "vert", "bleu", "jaune"]
# zip() donne un itérateur et n'est donc pas
# affichable, il faut le transformer en liste
# afin de l'afficher
print(list(zip(liste_1, liste_2)))
# parcours des deux listes
for x,y in zip(liste_1,liste_2):
print(f"{x} -> {y}")
On obtient le résultat suivant :
[(4, 'rouge'), (7, 'vert'), (9, 'bleu'), (1, 'jaune')]
4 -> rouge
7 -> vert
9 -> bleu
1 -> jaune
Itérateur : c'est un classe ou une structure de données qui permet de parcourir les containers d'objets
(liste, tableau, ensemble, dictionnaire, ...)
Par exemple en C++, on peut utiliser un itérateur pour parcourir un vecteur d'entiers :
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/vector_iterator.cpp
#include <iostream>
#include <vector>
using namespace std;
int main() {
// définition d'un vecteur d'entiers avec des valeurs
vector<int> v = {1, 4, 7, -1, 8, 3};
// parcours avec un indice,
// un indice peut être considéré comme un itérateur
for (size_t i = 0; i < v.size(); ++i) {
cout << v[i] << endl;
}
// parcours avec un itérateur (il s'agit d'un pointeur)
for (vector<int>::iterator it = v.begin(); it != v.end(); ++it) {
int x = *it; // valeur référencée par l'itérateur
cout << x << endl;
}
// parcours avec un itérateur caché
for (int x : v) {
cout << x << endl;
}
return EXIT_SUCCESS;
}
Exercice 11.1
Créez le fichier zip1.py et définir trois listes de même taille (au minimum de taille 4) :
- une liste d'entiers identifiants
- une liste de chaînes de caractères noms qui correspond à des noms de personnes
- une liste de flottants salaires
Itérer en utilisant zip et calculer la somme des salaires tout en affichant pour chaque personne
son nom, son identifiant et combien elle gagne.
Par exemple :
Bob d'identifiant 7 gagne 4000 €
Alice d'identifiant 4 gagne 6000 €
...
11.3. La fonction sorted
La fonction sorted en Python est utilisée pour trier un itérable (comme une liste, un tuple ou un objet itérateur)
et retourne une nouvelle liste triée, sans modifier l'itérable original. Elle offre une grande flexibilité grâce à ses options pour
personnaliser l'ordre de tri.
Cette fonction accepte trois paramètres :
- iterable : l'objet à trier
- key (optionnel) qui indique sur quoi trier, par défault on utilise les valeurs brutes (champ 1, puis champ 2, ...)
- reverse (optionnel) un booléen qui si il est à True trie en ordre inverse
Voici un exemple avec trois listes sur lesquelles on applique la fonction zip, puis la fonction
sorted.
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/fonction_sorted.py
identifiants = [4, 2, 4, 2]
noms = ["richer", "richer", "vazquez", "vazquez"]
prenoms = ["sarah", "jean-michel", "karla", "emily"]
print(sorted(zip(identifiants, noms, prenoms)))
print(sorted(zip(noms,prenoms,identifiants)))
print(sorted(zip(prenoms, noms, identifiants)))
print(sorted(zip(noms, identifiants, prenoms)))
On obtient le résultat suivant :
[(2, 'richer', 'jean-michel'), (2, 'vazquez', 'emily'), (4, 'richer', 'sarah'), (4, 'vazquez', 'karla')]
[('richer', 'jean-michel', 2), ('richer', 'sarah', 4), ('vazquez', 'emily', 2), ('vazquez', 'karla', 4)]
[('emily', 'vazquez', 2), ('jean-michel', 'richer', 2), ('karla', 'vazquez', 4), ('sarah', 'richer', 4)]
[('richer', 2, 'jean-michel'), ('richer', 4, 'sarah'), ('vazquez', 2, 'emily'), ('vazquez', 4, 'karla')]
On peut également utiliser la clé (key) afin de redéfinir l'ordre de tri en utilisant une fonction lambda :
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/fonction_sorted_cle.py
noms = ["richer", "dupond", "vazquez", "martin"]
prenoms = ["sarah", "jean-michel", "karla", "emily"]
# on trie uniquement sur le champ 1 = prenom
# le champ x[0] est le nom
print(sorted(zip(noms, prenoms), key=lambda x: x[1]))
# on récupère les noms et prénoms triés grâce à zip(*...)
n_t, p_t = zip(*sorted(zip(noms, prenoms), key=lambda x: x[1]))
# affiche la liste des noms correspondant au tri précédent
# sur les prénoms
print(n_t)
# affiche la liste des prénoms correspondant au tri précédent
# sur les prénoms
print(p_t)
[('martin', 'emily'), ('dupond', 'jean-michel'), ('vazquez', 'karla'), ('richer', 'sarah')]
('martin', 'dupond', 'vazquez', 'richer')
('emily', 'jean-michel', 'karla', 'sarah')
Dans le code précédent, la fonction zip(*...) permet de récupérer des listes correspondant aux éléments triés.
Voici le même code sans fonction lambda, on doit alors créer une fonction trier_par_prenom :
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/fonction_sorted_cle_2.py
noms = ["richer", "dupond", "vazquez", "martin"]
prenoms = ["sarah", "jean-michel", "karla", "emily"]
# fonction qui retourne le champ sur lequel trier
def trier_par_prenom(element):
# Retourne le deuxième élément du tuple (le prénom)
return element[1]
# on trie uniquement sur le champ prenom
print(sorted(zip(noms, prenoms), key=trier_par_prenom))
# on récupère les noms et prénoms triés grâce à zip(*...)
n_t, p_t = zip(*sorted(zip(noms, prenoms), key=lambda x: x[1]))
# affiche la liste des noms correspondant au tri précédent
# sur les prénoms
print(n_t)
# affiche la liste des prénoms correspondant au tri précédent
# sur les prénoms
print(p_t)
11.4. La fonction map
La fonction map consiste à appliquer une fonction à tous les éléments d'une liste.
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/fonction_map.py
liste_initiale = [ 2, 4, "to", 7, 3.14]
def mul2(x):
return x*2
# utilisation d'une fonction
liste_modifiee = list(map(mul2, liste_initiale))
print(liste_modifiee)
# utilisation d'une fonction lambda
liste_modifiee = list(map(lambda x: x*3, liste_initiale))
print(liste_modifiee)
Le résultat est le suivant :
[4, 8, 'toto', 14, 6.28]
[6, 12, 'tototo', 21, 9.42]
11.5. La fonction filter
La fonction filter permet de sélectionner des éléments d'un itérable.
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/fonction_filter.py
dico = { 0: "noir", 2: "rouge", 3:"bleu", 15:"blanc" }
couleurs = dict(filter(lambda x: x[1].startswith("bl"), dico.items()))
print(couleurs)
Le code précédent permet de sélectionner les couleurs dont le nom commence par "bl". Le résultat est le suivant :
{3: 'bleu', 15: 'blanc'}
11.6. Exercices
Exercice 11.2
Ecrire un programme exercice_map_filter.py qui analyse une phrase donnée et retourne
les informations suivantes :
- une liste des longueurs de tous les mots dans la phrase
- une liste des mots dont la longueur est supérieure à une valeur spécifiée (par exemple, 4)
- une phrase reconstruite où chaque mot est remplacé par sa longueur
Vous devez utiliser map et filter pour accomplir cette tâche.
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/exercice_map_filter.py
# Étape 1 : Extraire les longueurs des mots
def extraire_longueurs(phrase):
mots = phrase.split()
return list(map(_____))
# Étape 2 : Filtrer les mots de longueur minimale
def filtrer_mots(phrase, longueur_min):
mots = phrase.split()
return list(filter(_____, mots))
# Étape 3 : Remplacer les mots par leur longueur
def remplacer_par_longueurs(phrase):
mots = phrase.split()
return " ".join(map(_____))
# Exemple de phrase de test
phrase = "Python est un langage de programmation étonnant"
longueur_minimum = 4
# [6, 3, 2, 7, 2, 13, 8]
print(extraire_longueurs(phrase))
# ['Python', 'langage', 'programmation', 'étonnant']
print(filtrer_mots(phrase, longueur_minimum))
# 6 3 2 7 2 13 8
print(remplacer_par_longueurs(phrase))
Exercice 11.3
On désire chercher des mots comme dans le jeu "le mot le plus long" des Chiffre et des Lettres.
Utilisez le dictionnaire du français (french.txt)
Ne garder que les mots de 3 à 9 lettres (utilisez filter).
Affichez combien il existe de mots de 3, 4, ..., 9 lettres, utilisez un dictionnaire pour stocker le
nombre d'occurrences .
Attention, le dictionnaire contient des accents et des séparateurs comme dans "abat-vent" ou "ac.". Il est nécessaire
de supprimer les accents et éliminer les séparateurs.
Pour supprimer les accents et les séparateurs, on peut utiliser le code suivant :
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/supprimer_accent.py
import unicodedata
def sans_accent(mot):
return ''.join(
char for char in unicodedata.normalize('NFD', mot)
if unicodedata.category(char) != 'Mn'
)
mots_avec_accent = [ "économie", "élève", "chaîne" ];
mots_sans_accent = [ sans_accent(mot.strip('\n').replace("-","").replace('.','')) for mot in mots_avec_accent ]
print(mots_sans_accent)
On obtient alors
['economie', 'eleve', 'chaine']
Vous devriez obtenir les occurrences suivantes en fonction de la longueur des mots :
3 => 553
4 => 2221
5 => 7104
6 => 16343
7 => 28999
8 => 42257
9 => 51046
Exercice 11.4
Reprendre l'exercice précédent et permettre à l'utilisateur de saisir un mot (entre 3 et 9 lettres) et
de rechercher tous les mots de qui contiennent le même nombre de lettres.
Créez pour cela le dictionnaire dico_mots qui contient pour chaque longueur de mot
(entre 3 et 9 lettres) la liste des mots correspondants :
3: ['abu', 'ace' ... ]
4: ['abat', 'abbe', ... ]
5: ['abaca', 'abats', ... ]
6: ['abaque', 'abasie', ... ]
...
9: ['abaissais', 'abaissait', ... ]
Pour le mot donné par l'utilisateur on génèrera toutes les permutations possibles et on cherchera celles
qui sont présentent dans le dictionnaire.
Pour obtenir l'ensemble des permutations des lettres à partir d'un mot, on peut utiliser le code suivant :
Afficher le code ens/l1/python1/tp11_traitements_de_donnees/permutations_mot.py
from itertools import permutations
def calculer_permutations(mot):
# Génère toutes les permutations sous forme de tuples
toutes_les_permutations = permutations(mot)
# Transforme les tuples en chaînes
permutations_en_chaines = [''.join(p) for p in toutes_les_permutations]
return permutations_en_chaines
Par exemple à partir du mot suivant "aient" vous devriez obtenir :
saisir un mot entre 3 et 9 lettres :aient
permutations = ['aient', 'aietn', 'ainet', 'ainte', 'aiten', 'aitne', 'aeint', 'aeitn', 'aenit', 'aenti', 'aetin', 'aetni', 'aniet', 'anite', 'aneit', 'aneti', 'antie', 'antei', 'atien', 'atine', 'atein', 'ateni', 'atnie', 'atnei', 'iaent', 'iaetn', 'ianet', 'iante', 'iaten', 'iatne', 'ieant', 'ieatn', 'ienat', 'ienta', 'ietan', 'ietna', 'inaet', 'inate', 'ineat', 'ineta', 'intae', 'intea', 'itaen', 'itane', 'itean', 'itena', 'itnae', 'itnea', 'eaint', 'eaitn', 'eanit', 'eanti', 'eatin', 'eatni', 'eiant', 'eiatn', 'einat', 'einta', 'eitan', 'eitna', 'enait', 'enati', 'eniat', 'enita', 'entai', 'entia', 'etain', 'etani', 'etian', 'etina', 'etnai', 'etnia', 'naiet', 'naite', 'naeit', 'naeti', 'natie', 'natei', 'niaet', 'niate', 'nieat', 'nieta', 'nitae', 'nitea', 'neait', 'neati', 'neiat', 'neita', 'netai', 'netia', 'ntaie', 'ntaei', 'ntiae', 'ntiea', 'nteai', 'nteia', 'taien', 'taine', 'taein', 'taeni', 'tanie', 'tanei', 'tiaen', 'tiane', 'tiean', 'tiena', 'tinae', 'tinea', 'teain', 'teani', 'teian', 'teina', 'tenai', 'tenia', 'tnaie', 'tnaei', 'tniae', 'tniea', 'tneai', 'tneia']
=========================
mots dans le dictionnaire
=========================
aient
entai
etain
tenia
Avec "aeinst", on obtient :
=========================
mots dans le dictionnaire
=========================
entais
etains
nastie
niates
tanise
tisane
tenais
tenias
sainte
satine