05 - Tableau des fréquences et histogramme statistique en ASCII

@joekakone

Joseph Konka @joekakone

03/03/2026 · 14 min

Construisez un analyseur statistique complet en langage C. Calculez les effectifs, les fréquences relatives, les cumuls et générez des histogrammes verticaux et horizontaux en ASCII art.

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.

Niveau y
  15 |        #
  14 |        #
  12 |  #     #
   9 |  #  #  #
   7 |  #  #  #  #
     +--------------
        A  B  C  D

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.csv en utilisant les fonctions de la partie 7 (fprintf).

Commentaires

Inscrivez-vous à une formation complète

Voir le catalogue