#/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