diff --git a/pymath/__init__.py b/pymath/__init__.py index 57f60d2..f4effb6 100644 --- a/pymath/__init__.py +++ b/pymath/__init__.py @@ -2,7 +2,7 @@ # encoding: utf-8 from .calculus import Expression, Polynom, Fraction, random_str - +from .stat import Dataset # ----------------------------- # Reglages pour 'vim' diff --git a/pymath/stat/__init__.py b/pymath/stat/__init__.py new file mode 100644 index 0000000..9573133 --- /dev/null +++ b/pymath/stat/__init__.py @@ -0,0 +1,9 @@ +#!/usr/bin/env python +# encoding: utf-8 + +from .dataset import Dataset + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del diff --git a/pymath/stat/dataset.py b/pymath/stat/dataset.py new file mode 100644 index 0000000..8ca0fff --- /dev/null +++ b/pymath/stat/dataset.py @@ -0,0 +1,276 @@ +#/usr/bin/env python +# -*- coding:Utf-8 -*- + +# +# +# Ensemble de fonction rendant beaucoup plus pratique la résolution et l'élaboration des exercices de stat au lycée +# +# + +from math import sqrt, cos, ceil + +class Dataset(): + """ Classe réprésentant un série statistique avec rendu latex """ + + def __init__(self, data = [], data_name = "Valeurs"): + """ + Create a numeric data set + + :param data: values of the data set + :param data_name: name of the data set + """ + self.data = list(data) + + self.data_name = data_name + + def add_data(self, data): + """Add datas to the data set + + :param data: datas + """ + try: + self.data += data + except TypeError: + self.data += [data] + + def sort(self, *args, **kwrds): + """ Apply sort to data """ + self.data.sort(*args, **kwrds) + + def __len__(self): + return len(self.data) + + def sum(self): + return sum(self.data) + + def mean(self): + return self.sum()/len(self) + + def deviation(self): + """ Compute the deviation (not normalized) """ + mean = self.mean() + return sum([(x - mean)**2 for x in self.data]) + + def variance(self): + return self.deviation()/len(self.data) + + def sd(self): + """ Compute the standard deviation """ + return sqrt(self.variance()) + + def quartiles(self): + """ + Compute quartiles + + :return: (min, Q1, Me, Q3, Max) + """ + return (min(self.data) , self.quartile(1) , self.quartile(2) , self.quartile(3), max(self.data)) + + def quartile(self, quartile = 1): + """ + Calcul un quartile de la série. + + :param quartile: quartile à calculer (par defaut 1 -> Q1) + + :return: le quartile demandé + + : Example: + + >>> s = Dataset([2, 3, 4, 5, 6, 6, 6, 7]) + >>> + + """ + position = self.posi_quartile(quartile)[0] + # À vérifier... + return self.data[position] + + + def posi_quartile(self, quartile = 1): + """ + Calcul la position du quartile + + :param quartile: le quartile concerné + + :return : la position du quartile (arondis à l'entier suppérieur, non arrondis) + """ + return (ceil(quartile * self.effectif_total / 4), (quartile * self.effectif_total / 4)) + + + # -------------------------- + # Rendu latex + + def moyenne_latex(self, val_cara = "x", eff_cara = "n", end_cara = "p", moy_cara= "\\bar{x}"): + """ + Renvoie le code latex pour afficher le calcul de la moyenne + + :param val_cara: caractère représentant les valeurs (x par défaut) + :param eff_cara: caractère représentant les effectifs (n par défaut) + :param end_cara: caractère représentant le nombre de valeurs (p par défaut) + :param moy_cara: nom de la moyenne (\\bar{x} par défaut) + + :return: le code latex pour afficher le calcul de la moyenne + """ + moy = self.moyenne() + latex = moy_cara + " &=& " + latex += "\\frac{{{x}_1 \\times {n}_1 + {x}_2 \\times {n}_2 + ... + {x}_{p} \\times {n}_{p}}}{{{n}_1 + {n}_2 + ... + {n}_p}} \\\\ \n".format(x = val_cara, n=eff_cara, p = end_cara) + latex += "\t &=& \\frac{" + for (i,v) in enumerate(self.valeurs): + latex += "{x:.2f} \\times {p:.2f} + ".format(x = v, p = self.effectifs[i]) + latex = latex[:-2] # on enlève le + et l'espace de fin de calcul + latex += "}}{{{eff_tot}}}\\\\ \n".format(eff_tot = self.effectif_total) + latex += "\t &=& {moy:.2f}".format(moy=moy) + + return latex + + def variance_latex(self, val_cara = "x", eff_cara = "n", end_cara = "p", moy_cara= "\\bar{x}", var_cara = "V"): + """ + Renvoie le code latex pour afficher le calcul de la moyenne + + :param val_cara: caractère représentant les valeurs (x par défaut) + :param eff_cara: caractère représentant les effectifs (n par défaut) + :param end_cara: caractère représentant le nombre de valeurs (p par défaut) + :param moy_cara: nom de la moyenne (\\bar{x} par défaut) + :param var_var: nom de la variance (V par défaut) + + :return: le code latex pour afficher le calcul de la moyenne + """ + moy = self.moyenne() + var = self.variance() + + latex = var_cara + " &=& " + latex += "\\frac{{ {n}_1 ({x}_1 - {moy})^2 + {n}_2 ({x}_2 - {moy})^2 + ... + {n}_{p} ({x}_{p} - {moy})^2}}{{{n}_1 + {n}_2 + ... + {n}_p}}\\\\ \n".format(x = val_cara, n=eff_cara, p = end_cara, moy = moy_cara) + latex += "\t &=& \\frac{ " + for (i,v) in enumerate(self.valeurs): + latex += "{p:.2f} ({x:.2f} - {moy:.2f})**2 + ".format(p = self.effectifs[i], x = v, moy = moy) + latex = latex[:-2] # on enlève le + et l'espace de fin de calcul + latex += "}}{{{eff_tot}}}\\\\ \n".format(eff_tot = self.effectif_total) + latex += "\t &=& {var:.2f}".format(var = var) + + return latex + + def ecart_type_latex(self, val_cara = "x", eff_cara = "n", end_cara = "p", moy_cara= "\\bar{x}", var_cara = "V", ecar_cara = "\\sigma"): + """ + Renvoie le code latex pour afficher le calcul de la moyenne + + :param val_cara: caractère représentant les valeurs (x par défaut) + :param eff_cara: caractère représentant les effectifs (n par défaut) + :param end_cara: caractère représentant le nombre de valeurs (p par défaut) + :param moy_cara: nom de la moyenne (\\bar{x} par défaut) + :param var_var: nom de la variance (V par défaut) + :param ecar_var: nom de la variance (V par défaut) + + :return: le code latex pour afficher le calcul de la moyenne + """ + ecart = self.ecart_type() + + # On récupère le calcul de la variance + latex = self.variance_latex(val_cara, eff_cara, end_cara, moy_cara, var_cara) + latex += "\n\n" + + # On y ajoute celui de l'écart-type (ya un soucis ici à cause du conflit entre format et { + latex += "{ecar_cara} &=& \\sqrt{{{var_cara}}} \\\\ \n".format(ecar_cara = ecar_cara, var_cara = var_cara) + latex += "\t &=& {ecart:.2f}".format(ecart = ecart) + + return latex + + def quartiles_latex(self): + """ Renvoie le code latex pour afficher le calcul des quartiles + + :return : le code latex pour afficher le calcul des quartiles + """ + latex = self.quartile_latex() + latex += self.quartile_latex(1) + latex += self.quartile_latex(3) + + return latex + + def quartile_latex(self, quartile = 2): + """ Renvoie le code latex pour afficher le calcul du quartile + + :param quartile: numéro du quartile + + :return : le code latex pour afficher le calcul du quartile + """ + if quartile == 2 : # médiane + quartile_tpl = """ Position de la médiane: $\\dfrac{{\\mbox{{effectif total}}}}{{2}} = \\dfrac{{{eff_tot}}}{{2}} = {posi_q}$. Donc la médiane se trouve à la position: {posi_q_ceil}. + +On a ainsi $Me = {val_q}$ + """ + else: + quartile_tpl = """ Position de $Q_{q}$: $\\dfrac{{{q} \\times \\mbox{{effectif total}}}}{{4}} = \\dfrac{{{q} \\times {eff_tot}}}{{4}} = {posi_q}$. Donc $Q_{q}$ se trouve à la position: {posi_q_ceil}. + +On a ainsi $Q_{q} = {val_q}$ + """ + posi_q_ceil , posi_q = self.posi_quartile(quartile) + val_q = self.quartile(quartile) + + latex = quartile_tpl.format(eff_tot = self.effectif_total, q = quartile, posi_q = posi_q, posi_q_ceil = posi_q_ceil, val_q = val_q) + + return latex + + def tabular_latex(self, nbr_lines = 1): + """ Renvoie le code latex pour afficher le tableau + + :return : le code latex pour afficher le tableau + """ + d_per_line = len(self) // nbr_lines + d_last_line = len(self) % d_per_line + splited_data = [self.data[x:x+d_per_line] for x in range(0, len(self.data), d_per_line)] + # On ajoute les éléments manquant pour la dernière line + if d_last_line: + splited_data[-1] += [' ']*(d_per_line - d_last_line) + + # Construction du tableau + latex = "\\begin{{center}} \n \t \\begin{{tabular}}{{|c|*{{{nbr_col}}}{{c|}}}} \n".format(nbr_col = d_per_line) + latex += "\t\t \hline \n" + + d_lines = [' & '.join(map(str,l)) for l in splited_data] + latex += " \\\\ \n \\hline \n".join(d_lines) + + latex += " \\\\ \n \\hline \n" + latex += "\t \\end{tabular} \n \\end{center}" + + return latex + +if __name__ == '__main__': + valeurs = [65, 75, 85, 95, 105, 115, 125, 135] + valeurs.sort() + print(valeurs) + effectifs = [ 15, 2, 21, 24, 12, 9, 5, 2] + + + s = Dataset() + + s.set_values(valeurs, effectifs) + print(s.effectif_total) + + print(s.valeurs) + print(s.effectifs) + print(s.data) + + # print(s.tabular_latex()) + + # print("Moyenne ", s.moyenne()) + # print(s.variance()) + # print(s.ecart_type()) + + print("\n-----------------------\n") + print(s.moyenne_latex()) + print("\n-----------------------\n") + print(s.variance_latex()) + print("\n-----------------------\n") + print(s.ecart_type_latex()) + + # print(s.quartiles()) + print("\n-----------------------\n") + print(s.quartile_latex()) + print(s.quartile_latex(1)) + print(s.quartile_latex(3)) + + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del + diff --git a/pymath/stat/weightedDataset.py b/pymath/stat/weightedDataset.py new file mode 100644 index 0000000..c2d00fe --- /dev/null +++ b/pymath/stat/weightedDataset.py @@ -0,0 +1,319 @@ +#/usr/bin/env python +# -*- coding:Utf-8 -*- + +# +# +# Ensemble de fonction rendant beaucoup plus pratique la résolution et l'élaboration des exercices de stat au lycée +# +# + +from math import sqrt, cos, ceil + +class Serie(): + """ Classe réprésentant un série statistique avec rendu latex """ + + def __init__(self, valeurs = None, val_name = "Valeurs", effectifs = None, eff_name = "Effectifs", random = 0): + """ + Initialisation de la série statistique + Les paramètres sont optionnels ils pourront être ajouté après la création de la série + + :param valeurs: valeurs de la série statistique + :param val_name: nom pour les "valeurs" + :param effectifs: effectifs de chaque + :param eff_name: nom pour les "effectifs" + :param random: taille de série si elle doit être initialisé aléatoirement (uniformement sur [0,1] + """ + self.set_serie = False + if valeurs: + self.set_values(valeurs, effectifs) + + self.val_name = val_name + self.eff_name = eff_name + + def set_values(self, valeurs, effectifs = None): + """ + Effecte les valeurs de la série statistique + /!\ mettre les valeurs dans l'ordre croissant si elles sont pondérées!! + + :param valeurs: valeurs de la série statistique + :param effectifs: effectifs de chaque + """ + if not effectifs: + effectifs = [1]*len(valeurs) + valeurs.sort() + + if len(valeurs) != len(effectifs): + raise ValueError("Valeurs et effectifs ne sont pas de la même longueur") + + dict_tmp = [(v,effectifs[i]) for (i,v) in enumerate(valeurs)] + + self.serie = dict(dict_tmp) + self.valeurs = valeurs + self.effectifs = effectifs + self.effectif_total = sum(self.effectifs) + + # On classe les données dans un dictionnaire + # Il faut plutot utiliser un dictionnaire car il trie automatiquement dans l'ordre croissant les clés. + self.serie = {} + for (i,v) in enumerate(self.valeurs): + if v in self.serie.keys(): + self.serie[v] += self.effectifs[i] + else: + self.serie[v] = self.effectifs[i] + + # On garde une forme (valeur, effectif) pour pouvoir trier les éléments car les dictionnaires ne le permettent pas) + self.serieCouple = [(v,e) for (v,e) in self.serie.items()] + self.serieCouple.sort(key = lambda s:s[0]) + + self.set_serie = True + + def moyenne(self): + """ + Calcul la moyenne des valeurs pondérées par les effectifs (s'ils ont été passé en arguments) + + :return: renvoie la moyenne. + """ + if self.set_serie: + val_eff = [i*self.serie[i] for i in self.serie] + return sum(val_eff) / self.effectif_total + else: + raise ValueError("La série statistique n'a pas été rentrée") + + def variance(self): + """ + Calcul la variance des valeurs pondérées par les effectifs (s'ils ont été passé en arguments) + + :return: renvoie la variance + """ + moy = self.moyenne() + ecart = [self.serie[v] * (v - moy)**2 for v in self.serie.keys()] + + return sum(ecart) / self.effectif_total + + def ecart_type(self): + """ + Calcul l'écart type des valeurs pondérées par les effectifs (s'ils ont été passé en arguments) + + :return: renvoie l'écart-type + """ + return sqrt(self.variance()) + + def quartiles(self): + """ + Calcul les quartiles de la série. + + :return: un tuple avec (min, Q1, Me, Q3, Max) + """ + return (min(self.serie) , self.quartile(1) , self.quartile(2) , self.quartile(3), max(self.serie)) + + def quartile(self, quartile = 1): + """ + Calcul un quartile de la série. + + :param quartile: quartile à calculer (par defaut 1 -> Q1) + + :return: le quartile demandé + + : Example: + + >>> s = Serie() + >>> + + """ + position = self.posi_quartile(quartile)[0] + + conteur = 0 + # on utilise la forme avec les couples pour avoir des valeurs classées. + for (val , eff) in self.serieCouple: + conteur += eff + if conteur >= position: + val_quartile = val + break + + return val_quartile + + def posi_quartile(self, quartile = 1): + """ + Calcul la position du quartile + + :param quartile: le quartile concerné + + :return : la position du quartile (arondis à l'entier suppérieur, non arrondis) + """ + return (ceil(quartile * self.effectif_total / 4), (quartile * self.effectif_total / 4)) + + + # -------------------------- + # Rendu latex + + def moyenne_latex(self, val_cara = "x", eff_cara = "n", end_cara = "p", moy_cara= "\\bar{x}"): + """ + Renvoie le code latex pour afficher le calcul de la moyenne + + :param val_cara: caractère représentant les valeurs (x par défaut) + :param eff_cara: caractère représentant les effectifs (n par défaut) + :param end_cara: caractère représentant le nombre de valeurs (p par défaut) + :param moy_cara: nom de la moyenne (\\bar{x} par défaut) + + :return: le code latex pour afficher le calcul de la moyenne + """ + moy = self.moyenne() + latex = moy_cara + " &=& " + latex += "\\frac{{{x}_1 \\times {n}_1 + {x}_2 \\times {n}_2 + ... + {x}_{p} \\times {n}_{p}}}{{{n}_1 + {n}_2 + ... + {n}_p}} \\\\ \n".format(x = val_cara, n=eff_cara, p = end_cara) + latex += "\t &=& \\frac{" + for (i,v) in enumerate(self.valeurs): + latex += "{x:.2f} \\times {p:.2f} + ".format(x = v, p = self.effectifs[i]) + latex = latex[:-2] # on enlève le + et l'espace de fin de calcul + latex += "}}{{{eff_tot}}}\\\\ \n".format(eff_tot = self.effectif_total) + latex += "\t &=& {moy:.2f}".format(moy=moy) + + return latex + + def variance_latex(self, val_cara = "x", eff_cara = "n", end_cara = "p", moy_cara= "\\bar{x}", var_cara = "V"): + """ + Renvoie le code latex pour afficher le calcul de la moyenne + + :param val_cara: caractère représentant les valeurs (x par défaut) + :param eff_cara: caractère représentant les effectifs (n par défaut) + :param end_cara: caractère représentant le nombre de valeurs (p par défaut) + :param moy_cara: nom de la moyenne (\\bar{x} par défaut) + :param var_var: nom de la variance (V par défaut) + + :return: le code latex pour afficher le calcul de la moyenne + """ + moy = self.moyenne() + var = self.variance() + + latex = var_cara + " &=& " + latex += "\\frac{{ {n}_1 ({x}_1 - {moy})^2 + {n}_2 ({x}_2 - {moy})^2 + ... + {n}_{p} ({x}_{p} - {moy})^2}}{{{n}_1 + {n}_2 + ... + {n}_p}}\\\\ \n".format(x = val_cara, n=eff_cara, p = end_cara, moy = moy_cara) + latex += "\t &=& \\frac{ " + for (i,v) in enumerate(self.valeurs): + latex += "{p:.2f} ({x:.2f} - {moy:.2f})**2 + ".format(p = self.effectifs[i], x = v, moy = moy) + latex = latex[:-2] # on enlève le + et l'espace de fin de calcul + latex += "}}{{{eff_tot}}}\\\\ \n".format(eff_tot = self.effectif_total) + latex += "\t &=& {var:.2f}".format(var = var) + + return latex + + def ecart_type_latex(self, val_cara = "x", eff_cara = "n", end_cara = "p", moy_cara= "\\bar{x}", var_cara = "V", ecar_cara = "\\sigma"): + """ + Renvoie le code latex pour afficher le calcul de la moyenne + + :param val_cara: caractère représentant les valeurs (x par défaut) + :param eff_cara: caractère représentant les effectifs (n par défaut) + :param end_cara: caractère représentant le nombre de valeurs (p par défaut) + :param moy_cara: nom de la moyenne (\\bar{x} par défaut) + :param var_var: nom de la variance (V par défaut) + :param ecar_var: nom de la variance (V par défaut) + + :return: le code latex pour afficher le calcul de la moyenne + """ + ecart = self.ecart_type() + + # On récupère le calcul de la variance + latex = self.variance_latex(val_cara, eff_cara, end_cara, moy_cara, var_cara) + latex += "\n\n" + + # On y ajoute celui de l'écart-type (ya un soucis ici à cause du conflit entre format et { + latex += "{ecar_cara} &=& \\sqrt{{{var_cara}}} \\\\ \n".format(ecar_cara = ecar_cara, var_cara = var_cara) + latex += "\t &=& {ecart:.2f}".format(ecart = ecart) + + return latex + + def quartiles_latex(self): + """ Renvoie le code latex pour afficher le calcul des quartiles + + :return : le code latex pour afficher le calcul des quartiles + """ + latex = self.quartile_latex() + latex += self.quartile_latex(1) + latex += self.quartile_latex(3) + + return latex + + def quartile_latex(self, quartile = 2): + """ Renvoie le code latex pour afficher le calcul du quartile + + :param quartile: numéro du quartile + + :return : le code latex pour afficher le calcul du quartile + """ + if quartile == 2 : # médiane + quartile_tpl = """ Position de la médiane: $\\dfrac{{\\mbox{{effectif total}}}}{{2}} = \\dfrac{{{eff_tot}}}{{2}} = {posi_q}$. Donc la médiane se trouve à la position: {posi_q_ceil}. + +On a ainsi $Me = {val_q}$ + """ + else: + quartile_tpl = """ Position de $Q_{q}$: $\\dfrac{{{q} \\times \\mbox{{effectif total}}}}{{4}} = \\dfrac{{{q} \\times {eff_tot}}}{{4}} = {posi_q}$. Donc $Q_{q}$ se trouve à la position: {posi_q_ceil}. + +On a ainsi $Q_{q} = {val_q}$ + """ + posi_q_ceil , posi_q = self.posi_quartile(quartile) + val_q = self.quartile(quartile) + + latex = quartile_tpl.format(eff_tot = self.effectif_total, q = quartile, posi_q = posi_q, posi_q_ceil = posi_q_ceil, val_q = val_q) + + return latex + + def tabular_latex(self): + """ Renvoie le code latex pour afficher le tableau + + :return : le code latex pour afficher le tableau + """ + latex = "\\begin{{center}} \n \t \\begin{{tabular}}{{|c|*{{{nbr_col}}}{{c|}}}} \n".format(nbr_col = len(self.serie)) + latex += "\t\t \hline \n" + latex += "\t\t {val_name} ".format(val_name = self.val_name) + eff_ligne = "\t\t {eff_name} ".format(eff_name = self.eff_name) + + for (v,e) in self.serieCouple: + latex += "& {val:.2f} ".format(val = v) + eff_ligne += "& {eff:.2f} ".format(eff = e) + + latex += "\\\\ \hline \n" + latex += eff_ligne + " \\\\ \hline \n" + latex += "\t \\end{tabular} \n \\end{center}" + + return latex + +if __name__ == '__main__': + valeurs = [65, 75, 85, 95, 105, 115, 125, 135] + valeurs.sort() + print(valeurs) + effectifs = [ 15, 2, 21, 24, 12, 9, 5, 2] + + + s = Serie() + + s.set_values(valeurs, effectifs) + print(s.effectif_total) + + print(s.valeurs) + print(s.effectifs) + print(s.serie) + + # print(s.tabular_latex()) + + # print("Moyenne ", s.moyenne()) + # print(s.variance()) + # print(s.ecart_type()) + + print("\n-----------------------\n") + print(s.moyenne_latex()) + print("\n-----------------------\n") + print(s.variance_latex()) + print("\n-----------------------\n") + print(s.ecart_type_latex()) + + # print(s.quartiles()) + print("\n-----------------------\n") + print(s.quartile_latex()) + print(s.quartile_latex(1)) + print(s.quartile_latex(3)) + + + +# ----------------------------- +# Reglages pour 'vim' +# vim:set autoindent expandtab tabstop=4 shiftwidth=4: +# cursor: 16 del +