3 A savoir faire
3.1 Lecture csv et transformation via Pandas
# exercice pandas, csv, transformations par map sur un fichier
# de scraping du site FUN
# lire un csv via pandas, traiter le dataframe, sauver et contrôler le résultat
import pandas as pd
path_csv = "dataFUN.csv"
df = pd.read_csv(path_csv, sep=' ')
print(df)--| Column 1
--| 0 Maîtriser le shell Bash - session 4\n \... NaN
--| 1 Smartphone Pocket Lab: Experimental Classical ... NaN
--| 2 Se former aux soins palliatifs\n \n ... NaN
--| 3 La physique générale pour bien entamer l'ensei... NaN
--| 4 Stratégies diagnostiques des cancers\n ... NaN
--| .. ... ..
--| 371 Web sémantique et Web de données - session 2\n... NaN
--| 372 Introduction à la cartographie des processus m... NaN
--| 373 Fondamentaux pour le Big Data - session 1\n ... NaN
--| 374 Analyse des données multidimensionnelles - ses... NaN
--| 375 Principes des Réseaux de données - Session 02\... NaN
--|
--| [376 rows x 2 columns]
print(df['Column']) # car la première colonne s'appelle ainsi--| 0 Maîtriser le shell Bash - session 4\n \...
--| 1 Smartphone Pocket Lab: Experimental Classical ...
--| 2 Se former aux soins palliatifs\n \n ...
--| 3 La physique générale pour bien entamer l'ensei...
--| 4 Stratégies diagnostiques des cancers\n ...
--| ...
--| 371 Web sémantique et Web de données - session 2\n...
--| 372 Introduction à la cartographie des processus m...
--| 373 Fondamentaux pour le Big Data - session 1\n ...
--| 374 Analyse des données multidimensionnelles - ses...
--| 375 Principes des Réseaux de données - Session 02\...
--| Name: Column, Length: 376, dtype: object
Analyse du contenu et transformations diverses via map et lambda
l = list(df['Column']) # on constate la présence de \n
c40 = list(map(lambda x:x[0:40], l)) # essai : raccourcir les strings
for s in c40[0: 5] : print(s) # lvisualisons les 5 premières lignes
# KO: elles comportent des sauts de lignes--| Maîtriser le shell Bash - session 4
--|
--| Smartphone Pocket Lab: Experimental Clas
--| Se former aux soins palliatifs
--|
--|
--| La physique générale pour bien entamer l
--| Stratégies diagnostiques des cancers
--|
Confirmation du problème, on voit des \n.
df_40 = pd.DataFrame(c40) # un nouveau dataframe, pas génial
print(df_40)--| 0
--| 0 Maîtriser le shell Bash - session 4\n
--| 1 Smartphone Pocket Lab: Experimental Clas
--| 2 Se former aux soins palliatifs\n \n
--| 3 La physique générale pour bien entamer l
--| 4 Stratégies diagnostiques des cancers\n
--| .. ...
--| 371 Web sémantique et Web de données - sessi
--| 372 Introduction à la cartographie des proce
--| 373 Fondamentaux pour le Big Data - session
--| 374 Analyse des données multidimensionnelles
--| 375 Principes des Réseaux de données - Sessi
--|
--| [376 rows x 1 columns]
Amélioration en traitant vraiment les strings. Faisons un test.
"sfqsf\nfsdfsd".split("\n") # essai syntaxe split sur \n
# fabrique une liste par libellé--| ['sfqsf', 'fsdfsd']
On se lance !
ll = list(map(lambda x: x.split("\n"), l)) # on obtient une liste de listes
# seule le premier élément de chaque
# liste nous intéressera !print(ll[0:1]) # observons le premier élément--| [ [ 'Maîtriser le shell Bash - session 4', ' ', ' ',
--| ' univ-reunion - ', ' 128001', ' ',
--| ' Début: févr 12, 2023', ' ', ' ', ' ',
--| ' ', ' ', ' ',
--| ' Course options dropdown', ' ',
--| ' ', ' ', ' ',
--| ' ', ' ',
--| ' Se Désinscrire', ' ',
--| ' ', ' ',
--| ' Paramètres de messagerie']]
Cela confirme que le premier élément de la liste est une liste, dont seul chaque premier élément nous intéresse. On va donc extraire chaque premier élément.
lll = list(map(lambda x: x[0], ll)) # on ne conserve que le premier
# élément de chaque liste
df_1 = pd.DataFrame(lll) # création d'un dataframe
# il faut donner un nom aux, ici à, la colonne
df_1.columns = ["libellé"] # liste de noms de colonnes, ici une seule
print(df_1["libellé"])--| 0 Maîtriser le shell Bash - session 4
--| 1 Smartphone Pocket Lab: Experimental Classical ...
--| 2 Se former aux soins palliatifs
--| 3 La physique générale pour bien entamer l'ensei...
--| 4 Stratégies diagnostiques des cancers
--| ...
--| 371 Web sémantique et Web de données - session 2
--| 372 Introduction à la cartographie des processus m...
--| 373 Fondamentaux pour le Big Data - session 1
--| 374 Analyse des données multidimensionnelles - ses...
--| 375 Principes des Réseaux de données - Session 02
--| Name: libellé, Length: 376, dtype: object
Vérifions quelques ligness : ici une ligne toutes les 50 lignes, en partant de la fin (dernière ligne exclue). Quelques essais de ce type nous permettent de ne pas se cantonner à vérifier les premières ou les dernières lignes !
for s in df_1["libellé"][ :-1 : 50] : print(s)--| Maîtriser le shell Bash - session 4
--| Se former pour enseigner dans le supérieur
--| Spectroscopie : fondamentaux et applications
--| Des rivières et des hommes : hydrologie, hydraulique et géomorphologie
--| Anatomie du Bois
--| La musique au-delà du numérique - session 2
--| Introduction à la statistique avec R -session 10
--| Concevoir pour innover : introduction à la théorie C-K - Session 2
Cela semble correct, sauvons notre travail dans un .csv.
path_csv_propre = 'dataFUN_propre.csv' # sauver notre travail en csv
df_1.to_csv(path_csv_propre ,
sep = ' ',
index = False,
header = True
)On controle que cela a bien fonctionné.
df_1_control = pd.read_csv(path_csv_propre) # pour contrôler que tout est ok
print(df_1_control)--| libellé
--| 0 Maîtriser le shell Bash - session 4
--| 1 Smartphone Pocket Lab: Experimental Classical ...
--| 2 Se former aux soins palliatifs
--| 3 La physique générale pour bien entamer l'ensei...
--| 4 Stratégies diagnostiques des cancers
--| .. ...
--| 371 Web sémantique et Web de données - session 2
--| 372 Introduction à la cartographie des processus m...
--| 373 Fondamentaux pour le Big Data - session 1
--| 374 Analyse des données multidimensionnelles - ses...
--| 375 Principes des Réseaux de données - Session 02
--|
--| [376 rows x 1 columns]
3.2 Valider et affecter des types simples en toute sécurité
Nous allons utiliser un package assez ancien, de façon très partielle, en invoquant les contrôles de type qu’il procure : le package hug.
# !pip install hug
# Affectation, validation et casting de types simples : import des types
from hug import types as typ_hCréons une fonction générique qui valide, affecte et traduit une valeur dans le format recherché. Via l’utilisation des instructions try, except et raise, nous “cassons” le programme si la valeur proposée n’est pas conforme. Cette technique correspond à une autre façon de ce que nous avions appelé mourir vite plus haut.
def valide(x,f_type) :
try :
x = f_type(x)
return x
except :
lib = "type invalide, il faut un : " + f_type.__doc__
print(lib)
raise Exception(lib)Nous allons tester le fait qu’une valeur représente un entier valide.
# affectation d'un nombre entier valide
x = valide(10,typ_h.number)
print(x, type(x))--| 10 <class 'int'>
x = valide("100",typ_h.number)
print(x, type(x))--| 100 <class 'int'>
Ceci “plante” le programme :
x = valide("100.1",typ_h.number)
x = valide("eee",typ_h.number)Le message est généré automatiquement avec une mention du problème trouvé, ici :
type invalide : A whole number
Voici le traitement d’une valeur en chaine de caractère.
# affectation d'une chaine de caractères
x = valide("un texte",typ_h.text)
print(x, type(x))--| un texte <class 'str'>
x = valide(666,typ_h.text)
print(x, type(x))--| 666 <class 'str'>
Ceci “plante” le programme :
x = valide([8,4],typ_h.text)Il est possible de gérer des valeurs réelles.
# affectation d'un réel
x = valide(10.145,typ_h.float_number)
print(x, type(x))--| 10.145 <class 'float'>
x = valide(10,typ_h.float_number)
print(x, type(x))--| 10.0 <class 'float'>
x = valide("10",typ_h.float_number)
print(x, type(x))--| 10.0 <class 'float'>
Ceci “plante” le programme :
x = valide("fff",typ_h.float_number)Il existe de nombreuses façons d’affecter un booleen, ici nous les faisons converger.
# affectation d'un booléen
x = valide(0,typ_h.smart_boolean)
print(x, type(x))--| False <class 'bool'>
x = valide(True,typ_h.smart_boolean)
print(x, type(x))--| True <class 'bool'>
x = valide("F",typ_h.smart_boolean)
print(x, type(x))--| False <class 'bool'>
x = valide("0",typ_h.smart_boolean)
print(x, type(x))--| False <class 'bool'>
Ceci “plante” le programme :
x = valide("0y",typ_h.smart_boolean)Vous pourriez créer vos propres fonctions de validation/affectation en utilisant des techniques similaires.
3.3 Tri récursif d’un vecteur de données (liste)
Nous allons implémenter le tri d’une liste. Evidemment, les listes possèdent une méthode de tri, qui trie la liste “sur place”, c’est à dire que l’ordre d’origine de la liste est perdu (mais elle n’est pas dupliquée, ce qui est économe).
L’idée est la suivante : on prend le premier élément de la liste et on positionne tous les éléments plus petits avant et les autres après, ce après avoir effectué la même opération sur ces deux listes (celle des plus petit et celle des plus grands). Comme on appelle notre fonction au sein d’elle même on est dans un processus récursif. Le danger d’un tel processus serait de ne jamais s’arrêter, d’où la détermination d’une exception, ici un test sur la longueur de la liste, telle que pour cette exception on n’opère pas la récursivité.
Ce qui nous donne l’algorithme classique suivant :
def tri_R(liste):
if len(liste) > 1:
e_gauche = liste[0]
l = liste[1: ]
l_gauche = [e for e in l if e <= e_gauche]
l_droite = [e for e in l if e > e_gauche]
# concaténation, syntaxe différence suivant les types /!\
return tri_R(l_gauche) + [e_gauche] + tri_R(l_droite)
else:
return liste
# test
print([1,8,1,999,-456]," --> ",tri_R([1,8,1,999,-456]) )--| [1, 8, 1, 999, -456] --> [-456, 1, 1, 8, 999]
print([] ," --> ",tri_R([]) )--| [] --> []
print([9] ," --> ",tri_R([9]) )--| [9] --> [9]
Nous allons maintenant écrire le même algorithme d’une façon telle que l’on a pas à se préoccuper de la nature de l’exception et avec un seul return (c’est plus “propre”).
def tri_r(liste):
try :
e_gauche = liste[0]
l = liste[1: ]
l_gauche = [e for e in l if e <= e_gauche]
l_droite = [e for e in l if e > e_gauche]
# concaténation, syntaxe différence suivant les types /!\
liste = tri_r(l_gauche) + [e_gauche] + tri_r(l_droite)
except : None
return liste
print([1,8,1,999,-456]," --> ",tri_r([1,8,1,999,-456]) )--| [1, 8, 1, 999, -456] --> [-456, 1, 1, 8, 999]
print([] ," --> ",tri_r([]) )--| [] --> []
print([9] ," --> ",tri_r([9]) )--| [9] --> [9]
if tri_r([1,8,1,999,-456]) == tri_R([1,8,1,999,-456]) :
print("Les deux fonctions donnent le même résultat ! ")--| Les deux fonctions donnent le même résultat !