diff --git a/app/pe/pe_settag.py b/app/pe/pe_settag.py index 74a0cb22e..61f4fe90e 100644 --- a/app/pe/pe_settag.py +++ b/app/pe/pe_settag.py @@ -35,6 +35,7 @@ Created on Fri Sep 9 09:15:05 2016 @author: barasc """ +from app.comp import moy_sem from app.comp.res_sem import load_formsemestre_results from app.models import FormSemestre from app.pe.pe_semestretag import SemestreTag @@ -92,12 +93,26 @@ class SetTag(pe_tagtable.TableTag): self.tags_sorted = self.do_taglist() """Construit le cube de notes""" - self.notes_cube = {} + self.notes_cube = self.compute_notes_cube() - """Les moyennes par tag""" + """Calcul les moyennes par tag sous forme d'un dataframe""" + etudids = self.get_etudids() + self.notes = compute_tag_moy(self.notes_cube, etudids, self.tags_sorted) + + """Synthétise les moyennes/classements par tag""" self.moyennes_tags = {} + for tag in self.tags_sorted: + moy_gen_tag = self.notes[tag] + class_gen_tag = moy_sem.comp_ranks_series(moy_gen_tag)[1] # en int + self.moyennes_tags[tag] = { + "notes": moy_gen_tag, + "classements": class_gen_tag, + "min": moy_gen_tag.min(), + "max": moy_gen_tag.max(), + "moy": moy_gen_tag.mean(), + "nb_inscrits": len(moy_gen_tag), + } - # ------------------------------------------------------------------------------------------------------------------- def compute_notes_cube(self): """Construit le cube de notes (etudid x tags x semestre_aggregé) nécessaire au calcul des moyennes de l'aggrégat @@ -115,7 +130,7 @@ class SetTag(pe_tagtable.TableTag): for frmsem_id in semestres_id: """Partant d'un dataframe vierge""" - df = pd.DataFrame(np.nan, index=etudids, columns=self.tags_sorted) + df = pd.DataFrame(np.nan, index=etudids, columns=tags) """Charge les notes du semestre tag""" notes = self.semestres_tags_aggreges[frmsem_id].notes @@ -138,11 +153,8 @@ class SetTag(pe_tagtable.TableTag): return etudids_x_tags_x_semestres - - - # ------------------------------------------------------------------------------------------------------------------- def get_etudids(self): - return list(self.identdict.keys()) + return list(self.etudiants.keys()) # ------------------------------------------------------------------------------------------------------------------- def do_taglist(self): @@ -156,68 +168,6 @@ class SetTag(pe_tagtable.TableTag): tags.extend(self.semestres_tags_aggreges[frmsem_id].tags_sorted) return sorted(set(tags)) - # ------------------------------------------------------------------------------------------------------------------- - def do_tagdict(self): - """Synthétise la liste des modules pris en compte dans le calcul d'un tag (pour analyse des résultats)""" - self.tagdict = {} - for semtag in self.SemTagDict.values(): - for tag in semtag.get_all_tags(): - if tag != "but": - if tag not in self.tagdict: - self.tagdict[tag] = {} - for mod in semtag.tagdict[tag]: - self.tagdict[tag][mod] = semtag.tagdict[tag][mod] - - # ------------------------------------------------------------------------------------------------------------------- - def get_NotesEtCoeffsSetTagEtudiant(self, tag, etudid): - """Récupère tous les notes et les coeffs d'un étudiant relatives à un tag dans ses semestres valides et les renvoie dans un tuple (notes, coeffs) - avec notes et coeffs deux listes""" - lesSemsDeLEtudiant = [ - self.parcoursDict[etudid][nom_sem] for nom_sem in self.parcours - ] # peuvent être None - - notes = [ - self.SemTagDict[fid].get_moy_from_resultats(tag, etudid) - for fid in lesSemsDeLEtudiant - if tag in self.SemTagDict[fid].taglist - ] # eventuellement None - coeffs = [ - self.SemTagDict[fid].get_coeff_from_resultats(tag, etudid) - for fid in lesSemsDeLEtudiant - if tag in self.SemTagDict[fid].taglist - ] - return (notes, coeffs) - - # ------------------------------------------------------------------------------------------------------------------- - def comp_MoyennesSetTag(self, tag, force=False): - """Calcule et renvoie les "moyennes" des étudiants à un tag donné, en prenant en compte tous les semestres taggués - de l'aggrégat, et leur coeff Par moyenne, s'entend une note moyenne, la somme des coefficients de pondération - appliqué dans cette moyenne. - - Force ou non le calcul de la moyenne lorsque des notes sont manquantes. - - Renvoie les informations sous la forme d'une liste [etudid: (moy, somme_coeff_normalisée, rang), ...} - """ - # if tag not in self.get_all_tags() : return None - - # Calcule les moyennes - lesMoyennes = [] - for ( - etudid - ) in ( - self.get_etudids() - ): # Pour tous les étudiants non défaillants du semestre inscrits dans des modules relatifs au tag - (notes, coeffs_norm) = self.get_NotesEtCoeffsSetTagEtudiant( - tag, etudid - ) # lecture des notes associées au tag - (moyenne, somme_coeffs) = pe_tagtable.moyenne_ponderee_terme_a_terme( - notes, coeffs_norm, force=force - ) - lesMoyennes += [ - (moyenne, somme_coeffs, etudid) - ] # Un tuple (pour classement résumant les données) - return lesMoyennes - class SetTagInterClasse(pe_tagtable.TableTag): """Récupère les moyennes de SetTag aggrégeant un même parcours (par ex un ['S1', 'S2'] n'ayant pas fini au même S2 @@ -339,3 +289,43 @@ class SetTagInterClasse(pe_tagtable.TableTag): (moyenne, somme_coeffs, etudid) ] # Un tuple (pour classement résumant les données) return lesMoyennes + + +def compute_tag_moy(set_cube: np.array, etudids: list, tags: list): + """Calcul de la moyenne par tag sur plusieurs semestres. + La moyenne est un nombre (note/20), ou NaN si pas de notes disponibles + + *Remarque* : Adaptation de moy_ue.compute_ue_moys_apc au cas des moyennes de tag + par aggrégat de plusieurs semestres. + + Args: + set_cube: notes moyennes aux modules ndarray + (etuds x modimpls x UEs), des floats avec des NaN + etudids: liste des étudiants (dim. 0 du cube) + tags: liste des tags (dim. 1 du cube) + Returns: + Un DataFrame avec pour columns les moyennes par tags, + et pour rows les etudid + """ + nb_etuds, nb_tags, nb_semestres = set_cube.shape + assert nb_etuds == len(etudids) + assert nb_tags == len(tags) + + # Quelles entrées du cube contiennent des notes ? + mask = ~np.isnan(set_cube) + + # Enlève les NaN du cube pour les entrées manquantes + set_cube_no_nan = np.nan_to_num(set_cube, nan=0.0) + + # Les moyennes par tag + with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) + etud_moy_tag = np.sum(set_cube_no_nan, axis=2) / np.sum(mask, axis=2) + + # Le dataFrame + etud_moy_tag_df = pd.DataFrame( + etud_moy_tag, + index=etudids, # les etudids + columns=tags, # les tags + ) + + return etud_moy_tag_df