Introduction à Python

Python est un langage de programmation en pleine croissance dans le domaine de la Data Science et du Big Data. Il a une syntaxe particulière pour certains aspects, avec des points communs tout de même avec de nombreux autres. Nous allons ici aborder les éléments suivants sur ce langage :

Eléments de base

Utilisation en mode console

python est un langage scripté, dont l'exécution se fait dans une console. Dans celle-ci, il est donc possible d'exécuter les commandes les unes après les autres. Il est aussi possible (et recommander) d'écrire son script dans un fichier texte (souvent avec l'extension .py) et de l'exécuter via execfile().

Pour accéder à l'aide d'une fonction, il existe la fonction help(), prenant éventuellement en paramètre une fonction directement, ou une chaîne de caractère. Si la fonction n'a pas de paramètre, elle démarre l'aide interactive.

Notebook

Le module jupyter permet de travailler avec des notebooks, qui sont des documents contenant à la fois le code, les résultat et du texte. Ce document est ainsi un notebook.

Types de données

Comme tous les autres langages, python a plusieurs types de base possibles pour les données. En voici quelques uns. Vous pouvez exécuter les commandes dans une console pour voir le résultat.

type valeur type() commentaires
entier 1 int
réel 1.234 float
chaîne de caractères "un mot" str on peut utiliser indifférement "" ou ''
liste [1, 2] list chaque élément peut être différent des autres
tuple (1, 2) tuple similaire à une liste mais constante
dictionnaire {"a": 1, "b": "deux"} dict ensemble de valeurs quelconques nommées

Les tuples, lists et les dicts peuvent s'imbriquer les uns dans les autres.

(1, (2, 3), [4, 5], {"a": 1, "b": "deux"})
[1, [2, 3], (4, 5), {"a": 1, "b": "deux"}]
{"a": 1, "b": "deux", "c": (5, 6), "d": [7, 8]}

Il existe des fonctions permettant de passer d'un type à l'autre (quand cela est possible), telles que int(), float(), str(), tuple() et list().

Il existe aussi des valeurs prédéfinies, telles que True (vrai), False (faux) et None (donnée absente).

Création et suppression de variables

Il n'y a pas de mot-clé pour la définition d'une variable. Celle-ci est définie/créée lors de sa première affectation. Si elle n'existe pas mais qu'on essaie de l'utiliser, alors un message d'erreur apparaît. Il est aussi possible de la supprimer via la fonction del().

Type dynamique

Bien que python soit rigoureux dans l'évaluation des expressions (il ne fait pas de cast automatique - i.e. changement de type des données), le type d'une variable est dit dynamique. Le type d'une variable dépend uniquement de la valeur de son affectation.

Affichage

Comme vu précédemment, il existe la fonction print() permettant d'afficher du texte et/ou le contenu des variables dans la console. Celle-ci peut prendre les paramètres sep, qui permet d'indiquer le ou les caractères séparant les champs (un espace " " par défaut), et end, qui permet d'indiquer le caractère de fin de ligne (retour à la ligne "\n" par défaut).

Opérateurs

Il existe bien évidemment tous les opérateurs classiques, tels que présentés ci-dessous.

Type Opérateurs
Arithmétiques + - * / // % **
Comparaisons > >= < <= == !=
Booléens | & not()

Eléments de langage

Traitement conditionnel

Comme dans tout langage, le traitement conditionnel se fait à partir d'un if. Une particularité de python est d'utiliser l'indentation (i.e. le décalage à droite à l'aide d'au moins une tabulation) pour définir les opérations à réaliser dans un bloc. Les clauses elif et else sont bien évidemment optionnelles.

if condition:
    ...
elif condition:
    ...
else:
    ...

Traitement itératif

On utilise en premier la boucle for dans laquelle on peut utiliser la fonction range() pour avoir les valeurs entre 0 (par défaut) et la valeur passée en paramètre - 1. Pour information, i est persistant à la boucle et garde la dernière valeur.

for i in range(5):
    print(i)

La fonction range() peut prendre deux ou trois paramètres, et dans ce cas, génère la boucle entre les deux par pas de 1 (ou autre selon le troisième paramètres - celui-ci doit être cohérent par rapport aux deux premières valeurs).

Il est aussi possible d'utiliser :

Enfin, on dispose aussi de la boucle while qui teste en début de boucle si une condition est toujours vérifiée.

while condition:
    ...

Création et manipulations d'objets

Comme indiqué, il existe différents types d'objets en python. Sont présentés ici des exemples de créations et de manipulations de chaînes (str), de tuples, de list et de dictionnaires (dict).

