Savoir (re)créer, en Python, un algorithme faisant des choses basiques est une compétence qui sera évaluée à tous les bacs technologiques à partir de 2020. SofusPy est un outil intéressant pour aborder ces algorithmes.
Dans cet article, on utilise cette version de SofusPy qui comprend des exemples très proches du programme de sections technologiques et l’outil d’export automatique vers le pseudo-code lui aussi très proche du programme.
Deux notions sont à la base du programme de maths en section technologique : Les compteurs (variables à incrémenter) et les accumulateurs (variables auxquelles on ajoute d’autres variables). L’article leur consacre donc une grande place, ce qui facilite la suite (exemples au programme).
L’article est placé sous licence libre CC-by-SA
Algorithmique et programmation
Variables
Le programme vise à « consolider la notion de variable » par trois « capacités attendues » :
- utiliser un générateur de nombres aléatoires entre 0 et 1 pour simuler une loi de Bernoulli de paramètre p ;
- utiliser la notion de compteur ;
- utiliser le principe d’accumulateur pour calculer une somme, un produit.
Sur les fonctions, deux autres capacités sont mises en exergue :
- identifier les entrées et les sorties d’une fonction ;
- structurer un programme en ayant recours aux fonctions.
On va donc utiliser autant que possible le formalisme des fonctions de Python, même pour illustrer le fonctionnement des variables.
Bernoulli
Une variable aléatoire de Bernoulli est un nombre B dépendant du hasard et prenant la valeur 0 avec probabilité 1-p et la valeur 1 avec probabilité p. Or le générateur aléatoire de Python simule une variable aléatoire uniforme entre 0 et 1 qui peut prendre de façon équiprobable toutes les valeurs possibles entre 0 et 1. Une telle variable aléatoire entre 0 et 1 est calculée par une fonction Python notée random()
. Or l’événement random()<0.36
a pour probabilité 0,36 comme on peut le constater par exemple on calculant cette probabilité avec la calculatrice :
On admet que la probabilité de l’événement random()<p
est égale à p pour toute valeur de p entre 0 et 1, pas seulement pour p=0,36. Pour simuler X, il suffit donc de lui donner la valeur 1 si random()<p
et 0 sinon. Comme p est un paramètre, on va construire une fonction dépendant de p pour cela.
Ce qui permet de fabriquer la variable aléatoire avec le script suivant
- from random import *
- def B(p):
- if random() < p:
- X = 1
- else:
- X = 0
- return X
- print(B(0.36))
La dernière ligne ne fait pas partie de la fonction, elle en est un exemple d’utilisation dans le cas où p=0,36.
Repères historiques : Jakob Bernoulli a inventé la variable aléatoire qui porte son nom parce qu’une somme de telles variables suit une loi binomiale, dont Bernoulli avait besoin pour étudier la fluctuation d’échantillonnage. Ses travaux datent du début du 18e siècle. George Boole a eu vers le milieu du 19e siècle l’idée de représenter la valeur logique faux par un 0 et la valeur logique vrai par un 1, ce qui lui a permis de ramener des opérations logiques (par exemple et ou « and ») à des opérations algébriques (par exemple la multiplication).
Compteur
Un compteur est une variable destinée à être incrémentée, c’est-à-dire qu’on y ajoute 1, soit de façon systématique (alors il sert à calculer le nombre de passages dans la boucle), soit si un test réussit (et dans ce cas il sert à compter les succès).
Par exemple, on voudrait savoir combien de fois il faut lancer un dé pour avoir un 6. Pour cela on va utiliser l’expression randint(1,6)
qui donne un nombre pseudo-aléatoire valant 1, 2, 3, 4, 5 ou 6 avec équiprobabilité. Et une variable appelée compteur servira à compter le nombre de lancers.
On peut alors programmer la fonction T (les variables aléatoires mesurant un temps s’appellent souvent ainsi) avec notamment le bloc d’augmentation de 1 présent dans la partie sofus du menu maths :
Le clic sur le bouton éditeur donne alors le script suivant :
- import random
- def de():
- return random.randint(1, 6)
- def T():
- global compteur
- compteur = 0
- while de() != 6:
- compteur = compteur + 1
- return compteur
En tout cas on y apprend comment réaliser l’incrémentation du compteur :
- on évalue l’expression compteur+1 qui donne la nouvelle valeur à donner au compteur
- on injecte le résultat de l’évaluation dans la variable compteur ce qui effectue l’incrémentation pour de vrai.
Il y a aussi une autre syntaxe avec un signe d’addition immédiatement suivi d’un signe d’égalité (sans espace entre les deux) qui augmente d’une quantité suivant ce symbole ésotérique, ici 1. Le code compteur += 1
exprime peut-être mieux l’idée de comptage que le fait la version avec évaluation d’expression puis injection dans la variable.
Accumulateur
Additionner plusieurs termes
Un accumulateur (informatique) est une variable à laquelle on ajoute successivement des valeurs (pour obtenir leur somme) ou que l’on multiplie par des facteurs successifs (pour obtenir le produit).
Voici un schéma montrant, à gauche, un additionneur (en forme de V) et à droite, un accumulateur :
L’additionneur a deux entrées où l’on injecte les opérandes, et une sortie. L’accumulateur n’utilise qu’une seule des deux entrées, l’autre étant confondue [1] avec la sortie : C’est cette mémoire servant à la fois d’entrée et de sortie, qui sert d’accumulateur. Certaines calculatrices en possèdent une notée M et l’accumulation se fait par le bouton M+.
Par exemple si on veut additionner les nombres affichés par 24 dés, on les additionne un par un (pour k allant de 0 à 23) en mémorisant, au fur et à mesure, les sommes partielles dans l’accumulateur :
Finalement il ne s’agit de rien de plus que de généraliser le comptage, ici les quantités accumulées sont variables alors que dans l’onglet précédent elles valaient toutes 1 (ou 0 si échec). La syntaxe Python est donc très similaire à celle de l’onglet précédent (où a été définie la fonction dé) :
- def S24():
- accu = 0
- for k in range(0,24):
- accu = accu + de()
- return accu
Multiplier plusieurs facteurs
Un accumulateur peut aussi être multiplicatif, on le multiplie régulièrement par des facteurs pour qu’il accumule leur produit. Mais dans ce cas sa valeur initiale ne sera pas 0 mais 1 (ou le premier terme u0 d’une suite géométrique).
Par exemple un résultat bien connu des luthiers est que chaque espace entre deux frettes successives dépasse de 6 pourcents l’espace suivant [2]. Et qu’entre la 11e et la 12e frette l’espace est la moitié de l’espace entre la 1ère frette et le sillet de tête. Pour le vérifier avec SofusPy, on compare avec le nombre 2, le résultat de ce script :
Le script annonce 2,0121964718355505 qui n’est effectivement pas loin de 2.
La traduction en Python donnée par SofusPy montre comment on augmente de 6 pourcents :
- accmul = 1
- for k in range(0,12):
- accmul = accmul + accmul * 6/100
En mettant accmul en facteur dans l’expression de la ligne 3, on vérifie que ce script donne le même résultat :
La version Python est
- accmul = 1
- for k in range(0,12):
- accmul = accmul * 1.06
Dans le programme, dans la partie sur les automatismes, il est écrit que cette connaissance que seul Sophus (parmi les langages de programmation) possède, doit être un automatisme :
passer d’une formulation additive ( « augmenter de 5 % », respectivement « diminuer de 5 % » ) à une formulation multiplicative ( « multiplier par 1,05 », respectivement« multiplier par 0,95 » )
Listes
Les attendus du programme sont les suivants :
- générer une liste (en extension, par ajouts successifs, en compréhension) ;
- manipuler des éléments d’une liste (ajouter, supprimer ... ) et leurs indices ;
- itérer sur les éléments d’une liste.
En plus, d’autres attendus sont cités sur les fichiers :
- traiter un fichier contenant des données réelles pour en extraire de l’information et l’analyser ;
- réaliser un tableau croisé de données sur deux critères à partir de données brutes.
Génération
Pour comparer les approches, on va les utiliser sur un même problème : On souhaite avoir une liste des puissances de 2 depuis 1=20 jusqu’à 256=28
en extension
[1, 2, 4, 8, 16, 32, 64, 128, 256]
On constate que les listes sont notées entre crochets (en Python tout du moins) et que les éléments de la liste sont séparés par des virgules. Donc si on veut manipuler une liste de flottants, il faut utiliser (comme toujours en Python) le point décimal pour les écrire, et pas la virgule, puisque celle-ci est déjà utilisée pour séparer les éléments de la liste.
Ce procédé de fabrication d’une liste est appelé en extension, ne serait-ce que parce que ça prend de la place pour une liste qui contient beaucoup de nombres [5].
par ajouts successifs
Ajouter un élément (un nombre par exemple) à la fin d’une liste est possible si la liste est une variable [6]. On appelle L cette liste variable, et on l’initialise à la liste vide. On en profite pour créer une autre variable accmul qui servira à calculer les puissances de 2 par accumulation multiplicative :
- L = []
- accmul = 1
- for k in range(0,9):
- L.append(accmul)
- accmul = accmul * 2
On apprend donc que pour ajouter un élément à la fin de la liste L
il faut écrire L.append(element)
ce qui résume de facto un dialogue entre l’utilisateur et L :
- Hé, L !
- Oui ?
- Ajoute-toi un element s’il te plaît !
- OK
En effet append décrit en anglais l’opération d’accrocher une caravane derrière une voiture.
en compréhension
On peut décrire la liste voulue comme « la liste des puissances de 2 » ou « la liste des 2k pour k allant de 0 à 8 ». Cette dernière version se traduit en Python par l’expression suivante :
[2**k for k in range(0,9)]
Cette simplicité tend à faire préférer les listes en compréhension aux autres formalismes, d’autant que comme il s’agit de simples expressions à évaluer, on peut les afficher dans la console interactive :
Manipulation
Lecture
Un être humain sait, à l’œil nu, que la troisième puissance de 2 est 4, ça se lit sur la liste L de l’onglet ci-contre. Mais qu’en est-il de Python ?
Le bloc suivant
est traduit par SofusPy en l’expression L[2]
.
Pourquoi ? Parce que dans Blockly (ou Sofus) le premier élément d’une liste est le numéro 1 alors qu’en Python le premier élément d’une liste est le numéro 0. Cela induit un décalage auquel il faut systématiquement penser lorsqu’on programme en Python. Ceci dit, avec l’utilisation de range en 2nde, les élèves devraient être habitués à ce que Python, contrairement aux êtres humains, compte à partir de 0 et non de 1 [8].
Suppression
Le bloc suivant
se traduit en Python par l’instruction L.pop(2)
.
On comprend d’où vient le 2 au lieu du 3, mais pour le reste il faut peut-être des explications : « pop » est le bruit que fait un bouchon de champagne au moment où on le retire [9]. Pour l’explication de ce qui est avant le pop, voir l’onglet précédent (et remplacer « ajouter » par « enlever »).
Ajout
On a vu dans l’onglet précédent comment ajouter un élément à la fin de la liste. Si on veut insérer en 3e position, un 5, on utilise ce bloc
qui produit l’instruction Python L.insert(2, 5)
et transforme la liste L en
- [1, 2, 5, 4, 8, 16, 32, 64, 128, 256]
.
Itération
Dans la plupart des langages de programmation, pour afficher tous les éléments d’une liste L, on fait quelque chose comme ceci :
Version Python :
- for k in range(0,9):
- print(L[k])
En Python (comme dans certains autres langages) on peut aussi itérer directement sur les éléments de la liste (sans passer par leurs indices) ; ainsi la variante que voici produit le même effet :
Voici la traduction Python :
- for p in L:
- print(p)
En fait, les deux versions peuvent montrer leur utilité : La seconde est idéale s’il s’agit de trouver le minimum des éléments de la liste. La première est indispensable si on veut savoir où est le minimum (ou si on veut connaître les deux, la position et la valeur du minimum). Ceci dit, Python possède une fonction min(L)
qui évalue le minimum de la liste L.
Fichiers
Comme exemple, on a choisi les données du ministère de l’éducation nationale sur les écoles et collèges équipés en numérique. Les données ont été filtrées un peu pour ne garder que 3 colonnes :
- l’identifiant de l’école ou du collège
- le type d’établissement (école d’application, élémentaire, maternelle ou collège)
- l’académie abritant l’établissement
Le résultat se trouve dans le fichier que voici, au format csv :
On peut l’ouvrir avec un tableur mais aussi avec Python, grâce au module csv, dont on commence par importer les fonctions (surtout reader qui permet de lire le fichier csv en sachant que c’est un csv) :
- from csv import *
- outremer = ["","GUYANE","MARTINIQUE","MAYOTTE","LA REUNION","GUADELOUPE","POLYNESIE FRANCAISE"]
- ecm = ["Ecole maternelle"]+6*[0]
- eel = ["Ecole élémentaire"]+6*[0]
- eea = ["Ecole élémentaire d'application"]+6*[0]
- col = ["Collège"]+6*[0]
les listes définies avant même l’ouverture du fichier sont celles que l’on affichera dans le tableau croisé à la fin :
- la liste outremer comprend une entrée vide (la première cellule d’un tableau croisé l’est toujours) puis les noms des départements d’outremer.
- la liste ecm concerne les écoles maternelles : Elle commence par le nom « Ecole maternelle » puis des nombres actuellement nuls (chacune de ses cellules est en fait un compteur)
- la liste eel fait pareil pour les écoles élémentaires
- la liste eea fait pareil pour les écoles d’application
- la liste col correspond aux collèges (il n’y a pas d’autres catégories d’établissements numériques outre-mer, sauf le lycée de Saint-Pierre et Miquelon)
Comme il y a 6 académies d’outre-mer, on a rajouté 6 fois le nombre 0 dans chaque liste, avec le symbole d’addition qui ajoute le tableau de 0 à la liste comprenant le type de l’établissement scolaire.
Toute la suite s’effectue après l’instruction with qui garantit qu’on ne fait rien si l’ouverture du fichier échoue (par exemple si le fichier Python et le fichier csv ne sont pas dans le même dossier). L’objet tableau est un reader (un lecteur capable de lire le fichier en tenant compte du format « comma separated value » ; on précise quand même que c’est la virgule « comma » qui a été choisie comme séparateur). On peut ensuite itérer sur ce reader. Pour chaque ligne,
- on ne fait rien si le nom de l’académie n’est pas dans la liste outremer. Si on est bien en outremer,
- on boucle sur les indices k possibles entre 1 et 6 (ceux qui donnent une académie d’outremer) ; dans cette boucle,
- on ne fait rien si on est dans la mauvaise colonne. Si on est dans la bonne académie, on sait qu’elle est à l’indice k dans la liste des académies d’outremer, alors pour cette valeur de k :
- si l’établissement est une école maternelle alors on incrémente le compteur correspondant à l’académie d’indice k parmi les écoles maternelles ;
- idem pour les autres catégories d’établissements numériques possibles :
- with open("ecn.csv") as fichier:
- tableau = reader(fichier,delimiter=",")
- for ligne in tableau:
- if ligne[2] in outremer:
- for k in range(1,7):
- if ligne[2]==outremer[k]:
- if ligne[1]=="Ecole maternelle":
- ecm[k] += 1
- elif ligne[1]=="Ecole élémentaire":
- eel[k] += 1
- elif ligne[1]=="Ecole élémentaire d'application":
- eea[k] += 1
- else:
- col[k] += 1
- print(outremer)
- print(ecm)
- print(eel)
- print(eea)
- print(col)
Cela donne ce tableau croisé :
’’ | ’GUYANE’ | ’MARTINIQUE’ | ’MAYOTTE’ | ’LA REUNION’ | ’GUADELOUPE’ | ’POLYNESIE FRANCAISE’ |
’Ecole maternelle’ | 0 | 4 | 0 | 1 | 0 | 0 |
’Ecole élémentaire’ | 19 | 20 | 15 | 58 | 37 | 3 |
« Ecole élémentaire d’application » | 0 | 1 | 0 | 0 | 0 | 0 |
’Collège’ | 35 | 8 | 21 | 54 | 34 | 9 |
En voici la version csv pour faire une étude sur la numérisation des établissements scolaires en outremer, avec un tableur :
Première
Algorithmes
Suites
- Calculer un terme de rang donné d’une suite, une somme finie de termes.
- Déterminer une liste de termes d’une suite et les représenter.
- 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.
Fonctions
- Calculer une valeur approchée d’une solution d’une équation par balayage.
Statistiques et probabilités
- À 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).
- Dresser le tableau croisé de deux variables catégorielles à partir du fichier des individus et calculer des fréquences conditionnelles ou marginales.
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.
- 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.
- Compter le nombre de valeurs situées dans un intervalle de la forme [p-ks ;p+ks] pour k ∈
{1;2;3}
Suites
Calculer un terme de rang donné d’une suite, une somme finie de termes
Pour calculer un terme de rang donné d’une suite, l’algorithme dépend de la défintion (explicite ou récurrente) de la suite.
Par exemple, pour la suite arithmétique un=3n+2 de premier terme 2 et de raison 3, on peut définir la suite par une fonction de Python :
- def u(n):
- return 3 * n + 2
Et pour connaître le 6e terme de cette suite on fait u(5)
.
Si la suite est récurrente par contre il faut deux variables supplémentaires, un compteur k allant de 1 à n et un accumulateur. Par exemple avec la suite vn=1,5×1,1n de premier terme 1,5 et de raison 1,1 :
- def v(n):
- accmul = 1.5
- for k in range(1,n + 1):
- accmul = accmul * 1.1
- return accmul
et c’est l’expression v(5)
qui donne le 6e terme de cette suite .
Pour la somme de n termes de type uk on utilise comme d’habitude un accumulateur :
- def Somme_de_u(ntermes):
- accumulateur = 0
- for k in range(0,ntermes ):
- accumulateur = accumulateur + u(k)
- return accmul
Déterminer une liste de termes d’une suite et les représenter
Si la suite est explicite on privilégie la définition en compréhension :
[u(n) for n in range(20)]
voire
[3*n+2 for n in range(20)]
Pour une suite récurrente par contre on procède par ajouts successifs :
- L = []
- accmul = 1.5
- for k in range(20):
- L.append(accmul)
- accmul = accmul * 1.1
La version en compréhension peut aussi être utilisée si on a défini v(n) comme une fonction comme on l’a fait ci-dessus, mais le calcul sera plus long.
Pour représenter graphiquement une suite vn, on place dans un repère des points de coordonnées k et v(k). Il est d’usage de faire cela avec matplotlib (en lui fournissant la liste des indices et la liste extraite de la suite) mais on peut faire plus court, avec la calculatrice Numworks.
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
Sur le graphique ci-dessus il est évident que vk est toujours inférieur à uk. En fait il faut se méfier de ce genre d’évidence puisqu’un théorème d’algorithmique dit que si une suite géométrique est croissante, elle finira par dépasser n’importe quelle suite arithmétique. Pour savoir quand cela va arriver, on va une fois de plus utiliser un compteur, représentant le rang cherché, et on va lui faire compter le nombre de tests de comparaison entre vrang et urang :
- rang = 0
- while v(rang) < u(rang):
- rang = rang + 1
- print(rang)
Fonctions
Calculer une valeur approchée d’une solution d’une équation par balayage
La question évoquée dans la partie sur les accumulateurs multiplicatifs n’a pas encore trouvé de réponse : D’où viennent ces fameux 6 pourcents ?
En fait, pour des raisons psycho-acoustiques, le rapport entre les intervalles entre frettes doit être non seulement le même d’une case (entre deux frettes) à l’autre, mais doit valoir 2, toutes les 12 frettes. Cela est dû à ce que l’octave (rapport 2) est découpé en 12 demi-tons.
On cherche à trouver la raison r d’une suite géométrique vérifiant r12=2. On peut rapidement estimer cette raison par ces constatations :
- 112=1 donc r est supérieur à 1 ;
- 212=4096 donc r est largement inférieur à 2 ;
- 1,112≈3,138 donc r est quelque part entre 1 et 1,1.
D’ailleurs on a vu que r est assez proche de 1,06.
Pour calculer r à 0,001 près on va encore une fois utiliser un accumulateur, mais cette fois-ci on ne l’augmente que de 0,001 à chaque étape :
SofusPy traduit ce script en Python par un simple clic sur le bouton « éditeur » :
- accumulateur = 1
- while accumulateur ** 12 < 2:
- accumulateur = accumulateur + 0.001
- print(accumulateur)
L’exécution du script donne la valeur 1.06
qui correspond bien à la valeur connue des luthiers.
Et le clic sur le bouton « pseudocode » fournit le pseudocode que voici :
accumulateur ← 1
Tant que accumulateur ^ 12 < 2
accumulateur ← accumulateur + 0.001
Stats
À 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)
Voir la partie sur les fichiers dans l’introduction : On a une liste d’établissements scolaires dont la colonne 2 donne le type d’établissement et la colonne 3 donne l’académie où est situé l’établissement.
En appliquant la fonction list au reader, on convertit celui-ci en une liste, donc on peut extraire des sous-listes par compréhension. La difficulté supplémentaire est qu’on a alors une liste de listes. Pour atténuer cette difficulté on va itérer sur les éléments de la liste et non leurs indices.
- Si on veut connaître les écoles maternelles numériques, on fait
- from csv import *
- with open("ecn.csv") as fichier:
- T = list(reader(fichier,delimiter=","))
- print([L for L in T if L[1]=="Ecole maternelle"])
(on fait la liste des lignes L de T pour lesquelles le second élément est « Ecole maternelle »)
- Si on veut connaître les écoles maternelles de l’académie de Dijon, on fait
- from csv import *
- with open("ecn.csv") as fichier:
- T = list(reader(fichier,delimiter=","))
- print([L for L in T if L[1]=="Ecole maternelle" and L[2]=="DIJON"])
(la traduction de ET en Python est and)
- Si on veut connaître les écoles maternelles qui ne sont pas dans l’académie de Dijon, on fait
- from csv import *
- with open("ecn.csv") as fichier:
- T = list(reader(fichier,delimiter=","))
- print([L for L in T if L[1]=="Ecole maternelle" and not L[2]=="DIJON"])
(la traduction de NON en Python est not)
- Si on veut connaître les établissements scolaires qui sont des écoles maternelles ou qui sont en Martinique, on fait
- from csv import *
- with open("ecn.csv") as fichier:
- T = list(reader(fichier,delimiter=","))
- print([L for L in T if L[1]=="Ecole maternelle" or L[2]=="MARTINIQUE"])
(la traduction de OU en Python est or)
Dresser le tableau croisé de deux variables catégorielles à partir du fichier des individus et calculer des fréquences conditionnelles ou marginales
On a vu dans les capacités sur les fichiers comment a été établi le tableau croisé des établissements numériques en outremer.
Comme il y a 33 établissements en Martinique, dont 4 sont des écoles maternelles, la fréquence conditionnelle des écoles maternelles parmi les établissements martiniquais est 4/33 soit environ 12% alors que comme il y a au total 5 écoles maternelles numériques outremer, la fréquence conditionnelle des écoles martiniquaises parmi les écoles maternelle est 4/5 soit 80%. Python n’est pas vraiment nécessaire pour cette étape.
Pour calculer les fréquences marginales, on commence par calculer les totaux par ligne, et on les « appende » à la fin de chaque ligne. Pour cela on ajoute à la fin du script de la partie « capacités » les lignes suivantes :
- ecm.append(sum([ecm[k] for k in range(1,7)]))
- eel.append(sum([eel[k] for k in range(1,7)]))
- eea.append(sum([eea[k] for k in range(1,7)]))
- col.append(sum([col[k] for k in range(1,7)]))
académies | GUYANE | MARTINIQUE | MAYOTTE | LA REUNION | GUADELOUPE | POLYNESIE FRANCAISE | Total Etablissement |
Ecole maternelle | 0 | 4 | 0 | 1 | 0 | 0 | 5 |
Ecole élémentaire | 19 | 20 | 15 | 58 | 37 | 3 | 152 |
Ecole d’application | 0 | 1 | 0 | 0 | 0 | 0 | 1 |
Collège | 35 | 8 | 21 | 54 | 34 | 9 | 161 |
Total académie | 54 | 33 | 36 | 113 | 71 | 12 | 319 |
Le total des totaux est 319 et il suffit de modifier les lignes précédentes pour avoir les fréquences : On divise par 319 (et on multiplie par 100 pour avoir un pourcentage) :
- ecm.append(sum([ecm[k] for k in range(1,7)])/3.19)
- eel.append(sum([eel[k] for k in range(1,7)])/3.19)
- eea.append(sum([eea[k] for k in range(1,7)])/3.19)
- col.append(sum([col[k] for k in range(1,7)])/3.19)
On apprend alors que parmi les établissements scolaires numériques en outremer, il y a environ 1,6% qui sont des écoles maternelles, 47,6% qui sont des écoles élémentaires, 0,3% qui sont des écoles d’application et 50,5% qui sont des collèges.
Probas
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
On a vu en début d’article comment simuler une variable de Bernoulli de paramètre p. Pour cela on a défini une fonction B(p) et il suffit de l’utiliser dans une liste en compréhension pour avoir un échantillon de taille n :
- def ech(n,p):
- return [B(p) for k in range(n)]
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
Avec la Numworks, on définit une couleur bleue et un fait un comptage en considérant la liste L comme une liste de compteurs :
- def histo(N,n,p):
- L =[0]*(n+1)
- for k in range(N):
- ns = ech(n,p).count(1)
- L[ns] = L[ns] + 1
- for k in range(n+1):
- fill_rect(2*k,200-L[k],2,L[k],bleu)
Un appel à histo(1000,200,0.36)
donne ce genre d’affichage :
Compter le nombre de valeurs situées dans un intervalle de la forme [p-ks ;p+ks] pour k ∈ {1;2;3}
Pour compter le nombre de valeurs situées dans un intervalle, on utilise ... un compteur !
Pour compter les 1 dans les échantillons, on fait faire le travail par Python, avec
- L = [ech(80,0.36).count(1)/80 for k in range(200)]
- s = ecart_type(L)
On en a profité pour calculer l’écart-type s. Et on a fait une liste des fréquences de 1, pas des effectifs, puisque ce sont les fréquences qu’on va comparer avec les nombres p-ks et p+ks.
Le script suivant affiche les fréquences de succés (appartenance à l’intervalle souhaité) :
- accumulateur = 0
- for ns in L:
- if 0.36-2*s <= ns <= 0.36+2*s:
- accumulateur = accumulateur + 1
- print(accumulateur/200)
En remplaçant les 2 par des 1 ou des 3 on a la réponse.
Terminale
algorithmes
Suites
- Écrire en langage Python une fonction qui calcule la somme des n premiers carrés, des n premiers cubes ou des n premiers inverses ; établir le lien entre l’écriture de la somme à l’aide du symbole Σ, et les composantes de l’algorithme (initialisation, sortie de boucle, accumulateur, compteur).
Fonctions
- Intercaler entre deux points déjà construits un troisième point ayant pour abscisse (resp. pour ordonnée) la moyenne arithmétique (resp. géométrique) des abscisses (resp. des ordonnées) des deux points initiaux.
Séries statistiques à deux variables quantitatives
- Automatiser le calcul de Σi(yi-(axi+b))².
- Rechercher un couple (a,b) minimisant cette expression parmi un ensemble fini de couples proposés par les élèves ou générés par balayage, tirage aléatoire ...
Variables aléatoires discrètes finies
- Générer un triangle de Pascal de taille n donnée.
- Représenter par un diagramme en bâtons la loi de probabilité d’une loi binomiale (n,p). Faire le lien avec l’histogramme des fréquences observées des 1 lors de la simulation de N échantillons de taille n d’une loi de Bernoulli de paramètre p faite en classe de première.
- Calculer l’espérance Σxipi d’une variable aléatoire suivant une loi de probabilité donnée ; cas particulier d’une variable aléatoire suivant la loi binomiale B(n,p).
- Représenter graphiquement l’espérance de lois binomiales B(n,p) à p fixé et n variable, à n fixé et p variable puis faire le lien avec l’expression admise de l’espérance.
Suites
Écrire en langage Python une fonction qui calcule la somme des n premiers carrés, des n premiers cubes ou des n premiers inverses ; établir le lien entre l’écriture de la somme à l’aide du symbole Σ, et les composantes de l’algorithme (initialisation, sortie de boucle, accumulateur, compteur)
Somme des carrés
Pour additionner les termes d’une suite, on utilise un accumulateur. Et comme il s’agit d’une suite, on utilise un compteur k. Et ce sont les valeurs de k² qui vont être accumulées.
- def Sigma2(n):
- compteur = 1
- accumulateur = 0
- while compteur <= n:
- accumulateur = accumulateur + compteur ** 2
- compteur = compteur + 1
- return accumulateur
Une fonction d’argument entier naturel (n supposé non nul puisque 0²=0 et on ne change pas la somme en ajoutant 0) est en fait une suite. Elle possède d’ailleurs une expression explicite [11].
La notation Σ est classique pour désigner une expression obtenue en sommant d’autres expressions. Et il est d’usage (même en Python) lorsqu’il n’y a qu’un seul compteur, de l’appeler k. La notation complète implique le compteur (en bleu), son initialisation (en vert) et la condition de sortie de la boucle (en rouge) :
La lettre Σ désigne alors l’accumulateur, et le k² ce qu’on accumule.
Somme des cubes
Pas de grand changement, il suffit de remplacer l’exposant 2 par un exposant 3 :
- def Sigma3(n):
- k = 1
- S = 0
- while k <= n:
- S = S + 1 / k
- k = k + 1
- return S
Somme des inverses
- def H(n):
- compteur = 1
- accumulateur = 0
- while compteur <= n:
- accumulateur = accumulateur + 1 / compteur
- compteur = compteur + 1
- return accumulateur
Le nom Hn donné à cette fonction vient de ce que la suite s’appelle série harmonique. Leonhard Euler a étudié cette suite au 18e siècle et lui a trouvé une allure logarithmique.
Fonctions
Intercaler entre deux points déjà construits un troisième point ayant pour abscisse (resp. pour ordonnée) la moyenne arithmétique (resp. géométrique) des abscisses (resp. des ordonnées) des deux points initiaux
La moyenne arithmétique est en fait une fonction, qui, à deux nombres a et b, associe la moitié de leur somme. On peut donc faire comme en 2nde et programmer cette fonction en Python :
- from math import *
- def moyarith(a,b):
- return (a+b)/2
- def moygeom(a,b):
- return sqrt(a*b)
On en profite pour programmer aussi la fonction donnant la moyenne géométrique. En assimilant un point à une liste de deux nombres, la fonction insert de Python permet d’insérer le nouveau point, ou tout au moins de le calculer :
- def nouveau_point(A,B):
- return [moyarith(A[0],B[0]) , moygeom(A[1],B[1])]
Mais ici on fait le choix de ne pas considérer deux points mais une liste de deux abscisses et une liste de deux ordonnées. La fonction Python va insérer la moyenne arithmétique dans la liste X des abscisses et la moyenne géométrique dans la liste des ordonnées :
- def insertion(X,Y):
- X.insert(1,moyarith(X[0],X[1]))
- Y.insert(1,moygeom(Y[0],Y[1]))
Avec
- X = [0,1]
- Y = [1,2]
au départ, on obtient après l’exécution de cette fonction
- X == [0,0.5,1]
- Y == [1,1.41421356237,2]
On gagne deux choses avec ce point de vue :
- On peut représenter graphiquement les deux listes X et Y dans matplotlib.pyplot ;
- On peut recommencer à insérer des points de ce genre dans les listes X et Y ce qui améliore la qualité de la représentation, et laisse voir qu’on définit ainsi une fonction :
- def insertion(X,Y):
- k = 0
- while k<len(X)-1:
- X.insert(k+1,moyarith(X[k],X[k+1]))
- Y.insert(k+1,moygeom(Y[k],Y[k+1]))
- k = k+2
Avec from matplotlib.pyplot import *
les deux lignes
- plot(X,Y)
- show()
donnent ce graphique :
qui représente la fonction 2x.
Remarque : Avec 10 à la place de 2 dans la liste Y au début, John Napier a créé au début du 17e siècle d’une manière similaire la fonction 10x et l’a inversée pour obtenir le logarithme décimal.
Stats
Automatiser le calcul de Σi(yi-(axi+b))²
Bien entendu, où il y a une somme, il y a un accumulateur. Pour faire un peu plus court on va l’appeler S.
- def somme2(a, b):
- S = 0
- for k in range(0,4):
- S = S + (Y[k] - (a * X[k] + b)) ** 2
- return S
On va chercher à minimiser cette fonction avec les listes suivantes :
- X = [2, 5, 13, 34]
- Y = [1, 3, 8, 21]
Rechercher un couple (a,b) minimisant cette expression parmi un ensemble fini de couples proposés par les élèves ou générés par balayage, tirage aléatoire ...
On va engendrer des couples (ar,br) au hasard et ne garder que ceux qui ont donné une valeur de m plus petite que la valeur actuelle (m est l’image de (ar,br) par la fonction précédente) Ceci revient à utiliser pour m une sort d’accumulateur mais au lieu de l’addition ou la multiplication, on prend l’opération qui à deux nombres, associe le plus petit des deux.
- am = 0
- bm = 0
- m = somme2(am, bm)
- for compteur in range(0,10001):
- (ar,br) = (random(),random())
- if somme2(ar, br) < m:
- m = somme2(ar, br)
- am = ar
- bm = br
Il faut de nombreuses itérations pour stabilisation de l’algorithme mais on peut tenter de deviner (ou lire graphiquement) les coordonnées optimales.
Probas
Générer un triangle de Pascal de taille n donnée
On va faire une liste de listes : Chacune de ces listes représente une ligne du triangle de Pascal. On initialise cette liste avec la liste correspondant à la première ligne du triangle de Pascal, à la ligne 1 (on rajoute un 0 à la fin de chaque ligne pour simplifier un peu le code Python) : Il y a une seule manière de choisir 0 élément parmi 0, et aucune manière de choisir 1 élément parmi 0. La ligne 3 est la boucle sur les lignes du tableau :
- def coeff_binomiaux(n):
- triangle = [[1,0]]
- for k in range(1,n+1):
- triangle.append([1]+(k+1)*[0])
- for j in range(1,k+1):
- triangle[k][j]=triangle[k-1][j]+triangle[k-1][j-1]
- return triangle
À la ligne 4 on crée une ligne du triangle de Pascal, remplie de 0 ou presque (le premier coefficient est le nombre de manières de choisir rien parmi n, c’est 1). La ligne 5 est une boucle sur l’élément de la ligne que l’on construit, par la relation de Pascal qui est à la ligne 6.
Représenter par un diagramme en bâtons la loi de probabilité d’une loi binomiale (n,p). Faire le lien avec l’histogramme des fréquences observées des 1 lors de la simulation de N échantillons de taille n d’une loi de Bernoulli de paramètre p faite en classe de première
Pour dessiner, rien de mieux que la calculatrice. Sauf qu’il faut reprogrammer l’algorithme de calcul de la loi binomiale pour éviter la saturation de la mémoire de la calculatrice :
Le résultat est à comparer avec l’« histogramme » vu en 1ère (onglet variables aléatoires) :
Calculer l’espérance Σxipi d’une variable aléatoire suivant une loi de probabilité donnée ; cas particulier d’une variable aléatoire suivant la loi binomiale B(n,p)
Pour calculer l’espérance, à partir de la loi (donnée sous forme d’une liste), on utilise un accumulateur dans lequel on va sommer les produits du compteur k par la probabilité que X=k :
- def E(loi):
- accumulateur = 0
- for k in range(len(loi)):
- accumulateur = accumulateur + k*loi[k]
- return accumulateur
Représenter graphiquement l’espérance de lois binomiales B(n,p) à p fixé et n variable, à n fixé et p variable puis faire le lien avec l’expression admise de l’espérance
Une fois importées les fonctions de matplotlib.pyplot on peut créer deux listes X (les valeurs de n) et Y (les valeurs de l’espérance pour n et 0,36) pui les dessiner :
- X = [n for n in range(2,200)]
- Y = [E([B(n,0.36,k) for k in range(n+1)]) for n in range(2,200)]
- plot(X,Y)
- show()
qui donne ce graphique montrant que l’espérance est proportionnelle à p :
Et la version suivante :
- X = [P for P in range(100)]
- Y = [E([B(40,P/100.,k) for k in range(41)]) for P in range(100)]
donne ce graphique (pour n=40) montrant que l’espérance est également proportionnelle à p :