Cet article peut être librement diffusé et son contenu réutilisé pour une utilisation non commerciale (contacter l’auteur pour une utilisation commerciale) suivant la licence CC-by-nc-sa
Dans le programme de mathématiques de première technologique, on trouve parmi la liste des compétences mathématiques travaillées :
- Calculer, appliquer des techniques et mettre en œuvre des algorithmes ;
Il y a dans ce programme des indications au sujet de ces algorithmes que l’on peut mettre en œuvre, nous allons ici les illustrer.
Nous faisons le choix de vous proposer une approche 100% fonctionnelle, comme préconisé dans les programmes.
Ceci concerne toutes les séries technologiques sauf la série STD2A.
Algorithmique et programmation
La pratique de l’algorithmique et de la programmation se poursuit au cycle terminal. En continuité avec la classe de seconde, le langage utilisé est Python. Le programme vise la consolidation des notions de variable, d’instruction conditionnelle et de boucle ainsi que l’utilisation des fonctions. La seule notion nouvelle est celle de liste qui trouve naturellement sa place dans de nombreuses parties du programme et aide à la compréhension de notions mathématiques telles que les suites numériques, les tableaux de valeurs, les séries statistiques...
Capacités attendues
Variables
– utiliser un générateur de nombres aléatoires entre 0 et 1 pour simuler une loi de Bernoulli de paramètre p ;
La loi de Bernoulli de paramètre p peut être simulée en coupant l’intervalle [0,1] en deux sous-intervalles, l’un de taille p, l’autre de taille 1−p :
- >>> from random import random
- >>> p=0.7
- >>> if random()<p:
- print(1)
- else:
- print(0)
- 1
– utiliser la notion de compteur ;
Lorsque l’on souhaite répéter un nombre donné de fois la même instruction ou le même bloc d’instructions, la commande for est la plus appropriée. Elle intègre un compteur, souvent appelé i (on peut lui donner le nom que l’on veut)
Admettons que l’on veuille répéter 7 fois la loi de Bernoulli de paramètre p ci-dessus. Voici ce que l’on peut faire.
- >>> from random import random
- >>> p=0.7
- >>> for i in range(7):
- if random()<p:
- print(1)
- else:
- print(0)
- 0
- 0
- 0
- 1
- 1
- 1
- 0
Lorsque l’on souhaite répéter un certain nombre de fois, inconnu, la même instruction ou le même bloc d’instructions, la commande while est la plus appropriée et le plus souvent elle nécessite un compteur. On va répéter la loi de Bernoulli de paramètre p jusqu’à ce qu’elle ait rencontré 10 succès.
- >>> from random import random
- >>> compteur=0
- >>> p=0.7
- >>> while compteur<10:
- if random()<p:
- print(1)
- compteur+=1
- else:
- print(0)
- 1
- 1
- 0
- 1
- 0
- 1
- 0
- 1
- 1
- 0
- 0
- 1
- 0
- 1
- 0
- 1
- 1
– utiliser le principe d’accumulateur pour calculer une somme, un produit.
On s’est servi de ce principe pour incrémenter le compteur ci-dessus, mais illustrons cela avec un calcul de somme, par exemple les carrés des nombres inférieurs à 10 :
- >>> somme=0
- >>> for i in range(10):
- somme+=i**2
- >>> print(somme)
- 285
Commentaires
– Les notions relatives aux types de variables et à l’affectation sont consolidées. Comme en classe de seconde, on utilise le symbole « ← » pour désigner l’affectation dans un algorithme écrit en langage naturel.
Python est un langage à typage dynamique, ce qui signifie que la valeur que l’on affecte à une variable définit son type. Le type du contenu d’une variable peut donc changer si on change sa valeur.
La fonction type()
Pour connaître le type d’une donnée ou d’une variable, il suffit d’utiliser la fonction type().
- >>> type(6)
- <class 'int'>
- >>> a = 6
- >>> type(a)
- <class 'int'>
- >>> a = "math"
- >>> type(a)
- <class 'str'>
- >>> a = 6.1
- >>> type(a)
- <class 'float'>
Le type int (entier)
Ce type est utilisé pour stocker un entier ( integer en anglais).
- >>> type(1234)
- <class 'int'>
Le type float (flottant)
Ce type est utilisé pour stocker des nombres à virgule flottante ( floating point numbers en anglais). En français, on parle de flottant.
- >>> a=12.3
- >>> type(a)
- <class 'float'>
- >>> a=6.
- >>> type(a)
- <class 'float'>
- >>> a
- 6.0
- >>> a = 2.99792458e8
- >>> a
- 299792458.0
- >>> type(a)
- <class 'float'>
Le type str (chaîne de caractères)
Dans Python, une donnée de type str est une suite quelconque de caractères délimitée soit par des apostrophes, soit par des guillemets. str est l’abréviation de string, qui veut dire chaîne en français.
- >>> a = "hello world !"
- >>> type(a)
- <class 'str'>
- >>> b="1+2"
- >>> type(b)
- <class 'str'>
- >>> b
- '1+2'
Le type list (liste)
Dans Python, on peut définir une liste comme une collection d’éléments séparés par des virgules, l’ensemble étant écrit entre crochets.
- >>> jour = ["lundi", "mardi", "mercredi", "jeudi", "vendredi","samedi","dimanche"]
- >>> type(jour)
- <class 'list'>
- >>> L=[x**2 for x in range(10)]
- >>> type(L)
- <class 'list'>
- >>> L
- [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
Fonctions
– identifier les entrées et les sorties d’une fonction ;
Prenons l’exemple de la loi de Bernoulli, on peut définir une fonction loi de Bernoulli de paramètre 0.7 :
- from random import random
- def bernoulli():
- if random()<0.7:
- return(1)
- else:
- return(0)
- >>> bernoulli()
- 1
- >>> bernoulli()
- 0
Il n’y a pas d’entrée, et en sortie on obtient 1 si l’expérience est un succès, 0 sinon.
Si l’on veut définir une loi de Bernoulli de paramètre p (au lieu de 0.7), on prendra en entrée le paramètre p, la sortie étant la même que précédemment :
- from random import random
- def bernoulli(p):
- if random()<p:
- return(1)
- else:
- return(0)
- >>> bernoulli(0.4)
- 1
- >>> bernoulli(0.8)
- 0
Si l’on veut répéter n fois l’expérience :
- from random import random
- def bernoulli(n,p):
- succes=0
- for i in range(n):
- if random()<p:
- succes+=1
- return succes
- >>> bernoulli(100,0.8)
- 82
En entrée, on renseigne le nombre d’expériences n et la probabilité du succès p. En sortie, on récupère le nombre de succès.
– structurer un programme en ayant recours aux fonctions. (Ceci est illustré partout dans l’article, nous n’en dirons pas plus ...)
Commentaires
– L’accent est mis sur la programmation modulaire qui permet de découper une tâche complexe en tâches plus simples.
Prenons l’exemple du calcul de l’écart-type pour une liste de données, on peut programmer la fonction :
- from math import sqrt
- def ecarttype(Liste):
- N=len(Liste)
- E_X=sum(Liste)/N
- varX = 0
- for i in range(N):
- varX += (Liste[i]-E_X)**2
- varX=varX/N
- return sqrt(varX)
- >>> ecarttype([x**2 for x in range(10)])
- 26.852374196707448
On peut aussi programmer les fonctions esperance et variance afin de les utiliser dans la fonction ecarttype et éventuellement de s’en servir par ailleurs :
- from math import sqrt
- def esperance(Liste):
- return sum(Liste)/len(Liste)
- def variance(Liste):
- E_X=esperance(Liste)
- N=len(Liste)
- varX = 0
- for i in range(N):
- varX += (Liste[i]-E_X)**2
- varX=varX/N
- return varX
- def ecarttype(Liste):
- return sqrt(variance(Liste))
- ecarttype([x**2 for x in range(10)])
Listes
– générer une liste (en extension, par ajouts successifs, en compréhension) ;
Une liste est une séquence modifiable. Un élément d’une liste peut être de n’importe quel type.
- >>> L=[6,1,69]
- >>> type(L)
- <class 'list'>
- >>> L[2]=1969
- >>> L
- [6, 1, 1969]
- >>> liste=[L,7,11,67,"Marie",18.2]
- >>> liste
- [[6, 1, 1969], 7, 11, 67, 'Marie', 18.2]
- >>> [a,b]=[0,1]
- >>> a
- 0
- >>> [a,b]
- [0, 1]
La liste vide :
- >>> L = []
- >>> L
- []
Longueur d’une liste : fonction len
- >>> a = [0,1,2,3]
- >>> len(a)
- 4
– manipuler des éléments d’une liste (ajouter, supprimer...) et leurs indices ;
Concaténation et multiplication
On concatène avec + :
- >>> a=[1,2,3]
- >>> b=a+[4,5]
- >>> b
- [1, 2, 3, 4, 5]
- >>> [0,1,2]+["Marie","Mylène"]+[67,72]
- [0, 1, 2, 'Marie', 'Mylène', 67, 72]
On peut utiliser la concaténation pour insérer un terme à la fin de la liste, mais on préférera utiliser la méthode append :
- >>> L = ["Benjamin","Alain"]
- >>> L.append("Yves")
- >>> L
- ['Benjamin', 'Alain', 'Yves']
On multiplie avec * :
- >>> [1,2,3]*3
- [1, 2, 3, 1, 2, 3, 1, 2, 3]
- >>> [1,2]*3
- [1, 2, 1, 2, 1, 2]
- >>> 2*["Pile","Face"]
- ['Pile', 'Face', 'Pile', 'Face']
Convertir avec la fonction list
On peut convertir n’importe quel itérable en liste :
- >>> list("abcdef")
- ['a', 'b', 'c', 'd', 'e', 'f']
- >>> list(b"abcdef")
- [97, 98, 99, 100, 101, 102]
- >>> list((0,1,2,3,4,5))
- [0, 1, 2, 3, 4, 5]
- >>> list(range(10))
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
- >>> list(range(5,9))
- [5, 6, 7, 8]
Indexing et slicing
Les listes sont des séquences, elles sont donc indexables (les items sont repérés par un indice) et sliceables (on peut en extraire des tranches grâce à des plages d’indices). Comme d’habitude, l’indice du premier item est zéro :
- >>> a=[42, 43, 45, 47]
- >>> a[2]
- 45
- >>> a[2]=12
- >>> a
- [42, 43, 12, 47]
Indices négatifs : Python numérote le dernier item avec -1, l’avant-dernier avec -2, et ainsi de suite :
- >>> a=[42, 43, 45, 47]
- >>> a[-1]
- 47
- >>> a[-2]
- 45
Si on est obligé d’initialiser les termes dans le désordre, on commencera par créer une liste triviale.
Supposons par exemple qu’on veuille L de longueur 10, on écrira :
- >>> L=[None]*10
- >>> L[5]=12
- >>> L
- [None, None, None, None, None, 12, None, None, None, None]
sans déclencher d’erreur.
Un peu de slicing :
- >>> a=[0,1,2,3,4,5,6,7,8,9]
- >>> a[3:7]
- [3, 4, 5, 6]
- >>> a[3:3]
- []
- >>> a[5:]
- [5, 6, 7, 8, 9]
- >>> a[:5]
- [0, 1, 2, 3, 4]
- >>> a[-3:-1]
- [7, 8]
- >>> a[-5:]
- [5, 6, 7, 8, 9]
- >>> a[:]
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
On peut faire du slicing avec un pas (positif ou négatif) :
- >>> a[2:20:3]
- [2, 5, 8]
- >>> a[::-1]
- [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
- >>> a[20:2:-2]
- [9, 7, 5, 3]
Remplacer une tranche par une autre
Dans une liste, on peut remplacer une tranche par une autre (il s’agit d’une mutation) :
- >>> L=list(range(15))
- >>> L[2:5]=5*[0]
- >>> L
- [0, 1, 0, 0, 0, 0, 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
On peut utiliser ce procédé pour changer un terme :
- >>> L=list(range(15))
- >>> L[3:4]=[7]
- >>> L
- [0, 1, 2, 7, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
On peut utiliser cette méthode pour supprimer une tranche :
- >>> L[2:5]=[]
- >>> L
- [0, 1, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
On peut utiliser ce procédé pour supprimer un terme d’indice connu :
- >>> L[3:4]=[]
- >>> L
- [0, 1, 5, 7, 8, 9, 10, 11, 12, 13, 14]
On peut utiliser ce procédé pour insérer un élément où on veut :
- >>> L[5:5]=[25]
- >>> L
- [0, 1, 5, 7, 8, 25, 9, 10, 11, 12, 13, 14]
On peut insérer une tranche :
- >>> L[5:5]=[1,1,1,1,1]
- >>> L
- [0, 1, 5, 7, 8, 1, 1, 1, 1, 1, 25, 9, 10, 11, 12, 13, 14]
Compréhension
En mathématiques (théorie des ensembles), l’axiome de compréhension est fondamental :
Axiome : Si E est un ensemble et P une propriété exprimée dans le langage de la théorie des ensembles, alors $\left\{x \in E | P\right\}$ est un ensemble.
Il est très courant en mathématiques de définir des ensembles en compréhension. L’ensemble des nombres pairs, par exemple est l’ensemble $\left\{n \in \mathbb{Z} | n\equiv 0 [2] \right\}$.
On peut avec Python définir des listes en compréhension (on dit aussi en intension avec un s) :
- >>> X=[1,5,7,12]
- >>> Y=[x**2 for x in X]
- >>> Y
- [1, 25, 49, 144]
Y est la liste des carrés des nombres appartenant à X. On peut même ajouter une condition :
- >>> Y=[x**2 for x in X if x**2<30]
- >>> Y
- [1, 25]
- >>> Y=[x**2 for x in X if x<10]
- >>> Y
- [1, 25, 49]
On peut redéfinir X à partir de X directement :
- >>> X=[1,5,7,12]
- >>> X=[x**2 for x in X]
- >>> X
- [1, 25, 49, 144]
On peut imbriquer des listes en compréhension :
- >>> L = [[k for k in range(m)] for m in range(6)]
- >>> L
- [[], [0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]
Fusionner
Soit L une liste de listes. On peut récupérer les items des listes de L en une seule instruction :
- >>> L = [[k for k in range(m)] for m in range(1,6)]
- >>> L
- [[0], [0, 1], [0, 1, 2], [0, 1, 2, 3], [0, 1, 2, 3, 4]]
- >>> fusion=[x for SL in L for x in SL]
- >>> fusion
- [0, 0, 1, 0, 1, 2, 0, 1, 2, 3, 0, 1, 2, 3, 4]
On peut utiliser cette technique pour effectuer des produits de listes :
- >>> valeur = [1,7,8,9,10,"Valet","Dame","Roi"]
- >>> couleur = ["Coeur","Carreau","Pique","Trèfle"]
- >>> jeu = [(n,c) for n in valeur for c in couleur]
- >>> jeu
- [(1, 'Coeur'), (1, 'Carreau'), (1, 'Pique'), (1, 'Trèfle'), (7, 'Coeur'), (7, 'Carreau'), (7, 'Pique'),
- (7, 'Trèfle'), (8, 'Coeur'), (8, 'Carreau'), (8, 'Pique'), (8, 'Trèfle'), (9, 'Coeur'), (9, 'Carreau'),
- (9, 'Pique'), (9, 'Trèfle'), (10, 'Coeur'), (10, 'Carreau'), (10, 'Pique'), (10, 'Trèfle'), ('Valet',
- 'Coeur'), ('Valet', 'Carreau'), ('Valet', 'Pique'), ('Valet', 'Trèfle'), ('Dame', 'Coeur'),
- ('Dame', 'Carreau'), ('Dame', 'Pique'), ('Dame', 'Trèfle'), ('Roi', 'Coeur'), ('Roi', 'Carreau'),
- ('Roi', 'Pique'), ('Roi', 'Trèfle')]
- >>> (10,"Trèfle") in jeu
- True
Trier avec sort ou sorted (arguments reverse, key)
La fonction sorted et la méthode sort font la même chose : elles trient les items dans l’ordre croissant (par défaut). La fonction sorted prend n’importe quel itérable et retourne les items dans l’ordre, sous forme de liste :
- >>> L=[7,12,3,2]
- >>> sorted(L)
- [2, 3, 7, 12]
- >>> L
- [7, 12, 3, 2]
La méthode sort s’applique à une liste et modifie cette liste :
- >>> L.sort()
- >>> L
- [2, 3, 7, 12]
Les deux, sort et sorted, acceptent les arguments reverse et key. L’argument reverse permet de trier dans l’ordre décroissant :
- >>> sorted([7,12,3,2],reverse=True)
- [12, 7, 3, 2]
L’argument key permet de choisir la fonction avec laquelle on fera le tri. Si on veut trier selon la valeur absolue, on fera :
- >>> sorted([-13,15,-2,6,-6],key=abs)
- [-2, 6, -6, -13, 15]
Très pratique avec des données complexes :
- >>> def f(t):
- return t[1]
- >>> L=[["Marie",21],["Mylène",17],["Fred",24],["Denis",23]]
- >>> sorted(L,key=f)
- [['Mylène', 17], ['Marie', 21], ['Denis', 23], ['Fred', 24]]
Instruction del (mot réservé)
Pour effacer un item selon son rang, ou une plage d’items :
- >>> L=[7,12,3,2]
- >>> del L[2]
- >>> L
- [7, 12, 2]
Une autre syntaxe :
- >>> del(L[2])
On peut utiliser del sur une plage d’indices :
- >>> L=list(range(11))
- >>> del L[2:5]
- >>> L
- [0, 1, 5, 6, 7, 8, 9, 10]
- >>> L=list(range(21))
- >>> L
- [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
- >>> del L[::3]
- >>> L
- [1, 2, 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20]
Méthode index
Pour trouver l’indice d’un terme :
- >>> L=[0, 1, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 8, 9, 10]
- >>> L.index(6)
- 2
C’est l’index de la première occurrence du terme qui est renvoyé, si l’on veut l’index de la seconde occurrence, on peut démarrer la recherche plus loin :
- >>> L.index(6,3)
- 10
Méthode count
Pour compter les occurrences d’un item :
- >>> L = [1,2,1,1,1,1,2,1,2]
- >>> L.count(2)
- 3
- >>> L.count(3)
- 0
Méthode remove
Pour supprimer une occurrence (ne supprime que la première occurrence) :
- >>> L = [1,10,56,23,897,56,1000]
- >>> L.remove(56)
- >>> L
- [1, 10, 23, 897, 56, 1000]
- >>> L.remove(100000)
- Traceback (most recent call last):
- File "<pyshell#165>", line 1, in <module>
- L.remove(100000)
- ValueError: list.remove(x): x not in list
Méthode append
Pour insérer un terme à la fin :
- >>> L = [1,10,56,23,897,56,1000]
- >>> L.append(1945)
- >>> L
- [1, 10, 56, 23, 897, 56, 1000, 1945]
Méthode insert
Pour insérer un terme où on veut :
- >>> L.insert(3,666)
- >>> L
- [1, 10, 56, 666, 23, 897, 56, 1000, 1945]
Méthode extend
Pour étendre une liste par concaténation :
- >>> LL=[456,567]
- >>> L.extend(LL)
- >>> L
- [1, 10, 56, 666, 23, 897, 56, 1000, 1945, 456, 567]
Méthode pop
Supprime le dernier terme et le retourne :
- >>> L.pop()
- 567
- >>> L
- [1, 10, 56, 666, 23, 897, 56, 1000, 1945, 456]
Fonction max
Retourne le plus grand élément :
- >>> max(L)
- 1945
Fonction min
Retourne le plus petit élément :
- >>> min(L)
- 1
Méthode copy
Pour copier une liste dans une autre :
- >>> LL=L.copy()
- >>> LL
- [1, 10, 56, 666, 23, 897, 56, 1000, 1945, 456]
- >>> LL==L
- True
- >>> LL is L
- False
Méthode clear
Pour effacer le contenu d’une liste :
- >>> L.clear()
- >>> L
- []
– itérer sur les éléments d’une liste.
Le type list est itérable
On peut itérer une liste :
- >>> for k in [1,2,3]:
- print(k,end=" ")
- 1 2 3
Les listes supportent les tests x in list et x not in list.
- >>> solide_platon=["Tétraèdre","Hexaèdre","Octaèdre","Dodécaèdre","Icosaèdre"]
- >>> "polyèdre" in solide_platon
- False
Commentaires
– La génération des listes en compréhension et en extension est mise en lien avec la notion d’ensemble. Les conditions apparaissant dans les listes définies en compréhension permettent de travailler la logique.
– Afin d’éviter des confusions, il est recommandé de se limiter aux listes sans présenter d’autres types de collections.
Sélection de données
– traiter un fichier contenant des données réelles pour en extraire de l’information et l’analyser ;
Nous utiliserons un gros fichier de données issu du site de l’INSEE, sur les communes de France métropolitaine et de Corse, débarrassé des données incomplètes (pour les DOM-TOM) :
Nous traiterons ce fichier avec le module pandas qui est une librairie Python spécialisée dans l’analyse des données. Pour ma part, je l’utilise dans Spyder, mais cela est un détail à régler de votre côté ... Un objet de type « data frame » permet de réaliser de nombreuses opérations de filtrage, prétraitements, etc., préalables à la modélisation statistique.
Dans Spyder, on crée un fichier Python :
- import matplotlib as plt
- import pandas
- data=pandas.read_csv("villes_virgule.csv",sep=",")
- pandas.options.display.max_rows = 10 #On fait le choix de n'afficher que 10 lignes dans la console
On obtient dans la console un extrait des données qui sont enregistrées dans 36568 lignes et 12 colonnes, des « ... » indiquent les « trous » présents dans cet affichage :
- In[63]:data
- Out[63]:
- dep nom cp ... lat alt_min alt_max
- 0 1 Ambérieu-en-Bugey 1500 ... 45.9500 237 753
- 1 1 Ambérieux-en-Dombes 1330 ... 46.0000 265 302
- 2 1 Ambléon 1300 ... 45.7500 330 940
- 3 1 Ambronay 1500 ... 46.0000 225 765
- 4 1 Ambutrix 1500 ... 45.9333 237 370
- .. ... ... ... ... ... ...
- 36563 2B Vivario 20219 ... 42.1731 400 2390
- 36564 2B Volpajola 20290 ... 42.5262 45 1231
- 36565 2B Zalana 20272 ... 42.2606 193 847
- 36566 2B Zilia 20214 ... 42.5303 172 1935
- 36567 2B Zuani 20272 ... 42.2714 411 1013
- [36568 rows x 12 columns]
Par rapport au fichier original, la colonne des index des lignes a été rajoutée à gauche.
Il est possible d’afficher toutes les données grâce à l’explorateur de variables :
Structure DataFrame
Une matrice DataFrame correspond à une matrice individus-variables où les lignes correspondent à des observations, les colonnes à des attributs décrivant les individus. Concernant notre fichier « villes_virgule.csv » : la première ligne correspond aux noms des champs (des variables) ; à partir de la seconde ligne, nous disposons des valeurs pour chaque enregistrement (individu, ici une commune). Dans ce qui suit, nous chargeons le fichier de données et nous procédons à quelques vérifications.
Si l’on demande le type de data :
- print(type(data))
- <class 'pandas.core.frame.DataFrame'>
Voyons maintenant l’architecture de la structure DataFrame :
- print(data.shape)
- (36568, 12)
La ligne d’en-tête et la colonne d’index ne sont pas comptées.
Pour afficher l’en-tête de toutes les colonnes :
- print(data.columns)
- Index(['dep', 'nom', 'cp', 'nb_hab_2010', 'nb_hab_1999', 'nb_hab_2012', 'dens',
- 'surf', 'long', 'lat', 'alt_min', 'alt_max'],
- dtype='object')
On a donc le numéro du département, le nom de la commune, le code postal, le nombre d’habitants en 2010, le nombre d’habitants en 1999, le nombre d’habitants en 2012, la densité, la surface, la longitude, la latitude, l’altitude minimum et l’altitude maximum.
On peut récupérer les données statistiques de base pour chacune des colonnes :
- print(data.describe())
- nb_hab_2010 nb_hab_1999 ... alt_min alt_max
- count 3.656800e+04 3.656800e+04 ... 36568.000000 36568.000000
- mean 1.716628e+03 1.598173e+03 ... 193.157569 391.109166
- std 1.470343e+04 1.393150e+04 ... 194.694120 449.305955
- min 0.000000e+00 0.000000e+00 ... -5.000000 2.000000
- 25% 1.940000e+02 1.750000e+02 ... 62.000000 140.000000
- 50% 4.270000e+02 3.795000e+02 ... 138.000000 236.000000
- 75% 1.050000e+03 9.252500e+02 ... 253.000000 435.000000
- max 2.243833e+06 2.125851e+06 ... 1785.000000 4807.000000
- [8 rows x 9 columns]
Certaines des données ont plus ou moins d’intérêt selon le contexte, ici par exemple count correspond au nombre de données pour chaque colonne c’est-à-dire 36568 ...
On peut alors demander plus précisément les données pour une colonne précise :
- print(data["dens"].describe())
- count 36568.000000
- mean 153.984112
- std 703.669064
- min 0.000000
- 25% 18.000000
- 50% 39.000000
- 75% 90.000000
- max 26660.000000
- Name: dens, dtype: float64
Si l’on demande le calcul explicite de la moyenne :
- print(data["nb_hab_2010"].mean())
- 1716.6284456355284
Ou la population totale en 2010 :
- sum(data["nb_hab_2010"])
- Out[75]: 62773669
Le nombre de communes par département :
- print(data['dep'].value_counts())
- 62 895
- 2 816
- 80 782
- 76 745
- 57 730
- ...
- 90 102
- 94 47
- 93 40
- 92 36
- 75 1
- Name: dep, Length: 96, dtype: int64
data[« dens »] est une liste, on peut donc lui appliquer toutes les méthodes des listes :
- data["dens"][0]
- Out[80]: 562
- data["dens"][0:3]
- Out[81]:
- 0 562
- 1 101
- 2 19
- Name: dens, dtype: int64
- data.dens[0:3]
- Out[82]:
- 0 562
- 1 101
- 2 19
- Name: dens, dtype: int64
- data["dens"].sort_values()
- Out[84]:
- 11593 0
- 22300 0
- 21144 0
- 3800 0
- 1577 0
- 35923 23476
- 36009 24343
- 36021 25377
- 35952 25778
- 35919 26660
- Name: dens, Length: 36568, dtype: int64
On peut accéder aux valeurs du DataFrame via des indices ou plages d’indice. La structure se comporte alors comme une matrice. La cellule en haut et à gauche est de coordonnées (0,0). Il y a différentes manières de le faire, l’utilisation de .iloc[,] constitue une des solutions les plus simples. N’oublions pas que Shape permet d’obtenir les dimensions (lignes et colonnes) du DataFrame :
- print(data.iloc[0,0])
- 1
- print(data.iloc[5,8])
- 5.65
- print(data.iloc[-1,0])
- 2B
- print(data.iloc[data.shape[0]-1,0])
- 2B
- print(data.iloc[0:5,:])
- dep nom cp ... lat alt_min alt_max
- 0 1 Ambérieu-en-Bugey 1500 ... 45.9500 237 753
- 1 1 Ambérieux-en-Dombes 1330 ... 46.0000 265 302
- 2 1 Ambléon 1300 ... 45.7500 330 940
- 3 1 Ambronay 1500 ... 46.0000 225 765
- 4 1 Ambutrix 1500 ... 45.9333 237 370
- [5 rows x 12 columns]
- print(data.iloc[0:5,0:2])
- dep nom
- 0 1 Ambérieu-en-Bugey
- 1 1 Ambérieux-en-Dombes
- 2 1 Ambléon
- 3 1 Ambronay
- 4 1 Ambutrix
- print(data.iloc[0:5,[0,2,4]])
- dep cp nb_hab_1999
- 0 1 1500 11432
- 1 1 1330 1407
- 2 1 1300 86
- 3 1 1500 2144
- 4 1 1500 586
Nous pouvons isoler les sous-ensembles d’observations répondant à des critères définis sur les champs. Nous utiliserons préférentiellement la méthode .loc[,] dans ce cadre. Par exemple si l’on veut toutes les données correspondant au code postal 34400 :
- print(data.loc[data['cp']=="34400",:])
- dep nom cp ... lat alt_min alt_max
- 13262 34 Lunel 34400 ... 43.6833 2 53
- 13263 34 Lunel-Viel 34400 ... 43.6833 6 50
- 13359 34 Saint-Christol 34400 ... 43.7333 24 92
- 13384 34 Saint-Just 34400 ... 43.6500 2 9
- 13391 34 Saint-Nazaire-de-Pézan 34400 ... 43.6333 0 5
- 13399 34 Saint-Sériès 34400 ... 43.7333 14 68
- 13405 34 Saturargues 34400 ... 43.7167 16 68
- 13437 34 Vérargues 34400 ... 43.7167 15 65
- 13447 34 Villetelle 34400 ... 43.7333 10 67
- [9 rows x 12 columns]
Si l’on veut les communes du Nord de l’Hérault :
- print(data.loc[(data['dep']=="34") & (data['lat'] >43.9),:])
- dep nom cp ... lat alt_min alt_max
- 13112 34 Agonès 34190 ... 43.9167 119 323
- 13169 34 Cazilhac 34190 ... 43.9250 132 523
- 13211 34 Ganges 34190 ... 43.9333 138 540
- 13235 34 Laroque 34190 ... 43.9167 124 490
- 13288 34 Montoulieu 34190 ... 43.9333 159 522
- 13291 34 Moulès-et-Baucels 34190 ... 43.9500 156 727
- [6 rows x 12 columns]
pour visualiser l’évolution démographique des communes Héraultaises de plus de 10000 habitants en 1999 :
- colonnes = ['nom','nb_hab_1999','nb_hab_2010','nb_hab_2012']
- print(data.loc[(data['dep'] =="34") & (data['nb_hab_1999'] >10000),colonnes])
- nom nb_hab_1999 nb_hab_2010 nb_hab_2012
- 13110 Agde 20066 24567 22500
- 13139 Béziers 69359 70955 71700
- 13161 Castelnau-le-Lez 14208 14948 15000
- 13208 Frontignan 19130 22526 23200
- 13236 Lattes 13760 15927 16300
- 13262 Lunel 22346 25277 24400
- 13271 Mauguio 14846 16307 15800
- 13289 Montpellier 225511 257351 253000
- 13412 Sète 39579 42774 42800
– réaliser un tableau croisé de données sur deux critères à partir de données brutes.
On utilisera un second fichier, plus approprié, qui répertorie, selon leur ville de résidence, la LV2 étudiée par des lycéens :
- import matplotlib as plt
- import pandas
- data=pandas.read_csv("LV2.csv",sep=",")
- pandas.options.display.max_rows = 10
- data
- Out[6]:
- LV2 ville
- 0 ANG Saint-Just
- 1 ITA Lansargues
- 2 ITA Saint-Just
- 3 ITA Lunel-Viel
- 4 ANG Lansargues
- .. ... ...
- 104 ITA Lunel
- 105 ALL Lunel
- 106 ANG Lunel
- 107 ITA Lansargues
- 108 ITA Lansargues
- [109 rows x 2 columns]
On peut alors calculer les effectifs et les fréquences :
- data["LV2"].value_counts()
- Out[2]:
- ANG 33
- ITA 33
- ALL 23
- ESP 20
- Name: LV2, dtype: int64
- data["LV2"].value_counts(normalize=True)
- Out[3]:
- ANG 0.302752
- ITA 0.302752
- ALL 0.211009
- ESP 0.183486
- Name: LV2, dtype: float64
Et réaliser le tri croisé :
- pandas.crosstab(data["LV2"],data["ville"])
- Out[5]:
- ville Lansargues Lunel Lunel-Viel Saint-Just
- LV2
- ALL 5 10 3 5
- ANG 7 12 8 6
- ESP 4 6 6 4
- ITA 9 11 7 6
Ou avec la métode pivot_table(), qui donne exactement la même chose :
- data.pivot_table(index="LV2",columns="ville",aggfunc=len)
Suites numériques
Calculer un terme de rang donné d’une suite, une somme finie de termes.
Le calcul d’un terme de rang donné d’une suite définie de manière explicite, c’est-à-dire à l’aide d’une fonction de n est quelque chose de très simple :
- def u(n):
- return 3*n+1
Si l’on veut simplement un terme de rang donné, il suffit d’utiliser la fonction u :
- >>> u(5)
- 16
Regardons maintenant du côté des suites définies par récurrence. Prenons le cas d’une suite définie par $u_{n+1} = f(u_n)$ et de premier terme $u_{p}$ :
- def f(x):
- return 3*x+1
- def suite_recurrente(f,debut,fin,u_p):
- u=u_p
- for i in range(debut,fin):
- u=f(u)
- return u
Après avoir défini la fonction $f$, qui calcule $u_{n+1}$ en fonction de $u_{n}$, on calcule à l’aide d’une boucle les termes d’indice compris entre début+1 et fin. Si l’on veut $u_{12}$ :
- >>> suite_recurrente(f,0,12,2)
- 1328602
Étant donné que les suites arithmétiques et géométriques apparaissent dans le programme, il semble légitime de s’y intéresser particulièrement. On peut bien sûr utiliser la fonction suite_recurrente() (l’expression explicite de ces suites est au programme de Terminale) précédentes, il suffit d’écrire la relation de récurrence adéquate. Sinon, il est possible aussi de créer un outil spécifique qui prendrait en paramètres les rangs de début et de fin ainsi que le terme initial et la raison.
- def suite_geometrique_recurrence(debut,fin,u_p,raison):
- u=u_p
- for i in range(debut,fin):
- u*=raison
- return u
- def suite_arithmetique_recurrence(debut,fin,u_p,raison):
- u=u_p
- for i in range(debut,fin):
- u+=raison
- return u
Utilisation :
- >>> suite_arithmetique_recurrence(0,10,2,0.9)
- 11.000000000000002
- >>> suite_geometrique_recurrence(0,10,2,0.9)
- 0.6973568802000003
A noter les petites différences avec les résultats attendus de l’ordre de $10^{-15}$ dues à la gestion des nombres décimaux (flottants) dans Python. Cela peut se régler en utilisant la fonction round().
Si la suite est définie de manière explicite et que l’on veut la somme des termes de rang compris entre debut et fin :
- def u(n):
- return 3*n+1
- def somme_explicite(debut,fin):
- s=0
- for i in range(debut,fin+1):
- s=s+u(i)
- return s
Utilisation :
- >>> somme_explicite(5,9)
- 110
Si la suite est définie de manière récurrente et que l’on veut la somme des termes de rang compris entre debut et fin avec $u_{debut} = u_p$ :
- def f(x):
- return 3*x+1
- def somme_recurrente(debut,fin,u_p):
- s=u_p
- u=u_p
- for i in range(debut,fin):
- u=f(u)
- s=s+u
- return s
Utilisation :
- >>> somme_recurrente(3,7,5)
- 663
Déterminer une liste de termes d’une suite et les représenter.
Pour une suite déterminée de manière explicite :
- import matplotlib.pyplot as plt
- def u(n):
- return 0.2*n**2-1.2*n+1.6
- def graphe(u,debut,fin):
- for i in range(debut,fin):
- plt.scatter(i,u(i),c="red",marker='x')
- plt.grid()
- plt.show()
Taper dans la console :
- >>> graphe(u,0,12)
- [1.6, 0.6, 0, -0.2, 0, 0.6, 1.6, 3.0, 4.8, 7.0, 9.6, 12.6]
Pour une suite déterminée de manière récurrente :
- import matplotlib.pyplot as plt
- def u(n):
- return 0.2*n**2-1.2*n+1.6
- def suite_recurrente(u,debut,fin,u_p):
- liste_x=[debut]
- liste_y=[u_p]
- for i in range(debut,fin):
- liste_x.append(i+1)
- liste_y.append(u(liste_y[i]))
- plt.scatter(liste_x,liste_y)
- plt.grid()
- plt.show()
- return liste_y
Taper dans la console :
- >>> suite_recurrente(u,0,25,3)
- [3, -0.200, 1.848, 0.065, 1.522, 0.237, 1.327, 0.360, 1.194, 0.452, 1.098, 0.523, 1.027, 0.579,
- 0.973, 0.622, 0.931, 0.656, 0.899, 0.683, 0.874, 0.704, 0.854, 0.721, 0.839, 0.734]
Déterminer le rang à partir duquel les termes d’une suite sont supérieurs ou inférieurs à un seuil donné, ou aux termes de même rang d’une autre suite
Pour une suite, définie de manière explicite, pour laquelle on cherche à partir de quel rang son terme devient supérieur à un seuil donné :
- def u(n):
- return 0.2*n**2-1.2*n+1.6
- def seuil(u,debut,s):
- u_n=u(debut)
- compteur=debut
- while u_n<s:
- compteur+=1
- u_n=u(compteur)
- return u_n,compteur
utilisation :
- >>> seuil(u,0,1000)
- (1008.0, 74)
Le seuil de 1000 est dépassé au rang 74 avec $u_{74}=1008$.
Pour une suite, définie par récurrence, pour laquelle on cherche à partir de quel rang son terme devient supérieur à un seuil donné :
- def u(n):
- return 3*n+1
- def seuil(u,debut,u_p,s):
- compteur=debut
- while u_p<s:
- compteur+=1
- u_p=u(u_p)
- return u_p,compteur
utilisation :
- >>> seuil(u,1,5,1000)
- (1336, 6)
Le seuil de 1000 est dépassé au rang 6 avec $u_{6}=1336$.
Pour une suite, définie de manière explicite, pour laquelle on cherche à partir de quel rang son terme devient inférieur à un seuil donné :
- def u(n):
- return -0.2*n**2+1.2*n+1000
- def seuil(u,debut,s):
- u_n=u(debut)
- compteur=debut
- while u_n>s:
- compteur+=1
- u_n=u(compteur)
- return u_n,compteur
utilisation :
- >>> seuil(u,0,500)
- (481.5999999999999, 54)
La suite passe sous le seuil de 500 au rang 54 avec $u_{54}=481.6$.
Pour une suite, définie par récurrence, pour laquelle on cherche à partir de quel rang son terme devient inférieur à un seuil donné :
- def u(n):
- return 1.03*n-250
- def seuil(u,debut,u_p,s):
- compteur=debut
- while u_p>s:
- compteur+=1
- u_p=u(u_p)
- return u_p,compteur
utilisation :
- >>> seuil(u,1,2000,250)
- (69.7698357481176, 10)
La suite passe sous le seuil de 250 au rang 10 avec $u_{11}\approx 69.77$.
Déterminer le rang à partir duquel les termes d’une suite sont supérieurs aux termes de même rang d’une autre suite avec deux suites définies par récurrence :
- def u(n):
- return n+400
- def v(n):
- return 1.025*n
- def seuil(u,v,debut,u_p,v_p):
- compteur=debut
- while u_p>=v_p:
- compteur+=1
- u_p=u(u_p)
- v_p=v(v_p)
- return u_p,v_p,compteur
utilisation :
- >>> seuil(u,v,0,10000,10000)
- (24800, 24933.486986108404, 37)
Déterminer le rang à partir duquel les termes d’une suite sont supérieurs aux termes de même rang d’une autre suite avec deux suites définies de manière implicite :
- def u(n):
- return 10000+400*n
- def v(n):
- return 10000*1.025**n
- def seuil(u,v,debut):
- compteur=debut
- u_p,v_p=u(debut),v(debut)
- while u_p>=v_p:
- compteur+=1
- u_p=u(compteur)
- v_p=v(compteur)
- return u_p,v_p,compteur
utilisation :
- >>> seuil(u,v,0)
- (24800, 24933.4869861084, 37)
Fonctions de la variable réelle
Calculer une valeur approchée d’une solution d’une équation par balayage.
Cette méthode, classique, consiste, pour une fonction continue et monotone sur un intervalle [a ; b] dans lequel on sait trouver la solution de $f(x) = k$, à calculer $f(x)$, pour $x$ allant de a à b avec un pas de h, après avoir vérifié la croissance ou la décroissance de la fonction. Si f est croissante, « Tant Que » f(x) < k est vérifiée (On utilisera pour cela un While.), on calcule f(x). Dès que f(x) > k on arrête l’algorithme. Si f est décroissante, « Tant Que » f(x) > k est vérifiée, on calcule f(x). Dès que f(x) < k on arrête l’algorithme. On obtient un encadrement de longueur h de la solution
Il faut déterminer a et b, les bornes de l’intervalle dans lequel on va appliquer le balayage.
Fonction qui calcule cet encadrement, renvoyé dans un tuple, en fonction du nombre n de décimales souhaitées :
Cet algorithme détermine par balayage un encadrement de racine de 2 d’amplitude 10^(-n).
- def balayage(f,k,a,b,n):
- fa,fb=f(a),f(b)
- h=10**(-n)
- x=a
- if fa<fb:
- while f(x)<k:
- x=x+h
- else:
- while f(x)>k:
- x=x+h
- return (round(x-h,n),round(x,n))
Utilisation : Compiler le fichier puis dans la console :
- >> balayage(f,0,0,5,5)
- (1.41421, 1.41422)
Le round permet ici de corriger quelques erreurs d’affichage des flottants [1].
Il est à noter que cet algorithme est très long à donner une réponse si n>=9.
On peut donc chercher à l’optimiser, par exemple en utilisant une boucle for qui va faire la même chose que le programme précédent mais pour h allant de 10-1 à 10-n en réduisant l’intervalle [a ; b] à chaque boucle.
C’est beaucoup plus rapide, jusqu’à n=16 où ça bogue, parce que les flottants (décimaux) ne sont affichés qu’avec 16 chiffres après la virgule.
- def balayage2(f,k,a,b,n):
- fa,fb=f(a),f(b)
- for i in range(1,n+1):
- h=10**(-i)
- x=a
- if fa<fb:
- while f(x)<k:
- x=x+h
- else:
- while f(x)>k:
- x=x+h
- a=x-h
- return (round(x-h,n),round(x,n))
Croisement de deux variables catégorielles
À partir de deux listes représentant deux caractères d’individus, déterminer un sous-ensemble d’individus répondant à un critère (filtre, utilisation des ET, OU, NON).
Soit l’on se donne une telle liste soit on la génère aléatoirement, par exemple :
- from random import randint
- taille=[randint(160,190) for t in range(35)]
- distance_lycee=[randint(0,25) for d in range(35)]
- echantillon=[]
- for i in range(35):
- echantillon.append([taille[i],distance_lycee[i]])
On obtient par exemple :
- >>> echantillon
- [[165, 18], [180, 19], [174, 22], [181, 17], [184, 12], [180, 16], [172, 10], [169, 3],
- [168, 25], [183, 5], [181, 4], [188, 12], [188, 23], [179, 2], [160, 23], [181, 14],
- [183, 1], [170, 7], [172, 3], [182, 15], [161, 9], [167, 1], [164, 22], [189, 17],
- [173, 11], [181, 11], [164, 11], [168, 25], [163, 14], [165, 12], [188, 8], [183, 2],
- [174, 19], [188, 8], [179, 0]]
On peut alors déterminer différents sous-ensembles :
- >>> grands=[x for x in echantillon if x[0]>185]
- >>> grands
- [[188, 12], [188, 23], [189, 17], [188, 8], [188, 8]]
- >>> petits=[x for x in echantillon if x[0]<165]
- >>> petits
- [[160, 23], [161, 9], [164, 22], [164, 11], [163, 14]]
- >>> proches=[x for x in echantillon if x[1]<5]
- >>> proches
- [[169, 3], [181, 4], [179, 2], [183, 1], [172, 3], [167, 1], [183, 2], [179, 0]]
- >>> pas_trop_loin=[x for x in echantillon if x[1]>5 and x[1]<15]
- >>> pas_trop_loin
- [[184, 12], [172, 10], [188, 12], [181, 14], [170, 7], [161, 9], [173, 11], [181, 11],
- [164, 11], [163, 14], [165, 12], [188, 8], [188, 8]]
- >>> petits_ou_proches=[x for x in echantillon if x[0]<165 or x[1]<5]
- >>> petits_ou_proches
- [[169, 3], [181, 4], [179, 2], [160, 23], [183, 1], [172, 3], [161, 9], [167, 1],
- [164, 22], [164, 11], [163, 14], [183, 2], [179, 0]]
- >>> petits_ou_grands=[x for x in echantillon if not(165<x[0]<185)]
- >>> petits_ou_grands
- [[165, 18], [188, 12], [188, 23], [160, 23], [161, 9], [164, 22], [189, 17], [164, 11],
- [163, 14], [165, 12], [188, 8], [188, 8]]
Dresser le tableau croisé de deux variables catégorielles à partir du fichier des individus et calculer des fréquences conditionnelles ou marginales.
Sans le module Pandas
On peut partir de deux listes, ou d’une liste regroupant les deux listes, nous choisissons de générer cette liste aléatoirement dans le programme Python, en utilisant la méthode choice() pour tirer aléatoirement un élément d’une liste (ici dans les deux listes intitules), puis de traiter les données afin d’établir le tableau croisé :
- from random import choice
- def tableau_croise(intitules1,intitules2,n):
- echantillon=[]
- L1=len(intitules1)
- L2=len(intitules2)
- for i in range(n):
- echantillon.append([choice(intitules1),choice(intitules2)])
- a=[[0]*len(intitules2)]
- for i in range(L1-1):
- a+=[[0]*len(intitules2)]
- for k in range(n):
- i = intitules1.index(echantillon[k][0])
- j = intitules2.index(echantillon[k][1])
- a[i][j]+=1
- etiquettes=["Effectifs",intitules2[0],intitules2[1],intitules2[2],"Total"]
- ligne1=[intitules1[0],a[0][0],a[0][1],a[0][2],a[0][0]+a[0][1]+a[0][2]]
- ligne2=[intitules1[1],a[1][0],a[1][1],a[1][2],a[1][0]+a[1][1]+a[1][2]]
- ligne3=["Total",a[0][0]+a[1][0],a[0][1]+a[1][1],a[0][2]+a[1][2],n]
- tab=[etiquettes,ligne1,ligne2,ligne3]
- form="{0:15}{1:^10}{2:^10}{3:^10}{4:^10}" # ^ sert à centrer le texte. 10 est la largeur en nombre de caractères
- for val in tab:
- print(form.format(*val))
La méthode index() cherche un élément dans la liste et renvoie son index. En termes simples, la méthode index() trouve un élément donné dans une liste et renvoie sa position, ce qui nous permet de les compter et d’établir le tableau des effectifs.
A noter que l’on crée la matrice a=[0,0,...,0]...[0,0,...,0] avec :
- a=[[0]*len(intitules2)]
- for i in range(L1-1):
- a+=[[0]*len(intitules2)]
et non pas avec :
- a=[[0]*len(intitules2)]*len(intitules1)
Plutôt qu’un long discours l’explication est dans le code ci-dessous :
- >>> b=[[0,0,0],[0,0,0]]
- >>> b
- [[0, 0, 0], [0, 0, 0]]
- >>> b[1][2]=1
- >>> b
- [[0, 0, 0], [0, 0, 1]]
- >>> a=[[0]*3]*2
- >>> a
- [[0, 0, 0], [0, 0, 0]]
- >>> a[1][2]=1
- >>> a
- [[0, 0, 1], [0, 0, 1]]
Une petite mise en forme s’impose si l’on veut obtenir quelque chose de lisible (ceci n’a pas besoin d’être expliqué aux élèves, il s’agit de cosmétique ...).
Utilisation :
- >>> tableau_croise(["Célibataire","Marié"],["Collège","Lycée","Supérieur"],35)
- Effectifs Collège Lycée Supérieur Total
- Marié 4 9 9 22
- Célibataire 4 9 10 23
- Total 8 18 19 45
Pour obtenir les fréquences, on complète le code précédent avec :
- print("\n")
- etiquettes_f=["Fréquences",intitules2[0],intitules2[1],intitules2[2],"Total"]
- ligne1_f=[intitules1[0],round(a[0][0]/n,4),round(a[0][1]/n,4),round(a[0][2]/n,4),round((a[0][0]+a[0][1]+a[0][2])/n,4)]
- ligne2_f=[intitules1[1],round(a[1][0]/n,4),round(a[1][1]/n,4),round(a[1][2]/n,4),round((a[1][0]+a[1][1]+a[1][2])/n,4)]
- ligne3_f=["Total",round((a[0][0]+a[1][0])/n,4),round((a[0][1]+a[1][1])/n,4),round((a[0][2]+a[1][2])/n,4),1]
- tab_freq=[etiquettes_f,ligne1_f,ligne2_f,ligne3_f]
- for val in tab_freq:
- print(form.format(*val))
Pour obtenir :
- Fréquences Collège Lycée Supérieur Total
- Marié 0.0889 0.2 0.2 0.4889
- Célibataire 0.0889 0.2 0.2222 0.5111
- Total 0.1778 0.4 0.4222 1
On a alors dans les colonnes « Total » les fréquences marginales :
– 17,78% des individus ont un niveau Collège.
– 48,89% des individus sont Mariés.
Avec le module Pandas
Sinon, on peut traiter un fichier csv qui contient ces données avec le module pandas qui est une librairie Python spécialisée dans l’analyse des données. Pour ma part, je l’utilise dans Spyder, mais cela est un détail à régler de votre côté ... Un objet de type « data frame » permet de réaliser de nombreuses opérations de filtrage, prétraitements, etc., préalables à la modélisation statistique.
Dans Spyder, on crée un fichier Python :
- import pandas
- data=pandas.read_csv("statut_niveau.csv",sep="\t|,")
- pandas.options.display.max_rows = 10
qui ouvre un fichier statut_niveau.csv qui contient les données, le voici :
On vérifie dans la console :
- data
- Out[33]:
- Statut Niveau
- 0 Célibataire Collège
- 1 Célibataire Lycée
- 2 Célibataire Collège
- 3 Célibataire Supérieur
- 4 Marié Supérieur
- .. ... ...
- 52 Marié Lycée
- 53 Marié Supérieur
- 54 Marié Lycée
- 55 Célibataire Supérieur
- 56 Célibataire Collège
- [57 rows x 2 columns]
Et on demande le tableau croisé :
- pandas.crosstab(data["Statut"],data["Niveau"])
- Out[34]:
- Niveau Collège Lycée Supérieur
- Statut
- Célibataire 13 6 7
- Marié 10 11 10
Avec les totaux par ligne et par colonne :
- pandas.crosstab(data["Statut"],data["Niveau"], margins=True)
- Out[75]:
- Niveau Collège Lycée Supérieur All
- Statut
- Célibataire 13 6 7 26
- Marié 10 11 10 31
- All 23 17 17 57
On peut obtenir le tableau des fréquences conditionnelles selon le niveau :
- pandas.crosstab(data["Statut"],data["Niveau"],normalize="index", margins=True)
- Out[41]:
- Niveau Collège Lycée Supérieur
- Statut
- Célibataire 0.500000 0.230769 0.269231
- Marié 0.322581 0.354839 0.322581
- All 0.403509 0.298246 0.298246
On lit ainsi que :
– « 50% des individus Célibataires ont un niveau Collège. » (fréquence conditionnelle)
– « 35,48% des individus Mariés ont un niveau Lycée . » (fréquence conditionnelle)
– « 40,35% desindividus ont un niveau Collège » (fréquence marginale)
On peut obtenir le tableau des fréquences conditionnelles selon le Statut :
- pandas.crosstab(data["Statut"],data["Niveau"], Normalize="columns", margins=True)
- Out[79]:
- Niveau Collège Lycée Supérieur All
- Statut
- Célibataire 0.565217 0.352941 0.411765 0.45614
- Marié 0.434783 0.647059 0.588235 0.54386
On lit ainsi que :
– « 35,29% des individus ayant un niveau Lycée sont célibataires. » (fréquence conditionnelle)
– « 58,82% des individus ayant un niveau Supérieur sont mariés. » (fréquence conditionnelle)
– « 45,61% des individus sont célibataires. » (fréquence marginale)
Et enfin le tableau des fréquences :
- pandas.crosstab(data["Statut"],data["Niveau"],normalize="all")
- Out[43]:
- Niveau Collège Lycée Supérieur
- Statut
- Célibataire 0.228070 0.105263 0.122807
- Marié 0.175439 0.192982 0.175439
Avec les totaux :
- pandas.crosstab(data["Statut"],data["Niveau"],normalize="all",margins=True)
- Out[80]:
- Niveau Collège Lycée Supérieur All
- Statut
- Célibataire 0.228070 0.105263 0.122807 0.45614
- Marié 0.175439 0.192982 0.175439 0.54386
- All 0.403509 0.298246 0.298246 1.00000
Où l’on retrouve les fréquences marginales dans la colonne et la ligne « All ».
Si l’on s’intéresse à des données numériques assez nombreuses, il peut être intéressant de croiser ces données par classes d’intervalles, avec le fichier ci-dessous :
- import pandas
- data=pandas.read_csv("taille_distance.csv",sep="\t|,")
- pandas.options.display.max_rows = 10
On demande alors dans la console :
- pandas.crosstab(pandas.cut(data["taille"], bins = [160, 170,180,190,200], include_lowest=True),
- ... pandas.cut(data["dist lycée"],bins=[0,10,20,30], include_lowest=True))
- Out[53]:
- dist lycée (-0.001, 10.0] (10.0, 20.0] (20.0, 30.0]
- taille
- (159.999, 170.0] 38 32 17
- (170.0, 180.0] 27 29 12
- (180.0, 190.0] 30 22 17
- (190.0, 200.0] 23 18 9
Variables aléatoires
Simuler des échantillons de taille n d’une loi de Bernoulli à partir d’un générateur de nombres aléatoires entre 0 et 1.
Le module random est un module qui regroupe des fonctions permettant de simuler le hasard. Parmi ces fonctions, la fonction random() donne un flottant au hasard dans l’intervalle [0 ; 1[. Soit p la probabilité du succès d’une expérience de Bernoulli.
On peut ainsi simuler une épreuve de Bernoulli :
- def bernoulli(p):
- if random()<p:
- return(1)
- else:
- return(0)
Utilisation :
- >>> bernoulli(0.8)
- 1
On peut alors répéter cette expérience n fois :
- def echantillon(n,p):
- L=[bernoulli(p) for i in range(n)]
- return L
Utilisation :
- >>> echantillon(25,0.6)
- [1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1]
On peut alors calculer la fréquence du succès lors de N expériences d’un échantillon de taille n :
- def frequences(N,n,p):
- F=[sum(echantillon(n,p))/n for k in range(N)]
- return F
Utilisation :
- >>> frequences(500,100,0.7)
- [0.66, 0.65, 0.68, 0.8, 0.67, 0.71, 0.68, 0.6, 0.78, 0.72, 0.7, 0.68, 0.63, ...
Représenter par un histogramme ou par un nuage de points les fréquences observées des 1 dans N échantillons de taille n d’une loi de Bernoulli.
On peut illustrer graphiquement le résultat obtenu après avoir calculé la fréquence du succès lors de N expériences d’un échantillon de taille n (voir paragraphe précédent la fonction frequences(N,n,p) réutilisée ici) :
– par un histogramme :
- import matplotlib.pyplot as plt
- def histogramme(N,n,p):
- plt.grid()
- plt.hist(frequences(N,n,p),range=(p-0.25,p+0.25),edgecolor = 'grey')
- plt.xlabel("fréquences")
- plt.ylabel("effectifs")
- plt.title("histogramme")
- return plt.show()
Utilisation :
- >>> histogramme(1000,100,0.8)
– par un nuage de points :
- import matplotlib.pyplot as plt
- def nuage(N,n,p):
- plt.grid()
- plt.scatter(range(N),frequences(N,n,p),c="red",marker=".")
- plt.xlim([0,N])
- plt.ylim([0,1])
- return plt.show()
Utilisation :
- >>> nuage(2000,500,0.7)
Compter le nombre de valeurs situées dans un intervalle de la forme [p-ks ; p+ks] pour k∈1 ; 2 ; 3
Pour calculer l’écart-type :
- from math import sqrt
- def esperance(Liste):
- return sum(Liste)/len(Liste)
- def variance(Liste):
- E_X=esperance(Liste)
- N=len(Liste)
- varX = 0
- for i in range(N):
- varX += (Liste[i]-E_X)**2
- varX=varX/N
- return varX
- def ecarttype(Liste):
- return sqrt(variance(Liste))
Pour compter le nombre de valeurs situées dans un intervalle de la forme $[p-ks ; p+ks]$ pour $k\in\left\{1 ; 2 ; 3\right\}$ :
- def effectifs(F,p,k):
- s=ecarttype(F)
- a=p-k*s
- b=p+k*s
- i=0
- for x in F:
- if x>=a and x<=b:
- i=i+1
- return i
Utilisation :
- >>> effectifs(frequences(1000,100,0.7),0.7,1)
- 658
- >>> effectifs(frequences(1000,100,0.7),0.7,2)
- 961
- >>> effectifs(frequences(1000,100,0.7),0.7,3)
- 998
Et si l’on veut plutôt récupérer la fréquence de 1 dans ces intervalles :
- def pourcentages(F,N,p,k):
- s=ecarttype(F)
- a=p-k*s
- b=p+k*s
- i=0
- for x in F:
- if x>=a and x<=b:
- i=i+1
- return(100*i/N)
Utilisation (en utilisant la fonction fréquence vue deux paragraphes au-dessus) :
- >>> pourcentages(frequences(1000,100,0.7),1000,0.7,3)
- 99.7
- >>> pourcentages(frequences(1000,100,0.7),1000,0.7,2)
- 96.2
- >>> pourcentages(frequences(1000,100,0.7),1000,0.7,1)
- 68.5
On peut utiliser la fonction nuage(N,n,p) vue précédemment pour y rajouter les droites d’équations y =μ-kσ et y = μ +kσ pour illustrer cela :
- def nuage_ks(N,n,p,k):
- L=frequences(N,n,p)
- E_X=esperance(L)
- s=ecarttype(L)
- a=E_X-k*s
- b=E_X+k*s
- plt.plot([0,N],[a,a],"b-")
- plt.plot([0,N],[b,b],"b-")
- titre=("Nuage de points et droites d'équations y =μ-{0}σ et y = μ +{0}σ.".format(k,k))
- plt.suptitle(titre)
- nuage(N,n,p)
- return plt.show()
Utilisation :
- >>> nuage_ks(1000,100,0.7,2)
- Bernoulli
Bibliographie
- Les algorithmes et les scripts en Python pour la classe de Seconde (2019) ;
- Les algorithmes et les scripts en Python pour la spécialité Mathématique de Première générale (2019) ;
- Quelques précisions données par l’Inspection Générale concernant l’écriture des programmes Python au lycée.
- Algorithmique et programmation au cycle 4, Commentaires et recommandations du groupe Informatique de la CII Lycée
- Les articles sur Python dans MathémaTICE
- Parcours Magistère : Algorithmique/Programmation au Lycée : Python
- Représentation binaire des Nombres Réels
- Pandas : Python Data Analysis Library
- Introduction à Pandas
- Trafic de données avec Python-pandas
- Apprenez Pandas