Chaînes

Une chaîne de caractère se définit à l'aide des quotes simples ('') ou doubles (""). Par défaut, python présentera les chaînes avec des simples quotes. Mais en présence d'une apostrophe dans la chaîne, il faut la déclarer avec des doubles quotes. Il est possible de connaître la longueur de la chaîne avec la fonction len().

Sur ces chaînes, on peut réaliser un certain nombre d'opérations classiques, telles que le changement de casse (upper() ou lower()), la mise en majuscule des premières lettres de chaque mot (capitalize()), la recherche d'une sous-chaîne (find() - première occurence), le remplacement d'une sous-chaîne (replace()), le dénombrement de sous-chaînes (count()) ou le découpage en sous-chaînes selon un caractère (split()).

Tuples

Un tuple en python est un ensemble déclaré via des (), composé de valeurs pas forcément de même type et éventuellement complexe, qu'il n'est pas possible de modifier. C'est une constante, une fois déclarée.

Listes

Une list est aussi un ensemble déclarée via des [], composé d'éléments pas forcément tous du même type et possiblement complexe. A la différence d'un tuple, une liste est modifiable.

Nous disposons sur ces listes de plusieurs fonctions tels que reverse() (pour inverser la liste), sort() (tri, avec l'option reverse pour le choix du tri), pop() (pour récupérer et supprimer le dernier élément), append() (pour ajouter un élément à la fin), insert() (pour insérer un élément dans la liste, à la position indiquée - paramètres = position suivie de la valeur), remove() (pour supprimer les valeurs passées en paramètre). Toutes ces fonctions modifient directement la liste sur laquelle on les applique.

Un autre moyen d'insérer une valeur, voire plusieurs, à une liste est d'utiliser l'opérateur +, tel qu'indiqué ci-dessous. Celui-ci permet une concaténation des deux listes en une seule. L'opérateur * permet lui de répéter une liste autant de fois que désiré.

Par contre, il faut faire très attention au passage de référence lorsqu'on copie une liste. En effet, dans le code suivant, on copie a dans b. Et en modifiant a, on remarque que b est aussi modifié. Et l'inverse est aussi vrai. Pour remédier à ce problème, on doit dupliquer la liste avec la fonction copy() de la liste initiale.

Dictionnaires

Les dictionnaires (dict en python) sont des listes nommées (définies via des {}), c'est-à-dire que chaque élément a un nom (appelé aussi clé). Ces éléments ne sont pas forcément tous du même type, et peuvent aussi être complexe. Ils sont similaires (pour ne pas dire identique) à des littéraux JSON.

Pour accéder aux élements d'un dictionnaire, on utlise le nom du champs dont on veut la valeur entre []. Il existe aussi des fonctions utiles sur ces objets, telles que get() (pour récupérer la valeur d'une clé), keys() (pour avoir la liste des clés de l'objet), values() (pour avoir les valeurs des clés, dans le même ordre que listé dans keys()), popitem() (pour récupérer un dictionnaire avec le dernier item, et le supprimer du dictionnaire initiale) et pop() (pour récupérer la valeur de l'item passé en paramètre, et le supprimer de l'élément de départ).

On peut ajouter facilement un item à un dictionnaire, en lui affectant simplement une valeur.

De même que pour les listes, il faut faire attention lors de l'affectation d'un dictionnaire à un autre. La fonction copy() permet donc d'obtenir une copie indépendante de l'objet initial.

Indexation

Pour indexer une liste, un tuple, voire une chaîne de caractères, nous passons entre [] les valeurs de la position, avec plusieurs possibilités :

Manipulation de type comprehension

On peut utiliser un mécanisme spécifique, appelé list comprehension (fonctionnant aussi sur les chaînes et les tuples), permettant de récupérer les valeurs (ou un calcul sur chaque valeur) pour tous les éléments de la liste (ou certains si on applique un if).

Le mécanisme de list comprehension est aussi utilisable pour créer un dictionnaire. Il faut dans ce cas indiquer deux valeus : la clé et sa valeur. Dans notre cas, la fonction dict() appliqué sur le résultat de la fonction zip() des deux listes nous permet d'avoir le même résultat.

Fonctions

Définition

L'opérateur def permet de créer une fonction (ou une procédure qui sera juste une fonction ne renvoyant rien). L'opérateur return indiquant le résultat à renvoyer le cas échéant. Comme pour un if, le bloc d'instructions est défini selon l'indentation.

Il est bien évidemment possible de passer un paramètre à une fonction, sans qu'on ait à déclarer son type.

Lorqu'il y a plus d'un paramètre, on peut faire un appel classique. Mais il est aussi possible de nommer explicitement les paramètres. Avec ce mécanisme, il est ainsi possible de les déclarer dans l'ordre que l'on veut. Mais si l'on nomme un paramètre, il est obligatoire de nommer les autres (erreur d'exécution sinon).

