Projet 05 : Tableau des fréquences et histogramme statistique en ASCII#
En analyse exploratoire des données (Exploratory Data Analysis - EDA), l'étude des distributions de variables qualitatives ou discrètes repose sur deux piliers fondamentaux : 1. Le tableau des fréquences : inventaire quantitatif des effectifs \(n_i\), des fréquences relatives \(f_i\) et des fréquences cumulées. 2. L'histogramme ou diagramme en bâtons : représentation graphique immédiate permettant de visualiser le mode, l'asymétrie et la dispersion de la distribution.
L'objectif de ce projet est de concevoir un moteur d'analyse descriptive complet en langage C capable de calculer ces indicateurs et de tracer des graphiques en barres verticaux et horizontaux directement dans la console texte.
1. Notions mathématiques et statistiques#
Soit une variable statistique discrète présentant \(K\) modalités distinctes \(M_1, M_2, \dots, M_K\) associées à des effectifs observés \(n_1, n_2, \dots, n_K\).
A. Effectif total (\(N\))#
La somme de tous les effectifs observés constitue la taille de l'échantillon : $\(N = \sum_{i=1}^K n_i\)$
B. Fréquence relative (\(f_i\))#
Proportion d'individus présentant la modalité \(M_i\) : $\(f_i = \frac{n_i}{N} \qquad (\text{avec } \sum_{i=1}^K f_i = 1 \text{ soit } 100\%)\)$
C. Fréquence cumulée croissante (\(F_i\))#
Proportion cumulée des individus jusqu'à la \(i\)-ème modalité : $\(F_i = \sum_{j=1}^i f_j\)$
D. Le Mode statistique#
La modalité \(M^*\) présentant l'effectif le plus élevé : $\(M^* = \arg\max_{i} (n_i)\)$
2. Le défi du rendu vertical dans un terminal texte#
Si tracer un diagramme à barres horizontal est trivial (une ligne de caractères # par modalité), le tracé d'un diagramme à barres vertical impose d'écrire de haut en bas :
1. Identifier la hauteur maximale \(H_{\max} = \max(n_i)\).
2. Pour chaque niveau de hauteur décroissant \(y\) de \(H_{\max}\) jusqu'à \(1\) :
- Afficher la graduation de l'axe vertical \(y\).
- Pour chaque modalité \(i\), si son effectif \(n_i \ge y\), afficher une barre #, sinon afficher un espace ' '.
- Revenir à la ligne \n.
3. Tracer l'axe horizontal inférieur et étiqueter les modalités.
3. Implémentation complète en langage C#
Voici le code source intégral respectant les normes C99 et modélisant proprement la distribution statistique :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_MODALITES 20
// Modèle d'une modalité statistique
typedef struct
{
char etiquette[16];
int effectif;
double frequence;
double frequence_cumulee;
} Modalite;
// Modèle de la série statistique
typedef struct
{
char titre[64];
Modalite elements[MAX_MODALITES];
int nb_modalites;
int effectif_total;
int effectif_max;
int index_mode;
} SerieStatistique;
// Initialise une série statistique et calcule l'ensemble des indicateurs
void CalculerStatistiques(SerieStatistique *s)
{
s->effectif_total = 0;
s->effectif_max = 0;
s->index_mode = 0;
// 1. Calcul du total et du maximum
for (int i = 0; i < s->nb_modalites; i++)
{
s->effectif_total += s->elements[i].effectif;
if (s->elements[i].effectif > s->effectif_max)
{
s->effectif_max = s->elements[i].effectif;
s->index_mode = i;
}
}
// 2. Calcul des fréquences relatives et cumulées
double cumul = 0.0;
for (int i = 0; i < s->nb_modalites; i++)
{
if (s->effectif_total > 0)
{
s->elements[i].frequence = (double)s->elements[i].effectif / s->effectif_total;
}
else
{
s->elements[i].frequence = 0.0;
}
cumul += s->elements[i].frequence;
s->elements[i].frequence_cumulee = cumul;
}
}
// Affiche le tableau des fréquences formatté
void AfficherTableauFrequences(const SerieStatistique *s)
{
printf("=======================================================================\n");
printf(" TABLEAU DES FREQUENCES : %s\n", s->titre);
printf("=======================================================================\n");
printf("%-12s | %-10s | %-14s | %-16s\n",
"Modalite", "Effectif", "Frequence (%)", "Freq. Cumulee (%)");
printf("-----------------------------------------------------------------------\n");
for (int i = 0; i < s->nb_modalites; i++)
{
const Modalite *m = &s->elements[i];
printf("%-12s | %10d | %12.2f %% | %14.2f %%\n",
m->etiquette,
m->effectif,
m->frequence * 100.0,
m->frequence_cumulee * 100.0);
}
printf("-----------------------------------------------------------------------\n");
printf("%-12s | %10d | %12.2f %% | %14.2f %%\n",
"TOTAL", s->effectif_total, 100.0, 100.0);
printf("=======================================================================\n");
printf(">> Mode de la distribution : '%s' avec %d observations.\n\n",
s->elements[s->index_mode].etiquette, s->effectif_max);
}
// Trace un diagramme horizontal simple
void TracerDiagrammeHorizontal(const SerieStatistique *s)
{
printf(">>> DIAGRAMME EN BATONS HORIZONTAL :\n\n");
for (int i = 0; i < s->nb_modalites; i++)
{
printf("%-10s | ", s->elements[i].etiquette);
// Affiche un pavé pour chaque observation
for (int b = 0; b < s->elements[i].effectif; b++)
{
putchar('#');
}
printf(" (%d)\n", s->elements[i].effectif);
}
printf("\n");
}
// Trace un histogramme vertical en ASCII
void TracerDiagrammeVertical(const SerieStatistique *s)
{
printf(">>> HISTOGRAMME VERTICAL EN ASCII :\n\n");
// Parcours descendant des niveaux d'effectif
for (int niveau = s->effectif_max; niveau >= 1; niveau--)
{
// Graduation de l'axe vertical Y
printf("%3d | ", niveau);
for (int i = 0; i < s->nb_modalites; i++)
{
if (s->elements[i].effectif >= niveau)
{
printf(" [###] ");
}
else
{
printf(" ");
}
}
printf("\n");
}
// Axe horizontal X
printf("----+");
for (int i = 0; i < s->nb_modalites; i++)
{
printf("---------");
}
printf("\n | ");
// Libellés des modalités
for (int i = 0; i < s->nb_modalites; i++)
{
printf(" %-7s ", s->elements[i].etiquette);
}
printf("\n\n");
}
int main(void)
{
// Exemple : Répartition des mentions d'un examen universitaire
SerieStatistique serie = {
.titre = "Mentions Examen Informatique L3",
.nb_modalites = 5,
.elements = {
{"Passable", 12, 0.0, 0.0},
{"Assez Bien", 18, 0.0, 0.0},
{"Bien", 14, 0.0, 0.0},
{"Tres Bien", 7, 0.0, 0.0},
{"Ajourne", 9, 0.0, 0.0}
}
};
// 1. Calculs
CalculerStatistiques(&serie);
// 2. Tableau descriptif
AfficherTableauFrequences(&serie);
// 3. Graphique horizontal
TracerDiagrammeHorizontal(&serie);
// 4. Graphique vertical
TracerDiagrammeVertical(&serie);
return EXIT_SUCCESS;
}
4. Discussion pédagogique et extensions#
- Échelonnage dynamique (Scaling) : Si l'effectif maximal atteint 10 000, l'affichage vertical direct de 10 000 lignes ferait défiler l'écran hors de vue. Dans une version avancée, on normalise la hauteur graphique sur une échelle fixe de 20 lignes : $\(h_i = \left\lfloor 20 \times \frac{n_i}{n_{\max}} \right\rfloor\)$
- Export CSV :
Le tableau des fréquences calculé peut être immédiatement sauvegardé dans un fichier
statistiques.csven utilisant les fonctions de la partie 7 (fprintf).
Commentaires