forked from ScoDoc/ScoDoc
Relecture + améliorations diverses (dont tri systématique par etudids_sorted, acronymes_sorted, competences_sorted) des dataframes
This commit is contained in:
parent
8de1a44583
commit
83059cd995
@ -60,6 +60,7 @@ from app.pe.pe_rcstag import RCSTag
|
||||
from app.pe.pe_ressemtag import ResSemBUTTag
|
||||
from app.pe.pe_interclasstag import RCSInterclasseTag
|
||||
import app.pe.pe_rcss_jury as pe_rcss_jury
|
||||
import app.pe.rcss.rcss_constantes as rcss_constantes
|
||||
|
||||
|
||||
class JuryPE(object):
|
||||
@ -107,6 +108,7 @@ class JuryPE(object):
|
||||
self._gen_xls_diplomes(zipfile)
|
||||
self._gen_xls_ressembuttags(zipfile)
|
||||
self._gen_rcss()
|
||||
self._gen_rcsf()
|
||||
self._gen_xls_sxtags(zipfile)
|
||||
self._gen_rcrcfs()
|
||||
self._gen_xls_rcrcss_tags(zipfile)
|
||||
@ -166,11 +168,14 @@ class JuryPE(object):
|
||||
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for res_sem_tag in self.ressembuttags.values():
|
||||
onglet = res_sem_tag.get_repr(verbose=False)
|
||||
onglet = res_sem_tag.get_repr(verbose=True)
|
||||
onglets += []
|
||||
df = res_sem_tag.df_moyennes_et_classements()
|
||||
# écriture dans l'onglet
|
||||
df.to_excel(writer, onglet, index=True, header=True)
|
||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||
output.seek(0)
|
||||
|
||||
self.add_file_to_zip(
|
||||
@ -190,16 +195,19 @@ class JuryPE(object):
|
||||
|
||||
self.rcss_jury.cree_rcss(self.etudiants)
|
||||
|
||||
def _gen_xls_sxtags(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).
|
||||
"""
|
||||
def _gen_rcsf(self):
|
||||
"""Génère les RCF, regroupement de semestres de type Sx pour préparer
|
||||
le calcul des moyennes par Sx"""
|
||||
# Génère les regroupements de semestres de type Sx
|
||||
pe_affichage.pe_print(
|
||||
"*** Génère les RCSValid (RCS de même Sx donnant lieu à validation du semestre)"
|
||||
)
|
||||
self.rcss_jury.cree_rcfs(self.etudiants)
|
||||
|
||||
def _gen_xls_sxtags(self, zipfile: ZipFile):
|
||||
"""Génère les semestres taggués en s'appuyant sur les RCF 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 des SxTag")
|
||||
|
||||
@ -216,11 +224,15 @@ class JuryPE(object):
|
||||
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for sxtag in self.sxtags.values():
|
||||
onglet = sxtag.get_repr(verbose=False)
|
||||
onglets += [onglet]
|
||||
df = sxtag.df_moyennes_et_classements()
|
||||
# écriture dans l'onglet
|
||||
df.to_excel(writer, onglet, index=True, header=True)
|
||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||
|
||||
output.seek(0)
|
||||
|
||||
self.add_file_to_zip(
|
||||
@ -269,11 +281,14 @@ class JuryPE(object):
|
||||
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for rcs_tag in self.rcss_tags.values():
|
||||
onglet = rcs_tag.get_repr(verbose=False)
|
||||
onglets += [onglet]
|
||||
df = rcs_tag.df_moyennes_et_classements()
|
||||
# écriture dans l'onglet
|
||||
df.to_excel(writer, onglet, index=True, header=True)
|
||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||
output.seek(0)
|
||||
|
||||
self.add_file_to_zip(
|
||||
@ -296,12 +311,16 @@ class JuryPE(object):
|
||||
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for interclass_tag in self.interclassements_taggues.values():
|
||||
if interclass_tag.significatif: # Avec des notes
|
||||
onglet = interclass_tag.get_repr()
|
||||
onglets += [onglet]
|
||||
df = interclass_tag.df_moyennes_et_classements()
|
||||
# écriture dans l'onglet
|
||||
df.to_excel(writer, onglet, index=True, header=True)
|
||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||
|
||||
output.seek(0)
|
||||
|
||||
self.add_file_to_zip(
|
||||
@ -322,9 +341,12 @@ class JuryPE(object):
|
||||
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for onglet, df in self.synthese.items():
|
||||
onglets += [onglet]
|
||||
# écriture dans l'onglet:
|
||||
df.to_excel(writer, onglet, index=True, header=True)
|
||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||
output.seek(0)
|
||||
|
||||
self.add_file_to_zip(
|
||||
@ -342,9 +364,12 @@ class JuryPE(object):
|
||||
with pd.ExcelWriter( # pylint: disable=abstract-class-instantiated
|
||||
output, engine="openpyxl"
|
||||
) as writer:
|
||||
onglets = []
|
||||
for onglet, df in synthese.items():
|
||||
onglets += [onglet]
|
||||
# écriture dans l'onglet:
|
||||
df.to_excel(writer, onglet, index=True, header=True)
|
||||
pe_affichage.pe_print(f"=> Export excel de {', '.join(onglets)}")
|
||||
output.seek(0)
|
||||
|
||||
self.add_file_to_zip(
|
||||
@ -433,7 +458,7 @@ class JuryPE(object):
|
||||
|
||||
# Ajout des aggrégats
|
||||
for aggregat in pe_rcs.TOUS_LES_RCS:
|
||||
descr = app.pe.rcss.constantes.TYPES_RCS[aggregat]["descr"]
|
||||
descr = rcss_constantes.TYPES_RCS[aggregat]["descr"]
|
||||
|
||||
# Les trajectoires (tagguées) suivies par les étudiants pour l'aggrégat et le tag
|
||||
# considéré
|
||||
|
@ -3,9 +3,7 @@ import pandas as pd
|
||||
|
||||
from app import comp
|
||||
from app.comp.moy_sem import comp_ranks_series
|
||||
from app.models import UniteEns
|
||||
from app.pe import pe_affichage
|
||||
from app.scodoc.codes_cursus import UE_SPORT
|
||||
|
||||
|
||||
class Moyenne:
|
||||
@ -24,12 +22,12 @@ class Moyenne:
|
||||
"""Classe centralisant la synthèse des moyennes/classements d'une série
|
||||
de notes :
|
||||
|
||||
* des "notes": la Serie pandas des notes (float),
|
||||
* des "classements": la Serie pandas des classements (float),
|
||||
* des "min": la note minimum,
|
||||
* des "max": la note maximum,
|
||||
* des "moy": la moyenne,
|
||||
* des "nb_inscrits": le nombre d'étudiants ayant une note,
|
||||
* des "notes" : la Serie pandas des notes (float),
|
||||
* des "classements" : la Serie pandas des classements (float),
|
||||
* des "min" : la note minimum,
|
||||
* des "max" : la note maximum,
|
||||
* des "moy" : la moyenne,
|
||||
* des "nb_inscrits" : le nombre d'étudiants ayant une note,
|
||||
"""
|
||||
self.notes = notes
|
||||
"""Les notes"""
|
||||
@ -171,7 +169,7 @@ class MoyennesTag:
|
||||
tag: Un tag
|
||||
matrice_notes: Les moyennes (etudid x acronymes_ues ou etudid x compétences) aux différentes UEs ou compétences
|
||||
matrice_coeffs: Les coeff à appliquer pour le calcul de la moyenne générale
|
||||
# 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
|
||||
"""Le tag associé aux moyennes"""
|
||||
@ -207,7 +205,7 @@ class MoyennesTag:
|
||||
ont des notes
|
||||
|
||||
Returns:
|
||||
True si a des notes, False sinon
|
||||
True si la moytag a des notes, False sinon
|
||||
"""
|
||||
notes = self.matrice_notes
|
||||
nbre_nan = notes.isna().sum().sum()
|
||||
|
@ -152,7 +152,8 @@ class RCSsJuryPE:
|
||||
|
||||
# Ajout du RCRCF
|
||||
if rcf_id not in self.rcrcfs:
|
||||
self.rcrcfs[rcf_id] = pe_rcrcf.RCRCF(rcf_id, rcf.formsemestre_final)
|
||||
rcf_nom = rcf_id[0]
|
||||
self.rcrcfs[rcf_id] = pe_rcrcf.RCRCF(rcf_nom, rcf.formsemestre_final)
|
||||
rcrcf = self.rcrcfs[rcf_id]
|
||||
|
||||
# Ajout des RCFs au RCRCF
|
||||
|
@ -37,6 +37,7 @@ Created on Fri Sep 9 09:15:05 2016
|
||||
"""
|
||||
|
||||
from app.comp.res_sem import load_formsemestre_results
|
||||
from app.models import FormSemestre
|
||||
from app.pe import pe_affichage
|
||||
import pandas as pd
|
||||
import numpy as np
|
||||
@ -49,7 +50,7 @@ from app.pe.pe_moytag import MoyennesTag
|
||||
|
||||
|
||||
class RCSTag(TableTag):
|
||||
def __init__(self, rcrcf: pe_rcs.RCS, sxstags: dict[(str, int): pe_sxtag.SxTag]):
|
||||
def __init__(self, rcrcf: pe_rcs.RCS, sxstags: dict[(str, int) : pe_sxtag.SxTag]):
|
||||
"""Calcule les moyennes par tag (orientées compétences)
|
||||
d'un regroupement de SxTag
|
||||
(RCRCF), pour extraire les classements par tag pour un
|
||||
@ -71,17 +72,18 @@ class RCSTag(TableTag):
|
||||
self.nom = self.get_repr()
|
||||
"""Représentation textuelle du RCS taggué"""
|
||||
|
||||
self.formsemestre_terminal = rcrcf.formsemestre_final
|
||||
"""Le formsemestre terminal"""
|
||||
# Les données du semestre final
|
||||
self.formsemestre_terminal: FormSemestre = rcrcf.formsemestre_final
|
||||
"""Le semestre final"""
|
||||
self.fid_final: int = rcrcf.formsemestre_final.formsemestre_id
|
||||
"""Le fid du semestre final"""
|
||||
|
||||
# Affichage pour debug
|
||||
pe_affichage.pe_print(f"-> {self.get_repr(verbose=True)}")
|
||||
|
||||
# Les résultats du formsemestre terminal
|
||||
nt = load_formsemestre_results(self.formsemestre_terminal)
|
||||
|
||||
# Les données aggrégés (RCRCF + SxTags
|
||||
self.rcfs_aggreges = rcrcf.rcfs_aggreges
|
||||
"""Les RCFs aggrégés"""
|
||||
|
||||
self.sxstags = {}
|
||||
"""Les SxTag associés aux RCF aggrégés"""
|
||||
try:
|
||||
@ -91,41 +93,57 @@ class RCSTag(TableTag):
|
||||
raise ValueError("Semestres SxTag manquants")
|
||||
|
||||
# Les étudiants (etuds, états civils & etudis)
|
||||
self.etuds = nt.etuds
|
||||
self.add_etuds(nt.etuds)
|
||||
sxtag_final = self.sxstags[self.rcs_id]
|
||||
self.etuds = sxtag_final.etuds
|
||||
"""Les étudiants (extraits du semestre final)"""
|
||||
self.add_etuds(self.etuds)
|
||||
self.etudids_sorted = sorted(self.etudids)
|
||||
"""Etudids triés"""
|
||||
"""Les étudids triés"""
|
||||
|
||||
# Les compétences (extraites de tous les Sxtags)
|
||||
self.association_ues_comp = self.mapping_ue_competences()
|
||||
"""Association indiquant pour chaque UE , quelle compétence lui correspond"""
|
||||
pe_affichage.pe_print(f"* Association UEs -> compétences : {self.association_ues_comp}")
|
||||
|
||||
self.competences_sorted = self.do_complist()
|
||||
"""Compétences (triées) extraites de tous les SxTag aggrégés"""
|
||||
self.acronymes_ues_to_competences = self._do_acronymes_to_competences()
|
||||
"""L'association acronyme d'UEs -> compétence (extraites des SxTag aggrégés)"""
|
||||
pe_affichage.pe_print(
|
||||
f"* Association UEs -> compétences : {self.acronymes_ues_to_competences}"
|
||||
)
|
||||
self.competences_sorted = sorted(self.acronymes_ues_to_competences.values())
|
||||
"""Compétences (triées par nom, extraites des SxTag aggrégés)"""
|
||||
pe_affichage.pe_print(f"* Compétences : {', '.join(self.competences_sorted)}")
|
||||
|
||||
# Les tags
|
||||
self.tags_sorted = self.do_taglist()
|
||||
self.tags_sorted = self._do_taglist()
|
||||
"""Tags extraits de tous les SxTag aggrégés"""
|
||||
pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}")
|
||||
|
||||
# Les moyennes
|
||||
self.moyennes_tags: dict[str, MoyennesTag] = {}
|
||||
"""Synthétise les moyennes/classements par tag (qu'ils soient personnalisé ou de compétences)"""
|
||||
|
||||
for tag in self.tags_sorted:
|
||||
# Cube de note
|
||||
notes_cube, coeffs_cube = self.compute_notes_comps_cube(tag, self.etudids_sorted, self.competences_sorted)
|
||||
|
||||
# Calcule des moyennes/coeffs sous forme d'un dataframe"""
|
||||
moys_competences, coeffs_competences = compute_notes_competences(
|
||||
notes_cube, coeffs_cube, self.etudids_sorted, self.competences_sorted
|
||||
# Cube de notes (etudids_sorted x compétences_sorted x sxstags)
|
||||
notes_df, notes_cube = self.compute_notes_comps_cube(
|
||||
tag, self.etudids_sorted, self.competences_sorted, self.sxstags
|
||||
)
|
||||
# Calcule des moyennes/coeffs sous forme d'un dataframe"""
|
||||
moys_competences = compute_notes_competences(
|
||||
notes_cube, self.etudids_sorted, self.competences_sorted
|
||||
)
|
||||
# Cube de coeffs pour la moyenne générale,
|
||||
# traduisant les inscriptions des étudiants aux UEs (etudids_sorted x compétences_sorted x sxstags)
|
||||
coeffs_df, coeffs_cube = self.compute_coeffs_comps_cube(
|
||||
tag,
|
||||
self.etudids_sorted,
|
||||
self.competences_sorted,
|
||||
self.sxstags,
|
||||
)
|
||||
# Calcule la synthèse des coefficients à prendre en compte pour la moyenne
|
||||
# générale
|
||||
matrice_coeffs_moy_gen = compute_coeffs_competences(
|
||||
coeffs_cube, notes_cube, self.etudids_sorted, self.competences_sorted
|
||||
)
|
||||
# Mémorise les moyennes et les coeff associés
|
||||
self.moyennes_tags[tag] = MoyennesTag(
|
||||
tag, moys_competences, matrice_coeffs_moy_gen
|
||||
)
|
||||
|
||||
# Les moyennes
|
||||
self.moyennes_tags[tag] = MoyennesTag(tag, moys_competences,
|
||||
coeffs_competences)
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Egalité de 2 RCS taggués sur la base de leur identifiant"""
|
||||
@ -139,107 +157,200 @@ class RCSTag(TableTag):
|
||||
else:
|
||||
return f"{self.__class__.__name__} ({self.rcs_id})"
|
||||
|
||||
def compute_notes_comps_cube(self, tag, etudids_sorted: list[int], competences_sorted: list[str]):
|
||||
"""Pour un tag donné, construit :
|
||||
* le cube de notes (etudid x competences x SxTag) nécessaire au calcul des moyennes,
|
||||
en remplaçant les données d'UE (obtenus du SxTag) par les compétences
|
||||
* le cube de coeffs (etudid x competences x SxTag) (traduisant les inscriptions)
|
||||
appliqué au calcul des différents SxTag
|
||||
def compute_notes_comps_cube(
|
||||
self,
|
||||
tag,
|
||||
etudids_sorted: list[int],
|
||||
competences_sorted: list[str],
|
||||
sxstags: dict[(str, int) : pe_sxtag.SxTag],
|
||||
):
|
||||
"""Pour un tag donné, construit le cube de notes (etudid x competences x SxTag)
|
||||
nécessaire au calcul des moyennes,
|
||||
en remplaçant les données d'UE (obtenus du SxTag) par les compétences
|
||||
|
||||
Args:
|
||||
tag: Le tag visé
|
||||
etudids_sorted: Les etudis triés
|
||||
competences_sorted: Les compétences triées
|
||||
etudids_sorted: Les etudis triés (dim 0)
|
||||
competences_sorted: Les compétences triées (dim 1)
|
||||
sxstags: Les SxTag à réunir
|
||||
"""
|
||||
# nb_tags = len(self.tags_sorted)
|
||||
# nb_etudiants = len(self.etuds)
|
||||
# nb_semestres = len(self.semestres_tags_aggreges)
|
||||
|
||||
# Index du cube (etudids -> dim 0, tags -> dim 1)
|
||||
# etudids = [etud.etudid for etud in self.etuds]
|
||||
# competences_sorted = self.competences_sorted
|
||||
sxstags_ids = list(self.sxstags.keys())
|
||||
|
||||
notes_dfs = {}
|
||||
coeffs_dfs = {}
|
||||
|
||||
for sxtag_id, sxtag in self.sxstags.items():
|
||||
for sxtag_id, sxtag in sxstags.items():
|
||||
# Partant d'un dataframe vierge
|
||||
notes_df = pd.DataFrame(np.nan, index=etudids_sorted, columns=competences_sorted)
|
||||
coeffs_df = pd.DataFrame(np.nan, index=etudids_sorted, columns=competences_sorted)
|
||||
|
||||
notes_df = pd.DataFrame(
|
||||
np.nan, index=etudids_sorted, columns=competences_sorted
|
||||
)
|
||||
# Charge les notes du semestre tag (copie car changement de nom de colonnes à venir)
|
||||
moys_tag = sxtag.moyennes_tags[tag]
|
||||
|
||||
# Charge les notes et les coeffs du semestre tag
|
||||
notes = moys_tag.matrice_notes.copy() # avec une copie
|
||||
coeffs = moys_tag.matrice_coeffs_moy_gen.copy() # les coeffs
|
||||
|
||||
# Traduction des UE en compétences
|
||||
ues_columns_df = notes.columns
|
||||
comp_associes_aux_ues = [self.association_ues_comp[ue] for ue in ues_columns_df]
|
||||
notes.columns = comp_associes_aux_ues
|
||||
coeffs.columns = comp_associes_aux_ues
|
||||
# Traduction des acronymes d'UE en compétences
|
||||
acronymes_ues_columns = notes.columns
|
||||
acronymes_to_comps = [
|
||||
self.acronymes_ues_to_competences[acro]
|
||||
for acro in acronymes_ues_columns
|
||||
]
|
||||
notes.columns = acronymes_to_comps
|
||||
|
||||
# Les étudiants et les compétences communes
|
||||
etudids_communs, comp_communes = pe_comp.find_index_and_columns_communs(notes_df, notes)
|
||||
etudids_communs, comp_communes = pe_comp.find_index_and_columns_communs(
|
||||
notes_df, notes
|
||||
)
|
||||
|
||||
# Recopie des notes et des coeffs
|
||||
notes_df.loc[etudids_communs, comp_communes] = notes.loc[
|
||||
etudids_communs, comp_communes
|
||||
]
|
||||
|
||||
# Supprime tout ce qui n'est pas numérique
|
||||
# for col in notes_df.columns:
|
||||
# notes_df[col] = pd.to_numeric(notes_df[col], errors="coerce")
|
||||
|
||||
# Stocke les dfs
|
||||
notes_dfs[sxtag_id] = notes_df
|
||||
|
||||
"""Réunit les notes sous forme d'un cube etudids x competences x semestres"""
|
||||
sxtag_x_etudids_x_comps = [notes_dfs[sxtag_id] for sxtag_id in sxstags]
|
||||
notes_etudids_x_comps_x_sxtag = np.stack(sxtag_x_etudids_x_comps, axis=-1)
|
||||
|
||||
return notes_dfs, notes_etudids_x_comps_x_sxtag
|
||||
|
||||
def compute_coeffs_comps_cube(
|
||||
self,
|
||||
tag,
|
||||
etudids_sorted: list[int],
|
||||
competences_sorted: list[str],
|
||||
sxstags: dict[(str, int) : pe_sxtag.SxTag],
|
||||
):
|
||||
"""Pour un tag donné, construit
|
||||
le cube de coeffs (etudid x competences x SxTag) (traduisant les inscriptions
|
||||
des étudiants aux UEs en fonction de leur parcours)
|
||||
qui s'applique aux différents SxTag
|
||||
en remplaçant les données d'UE (obtenus du SxTag) par les compétences
|
||||
|
||||
Args:
|
||||
tag: Le tag visé
|
||||
etudids_sorted: Les etudis triés
|
||||
competences_sorted: Les compétences triées
|
||||
sxstags: Les SxTag à réunir
|
||||
"""
|
||||
coeffs_dfs = {}
|
||||
|
||||
for sxtag_id, sxtag in sxstags.items():
|
||||
# Partant d'un dataframe vierge
|
||||
coeffs_df = pd.DataFrame(
|
||||
np.nan, index=etudids_sorted, columns=competences_sorted
|
||||
)
|
||||
|
||||
moys_tag = sxtag.moyennes_tags[tag]
|
||||
|
||||
# Charge les notes et les coeffs du semestre tag
|
||||
coeffs = moys_tag.matrice_coeffs_moy_gen.copy() # les coeffs
|
||||
|
||||
# Traduction des acronymes d'UE en compétences
|
||||
acronymes_ues_columns = coeffs.columns
|
||||
acronymes_to_comps = [
|
||||
self.acronymes_ues_to_competences[acro]
|
||||
for acro in acronymes_ues_columns
|
||||
]
|
||||
coeffs.columns = acronymes_to_comps
|
||||
|
||||
# Les étudiants et les compétences communes
|
||||
etudids_communs, comp_communes = pe_comp.find_index_and_columns_communs(
|
||||
coeffs_df, coeffs
|
||||
)
|
||||
|
||||
# Recopie des notes et des coeffs
|
||||
coeffs_df.loc[etudids_communs, comp_communes] = coeffs.loc[
|
||||
etudids_communs, comp_communes
|
||||
]
|
||||
|
||||
# Supprime tout ce qui n'est pas numérique
|
||||
for col in notes_df.columns:
|
||||
notes_df[col] = pd.to_numeric(notes_df[col], errors="coerce")
|
||||
|
||||
# Stocke les dfs
|
||||
notes_dfs[sxtag_id] = notes_df
|
||||
coeffs_dfs[sxtag_id] = coeffs_df
|
||||
|
||||
"""Réunit les notes sous forme d'un cube etudids x competences x semestres"""
|
||||
sxtag_x_etudids_x_comps = [notes_dfs[fid].values for fid in notes_dfs]
|
||||
notes_etudids_x_comps_x_sxtag = np.stack(sxtag_x_etudids_x_comps, axis=-1)
|
||||
|
||||
"""Réunit les coeffs sous forme d'un cube etudids x competences x semestres"""
|
||||
sxtag_x_etudids_x_comps = [coeffs_dfs[fid].values for fid in notes_dfs]
|
||||
sxtag_x_etudids_x_comps = [coeffs_dfs[sxtag_id] for sxtag_id in sxstags]
|
||||
coeffs_etudids_x_comps_x_sxtag = np.stack(sxtag_x_etudids_x_comps, axis=-1)
|
||||
|
||||
return notes_etudids_x_comps_x_sxtag, coeffs_etudids_x_comps_x_sxtag
|
||||
return coeffs_dfs, coeffs_etudids_x_comps_x_sxtag
|
||||
|
||||
def do_taglist(self):
|
||||
"""Synthétise les tags à partir des Sxtags aggrégés
|
||||
def _do_taglist(self) -> list[str]:
|
||||
"""Synthétise les tags à partir des Sxtags aggrégés.
|
||||
|
||||
Returns:
|
||||
Une liste de tags triés par ordre alphabétique
|
||||
Liste de tags triés par ordre alphabétique
|
||||
"""
|
||||
tags = []
|
||||
for frmsem_id in self.sxstags:
|
||||
tags.extend(self.sxstags[frmsem_id].tags_sorted)
|
||||
return sorted(set(tags))
|
||||
|
||||
def mapping_ue_competences(self):
|
||||
"""Dictionnaire {ue: competences} extrait des SxTags"""
|
||||
def _do_acronymes_to_competences(self) -> dict[str:str]:
|
||||
"""Synthétise l'association complète {acronyme_ue: competences}
|
||||
extraite de toutes les données/associations des SxTags
|
||||
aggrégés.
|
||||
|
||||
Returns:
|
||||
Un dictionnaire {'acronyme_ue' : 'compétences'}
|
||||
"""
|
||||
dict_competences = {}
|
||||
for sxtag_id, sxtag in self.sxstags.items():
|
||||
comp = sxtag.competences
|
||||
dict_competences |= comp
|
||||
dict_competences |= sxtag.acronymes_ues_to_competences
|
||||
return dict_competences
|
||||
|
||||
def do_complist(self):
|
||||
"""Synthétise les compétences à partir des Sxtags aggrégés"""
|
||||
dict_competences = self.mapping_ue_competences()
|
||||
return sorted(set(dict_competences.values()))
|
||||
|
||||
def compute_coeffs_competences(
|
||||
coeff_cube: np.array,
|
||||
set_cube: np.array,
|
||||
etudids_sorted: list,
|
||||
competences_sorted: list,
|
||||
):
|
||||
"""Calcule les coeffs à utiliser pour la moyenne générale (toutes compétences
|
||||
confondues), en fonction des notes (set_cube) aggrégées.
|
||||
|
||||
Args:
|
||||
coeffs_cube: coeffs impliqués dans la moyenne générale (semestres par semestres)
|
||||
set_cube: notes moyennes aux modules ndarray
|
||||
(etuds x UEs|compétences x sxtags), des floats avec des NaN
|
||||
etudids_sorted: liste des étudiants (dim. 0 du cube)
|
||||
competences_sorted: list
|
||||
|
||||
Returns:
|
||||
Un DataFrame de coefficients (etudids_sorted x compétences_sorted)
|
||||
"""
|
||||
nb_etuds, nb_comps, nb_semestres = set_cube.shape
|
||||
assert nb_etuds == len(etudids_sorted)
|
||||
assert nb_comps == len(competences_sorted)
|
||||
|
||||
# Quelles entrées du cube contiennent des notes ?
|
||||
mask = ~np.isnan(set_cube)
|
||||
|
||||
# Enlève les NaN du cube de notes pour les entrées manquantes
|
||||
coeffs_cube_no_nan = np.nan_to_num(coeff_cube, nan=0.0)
|
||||
|
||||
# Retire les coefficients associées à des données sans notes
|
||||
coeffs_cube_no_nan = coeffs_cube_no_nan * mask
|
||||
|
||||
# Somme les coefficients (correspondant à des notes)
|
||||
coeff_tag = np.sum(coeffs_cube_no_nan, axis=2)
|
||||
|
||||
# Le dataFrame des coeffs
|
||||
coeffs_df = pd.DataFrame(
|
||||
coeff_tag, index=etudids_sorted, columns=competences_sorted
|
||||
)
|
||||
# Remet à Nan les coeffs à 0
|
||||
coeffs_df.fillna(np.nan)
|
||||
|
||||
return coeffs_df
|
||||
|
||||
|
||||
def compute_notes_competences(
|
||||
set_cube: np.array, coeff_cube: np.array, etudids_sorted: list, competences_sorted: list
|
||||
set_cube: np.array,
|
||||
etudids_sorted: list,
|
||||
competences_sorted: list,
|
||||
):
|
||||
"""Calcule:
|
||||
* la moyenne par compétences à un tag donné sur plusieurs semestres (partant du set_cube).
|
||||
* la somme des coeffs à utiliser pour la moyenne générale.
|
||||
"""Calcule la moyenne par compétences (à un tag donné) sur plusieurs semestres (partant du set_cube).
|
||||
|
||||
La moyenne est un nombre (note/20), ou NaN si pas de notes disponibles
|
||||
|
||||
@ -249,7 +360,6 @@ def compute_notes_competences(
|
||||
Args:
|
||||
set_cube: notes moyennes aux modules ndarray
|
||||
(etuds x UEs|compétences x sxtags), des floats avec des NaN
|
||||
coeffs_cube: somme des coeffs impliqués dans la moyennes
|
||||
etudids_sorted: liste des étudiants (dim. 0 du cube)
|
||||
competences_sorted: list
|
||||
tags: liste des tags (dim. 1 du cube)
|
||||
@ -266,13 +376,10 @@ def compute_notes_competences(
|
||||
|
||||
# Enlève les NaN du cube de notes pour les entrées manquantes
|
||||
set_cube_no_nan = np.nan_to_num(set_cube, nan=0.0)
|
||||
coeffs_cube_no_nan = np.nan_to_num(coeff_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)
|
||||
# La somme des coeffs
|
||||
coeff_tag = np.sum(coeffs_cube_no_nan, axis=2)
|
||||
|
||||
# Le dataFrame des notes moyennes
|
||||
etud_moy_tag_df = pd.DataFrame(
|
||||
@ -282,7 +389,4 @@ def compute_notes_competences(
|
||||
)
|
||||
etud_moy_tag_df.fillna(np.nan)
|
||||
|
||||
coeffs_df = pd.DataFrame(coeff_tag, index=etudids_sorted, columns=competences_sorted)
|
||||
coeffs_df.fillna(np.nan)
|
||||
|
||||
return etud_moy_tag_df, coeffs_df
|
||||
return etud_moy_tag_df
|
||||
|
@ -41,7 +41,7 @@ from app import db, ScoValueError
|
||||
from app import comp
|
||||
from app.comp.res_but import ResultatsSemestreBUT
|
||||
from app.comp.res_sem import load_formsemestre_results
|
||||
from app.models import FormSemestre
|
||||
from app.models import FormSemestre, UniteEns
|
||||
from app.models.moduleimpls import ModuleImpl
|
||||
import app.pe.pe_affichage as pe_affichage
|
||||
import app.pe.pe_etudiant as pe_etudiant
|
||||
@ -55,7 +55,7 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
"""
|
||||
Un ResSemBUTTag représente les résultats des étudiants à un semestre, en donnant
|
||||
accès aux moyennes par tag.
|
||||
Il s'appuie principalement sur FormSemestre et sur ResultatsSemestreBUT.
|
||||
Il s'appuie principalement sur un ResultatsSemestreBUT.
|
||||
"""
|
||||
|
||||
def __init__(self, formsemestre: FormSemestre):
|
||||
@ -69,51 +69,59 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
# Le nom du res_semestre taggué
|
||||
self.nom = self.get_repr(verbose=True)
|
||||
|
||||
pe_affichage.pe_print(f"--> Résultats de semestre taggués {self.nom}")
|
||||
pe_affichage.pe_print(f"--> ResultatsSemestreBUT taggués {self.nom}")
|
||||
|
||||
# Les étudiants (etuds, états civils & etudis) ajouté
|
||||
self.add_etuds(self.etuds)
|
||||
self.etudids_sorted = sorted(self.etudids)
|
||||
"""Les etudids des étudiants du ResultatsSemestreBUT triés"""
|
||||
|
||||
# Les UEs (et les dispenses d'UE)
|
||||
# self.ues
|
||||
ues_standards = [ue for ue in self.ues if ue.type == sco_codes.UE_STANDARD]
|
||||
self.ues_standards: list[UniteEns] = [
|
||||
ue for ue in self.ues if ue.type == sco_codes.UE_STANDARD
|
||||
]
|
||||
"""Liste des UEs standards du ResultatsSemestreBUT"""
|
||||
|
||||
# Les UEs en fonction des parcours
|
||||
self.ues_inscr_parcours_df = self.load_ues_inscr_parcours()
|
||||
|
||||
# Les compétences associées aux UEs (définies par les acronymes)
|
||||
self.competences = {}
|
||||
"""L'association acronyme d'UEs -> compétence"""
|
||||
for ue in self.ues:
|
||||
if ue.type == sco_codes.UE_STANDARD:
|
||||
assert ue.niveau_competence, ScoValueError(
|
||||
"Des UEs ne sont pas rattachées à des compétences"
|
||||
)
|
||||
nom = ue.niveau_competence.competence.titre
|
||||
self.competences[ue.acronyme] = nom
|
||||
|
||||
"""Les inscriptions des étudiants aux UEs du parcours"""
|
||||
# Les acronymes des UEs
|
||||
self.ues_to_acronymes = {ue.id: ue.acronyme for ue in ues_standards}
|
||||
self.ues_to_acronymes = {ue.id: ue.acronyme for ue in self.ues_standards}
|
||||
self.acronymes_sorted = sorted(self.ues_to_acronymes.values())
|
||||
"""Les acronymes de UE triés par ordre alphabétique"""
|
||||
|
||||
# Les compétences associées aux UEs (définies par les acronymes)
|
||||
self.acronymes_ues_to_competences = {}
|
||||
"""L'association acronyme d'UEs -> compétence"""
|
||||
for ue in self.ues_standards:
|
||||
assert ue.niveau_competence, ScoValueError(
|
||||
"Des UEs ne sont pas rattachées à des compétences"
|
||||
)
|
||||
nom = ue.niveau_competence.competence.titre
|
||||
self.acronymes_ues_to_competences[ue.acronyme] = nom
|
||||
self.competences_sorted = sorted(
|
||||
list(set(self.acronymes_ues_to_competences.values()))
|
||||
)
|
||||
"""Les compétences triées par nom"""
|
||||
|
||||
# Les tags personnalisés et auto:
|
||||
tags_dict = self._get_tags_dict()
|
||||
self._check_tags(tags_dict)
|
||||
|
||||
# Les coefficients pour le calcul de la moyenne générale
|
||||
self.matrice_coeffs_moy_gen = self.ues_inscr_parcours_df * [
|
||||
ue.ects for ue in ues_standards # if ue.type != UE_SPORT <= déjà supprimé
|
||||
]
|
||||
# Les coefficients pour le calcul de la moyenne générale, donnés par
|
||||
# acronymes d'UE
|
||||
self.matrice_coeffs_moy_gen = self._get_matrice_coeffs(
|
||||
self.ues_inscr_parcours_df, self.ues_standards
|
||||
)
|
||||
"""DataFrame indiquant les coeffs des UEs par ordre alphabétique d'acronyme"""
|
||||
|
||||
# Les capitalisations (mask etuids x acronyme_ue valant True si capitalisée, False sinon)
|
||||
self.capitalisations = self._get_capitalisations(ues_standards)
|
||||
|
||||
self.capitalisations = self._get_capitalisations(self.ues_standards)
|
||||
"""DataFrame indiquant les UEs capitalisables d'un étudiant (etudids x )"""
|
||||
|
||||
# Calcul des moyennes & les classements de chaque étudiant à chaque tag
|
||||
self.moyennes_tags = {}
|
||||
|
||||
"""Les moyennes par tags (personnalisés ou 'but')"""
|
||||
for tag in tags_dict["personnalises"]:
|
||||
# pe_affichage.pe_print(f" -> Traitement du tag {tag}")
|
||||
infos_tag = tags_dict["personnalises"][tag]
|
||||
@ -123,49 +131,76 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
)
|
||||
|
||||
# Ajoute les moyennes par UEs + la moyenne générale (but)
|
||||
df_ues = pd.DataFrame(
|
||||
{ue.id: self.etud_moy_ue[ue.id] for ue in ues_standards},
|
||||
index=self.etudids,
|
||||
)
|
||||
# Transforme les UEs en acronyme
|
||||
colonnes = df_ues.columns
|
||||
acronymes = [self.ues_to_acronymes[col] for col in colonnes]
|
||||
df_ues.columns = acronymes
|
||||
|
||||
moy_gen = self.compute_moy_gen()
|
||||
self.moyennes_tags["but"] = MoyennesTag(
|
||||
"but", df_ues, self.matrice_coeffs_moy_gen # , moy_gen_but
|
||||
"but", moy_gen, self.matrice_coeffs_moy_gen # , moy_gen_but
|
||||
)
|
||||
|
||||
self.tags_sorted = self.get_all_tags()
|
||||
"""Tags (personnalisés+compétences) par ordre alphabétique"""
|
||||
|
||||
def get_repr(self, verbose=False):
|
||||
"""Nom affiché pour le semestre taggué"""
|
||||
if verbose:
|
||||
return f"{self.formsemestre} (#{self.formsemestre.formsemestre_id})"
|
||||
def get_repr(self, verbose=False) -> str:
|
||||
"""Nom affiché pour le semestre taggué, de la forme (par ex.):
|
||||
|
||||
* S1#69 si verbose est False
|
||||
* S1 FI 2023 si verbose est True
|
||||
"""
|
||||
if not verbose:
|
||||
return f"{self.formsemestre}#{self.formsemestre.formsemestre_id}"
|
||||
else:
|
||||
return pe_etudiant.nom_semestre_etape(self.formsemestre, avec_fid=True)
|
||||
|
||||
def _get_capitalisations(self, ues_hors_sport) -> pd.DataFrame:
|
||||
"""Renvoie un dataFrame résumant les UEs capitalisables par les
|
||||
étudiants, d'après les décisions de jury
|
||||
def _get_matrice_coeffs(
|
||||
self, ues_inscr_parcours_df: pd.DataFrame, ues_standards: list[UniteEns]
|
||||
) -> pd.DataFrame:
|
||||
"""Renvoie un dataFrame donnant les coefficients à appliquer aux UEs
|
||||
dans le calcul de la moyenne générale (toutes UEs confondues).
|
||||
Prend en compte l'inscription des étudiants aux UEs en fonction de leur parcours
|
||||
(cf. ues_inscr_parcours_df).
|
||||
|
||||
Args:
|
||||
ues_hors_sport: Liste des UEs autres que le sport
|
||||
ues_inscr_parcours_df: Les inscriptions des étudiants aux UEs
|
||||
ues_standards: Les UEs standards à prendre en compte
|
||||
|
||||
Returns:
|
||||
Un dataFrame etudids x acronymes_UEs avec les coeffs des UEs
|
||||
"""
|
||||
capitalisations = pd.DataFrame(False, index=self.etudids_sorted, columns=self.acronymes_sorted)
|
||||
matrice_coeffs_moy_gen = ues_inscr_parcours_df * [
|
||||
ue.ects for ue in ues_standards # if ue.type != UE_SPORT <= déjà supprimé
|
||||
]
|
||||
matrice_coeffs_moy_gen.columns = [
|
||||
self.ues_to_acronymes[ue.id] for ue in ues_standards
|
||||
]
|
||||
# Tri par etudids (dim 0) et par acronymes (dim 1)
|
||||
matrice_coeffs_moy_gen = matrice_coeffs_moy_gen.sort_index()
|
||||
matrice_coeffs_moy_gen = matrice_coeffs_moy_gen.sort_index(axis=1)
|
||||
return matrice_coeffs_moy_gen
|
||||
|
||||
def _get_capitalisations(self, ues_standards) -> pd.DataFrame:
|
||||
"""Renvoie un dataFrame résumant les UEs capitalisables par les
|
||||
étudiants, d'après les décisions de jury (sous réserve qu'elles existent).
|
||||
|
||||
Args:
|
||||
ues_standards: Liste des UEs standards (notamment autres que le sport)
|
||||
Returns:
|
||||
Un dataFrame etudids x acronymes_UEs dont les valeurs sont ``True`` si l'UE
|
||||
est capitalisable, ``False`` sinon
|
||||
"""
|
||||
capitalisations = pd.DataFrame(
|
||||
False, index=self.etudids_sorted, columns=self.acronymes_sorted
|
||||
)
|
||||
self.get_formsemestre_validations() # charge les validations
|
||||
res_jury = self.validations
|
||||
if res_jury:
|
||||
for etud in self.etuds:
|
||||
etudid = etud.etudid
|
||||
decisions = res_jury.decisions_jury_ues.get(etudid, {})
|
||||
for ue in ues_hors_sport:
|
||||
for ue in ues_standards:
|
||||
if ue.id in decisions and decisions[ue.id]["code"] == sco_codes.ADM:
|
||||
capitalisations.loc[etudid, ue.acronyme] = True
|
||||
# pe_affichage.pe_print(
|
||||
# f" ⚠ Capitalisation de {ue.acronyme} pour {etud.etat_civil}"
|
||||
# )
|
||||
# Tri par etudis et par accronyme d'UE
|
||||
capitalisations = capitalisations.sort_index()
|
||||
capitalisations = capitalisations.sort_index(axis=1)
|
||||
return capitalisations
|
||||
|
||||
def compute_moy_ues_tag(self, info_tag: dict[int, dict]) -> pd.DataFrame:
|
||||
@ -208,14 +243,38 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
block=self.formsemestre.block_moyennes,
|
||||
)
|
||||
|
||||
# Ne conserve que les UEs standards
|
||||
colonnes = [ue.id for ue in self.ues_standards]
|
||||
moyennes_ues_tag = moyennes_ues_tag[colonnes]
|
||||
|
||||
# Transforme les UEs en acronyme
|
||||
colonnes = moyennes_ues_tag.columns
|
||||
ue_to_acro = {ue.id: ue.acronyme for ue in self.ues}
|
||||
acronymes = [ue_to_acro[col] for col in colonnes]
|
||||
acronymes = [self.ues_to_acronymes[ue.id] for ue in self.ues_standards]
|
||||
moyennes_ues_tag.columns = acronymes
|
||||
|
||||
# Tri par etudids et par ordre alphabétique d'acronyme
|
||||
moyennes_ues_tag = moyennes_ues_tag.sort_index()
|
||||
moyennes_ues_tag = moyennes_ues_tag.sort_index(axis=1)
|
||||
|
||||
return moyennes_ues_tag
|
||||
|
||||
def compute_moy_gen(self):
|
||||
"""Récupère les moyennes des UEs pour le calcul de la moyenne générale,
|
||||
en associant à chaque UE.id son acronyme (toutes UEs confondues)
|
||||
"""
|
||||
df_ues = pd.DataFrame(
|
||||
{ue.id: self.etud_moy_ue[ue.id] for ue in self.ues_standards},
|
||||
index=self.etudids,
|
||||
)
|
||||
# Transforme les UEs en acronyme
|
||||
colonnes = df_ues.columns
|
||||
acronymes = [self.ues_to_acronymes[col] for col in colonnes]
|
||||
df_ues.columns = acronymes
|
||||
|
||||
# Tri par ordre aphabétique de colonnes
|
||||
df_ues.sort_index(axis=1)
|
||||
|
||||
return df_ues
|
||||
|
||||
def _get_tags_dict(self):
|
||||
"""Renvoie les tags personnalisés (déduits des modules du semestre)
|
||||
et les tags automatiques ('but'), et toutes leurs informations,
|
||||
|
@ -54,20 +54,24 @@ class SxTag(TableTag):
|
||||
ressembuttags: dict[int, pe_ressemtag.ResSemBUTTag],
|
||||
):
|
||||
"""Calcule les moyennes/classements par tag d'un semestre de type 'Sx'
|
||||
(par ex. 'S1', 'S2', ...) avec une orientation par UE :
|
||||
(par ex. 'S1', 'S2', ...) représentés par acronyme d'UE.
|
||||
|
||||
* pour les étudiants non redoublants, ce sont les moyennes/classements
|
||||
Il représente :
|
||||
|
||||
* pour les étudiants *non redoublants* : moyennes/classements
|
||||
du semestre suivi
|
||||
* pour les étudiants redoublants, c'est une fusion des moyennes/classements
|
||||
dans les (2) 'Sx' qu'il a suivi
|
||||
* pour les étudiants *redoublants* : une fusion des moyennes/classements
|
||||
dans les (2) 'Sx' qu'il a suivi, en exploitant les informations de capitalisation :
|
||||
meilleure moyenne entre l'UE capitalisée et l'UE refaite (la notion de meilleure
|
||||
s'appliquant à la moyenne d'UE)
|
||||
|
||||
Un SxTag peut donc regrouper plusieurs semestres.
|
||||
Un SxTag (regroupant potentiellement plusieurs semestres) est identifié
|
||||
par un tuple ``(Sx, fid)`` où :
|
||||
|
||||
Un SxTag est identifié par un tuple (x, fid) où x est le numéro (semestre_id)
|
||||
du semestre et fid le formsemestre_id du semestre final (le plus récent) du
|
||||
regrouprement.
|
||||
* ``x`` est le rang (semestre_id) du semestre
|
||||
* ``fid`` le formsemestre_id du semestre final (le plus récent) du regroupement.
|
||||
|
||||
Les **tags**, les **UE** et les inscriptions aux UEs (pour les etudiants)
|
||||
Les **tags**, les **UE** et les inscriptions aux UEs (pour les étudiants)
|
||||
considérés sont uniquement ceux du semestre final.
|
||||
|
||||
Args:
|
||||
@ -85,6 +89,7 @@ class SxTag(TableTag):
|
||||
|
||||
self.rcf = rcf
|
||||
"""Le RCF sur lequel il s'appuie"""
|
||||
assert rcf.rcs_id == sxtag_id, "Problème de correspondance SxTag/RCF"
|
||||
|
||||
# Les resultats des semestres taggués à prendre en compte dans le RCF
|
||||
self.ressembuttags = {fid: ressembuttags[fid] for fid in rcf.semestres_aggreges}
|
||||
@ -95,10 +100,9 @@ class SxTag(TableTag):
|
||||
self.ressembuttag_final = ressembuttags[self.fid_final]
|
||||
"""Le ResSemBUTTag final"""
|
||||
|
||||
self.etuds = ressembuttags[self.fid_final].etuds
|
||||
"""Les étudiants du ReSemBUTTag final"""
|
||||
|
||||
# Ajout les etudids et les états civils
|
||||
# Ajoute les etudids et les états civils
|
||||
self.etuds = self.ressembuttag_final.etuds
|
||||
"""Les étudiants (extraits du ReSemBUTTag final)"""
|
||||
self.add_etuds(self.etuds)
|
||||
self.etudids_sorted = sorted(self.etudids)
|
||||
"""Les etudids triés"""
|
||||
@ -108,88 +112,93 @@ class SxTag(TableTag):
|
||||
|
||||
# Les tags
|
||||
self.tags_sorted = self.ressembuttag_final.tags_sorted
|
||||
"""Tags (extraits uniquement du semestre final)"""
|
||||
"""Tags (extraits du ReSemBUTTag final)"""
|
||||
pe_affichage.pe_print(f"* Tags : {', '.join(self.tags_sorted)}")
|
||||
|
||||
# Les UE
|
||||
moy_sem_final = self.ressembuttag_final.moyennes_tags["but"]
|
||||
self.ues = list(moy_sem_final.matrice_notes.columns)
|
||||
# Les UE données par leur acronyme
|
||||
self.acronymes_sorted = self.ressembuttag_final.acronymes_sorted
|
||||
"""Les acronymes des UEs (extraits du ResSemBUTTag final)"""
|
||||
|
||||
# L'association UE-compétences extraites du dernier semestre
|
||||
self.competences = self.ressembuttag_final.competences
|
||||
self.acronymes_ues_to_competences = (
|
||||
self.ressembuttag_final.acronymes_ues_to_competences
|
||||
)
|
||||
"""L'association acronyme d'UEs -> compétence"""
|
||||
self.competences_sorted = sorted(self.acronymes_ues_to_competences.values())
|
||||
"""Les compétences triées par nom"""
|
||||
|
||||
# Les acronymes des UE
|
||||
self.acronymes_ues_sorted = sorted(self.ues)
|
||||
|
||||
# Les inscriptions des étudiants aux UEs
|
||||
# => ne conserve que les UEs du semestre final (pour les redoublants)
|
||||
self.ues_inscr_parcours_df = self.ressembuttag_final.ues_inscr_parcours_df
|
||||
self.ues_inscr_parcours_df.sort_index()
|
||||
|
||||
# Les coeffs pour la moyenne générale
|
||||
self.matrice_coeffs_moy_gen = self.ressembuttag_final.moyennes_tags[
|
||||
"but"
|
||||
].matrice_coeffs_moy_gen
|
||||
self.matrice_coeffs_moy_gen.sort_index() # Trie les coeff par etudids
|
||||
|
||||
# Les moyennes par tag
|
||||
self.moyennes_tags: dict[str, pd.DataFrame] = {}
|
||||
"""Les notes aux UEs dans différents tags"""
|
||||
# Les coeffs pour la moyenne générale (traduisant également l'inscription
|
||||
# des étudiants aux UEs) (etudids_sorted x acronymes_ues_sorted)
|
||||
self.matrice_coeffs_moy_gen = self.ressembuttag_final.matrice_coeffs_moy_gen
|
||||
|
||||
# Masque des inscriptions et des capitalisations
|
||||
self.masque_df, masque_cube = compute_masques_ues_cube(
|
||||
self.masque_df = None
|
||||
"""Le DataFrame traduisant les capitalisations des différents semestres"""
|
||||
self.masque_df, masque_cube = compute_masques_capitalisation_cube(
|
||||
self.etudids_sorted,
|
||||
self.acronymes_ues_sorted,
|
||||
self.acronymes_sorted,
|
||||
self.ressembuttags,
|
||||
self.fid_final,
|
||||
)
|
||||
self._aff_capitalisations()
|
||||
|
||||
# Les moyennes par tag
|
||||
self.moyennes_tags: dict[str, pd.DataFrame] = {}
|
||||
"""Moyennes aux UEs (identifiées par leur acronyme) des différents tags"""
|
||||
for tag in self.tags_sorted:
|
||||
# Y-a-t-il des notes ?
|
||||
if not self.has_notes(tag):
|
||||
pe_affichage.pe_print(f"> MoyTag 🏷{tag} actuellement sans ◯ notes")
|
||||
matrice_moys_ues = pd.DataFrame(np.nan, index=self.etudids_sorted, columns=self.acronymes_ues_sorted)
|
||||
|
||||
matrice_moys_ues = pd.DataFrame(
|
||||
np.nan, index=self.etudids_sorted, columns=self.acronymes_sorted
|
||||
)
|
||||
else:
|
||||
# Cube de note etudids x UEs
|
||||
notes_df, notes_cube = compute_notes_ues_cube(
|
||||
tag,
|
||||
self.etudids_sorted,
|
||||
self.acronymes_ues_sorted,
|
||||
self.acronymes_sorted,
|
||||
self.ressembuttags,
|
||||
)
|
||||
|
||||
# self.ues_inscr_parcours = ~np.isnan(self.matrice_coeffs.to_numpy())
|
||||
# inscr_mask = self.ues_inscr_parcours
|
||||
# Masque des inscriptions aux UEs (extraits de la matrice de coefficients)
|
||||
inscr_mask: np.array = ~np.isnan(self.matrice_coeffs_moy_gen.to_numpy())
|
||||
|
||||
# Calcule des moyennes sous forme d'un dataframe
|
||||
inscr_mask = ~np.isnan(self.ues_inscr_parcours_df.to_numpy())
|
||||
# Matrice des moyennes
|
||||
matrice_moys_ues: pd.DataFrame = compute_notes_ues(
|
||||
notes_cube,
|
||||
masque_cube,
|
||||
self.etudids_sorted,
|
||||
self.acronymes_ues_sorted,
|
||||
self.acronymes_sorted,
|
||||
inscr_mask,
|
||||
)
|
||||
|
||||
# Les profils d'ects (pour debug)
|
||||
profils_ects = []
|
||||
for i in self.matrice_coeffs_moy_gen.index:
|
||||
val = tuple(self.matrice_coeffs_moy_gen.loc[i].fillna("x"))
|
||||
if tuple(val) not in profils_ects:
|
||||
profils_ects.append(tuple(val))
|
||||
pe_affichage.pe_print(
|
||||
f"> MoyTag 🏷{tag} avec "
|
||||
+ f"ues={self.acronymes_ues_sorted} "
|
||||
+ f"ects={profils_ects}"
|
||||
)
|
||||
# Affichage de debug
|
||||
self.__aff_profil_coeff_ects(tag)
|
||||
|
||||
# Les moyennes au tag
|
||||
# Mémorise les infos pour la moyennes au tag
|
||||
self.moyennes_tags[tag] = MoyennesTag(
|
||||
tag, matrice_moys_ues, self.matrice_coeffs_moy_gen
|
||||
)
|
||||
tag, matrice_moys_ues, self.matrice_coeffs_moy_gen
|
||||
)
|
||||
|
||||
def __aff_profil_coeff_ects(self, tag):
|
||||
"""Extrait de la matrice des coeffs, les différents types d'inscription
|
||||
et de coefficients (appelés profil) des étudiants et les affiche
|
||||
(pour debug)
|
||||
"""
|
||||
|
||||
# Les profils d'ects (pour debug)
|
||||
profils_ects = []
|
||||
for i in self.matrice_coeffs_moy_gen.index:
|
||||
val = tuple(self.matrice_coeffs_moy_gen.loc[i].fillna("x"))
|
||||
if tuple(val) not in profils_ects:
|
||||
profils_ects.append(tuple(val))
|
||||
|
||||
# L'affichage
|
||||
ues = ", ".join(self.acronymes_sorted)
|
||||
pe_affichage.pe_print(
|
||||
f"> MoyTag 🏷{tag} avec " + f"ues={ues} " + f"inscr/ects={profils_ects}"
|
||||
)
|
||||
|
||||
def has_notes(self, tag):
|
||||
"""Détermine si le SxTag, pour un tag donné, est en cours d'évaluation.
|
||||
@ -229,7 +238,7 @@ class SxTag(TableTag):
|
||||
cap = []
|
||||
for frmsem_id in self.ressembuttags:
|
||||
if frmsem_id != self.fid_final:
|
||||
for accr in self.acronymes_ues_sorted:
|
||||
for accr in self.acronymes_sorted:
|
||||
if self.masque_df[frmsem_id].loc[etud.etudid, accr] > 0.0:
|
||||
cap += [accr]
|
||||
if cap:
|
||||
@ -239,7 +248,7 @@ class SxTag(TableTag):
|
||||
|
||||
|
||||
def compute_notes_ues_cube(
|
||||
tag, etudids_sorted, acronymes_ues_sorted, ressembuttags
|
||||
tag, etudids_sorted, acronymes_sorted, ressembuttags
|
||||
) -> (pd.DataFrame, np.array):
|
||||
"""Construit le cube de notes des UEs (etudid x accronyme_ue x semestre_aggregé)
|
||||
nécessaire au calcul des moyennes du tag pour le RCS Sx.
|
||||
@ -247,7 +256,7 @@ def compute_notes_ues_cube(
|
||||
|
||||
Args:
|
||||
etudids_sorted: La liste des etudids triés par ordre croissant (dim 0)
|
||||
acronymes_ues_sorted: La liste des acronymes de UEs triés par acronyme croissant (dim 1)
|
||||
acronymes_sorted: La liste des acronymes de UEs triés par acronyme croissant (dim 1)
|
||||
ressembuttags: Le dictionnaire des résultats de semestres BUT (tous tags confondus)
|
||||
"""
|
||||
# Index du cube (etudids -> dim 0, ues -> dim 1, semestres -> dim2)
|
||||
@ -259,7 +268,7 @@ def compute_notes_ues_cube(
|
||||
|
||||
for frmsem_id in semestres_id:
|
||||
# Partant d'un dataframe vierge
|
||||
df = pd.DataFrame(np.nan, index=etudids_sorted, columns=acronymes_ues_sorted)
|
||||
df = pd.DataFrame(np.nan, index=etudids_sorted, columns=acronymes_sorted)
|
||||
|
||||
# Charge les notes du semestre tag
|
||||
sem_tag = ressembuttags[frmsem_id]
|
||||
@ -289,23 +298,27 @@ def compute_notes_ues_cube(
|
||||
return dfs, etudids_x_ues_x_semestres
|
||||
|
||||
|
||||
def compute_masques_ues_cube(
|
||||
def compute_masques_capitalisation_cube(
|
||||
etudids_sorted: list[int],
|
||||
acronymes_ues_sorted: list[str],
|
||||
acronymes_sorted: list[str],
|
||||
ressembuttags: dict[int, pe_ressemtag.ResSemBUTTag],
|
||||
formsemestre_id_final: int,
|
||||
) -> (pd.DataFrame, np.array):
|
||||
"""Construit le cube traduisant le masque des UEs à prendre en compte dans le calcul
|
||||
des moyennes, en utilisant le df capitalisations de chaque ResSemBUTTag
|
||||
"""Construit le cube traduisant les masques des UEs à prendre en compte dans le calcul
|
||||
des moyennes, en utilisant le dataFrame de capitalisations de chaque ResSemBUTTag
|
||||
|
||||
Ce masque contient : 1 si la note doit être prise en compte ; 0 sinon
|
||||
Ces masques contiennent : 1 si la note doit être prise en compte, 0 sinon
|
||||
|
||||
Le masque des UEs à prendre en compte correspondant au semestre final (identifié par
|
||||
son formsemestre_id_final) est systématiquement à 1 (puisque les résultats
|
||||
de ce semestre doivent systématiquement
|
||||
être pris en compte notamment pour les étudiants non redoublant).
|
||||
|
||||
Args:
|
||||
etudids_sorted: La liste des etudids triés par ordre croissant (dim 0)
|
||||
acronymes_ues_sorted: La liste des acronymes de UEs triés par acronyme croissant (dim 1)
|
||||
# ues_inscr_parcours_df: Le dataFrame des inscriptions au UE en fonction du parcours
|
||||
acronymes_sorted: La liste des acronymes de UEs triés par acronyme croissant (dim 1)
|
||||
ressembuttags: Le dictionnaire des résultats de semestres BUT (tous tags confondus)
|
||||
formsemestre_id_final: L'identifiant du formsemestre_id_final (dont il faut forcément prendre en compte les coeffs)
|
||||
formsemestre_id_final: L'identifiant du formsemestre_id_final
|
||||
"""
|
||||
# Index du cube (etudids -> dim 0, ues -> dim 1, semestres -> dim2)
|
||||
# etudids_sorted = etudids_sorted
|
||||
@ -317,15 +330,16 @@ def compute_masques_ues_cube(
|
||||
for frmsem_id in semestres_id:
|
||||
# Partant d'un dataframe contenant des 1.0
|
||||
if frmsem_id == formsemestre_id_final:
|
||||
df = pd.DataFrame(1.0, index=etudids_sorted, columns=acronymes_ues_sorted)
|
||||
df = pd.DataFrame(1.0, index=etudids_sorted, columns=acronymes_sorted)
|
||||
else: # semestres redoublés
|
||||
df = pd.DataFrame(0.0, index=etudids_sorted, columns=acronymes_ues_sorted)
|
||||
df = pd.DataFrame(0.0, index=etudids_sorted, columns=acronymes_sorted)
|
||||
|
||||
# Traitement des capitalisations
|
||||
# Traitement des capitalisations : remplace les infos de capitalisations par les coeff 1 ou 0
|
||||
capitalisations = ressembuttags[frmsem_id].capitalisations
|
||||
capitalisations = capitalisations.replace(True, 1.0).replace(False, 0.0)
|
||||
|
||||
# Met à 0 les coeffs des UEs non capitalisées : 1.0*False => 0.0
|
||||
# Met à 0 les coeffs des UEs non capitalisées pour les étudiants
|
||||
# inscrits dans les 2 semestres: 1.0*False => 0.0
|
||||
etudids_communs, acronymes_communs = pe_comp.find_index_and_columns_communs(
|
||||
df, capitalisations
|
||||
)
|
||||
@ -347,7 +361,7 @@ def compute_notes_ues(
|
||||
set_cube: np.array,
|
||||
masque_cube: np.array,
|
||||
etudids_sorted: list,
|
||||
acronymes_ues_sorted: list,
|
||||
acronymes_sorted: list,
|
||||
inscr_mask: np.array,
|
||||
):
|
||||
"""Calcule la moyenne par UEs à un tag donné en prenant la note maximum (UE
|
||||
@ -359,7 +373,7 @@ def compute_notes_ues(
|
||||
masque_cube: masque indiquant si la note doit être prise en compte ndarray
|
||||
(semestre_ids x etudids x UEs), des 1.0 ou des 0.0
|
||||
etudids_sorted: liste des étudiants (dim. 0 du cube) trié par etudid
|
||||
acronymes_ues_sorted: liste des acronymes des ues (dim. 1 du cube) trié par acronyme
|
||||
acronymes_sorted: liste des acronymes des ues (dim. 1 du cube) trié par acronyme
|
||||
inscr_mask: masque etudids x UE traduisant les inscriptions des
|
||||
étudiants aux UE (du semestre terminal)
|
||||
Returns:
|
||||
@ -369,7 +383,7 @@ def compute_notes_ues(
|
||||
nb_etuds, nb_ues, nb_semestres = set_cube.shape
|
||||
nb_etuds_mask, nb_ues_mask = inscr_mask.shape
|
||||
assert nb_etuds == len(etudids_sorted)
|
||||
assert nb_ues == len(acronymes_ues_sorted)
|
||||
assert nb_ues == len(acronymes_sorted)
|
||||
assert nb_etuds == nb_etuds_mask
|
||||
assert nb_ues == nb_ues_mask
|
||||
|
||||
@ -397,7 +411,7 @@ def compute_notes_ues(
|
||||
etud_moy_tag_df = pd.DataFrame(
|
||||
etud_moy,
|
||||
index=etudids_sorted, # les etudids
|
||||
columns=acronymes_ues_sorted, # les tags
|
||||
columns=acronymes_sorted, # les acronymes d'UEs
|
||||
)
|
||||
|
||||
etud_moy_tag_df.fillna(np.nan)
|
||||
|
@ -105,7 +105,7 @@ def associe_ues_et_parcours(formation: Formation, formation_infos: dict):
|
||||
|
||||
# Niveaux compétences:
|
||||
if ue_infos.get("competence"):
|
||||
competence = referentiel_competence.competences.filter_by(
|
||||
competence = referentiel_competence.acronymes_ues_to_competences.filter_by(
|
||||
titre=ue_infos["competence"]
|
||||
).first()
|
||||
assert competence is not None # La compétence de titre indiqué doit exister
|
||||
|
Loading…
Reference in New Issue
Block a user