Il existe la possibilité de définir une valeur par défaut à un paramètre dans une fonction. Ceci permet d'appeler la fonction sans donner de valeur pour ce paramètre (la fonction utilisera la valeur par défaut donc).

def f(...):
    ...
    return ...

Il est possible d'ajouter une condition if dans la fonction lambda avec un formalisme de type valeurTrue if condition else valeurFalse. Ci-après, nous calculons le carré de chaque valeur, multiplié par -1 pour celles inférieur ou égale à 8.

Manipulation de données

Nous allons utiliser dans ce TP le module pandas permettant la gestion de données avec Python dans un format (individus décrits par des variables) plus classique pour les méthodes statistiques.

Importation de données avec pandas

Nous allons travailler sur les données tips. Vous pouvez trouver des informations (ici). Voici comment lire ces données dans python avec read_csv() de pandas.

Sur ces données, il est bien évidemment possible de voir quelques informations classiques.

Manipulation à la SQL

Une fois qu'on a des données, la première chose qu'on souhaite savoir faire souvent, est de pouvoir manipuler ces données; C'est-à-dire réaliser les opérations classiques en bases de données, à savoir :

Il y a bien évidmement d'autres opérations possibles, spécifiques ou non à Python.

Note Bene : certaines fonctions renvoient un nouvel objet qu'il faudra donc stocker dans une variable (nouvelle ou la même). Par contre, d'autres fonctions modifient directement l'objet en question.

Restriction

Première étape essentielle, cela consiste à sélectionner un certain nombre de lignes de la table, selon une condition sur les valeurs des variables. Il exite pour cela la fonction query() prenant en paramètre une chaîne de caractères contenant la condition à appliquer. Voici quelques exemples de condition. Il y a bien évidemment beaucoup d'autres fonctions existantes, en particuliers pour les chaînes.

Projection

Deuxième étape, celle-ci consiste tout simple à sélectionner certaines colonnes de la tables. En python, on utilise la fonction filter(). Il faut noter que celle-ci peut aussi fonctionner sur les lignes (quand celles-ci ont un index - pas vu ici).

Quand on fait ce genre d'opérations, il est courant que nous nous retrouvions avec des lignes identiques. Pour supprimer les doublons, nous utilisons la fonction drop_duplicates() sur le résultat.

On peut aussi utiliser le formalisme dataframe.colonne pour accéder aux valeurs d'une seule colonne

Tri et limitation des résultats

Pour le tri, il existe la fonction sort_values(), dans laquelle on indique la ou les variables à utiliser pour le tri. Si on veut un tri descendant, on modifie la valeur du paramètre ascending (True par défaut).

Pour se limiter aux premières lignes (respectivement les dernières), on utilise la fonction head() (resp. tail()), qui affiche par défaut 5 lignes. Cette valeur est bien évidemment modifiable, comme vu ci-après.

Ajout de nouvelles variables

Il y a 2 possibilités ici :

A partir de valeurs, soit vous en fournissez autant que de lignes, soit une seule qui sera donc dupliquée à toutes les lignes

Bien évidemment, on souhaite généralement faire un calcul à partir des autres variables. Ceci peut se faire avec la fonction assign().

Notez l'utilisation du mot-clé lambda pour la définition d'une fonction anonyme.

Agrégat

Le calcul d'un agrégat permet de calculer une statistique de base (dénombrement, somme, moyenne, minimum, maximum - rarement autre chose) sur un tableau de données. On peut soit calculer globalement, soit pour chaque modalité d'une variable (voire chaque couple de modalités de plusieurs variables).

Pour le faire globalement, on utilise la fonction aggregate() (ou agg()).

Pour le faire pour chaque modalité d'une variable, on utilise la fonction groupby() en plus. Si on ne réalise qu'un seul calcul, on a directement les fonctions associées.

On peut aussi définir plusieurs opérateurs d'agrégations.

Si on a plusieurs variables dans le regroupement, le calcul se fait donc pour chaque couple de modalités de celles-ci.

Visualisation de données

Le module seaborn est basé sur matplotlib. Il faut donc ajouter la ligne %matplotlib inline dans un notebook, pour pouvoir voir les graphiques.

Ce module contient toutes les fonctions directement, l'importation est donc assez simple.

Variable quantitative

