forked from ScoDoc/ScoDoc
Update opolka/ScoDoc from ScoDoc/ScoDoc #2
@ -50,6 +50,7 @@ from zipfile import ZipFile
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
from app.pe import pe_semtag
|
||||||
from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE
|
from app.pe.pe_affichage import NOM_STAT_PROMO, SANS_NOTE, NOM_STAT_GROUPE
|
||||||
import app.pe.pe_affichage as pe_affichage
|
import app.pe.pe_affichage as pe_affichage
|
||||||
from app.pe.pe_etudiant import * # TODO A éviter -> pe_etudiant.
|
from app.pe.pe_etudiant import * # TODO A éviter -> pe_etudiant.
|
||||||
@ -96,7 +97,9 @@ class JuryPE(object):
|
|||||||
pe_affichage.pe_print("*** Aucun étudiant diplômé")
|
pe_affichage.pe_print("*** Aucun étudiant diplômé")
|
||||||
else:
|
else:
|
||||||
self._gen_xls_diplomes(zipfile)
|
self._gen_xls_diplomes(zipfile)
|
||||||
|
self._gen_rcss()
|
||||||
self._gen_xls_resultats_semestres_taggues(zipfile)
|
self._gen_xls_resultats_semestres_taggues(zipfile)
|
||||||
|
self._gen_xls_semestres_taggues(zipfile)
|
||||||
# self._gen_xls_rcss_tags(zipfile)
|
# self._gen_xls_rcss_tags(zipfile)
|
||||||
# self._gen_xls_interclassements_rcss(zipfile)
|
# self._gen_xls_interclassements_rcss(zipfile)
|
||||||
# self._gen_xls_synthese_jury_par_tag(zipfile)
|
# self._gen_xls_synthese_jury_par_tag(zipfile)
|
||||||
@ -142,12 +145,53 @@ class JuryPE(object):
|
|||||||
output, engine="openpyxl"
|
output, engine="openpyxl"
|
||||||
) as writer:
|
) as writer:
|
||||||
for res_sem_tag in self.res_sems_tags.values():
|
for res_sem_tag in self.res_sems_tags.values():
|
||||||
onglet = res_sem_tag.get_repr()
|
onglet = res_sem_tag.get_repr(verbose=False)
|
||||||
df = res_sem_tag.df_moyennes_et_classements()
|
df = res_sem_tag.df_moyennes_et_classements()
|
||||||
# écriture dans l'onglet
|
# écriture dans l'onglet
|
||||||
df.to_excel(writer, onglet, index=True, header=True)
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
output.seek(0)
|
output.seek(0)
|
||||||
|
|
||||||
|
self.add_file_to_zip(
|
||||||
|
zipfile,
|
||||||
|
f"resultats_semestres_taggues_{self.diplome}.xlsx",
|
||||||
|
output.read(),
|
||||||
|
path="details",
|
||||||
|
)
|
||||||
|
|
||||||
|
def _gen_rcss(self):
|
||||||
|
"""Génère les RCS (attribut `rcss_jury`), combinaisons de semestres suivis par les étudiants au sens
|
||||||
|
d'un nom de RCS (par ex: '3S').
|
||||||
|
"""
|
||||||
|
pe_affichage.pe_print(
|
||||||
|
"*** Génère les RCS (différentes combinaisons de semestres) des étudiants"
|
||||||
|
)
|
||||||
|
self.rcss_jury = pe_rcs.RCSsJuryPE(self.diplome)
|
||||||
|
self.rcss_jury.cree_rcss(self.etudiants)
|
||||||
|
|
||||||
|
def _gen_xls_semestres_taggues(self, zipfile: ZipFile):
|
||||||
|
"""Génère les semestres taggués en s'appuyant sur les RCS de type Sx (pour
|
||||||
|
identifier les redoublements impactant les semestres taggués).
|
||||||
|
"""
|
||||||
|
# Génère les moyennes des RCS de type Sx
|
||||||
|
pe_affichage.pe_print("*** Calcule les moyennes de semestres = RCS de type Sx")
|
||||||
|
|
||||||
|
self.sems_tags = {}
|
||||||
|
for rcs_id, rcs in self.rcss_jury.rcss.items():
|
||||||
|
if rcs.nom.startswith("S"):
|
||||||
|
self.sems_tags[rcs_id] = pe_semtag.SemTag(rcs, self.res_sems_tags)
|
||||||
|
|
||||||
|
# Intègre le bilan des semestres taggués au zip final
|
||||||
|
output = io.BytesIO()
|
||||||
|
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||||
|
output, engine="openpyxl"
|
||||||
|
) as writer:
|
||||||
|
for sem_tag in self.sems_tags.values():
|
||||||
|
onglet = sem_tag.get_repr(verbose=False)
|
||||||
|
df = sem_tag.df_moyennes_et_classements()
|
||||||
|
# écriture dans l'onglet
|
||||||
|
df.to_excel(writer, onglet, index=True, header=True)
|
||||||
|
output.seek(0)
|
||||||
|
|
||||||
self.add_file_to_zip(
|
self.add_file_to_zip(
|
||||||
zipfile,
|
zipfile,
|
||||||
f"semestres_taggues_{self.diplome}.xlsx",
|
f"semestres_taggues_{self.diplome}.xlsx",
|
||||||
@ -156,11 +200,7 @@ class JuryPE(object):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def _gen_xls_rcss_tags(self, zipfile: ZipFile):
|
def _gen_xls_rcss_tags(self, zipfile: ZipFile):
|
||||||
"""Génère :
|
"""Génère les RCS tagguées des RCS, en calculant les moyennes et les classements par tag
|
||||||
|
|
||||||
* les RCS (combinaisons de semestres suivis par les étudiants au sens
|
|
||||||
d'un aggrégat (par ex: '3S'))
|
|
||||||
* les RCS tagguées des RCS, en calculant les moyennes et les classements par tag
|
|
||||||
pour chacune.
|
pour chacune.
|
||||||
|
|
||||||
Stocke le résultat dans self.rccs_tag, un dictionnaire de
|
Stocke le résultat dans self.rccs_tag, un dictionnaire de
|
||||||
@ -183,14 +223,9 @@ class JuryPE(object):
|
|||||||
|
|
||||||
|
|
||||||
"""
|
"""
|
||||||
pe_affichage.pe_print(
|
|
||||||
"*** Génère les trajectoires (différentes combinaisons de semestres) des étudiants"
|
|
||||||
)
|
|
||||||
self.rcss_jury = pe_rcs.RCSsJuryPE(self.diplome)
|
|
||||||
self.rcss_jury.cree_rcss(self.etudiants)
|
|
||||||
|
|
||||||
# Génère les moyennes par tags des trajectoires
|
# Génère les moyennes des RCS de type Sx
|
||||||
pe_affichage.pe_print("*** Calcule les moyennes par tag des RCS possibles")
|
pe_affichage.pe_print("*** Calcule les moyennes des RCS de type Sx")
|
||||||
|
|
||||||
self.rcss_tags = {}
|
self.rcss_tags = {}
|
||||||
for rcs_id, rcs in self.rcss_jury.rcss.items():
|
for rcs_id, rcs in self.rcss_jury.rcss.items():
|
||||||
@ -597,9 +632,6 @@ def compute_resultats_semestres_tag(etudiants: EtudiantsJuryPE) -> dict:
|
|||||||
return semestres_tags
|
return semestres_tags
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def compute_interclassements(
|
def compute_interclassements(
|
||||||
etudiants: EtudiantsJuryPE,
|
etudiants: EtudiantsJuryPE,
|
||||||
trajectoires_jury_pe: pe_rcs.RCSsJuryPE,
|
trajectoires_jury_pe: pe_rcs.RCSsJuryPE,
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
from app import comp
|
||||||
from app.comp.moy_sem import comp_ranks_series
|
from app.comp.moy_sem import comp_ranks_series
|
||||||
from app.models import UniteEns
|
from app.models import UniteEns
|
||||||
from app.pe import pe_affichage
|
from app.pe import pe_affichage
|
||||||
|
from app.scodoc.codes_cursus import UE_SPORT
|
||||||
|
|
||||||
|
|
||||||
class Moyenne:
|
class Moyenne:
|
||||||
@ -157,8 +159,9 @@ class MoyennesTag:
|
|||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
tag: str,
|
tag: str,
|
||||||
ues: list[UniteEns],
|
ues: dict[int, UniteEns],
|
||||||
notes_ues: pd.DataFrame,
|
notes_ues: pd.DataFrame,
|
||||||
|
ues_inscr_parcours_df: pd.DataFrame
|
||||||
# notes_gen: pd.Series,
|
# notes_gen: pd.Series,
|
||||||
):
|
):
|
||||||
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
||||||
@ -169,21 +172,39 @@ class MoyennesTag:
|
|||||||
tag: Un tag
|
tag: Un tag
|
||||||
ues: La liste des UEs ayant servie au calcul de la moyenne
|
ues: La liste des UEs ayant servie au calcul de la moyenne
|
||||||
notes_ues: Les moyennes (etudid x acronymes_ues) aux différentes UEs et pour le tag
|
notes_ues: Les moyennes (etudid x acronymes_ues) aux différentes UEs et pour le tag
|
||||||
|
ues_inscr_parcours_df: Les inscriptions des etudid au UE
|
||||||
# notes_gen: Une série de notes (moyenne) sous forme d'un pd.Series() (toutes UEs confondues)
|
# notes_gen: Une série de notes (moyenne) sous forme d'un pd.Series() (toutes UEs confondues)
|
||||||
"""
|
"""
|
||||||
self.tag = tag
|
self.tag = tag
|
||||||
"""Le tag associé aux moyennes"""
|
"""Le tag associé aux moyennes"""
|
||||||
|
|
||||||
# Les UE
|
# Les UE
|
||||||
self.ues: dict[int, UniteEns] = {ue.id: ue for ue in ues}
|
self.ues: dict[int, UniteEns] = ues
|
||||||
"""Les UEs sur lesquelles sont calculées les moyennes"""
|
"""Les UEs sur lesquelles sont calculées les moyennes"""
|
||||||
|
|
||||||
colonnes = list(notes_ues.columns)
|
colonnes = list(notes_ues.columns)
|
||||||
acronymes = [self.ues[ue_id].acronyme for ue_id in colonnes]
|
acronymes: list[str] = [self.ues[ue_id].acronyme for ue_id in self.ues]
|
||||||
assert len(set(acronymes)) == len(colonnes), \
|
assert len(set(acronymes)) == len(
|
||||||
"Deux UEs ne peuvent pas avoir le même acronyme"
|
colonnes
|
||||||
|
), "Deux UEs ne peuvent pas avoir le même acronyme"
|
||||||
|
|
||||||
|
# Les inscriptions des etudids aux UEs
|
||||||
|
self.ues_inscr_parcours_df: pd.DataFrame = ues_inscr_parcours_df
|
||||||
|
"""Les inscriptions des etudids au UE en fonction de leur parcours"""
|
||||||
|
|
||||||
|
# Les coefficients à appliquer aux UEs pour la moyenne générale = ECTS
|
||||||
|
self.ects = self.ues_inscr_parcours_df.fillna(0.0) * [
|
||||||
|
ue.ects
|
||||||
|
for ue in self.ues.values() # if ue.type != UE_SPORT <= déjà supprimé
|
||||||
|
]
|
||||||
|
# Les profils d'ects (pour debug)
|
||||||
|
profils_ects = []
|
||||||
|
for val in list(self.ects.values):
|
||||||
|
if tuple(val) not in profils_ects:
|
||||||
|
profils_ects.append(tuple(val))
|
||||||
|
|
||||||
# Les moyennes par UE
|
# Les moyennes par UE
|
||||||
self.notes_ues = notes_ues
|
self.notes_ues: pd.DataFrame = notes_ues
|
||||||
"""Les notes aux UEs (dataframe)"""
|
"""Les notes aux UEs (dataframe)"""
|
||||||
self.notes_ues.columns = acronymes # remplace les ue.id par leur acronyme
|
self.notes_ues.columns = acronymes # remplace les ue.id par leur acronyme
|
||||||
self.moys_ues: dict[int, pd.DataFrame] = {}
|
self.moys_ues: dict[int, pd.DataFrame] = {}
|
||||||
@ -193,11 +214,42 @@ class MoyennesTag:
|
|||||||
self.moys_ues[ue.acronyme] = Moyenne(notes)
|
self.moys_ues[ue.acronyme] = Moyenne(notes)
|
||||||
|
|
||||||
# Les moyennes générales
|
# Les moyennes générales
|
||||||
|
notes_gen = self.compute_moy_gen(self.notes_ues, self.ects)
|
||||||
self.notes_gen = notes_gen
|
self.notes_gen = notes_gen
|
||||||
"""Les notes générales (moyenne toutes UEs confonudes)"""
|
"""Les notes générales (moyenne toutes UEs confonudes)"""
|
||||||
self.moy_gen = Moyenne(notes_gen)
|
self.moy_gen = Moyenne(notes_gen)
|
||||||
"""Le dataframe retraçant les moyennes/classements/statistiques général"""
|
"""Le dataframe retraçant les moyennes/classements/statistiques général"""
|
||||||
|
|
||||||
|
pe_affichage.pe_print(f"> MoyTag pour {tag} avec")
|
||||||
|
pe_affichage.pe_print(f" - ues={acronymes}")
|
||||||
|
pe_affichage.pe_print(f" - ects={profils_ects}")
|
||||||
|
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""Egalité de deux MoyenneTag lorsque leur tag sont identiques"""
|
"""Egalité de deux MoyenneTag lorsque leur tag sont identiques"""
|
||||||
return self.tag == other.tag
|
return self.tag == other.tag
|
||||||
|
|
||||||
|
def compute_moy_gen(
|
||||||
|
self, moy_ues: pd.DataFrame, coeff_ues: pd.DataFrame
|
||||||
|
) -> pd.Series:
|
||||||
|
"""Calcule la moyenne générale (toutes UE confondus)
|
||||||
|
pour le tag considéré, en pondérant les notes obtenues au UE
|
||||||
|
par les crédits ECTS.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
moy_ues: Les moyennes etudids x acronymes_ues
|
||||||
|
coeff_ues: Les coeff etudids x ueids
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Calcule la moyenne générale dans le semestre (pondérée par le ECTS)
|
||||||
|
try:
|
||||||
|
moy_gen_tag = comp.moy_sem.compute_sem_moys_apc_using_ects(
|
||||||
|
moy_ues,
|
||||||
|
coeff_ues,
|
||||||
|
# formation_id=self.formsemestre.formation_id,
|
||||||
|
skip_empty_ues=True,
|
||||||
|
)
|
||||||
|
except TypeError as e:
|
||||||
|
raise TypeError("Pb dans le calcul de la moyenne toutes UEs confondues")
|
||||||
|
|
||||||
|
return moy_gen_tag
|
||||||
|
@ -94,7 +94,7 @@ class RCSTag(TableTag):
|
|||||||
self.etuds = nt.etuds
|
self.etuds = nt.etuds
|
||||||
|
|
||||||
# assert self.etuds == trajectoire.suivi # manque-t-il des étudiants ?
|
# assert self.etuds == trajectoire.suivi # manque-t-il des étudiants ?
|
||||||
self.etudiants = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
self.etats_civils = {etud.etudid: etud.nomprenom for etud in self.etuds}
|
||||||
|
|
||||||
self.tags_sorted = self.do_taglist()
|
self.tags_sorted = self.do_taglist()
|
||||||
"""Tags extraits de tous les semestres"""
|
"""Tags extraits de tous les semestres"""
|
||||||
@ -102,7 +102,7 @@ class RCSTag(TableTag):
|
|||||||
self.notes_cube = self.compute_notes_cube()
|
self.notes_cube = self.compute_notes_cube()
|
||||||
"""Cube de notes"""
|
"""Cube de notes"""
|
||||||
|
|
||||||
etudids = list(self.etudiants.keys())
|
etudids = list(self.etats_civils.keys())
|
||||||
self.notes = compute_tag_moy(self.notes_cube, etudids, self.tags_sorted)
|
self.notes = compute_tag_moy(self.notes_cube, etudids, self.tags_sorted)
|
||||||
"""Calcul les moyennes par tag sous forme d'un dataframe"""
|
"""Calcul les moyennes par tag sous forme d'un dataframe"""
|
||||||
|
|
||||||
|
@ -70,19 +70,15 @@ class ResSemTag(TableTag):
|
|||||||
self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
self.formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
|
||||||
|
|
||||||
# Le nom du res_semestre taggué
|
# Le nom du res_semestre taggué
|
||||||
self.nom = self.get_repr(mode="long")
|
self.nom = self.get_repr(verbose=True)
|
||||||
|
|
||||||
pe_affichage.pe_print(
|
pe_affichage.pe_print(f"--> Résultats de semestre taggués {self.nom}")
|
||||||
f"--> Résultats de Semestre taggués {self.nom}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Les résultats du semestre
|
# Les résultats du semestre
|
||||||
self.nt = load_formsemestre_results(self.formsemestre)
|
self.nt = load_formsemestre_results(self.formsemestre)
|
||||||
|
|
||||||
# Les étudiants
|
# Les étudiants (etuds, états civils & etudis)
|
||||||
self.etuds = self.nt.etuds
|
self.add_etuds(self.nt.etuds)
|
||||||
self.etudiants = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
|
||||||
self.etudids = list(self.etudiants.keys())
|
|
||||||
|
|
||||||
# Les notes, les modules implémentés triés, les étudiants, les coeffs,
|
# Les notes, les modules implémentés triés, les étudiants, les coeffs,
|
||||||
# récupérés notamment de py:mod:`res_but`
|
# récupérés notamment de py:mod:`res_but`
|
||||||
@ -113,8 +109,13 @@ class ResSemTag(TableTag):
|
|||||||
moy_ues_tag = self.compute_moy_ues_tag(infos_tag)
|
moy_ues_tag = self.compute_moy_ues_tag(infos_tag)
|
||||||
# moy_gen_tag = self.compute_moy_gen_tag(moy_ues_tag)
|
# moy_gen_tag = self.compute_moy_gen_tag(moy_ues_tag)
|
||||||
|
|
||||||
|
ues_dict = {ue.id: ue for ue in ues_hors_sport}
|
||||||
self.moyennes_tags[tag] = MoyennesTag(
|
self.moyennes_tags[tag] = MoyennesTag(
|
||||||
tag, ues_hors_sport, moy_ues_tag # moy_gen_tag
|
tag,
|
||||||
|
ues_dict,
|
||||||
|
moy_ues_tag,
|
||||||
|
self.ues_inscr_parcours_df
|
||||||
|
# moy_gen_tag
|
||||||
)
|
)
|
||||||
|
|
||||||
# Ajoute les d'UE moyennes générales de BUT pour le semestre considéré
|
# Ajoute les d'UE moyennes générales de BUT pour le semestre considéré
|
||||||
@ -128,8 +129,10 @@ class ResSemTag(TableTag):
|
|||||||
)
|
)
|
||||||
# moy_ues = self.nt.etud_moy_ue[ue_id]
|
# moy_ues = self.nt.etud_moy_ue[ue_id]
|
||||||
# moy_gen_but = self.nt.etud_moy_gen
|
# moy_gen_but = self.nt.etud_moy_gen
|
||||||
|
ues_dict = {ue.id: ue for ue in ues_hors_sport}
|
||||||
|
|
||||||
self.moyennes_tags["but"] = MoyennesTag(
|
self.moyennes_tags["but"] = MoyennesTag(
|
||||||
"but", ues_hors_sport, df_ues #, moy_gen_but
|
"but", ues_dict, df_ues, self.ues_inscr_parcours_df # , moy_gen_but
|
||||||
)
|
)
|
||||||
|
|
||||||
self.tags_sorted = self.get_all_tags()
|
self.tags_sorted = self.get_all_tags()
|
||||||
@ -144,11 +147,11 @@ class ResSemTag(TableTag):
|
|||||||
# f" => Traitement des tags {', '.join(self.tags_sorted)}"
|
# f" => Traitement des tags {', '.join(self.tags_sorted)}"
|
||||||
# )
|
# )
|
||||||
|
|
||||||
def get_repr(self, mode="long"):
|
def get_repr(self, verbose=False):
|
||||||
"""Nom affiché pour le semestre taggué"""
|
"""Nom affiché pour le semestre taggué"""
|
||||||
if mode == "short":
|
if verbose:
|
||||||
return f"{self.formsemestre} ({self.formsemestre_id})"
|
return f"{self.formsemestre} ({self.formsemestre_id})"
|
||||||
else: # mode == "long"
|
else:
|
||||||
return pe_etudiant.nom_semestre_etape(self.formsemestre, avec_fid=True)
|
return pe_etudiant.nom_semestre_etape(self.formsemestre, avec_fid=True)
|
||||||
|
|
||||||
def compute_moy_ues_tag(self, info_tag: dict[int, dict]) -> pd.DataFrame:
|
def compute_moy_ues_tag(self, info_tag: dict[int, dict]) -> pd.DataFrame:
|
||||||
@ -192,25 +195,6 @@ class ResSemTag(TableTag):
|
|||||||
)
|
)
|
||||||
return moyennes_ues_tag
|
return moyennes_ues_tag
|
||||||
|
|
||||||
def compute_moy_gen_tag(self, moy_ues_tag: pd.DataFrame) -> pd.Series:
|
|
||||||
"""Calcule la moyenne générale (toutes UE confondus)
|
|
||||||
pour le tag considéré, en les pondérant par les crédits ECTS.
|
|
||||||
"""
|
|
||||||
# Les ects
|
|
||||||
ects = self.ues_inscr_parcours_df.fillna(0.0) * [
|
|
||||||
ue.ects for ue in self.ues if ue.type != UE_SPORT
|
|
||||||
]
|
|
||||||
|
|
||||||
# Calcule la moyenne générale dans le semestre (pondérée par le ECTS)
|
|
||||||
moy_gen_tag = comp.moy_sem.compute_sem_moys_apc_using_ects(
|
|
||||||
moy_ues_tag,
|
|
||||||
ects,
|
|
||||||
formation_id=self.formsemestre.formation_id,
|
|
||||||
skip_empty_ues=True,
|
|
||||||
)
|
|
||||||
|
|
||||||
return moy_gen_tag
|
|
||||||
|
|
||||||
def _get_tags_dict(self):
|
def _get_tags_dict(self):
|
||||||
"""Renvoie les tags personnalisés (déduits des modules du semestre)
|
"""Renvoie les tags personnalisés (déduits des modules du semestre)
|
||||||
et les tags automatiques ('but'), et toutes leurs informations,
|
et les tags automatiques ('but'), et toutes leurs informations,
|
||||||
@ -272,8 +256,6 @@ class ResSemTag(TableTag):
|
|||||||
raise ScoValueError(message)
|
raise ScoValueError(message)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_moduleimpl(modimpl_id) -> dict:
|
def get_moduleimpl(modimpl_id) -> dict:
|
||||||
"""Renvoie l'objet modimpl dont l'id est modimpl_id"""
|
"""Renvoie l'objet modimpl dont l'id est modimpl_id"""
|
||||||
modimpl = db.session.get(ModuleImpl, modimpl_id)
|
modimpl = db.session.get(ModuleImpl, modimpl_id)
|
||||||
|
@ -49,7 +49,7 @@ from app.pe.pe_moytag import MoyennesTag
|
|||||||
|
|
||||||
|
|
||||||
class SemTag(TableTag):
|
class SemTag(TableTag):
|
||||||
def __init__(self, rcs: RCS, semestres_taggues: dict[int, ResSemTag]):
|
def __init__(self, rcs: RCS, res_sems_tags: dict[int, ResSemTag]):
|
||||||
"""Calcule les moyennes/classements par tag à un RCS d'un seul semestre
|
"""Calcule les moyennes/classements par tag à un RCS d'un seul semestre
|
||||||
(ici semestre) de type 'Sx' (par ex. 'S1', 'S2', ...) :
|
(ici semestre) de type 'Sx' (par ex. 'S1', 'S2', ...) :
|
||||||
|
|
||||||
@ -62,7 +62,7 @@ class SemTag(TableTag):
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
rcs: Un RCS (identifié par un nom et l'id de son semestre terminal)
|
rcs: Un RCS (identifié par un nom et l'id de son semestre terminal)
|
||||||
semestres_taggues: Les données sur les semestres taggués
|
res_sems_tags: Les données sur les résultats des semestres taggués
|
||||||
"""
|
"""
|
||||||
TableTag.__init__(self)
|
TableTag.__init__(self)
|
||||||
|
|
||||||
@ -88,27 +88,20 @@ class SemTag(TableTag):
|
|||||||
self.semestres_aggreges = rcs.semestres_aggreges
|
self.semestres_aggreges = rcs.semestres_aggreges
|
||||||
"""Les semestres aggrégés"""
|
"""Les semestres aggrégés"""
|
||||||
|
|
||||||
self.semestres_tags_aggreges = {}
|
self.res_sems_tags = {}
|
||||||
"""Les semestres tags associés aux semestres aggrégés"""
|
"""Les résultats des semestres taggués (limités aux semestres aggrégés)"""
|
||||||
try:
|
try:
|
||||||
for frmsem_id in self.semestres_aggreges:
|
for frmsem_id in self.semestres_aggreges:
|
||||||
self.semestres_tags_aggreges[frmsem_id] = semestres_taggues[frmsem_id]
|
self.res_sems_tags[frmsem_id] = res_sems_tags[frmsem_id]
|
||||||
except:
|
except:
|
||||||
raise ValueError("Semestres taggués manquants")
|
raise ValueError("Résultats des semestres taggués manquants")
|
||||||
|
|
||||||
# Les données des étudiants
|
# Les étudiants (etuds, états civils & etudis)
|
||||||
self.etuds = nt.etuds
|
self.add_etuds(nt.etuds)
|
||||||
"""Les étudiants"""
|
|
||||||
self.etudids = [etud.etudid for etud in self.etuds]
|
|
||||||
"""Les etudids"""
|
|
||||||
self.etats_civils = {
|
|
||||||
etudid: self.etuds[etudid].etat_civil for etudid in self.etudids
|
|
||||||
}
|
|
||||||
"""Les états civils"""
|
|
||||||
|
|
||||||
# Les tags
|
# Les tags
|
||||||
self.tags_sorted = self.comp_tags_list()
|
self.tags_sorted = self.comp_tags_list()
|
||||||
"""Tags extraits du semestre terminal de l'aggrégat"""
|
"""Tags (extraits uniquement du semestre terminal de l'aggrégat)"""
|
||||||
|
|
||||||
# Les UEs
|
# Les UEs
|
||||||
self.ues = self.comp_ues(tag="but")
|
self.ues = self.comp_ues(tag="but")
|
||||||
@ -116,20 +109,33 @@ class SemTag(TableTag):
|
|||||||
"""UEs extraites du semestre terminal de l'aggrégat (avec
|
"""UEs extraites du semestre terminal de l'aggrégat (avec
|
||||||
check de concordance sur les UE des semestres_aggrégés)"""
|
check de concordance sur les UE des semestres_aggrégés)"""
|
||||||
|
|
||||||
|
# Les inscriptions aux UEs
|
||||||
|
self.ues_inscr_parcours_df = self.comp_ues_inscr_parcours(tag="but")
|
||||||
|
"""Les inscriptions aux UEs (extraites uniquement du semestre terminal)"""
|
||||||
|
|
||||||
self.moyennes_tags: dict[str, MoyennesTag] = {}
|
self.moyennes_tags: dict[str, MoyennesTag] = {}
|
||||||
"""Moyennes/classements par tag (qu'ils soient personnalisés ou automatiques)"""
|
"""Moyennes/classements par tag (qu'ils soient personnalisés ou automatiques)"""
|
||||||
|
|
||||||
self.notes: dict[str, pd.DataFrame] = {}
|
self.moyennes_tags: dict[str, pd.DataFrame] = {}
|
||||||
"""Les notes aux différents tags"""
|
"""Les notes aux UEs dans différents tags"""
|
||||||
|
# Masque des inscriptions
|
||||||
|
inscr_mask = self.ues_inscr_parcours_df.to_numpy()
|
||||||
for tag in self.tags_sorted:
|
for tag in self.tags_sorted:
|
||||||
# Cube de note
|
# Cube de note
|
||||||
notes_cube = self.compute_notes_ues_cube(tag, self.acronymes_ues)
|
notes_cube = self.compute_notes_ues_cube(tag, self.acronymes_ues_sorted)
|
||||||
|
|
||||||
# Calcule des moyennes sous forme d'un dataframe"""
|
# Calcule des moyennes sous forme d'un dataframe"""
|
||||||
self.notes[tag] = compute_notes_ues(notes_cube, self.etudids, self.acronymes_ues)
|
moys_ues = compute_notes_ues(
|
||||||
|
notes_cube,
|
||||||
|
self.etudids,
|
||||||
|
self.acronymes_ues_sorted,
|
||||||
|
inscr_mask,
|
||||||
|
)
|
||||||
# Les moyennes
|
# Les moyennes
|
||||||
self.moyennes_tags[tag] = MoyennesTag(tag, self.notes[tag])
|
self.moyennes_tags[tag] = MoyennesTag(tag,
|
||||||
|
self.ues,
|
||||||
|
moys_ues,
|
||||||
|
self.ues_inscr_parcours_df)
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
"""Egalité de 2 RCS taggués sur la base de leur identifiant"""
|
"""Egalité de 2 RCS taggués sur la base de leur identifiant"""
|
||||||
@ -147,7 +153,7 @@ class SemTag(TableTag):
|
|||||||
# Index du cube (etudids -> dim 0, ues -> dim 1, semestres -> dim2)
|
# Index du cube (etudids -> dim 0, ues -> dim 1, semestres -> dim2)
|
||||||
etudids = [etud.etudid for etud in self.etuds]
|
etudids = [etud.etudid for etud in self.etuds]
|
||||||
# acronymes_ues = sorted([ue.acronyme for ue in self.ues.values()])
|
# acronymes_ues = sorted([ue.acronyme for ue in self.ues.values()])
|
||||||
semestres_id = list(self.semestres_tags_aggreges.keys())
|
semestres_id = list(self.res_sems_tags.keys())
|
||||||
|
|
||||||
dfs = {}
|
dfs = {}
|
||||||
|
|
||||||
@ -156,10 +162,12 @@ class SemTag(TableTag):
|
|||||||
df = pd.DataFrame(np.nan, index=etudids, columns=acronymes_ues_sorted)
|
df = pd.DataFrame(np.nan, index=etudids, columns=acronymes_ues_sorted)
|
||||||
|
|
||||||
# Charge les notes du semestre tag
|
# Charge les notes du semestre tag
|
||||||
sem_tag = self.semestres_tags_aggreges[frmsem_id]
|
sem_tag = self.res_sems_tags[frmsem_id]
|
||||||
moys_tag = sem_tag.moyennes_tags[tag]
|
moys_tag = sem_tag.moyennes_tags[tag]
|
||||||
notes = moys_tag.notes_ues # dataframe etudids x ues
|
notes = moys_tag.notes_ues # dataframe etudids x ues
|
||||||
acronymes_ues_sem = list(notes.columns) # les acronymes des UEs du semestre tag
|
acronymes_ues_sem = list(
|
||||||
|
notes.columns
|
||||||
|
) # les acronymes des UEs du semestre tag
|
||||||
|
|
||||||
# UEs communes à celles du SemTag (celles du dernier semestre du RCS)
|
# UEs communes à celles du SemTag (celles du dernier semestre du RCS)
|
||||||
ues_communes = list(set(acronymes_ues_sorted) & set(acronymes_ues_sem))
|
ues_communes = list(set(acronymes_ues_sorted) & set(acronymes_ues_sem))
|
||||||
@ -168,7 +176,9 @@ class SemTag(TableTag):
|
|||||||
etudids_communs = df.index.intersection(notes.index)
|
etudids_communs = df.index.intersection(notes.index)
|
||||||
|
|
||||||
# Recopie
|
# Recopie
|
||||||
df.loc[etudids_communs, ues_communes] = notes.loc[etudids_communs, ues_communes]
|
df.loc[etudids_communs, ues_communes] = notes.loc[
|
||||||
|
etudids_communs, ues_communes
|
||||||
|
]
|
||||||
|
|
||||||
# Supprime tout ce qui n'est pas numérique
|
# Supprime tout ce qui n'est pas numérique
|
||||||
for col in df.columns:
|
for col in df.columns:
|
||||||
@ -182,7 +192,7 @@ class SemTag(TableTag):
|
|||||||
etudids_x_ues_x_semestres = np.stack(semestres_x_etudids_x_ues, axis=-1)
|
etudids_x_ues_x_semestres = np.stack(semestres_x_etudids_x_ues, axis=-1)
|
||||||
return etudids_x_ues_x_semestres
|
return etudids_x_ues_x_semestres
|
||||||
|
|
||||||
def comp_tags_list(self):
|
def comp_tags_list(self) -> list[str]:
|
||||||
"""Récupère les tag du semestre taggué associé au semestre final du RCS
|
"""Récupère les tag du semestre taggué associé au semestre final du RCS
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
@ -190,7 +200,7 @@ class SemTag(TableTag):
|
|||||||
"""
|
"""
|
||||||
tags = []
|
tags = []
|
||||||
dernier_frmid = self.formsemestre_terminal.formsemestre_id
|
dernier_frmid = self.formsemestre_terminal.formsemestre_id
|
||||||
dernier_semestre_tag = self.semestres_tags_aggreges[dernier_frmid]
|
dernier_semestre_tag = self.res_sems_tags[dernier_frmid]
|
||||||
tags = dernier_semestre_tag.tags_sorted
|
tags = dernier_semestre_tag.tags_sorted
|
||||||
pe_affichage.pe_print(f"* Tags : {', '.join(tags)}")
|
pe_affichage.pe_print(f"* Tags : {', '.join(tags)}")
|
||||||
return tags
|
return tags
|
||||||
@ -203,12 +213,29 @@ class SemTag(TableTag):
|
|||||||
Un dictionnaire donnant les UEs
|
Un dictionnaire donnant les UEs
|
||||||
"""
|
"""
|
||||||
dernier_frmid = self.formsemestre_terminal.formsemestre_id
|
dernier_frmid = self.formsemestre_terminal.formsemestre_id
|
||||||
dernier_semestre_tag = self.semestres_tags_aggreges[dernier_frmid]
|
dernier_semestre_tag = self.res_sems_tags[dernier_frmid]
|
||||||
moy_tag = dernier_semestre_tag.moyennes_tags[tag]
|
moy_tag = dernier_semestre_tag.moyennes_tags[tag]
|
||||||
return moy_tag.ues # les UEs
|
return moy_tag.ues # les UEs
|
||||||
|
|
||||||
|
def comp_ues_inscr_parcours(self, tag="but") -> pd.DataFrame:
|
||||||
|
"""Récupère les informations d'inscription des étudiants aux UEs : ne
|
||||||
|
conserve que les UEs du semestre terminal (pour les redoublants)
|
||||||
|
|
||||||
def compute_notes_ues(set_cube: np.array, etudids: list, acronymes_ues: list):
|
Returns:
|
||||||
|
Un dataFrame etudids x UE indiquant si un étudiant est inscrit à une UE
|
||||||
|
"""
|
||||||
|
dernier_frmid = self.formsemestre_terminal.formsemestre_id
|
||||||
|
dernier_semestre_tag = self.res_sems_tags[dernier_frmid]
|
||||||
|
moy_tag = dernier_semestre_tag.moyennes_tags[tag]
|
||||||
|
return moy_tag.ues_inscr_parcours_df
|
||||||
|
|
||||||
|
|
||||||
|
def compute_notes_ues(
|
||||||
|
set_cube: np.array,
|
||||||
|
etudids: list,
|
||||||
|
acronymes_ues: list,
|
||||||
|
inscr_mask: np.array,
|
||||||
|
):
|
||||||
"""Calcule la moyenne par UEs à un tag donné en prenant la note maximum (UE
|
"""Calcule la moyenne par UEs à un tag donné en prenant la note maximum (UE
|
||||||
par UE) obtenue par un étudiant à un semestre.
|
par UE) obtenue par un étudiant à un semestre.
|
||||||
|
|
||||||
@ -217,18 +244,27 @@ def compute_notes_ues(set_cube: np.array, etudids: list, acronymes_ues: list):
|
|||||||
(semestre_ids x etudids x UEs), des floats avec des NaN
|
(semestre_ids x etudids x UEs), des floats avec des NaN
|
||||||
etudids: liste des étudiants (dim. 0 du cube)
|
etudids: liste des étudiants (dim. 0 du cube)
|
||||||
acronymes_ues: liste des acronymes des ues (dim. 1 du cube)
|
acronymes_ues: liste des acronymes des ues (dim. 1 du cube)
|
||||||
|
inscr_mask: masque etudids x UE traduisant les inscriptions des
|
||||||
|
étudiants aux UE (du semestre terminal)
|
||||||
Returns:
|
Returns:
|
||||||
Un DataFrame avec pour columns les moyennes par ues,
|
Un DataFrame avec pour columns les moyennes par ues,
|
||||||
et pour rows les etudid
|
et pour rows les etudid
|
||||||
"""
|
"""
|
||||||
nb_etuds, nb_ues, nb_semestres = set_cube.shape
|
nb_etuds, nb_ues, nb_semestres = set_cube.shape
|
||||||
|
nb_etuds_mask, nb_ues_mask = inscr_mask.shape
|
||||||
assert nb_etuds == len(etudids)
|
assert nb_etuds == len(etudids)
|
||||||
assert nb_ues == len(acronymes_ues)
|
assert nb_ues == len(acronymes_ues)
|
||||||
|
assert nb_etuds == nb_etuds_mask
|
||||||
|
assert nb_ues == nb_ues_mask
|
||||||
|
|
||||||
# Quelles entrées du cube contiennent des notes ?
|
# Quelles entrées du cube contiennent des notes ?
|
||||||
mask = ~np.isnan(set_cube)
|
mask = ~np.isnan(set_cube)
|
||||||
|
|
||||||
# Enlève les NaN du cube pour les entrées manquantes
|
# Entrées à garder dans le cube en fonction du mask d'inscription
|
||||||
|
inscr_mask_3D = np.stack([inscr_mask]*nb_semestres, axis=-1)
|
||||||
|
set_cube = set_cube*inscr_mask_3D
|
||||||
|
|
||||||
|
# Enlève les NaN du cube pour les entrées manquantes : NaN -> -1.0
|
||||||
set_cube_no_nan = np.nan_to_num(set_cube, nan=-1.0)
|
set_cube_no_nan = np.nan_to_num(set_cube, nan=-1.0)
|
||||||
|
|
||||||
# Les moyennes par ues
|
# Les moyennes par ues
|
||||||
|
@ -39,6 +39,8 @@ Created on Thu Sep 8 09:36:33 2016
|
|||||||
|
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
|
|
||||||
|
from app.models import Identite
|
||||||
|
|
||||||
TAGS_RESERVES = ["but"]
|
TAGS_RESERVES = ["but"]
|
||||||
|
|
||||||
|
|
||||||
@ -47,7 +49,23 @@ class TableTag(object):
|
|||||||
"""Classe centralisant différentes méthodes communes aux
|
"""Classe centralisant différentes méthodes communes aux
|
||||||
SemestreTag, TrajectoireTag, AggregatInterclassTag
|
SemestreTag, TrajectoireTag, AggregatInterclassTag
|
||||||
"""
|
"""
|
||||||
pass
|
# Les étudiants
|
||||||
|
self.etuds: list[Identite] = None # A venir
|
||||||
|
"""Les étudiants"""
|
||||||
|
self.etats_civils: dict[int, Identite] = None
|
||||||
|
"""Les états civils"""
|
||||||
|
self.etudids: list[int] = None
|
||||||
|
"""Les etudids"""
|
||||||
|
|
||||||
|
def add_etuds(self, etuds: list[Identite]):
|
||||||
|
"""Mémorise les informations sur les étudiants
|
||||||
|
|
||||||
|
Args:
|
||||||
|
etuds: la liste des identités de l'étudiant
|
||||||
|
"""
|
||||||
|
self.etuds = etuds
|
||||||
|
self.etats_civils = {etud.etudid: etud.etat_civil for etud in self.etuds}
|
||||||
|
self.etudids = list(self.etats_civils.keys())
|
||||||
|
|
||||||
def get_all_tags(self):
|
def get_all_tags(self):
|
||||||
"""Liste des tags de la table, triée par ordre alphabétique,
|
"""Liste des tags de la table, triée par ordre alphabétique,
|
||||||
@ -70,15 +88,23 @@ class TableTag(object):
|
|||||||
Le dataframe des notes et des classements
|
Le dataframe des notes et des classements
|
||||||
"""
|
"""
|
||||||
|
|
||||||
etudiants = self.etudiants
|
etudiants = self.etats_civils
|
||||||
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom"])
|
df = pd.DataFrame.from_dict(etudiants, orient="index", columns=["nom"])
|
||||||
|
|
||||||
tags_tries = self.get_all_tags()
|
tags_tries = self.get_all_tags()
|
||||||
for tag in tags_tries:
|
for tag in tags_tries:
|
||||||
moy_tag = self.moyennes_tags[tag]
|
moy_tag = self.moyennes_tags[tag]
|
||||||
|
for acronyme in moy_tag.moys_ues:
|
||||||
|
moy = moy_tag.moys_ues[acronyme] # une moyenne
|
||||||
|
df = df.join(moy.synthese["notes"].rename(f"Moy {tag}-{acronyme}"))
|
||||||
|
df = df.join(
|
||||||
|
moy.synthese["classements"].rename(f"Class {tag}-{acronyme}")
|
||||||
|
)
|
||||||
moy_gen = moy_tag.moy_gen
|
moy_gen = moy_tag.moy_gen
|
||||||
df = df.join(moy_gen.synthese["notes"].rename(f"Moy {tag}"))
|
df = df.join(moy_gen.synthese["notes"].rename(f"Moy {tag} (gen)"))
|
||||||
df = df.join(moy_gen.synthese["classements"].rename(f"Class {tag}"))
|
df = df.join(moy_gen.synthese["classements"].rename(f"Class {tag} (gen)"))
|
||||||
|
|
||||||
|
df.sort_values(by=['nom'])
|
||||||
|
|
||||||
return df
|
return df
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user