Présentation des outils de statistiques de Mapytex
=================================================

La partie statistique de Mapytex est un module python qui permet generer des données statistiques et de les analyser pour un niveau collège - début de lycée.

Analyse des données
-------------------

La gestion des données statistiques se fait à travers 2 classes: *Dataset* (ensemble de données) et *WeightedDataset* (ensemble de données pondérées).

    .. code-block:: python

        >>> from pytmath import Dataset, WeightedDataset
        >>> d = Dataset([1, 3, 4, 2, 4, 1], data_name = "Points")
        >>> print(d)
        [1, 3, 4, 2, 4, 1] 
        >>> w = WeightedDataset({1:3, 2:4, 3:5}, data_name = "Nombre de frères", weight_name = "Effectifs" )
        >>> print(w)
        {1:3, 2:4, 3:5}

Le passage du *Dataset* à *WeightedDataset* revient à compter les effectifs de chaque classe (il n'est pas encore possible de définir des classes sous forme d'intervals).

    .. code-block:: python
        
        >>> W = WeightedDataset(d)
        >>> print(W)
        {1: 2, 2: 1, 3: 1, 4: 2}

Une fois les données définies, on peut calculer les indicateurs statistiques suivants:

- L'effectif total (ou la pondération totale):

    .. code-block:: python

        >>> d.effectif_total()
        6
        >>> w.effectif_total()
        12

- La somme:

    .. code-block:: python

        >>> d.sum()
        15
        >>> w.sum() #/!\ c'est une somme pondérée
        26

- La moyenne:

    .. code-block:: python

        >>> d.mean()
        2.5
        >>> w.mean()
        2.17

- La variance et l'écart-type (sd):

    .. code-block:: python

        >>> d.variance()
        1.58
        >>> d.sd()
        1.26
        >>> w.variance()
        0.64
        >>> w.sd()
        0.8

- Les quartiles et les valeurs extrèmes:

    .. code-block:: python

        >>> max(d)
        4
        >>> d.quartiles() #(min, Q1, Me, Q3, Max)
        (1, 3, 3, 4, 4)
        >>> d.quartile(1) # Q1
        3
        >>> min(w)
        1
        >>> w.quartiles() #(min, Q1, Me, Q3, Max)
        (1, 1.5, 2, 3, 3)
        >>> w.quartile(2) #Me
        2

Enfin une fonction rudimentaire a été ajouté pour présenter ces données dans un tableau formaté pour Latex

    .. code-block:: python

        >>> print(d.tabular_latex())
        \begin{tabular}{|c|*{6}{c|}} 
                \hline 
        1 & 3 & 4 & 2 & 4 & 1 \\ 
        \hline 
        \end{tabular}
        >>> print(w.tabular_latex())
        \begin{tabular}{|c|*{3}{c|}} 
            \hline 
            Nombre de frères & 1 & 2 & 3 \\ 
            \hline 
            Effectifs & 3 & 4 & 5 \\ 
            \hline 
        \end{tabular}

Générer des données aléatoirement
---------------------------------

Ce module permet aussi de créer aléatoirement des données à travers la méthode *random* de *Dataset*.

    .. code-block:: python

        >>> Dataset.random(10)
        [-0.14, 0.3, -0.55, 1.02, -2.02, -1.17, 1.47, 1.22, -1.38, 0.02]

Par défaut, les données sont générées suivant une loi normale de paramètres 0, 1 et les valeurs sont arrondis à deux chiffres après la virgule. 

Ces paramètres sont modifiables pour avoir une gestion plus fine des données souhaitées.

Distribution des données
^^^^^^^^^^^^^^^^^^^^^^^^

La méthode random accepte deux arguments pour gérer la création de données:

- *distrib*: cet argument peut avoir deux formes. Soit c'est la fonction qui genèrera des données soit c'est un élément de la liste ["gauss", "uniform", "randint", "choice"] qui fera directement appel aux fonctions correspondantes du module *random* intégré dans python.

- rd_args: Ce sont les arguments à faire passer à *distrib*.

  .. code-block:: python
    
        >>> Dataset.random(10, distrib = "uniform", rd_args = (20, 30)) # des données uniformes entre 20 et 30
        [23.2, 25.84, 28.97, 24.38, 20.07, 24.57, 28.54, 26.73, 20.36, 22.03]
        >>> Dataset.random(10, distrib = "choice", rd_args = [[10, 50, 100]]) # Tirage aléatoire entre 10, 50 et 100
        [100, 10, 10, 50, 50, 50, 10, 100, 50, 100]
        >>> toujours_un = lambda *args:1 #un fonction qui renvoie toujours 1
        >>> Dataset.random(10, distrib = toujours_un) # Génère des données pas très aléatoire ici...
        [1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
        >>> from random import expovariate
        >>> Dataset.random(10, distrib=expovariate, rd_args=[2])
        [0.75, 0.0, 0.21, 0.12, 0.23, 0.38, 0.53, 0.22, 0.15, 0.67]

Formatage des données
^^^^^^^^^^^^^^^^^^^^^

Il est possible de gérer le formatage des données crées par la fonction de distribution avec la méthode *nbr_format*. Ce doit être une fonction.

Par défaut cette fonction, arrondis tous les nombres au centième.

    .. code-block:: python

        >>> Dataset.random(10, nbr_format = int) # Tous les nombres devront être des entiers.
        [1, 0, 0, 0, -1, 1, -2, -1, 0, 0]
        >>> Dataset.random(3, nbr_format = lambda x : 10*x+100) # Tous les nombres générés sont multipliés par 10 et augmenter de 100.
        [83.25478349417327, 87.48915747851468, 109.2031945412872]
        >>> Dataset.random(10, distrib="choice", rd_args=["LOTERIE"], nbr_format=str) # Tirage aléatoire des lettres du mot LOTERIE
        ['E', 'E', 'O', 'T', 'T', 'T', 'L', 'E', 'I', 'I']

Restrindre les données
^^^^^^^^^^^^^^^^^^^^^^

On peut vouloir (en particulier pour une distribution normale - gaussienne) que les valeurs générées soient comprises entre deux nombres. Deux arguments gèrent la valeur maximale et minimale: *v_min* et *v_max*.

    .. code-block:: python

        >>> Dataset.random(10, v_min = 0)
        [2.31, 0.6, 1.21, 0.86, 0.1, 0.09, 0.86, 0.85, 0.59, 0.22]

Contrôle de la moyenne
^^^^^^^^^^^^^^^^^^^^^^

Il est possible de contrôler la moyenne des données générées grâce à l'argument *exact_mean*:

    .. code-block:: python

        >>> d = Dataset.random(10)
        >>> d.mean()
        -0.29
        >>> d = Dataset.random(10, exact_mean = 0)
        >>> d
        [-1.55, 1.07, 0.54, -1.79, -0.8, -0.18, 0.85, 1.33, -0.93, 1.46]
        >>> d.mean()
        0
        >>> d = Dataset.random(10, exact_mean = 10) 
        >>> d # On remarque que la dernière valeur n'est plus générée par une N(0,1)
        [-0.07, 0.93, 0.05, -1.05, 2.34, 0.27, 0.96, -0.9, 0.02, 97.45]
        >>> d.mean()
        10