La fonction displot() nous permet de réaliser les graphiques de distribution d'une variable quantitative. Par défaut, elle réaliser un histogramme.

C'est la fonction boxplot() qui nous permet de réaliser une boîte à moustache (soit verticale en mettant la variable en y, soit horizontale en la mettant en x).

Une autre représentation possible est obtenue avec la fonction pointplot(), qui représente la moyenne et l'écarte-type, avec le choix entre vertical (y) ou horizontal (x).

Un autre graphique possible est celui obtenu avec violinplot(), qui représente la densité d'une variable, toujours avec le choix vertical/horizontale (y/x).

Enfin, il est possible de représenter toutes les valeurs sur un pseudo nuage de points. Avec striplot() dont l'option jitter a été activée, les points sont aléatoirement répartis sur l'axe des $x$ (si on utilise y - inversement sinon).

Variable qualitative

Le diagramme en barres en effectifs est obtenu via la fonction countplot(). Il est soit horizontal (avec la variable en x), soit vertical (en y).

Pour avoir la version en pourcentages (ou en proportions) de ce graphique, nous devons utiliser la fonction barplot(), sur la table de proportions calculée avant. Cette fonction réalise un calcul (moyenne par défaut) sur une variable (ici freq) en fonction des modalités d'une autre variable (sex ici donc).

Pour réaliser un diagramme en barres empilées, il faudra le créer soi-même. Nous ne verrons pas ici.

Var quantitative - Var quantitative

Pour réaliser le nuage de points, on utilise la fonction jointplot(). Elle a l'avantage d'ajouter par défaut les histogrammes de chaque variable. Elle réalise par défaut le nuage de points simple (scatter).

En choississant le type reg avec le paramètre kind, on obtient en plus l'ajustement linéaire de la variable en y par celle en x.

Si on souhaite ne pas avoir les distributions marginales, la fonctionregplot() nous permet de réaliser le nuage de points avec ou sans ajustement (paramètre fit_reg).

Il est possible d'obtenir directement tous les nuages de points 2 à 2, avec la fonction pairplot(). Le paramètre vars permet de sélectionner certaines variables. Par défaut, la fonction utilise toutes les variables numériques.

Var qualitative - Var qualitative

Pour obtenir le diagramme en barres séparées (en effectifs), nous utilisons la fonction countplot() avec le paramètre hue pour indiquer la variable servant de coloriage aux barres.

Var quantitative - Var qualitative

Pour réaliser les boîtes à moustaches de la variable quantitative pour chaque modalité de la variable qualitative, on utilise la fonction catplot().

On peut aussi représenter la moyenne et l'écart-type à l'aide du graphique pointplot (qu'on réalise ici via catplot()).

Compléments

Il est bien évidemment possible de personnaliser le graphique de différentes façons, dont certains sont présentées ci-dessous. On accède aux fonctions de personnalisation soit via des paramètres de la fonction, soit via l'objet renvoyé par la fonction utilisée pour créer le graphique, soit via le module directement. Dans ce cas, ce sont des changements qui affecteront aussi les graphiques futurs.

Données Velib

Nous allons travailler sur des données Velib en temps réel, qui sont disponibles sur cette page.

Pour cela, nous avons besoin du module requests, tel qu'utilisé ci-dessous.

Dans ce résultat, nous voyons qu'il y a 1393 enregistrements à récupérer (nhits), et que nous en avons récupérer ici uniquement 10 (parameters.rows). Pour avoir les 10 suivants, on doit faire comme ci-dessous

Ce qui nous intéresse ici est le champ records, qui contient les enregistrements de 10 premières stations donc. En le transformant en data frame avec pandas, on voit que le tableau obtenu n'est pas très lisible.

On souhaite finalement se restreindre qu'aux informations contenues dans le champs fields. Pour cela, on utilise le mécanisme de list comprehension.

Carte avec leaflet

Dans ce TP, nous allons aussi aborder l'aspect cartographie sous python avec le package folium (à installer donc). L'idée sera d'ajouter à un fond de carte des formes de couleurs, en fonction d'une information tierce. Le package folium est une interface entre python et la librairie leaflet. Elle s'utilise très facilement, comme nous pouvons le voir ci-dessous pour la création d'une carte. Les coordonnées indiquées sont la latitude et la longitude de Paris.

Avec des marqueurs

En reprenant le data frame vu juste avant (et en le stockant dans une variable), on peut créer une carte avec des marqueurs, qui affichent le nom de la station lorsqu'on passe la souris dessus, et le nom de la station + la ville en cliquant dessus (notez l'usage de code HTML possible dans la pop-up).

A faire