Moyenne avec UEs multiples pour une même comp ; Amélioration calcul coeffs + moyennes notamment pour démissionnaires
This commit is contained in:
parent
35a038fd3a
commit
99bb0f471b
@ -119,7 +119,7 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
)
|
||||
"""Compétences (triées par nom, extraites des SxTag aggrégés)"""
|
||||
aff = pe_affichage.repr_comp_et_ues(self.acronymes_ues_to_competences)
|
||||
pe_affichage.pe_print(f"--> Compétences : {', '.join(self.competences_sorted)}")
|
||||
pe_affichage.pe_print(f"--> Compétences : {aff}")
|
||||
|
||||
# Les tags
|
||||
self.tags_sorted = self._do_taglist()
|
||||
@ -134,28 +134,24 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
for tag in self.tags_sorted:
|
||||
pe_affichage.pe_print(f"--> Moyennes du tag 👜{tag}")
|
||||
|
||||
# Traitement des inscriptions aux semX(tags)
|
||||
# ******************************************
|
||||
# Cube d'inscription (etudids_sorted x compétences_sorted x sxstags)
|
||||
# indiquant quel sxtag est valide pour chaque étudiant
|
||||
inscr_df, inscr_cube = self.compute_inscriptions_comps_cube(tag)
|
||||
# Cubes d'inscription (etudids_sorted x compétences_sorted x sxstags),
|
||||
# de notes et de coeffs pour la moyenne générale
|
||||
# en "aggrégant" les données des sxstags, compétence par compétence
|
||||
(
|
||||
inscr_df,
|
||||
inscr_cube,
|
||||
notes_df,
|
||||
notes_cube,
|
||||
coeffs_df,
|
||||
coeffs_cube,
|
||||
) = self.compute_cubes(tag)
|
||||
|
||||
# Traitement des notes
|
||||
# ********************
|
||||
# Cube de notes (etudids_sorted x compétences_sorted x sxstags)
|
||||
notes_df, notes_cube = self.compute_notes_comps_cube(tag)
|
||||
# Calcule les moyennes sous forme d'un dataframe en les "aggrégant"
|
||||
# compétence par compétence
|
||||
moys_competences = self.compute_notes_competences(notes_cube, inscr_cube)
|
||||
|
||||
# Traitement des coeffs pour la moyenne générale
|
||||
# ***********************************************
|
||||
# Df des coeffs sur tous les SxTags aggrégés
|
||||
coeffs_df, coeffs_cube = self.compute_coeffs_comps_cube(tag)
|
||||
|
||||
# Synthèse des coefficients à prendre en compte pour la moyenne générale
|
||||
matrice_coeffs_moy_gen = self.compute_coeffs_competences(
|
||||
coeffs_cube, inscr_cube, notes_cube
|
||||
# Calcule les moyennes, et synthétise les coeffs
|
||||
(
|
||||
moys_competences,
|
||||
matrice_coeffs_moy_gen,
|
||||
) = self.compute_notes_et_coeffs_competences(
|
||||
notes_cube, coeffs_cube, inscr_cube
|
||||
)
|
||||
|
||||
# Affichage des coeffs
|
||||
@ -186,10 +182,17 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
else:
|
||||
return f"{self.__class__.__name__} {self.rcs_id}"
|
||||
|
||||
def compute_notes_comps_cube(self, tag):
|
||||
"""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
|
||||
def compute_cubes(self, tag):
|
||||
"""Pour un tag donné, construit les cubes de :
|
||||
* d'inscriptions aux compétences (etudid x competences x SxTag)
|
||||
* de notes (etudid x competences x SxTag)
|
||||
* de coeffs (etudid x competences x SxTag)
|
||||
|
||||
nécessaire au calcul des moyennes, en :
|
||||
|
||||
* transformant les données des UEs en données de compétences (changement de noms)
|
||||
* fusionnant les données d'un même semestre, lorsque plusieurs UEs traitent d'une même compétence (cas des RCSx = Sx)
|
||||
* aggrégeant les données de compétences sur plusieurs semestres (cas des RCSx = xA ou xS)
|
||||
|
||||
Args:
|
||||
tag: Le tag visé
|
||||
@ -197,144 +200,75 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
# etudids_sorted: list[int],
|
||||
# competences_sorted: list[str],
|
||||
# sxstags: dict[(str, int) : pe_sxtag.SxTag],
|
||||
|
||||
inscriptions_dfs = {}
|
||||
notes_dfs = {}
|
||||
coeffs_dfs = {}
|
||||
|
||||
for sxtag_id, sxtag in self.sxstags_aggreges.items():
|
||||
# Partant d'un dataframe vierge
|
||||
# Partant de dataframes vierges
|
||||
inscription_df = pd.DataFrame(
|
||||
np.nan, index=self.etudids_sorted, columns=self.competences_sorted
|
||||
)
|
||||
notes_df = pd.DataFrame(
|
||||
np.nan, index=self.etudids_sorted, columns=self.competences_sorted
|
||||
)
|
||||
# Charge les notes du semestre tag (copie car changement de nom de colonnes à venir)
|
||||
coeffs_df = pd.DataFrame(
|
||||
np.nan, index=self.etudids_sorted, columns=self.competences_sorted
|
||||
)
|
||||
|
||||
# Charge les données du semestre tag (copie car changement de nom de colonnes à venir)
|
||||
if tag in sxtag.moyennes_tags: # si le tag est présent dans le semestre
|
||||
moys_tag = sxtag.moyennes_tags[tag]
|
||||
|
||||
notes = moys_tag.matrice_notes_gen.copy() # dataframe etudids x ues
|
||||
# Les inscr, les notes, les coeffs
|
||||
acro_ues_inscr_parcours = sxtag.acro_ues_inscr_parcours
|
||||
notes = moys_tag.matrice_notes_gen
|
||||
coeffs = moys_tag.matrice_coeffs_moy_gen # les coeffs
|
||||
|
||||
# Traduction des acronymes d'UE en compétences
|
||||
# comp_to_ues = pe_comp.asso_comp_to_accronymes(self.acronymes_ues_to_competences)
|
||||
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
|
||||
for acronyme in acronymes_ues_columns:
|
||||
# La compétence visée
|
||||
competence = self.acronymes_ues_to_competences[acronyme] # La comp
|
||||
|
||||
# Les étudiants et les compétences communes
|
||||
(
|
||||
etudids_communs,
|
||||
comp_communes,
|
||||
) = pe_comp.find_index_and_columns_communs(notes_df, notes)
|
||||
# Les étud inscrits à la comp reportés dans l'inscription au RCSemX
|
||||
comp_inscr = acro_ues_inscr_parcours[
|
||||
acro_ues_inscr_parcours.notnull()
|
||||
].index
|
||||
etudids_communs = list(
|
||||
inscription_df.index.intersection(comp_inscr)
|
||||
)
|
||||
inscription_df.loc[
|
||||
etudids_communs, competence
|
||||
] = acro_ues_inscr_parcours.loc[etudids_communs, acronyme]
|
||||
|
||||
# Recopie des notes et des coeffs
|
||||
notes_df.loc[etudids_communs, comp_communes] = notes.loc[
|
||||
etudids_communs, comp_communes
|
||||
]
|
||||
# Les étud ayant une note à l'acronyme de la comp (donc à la comp)
|
||||
etuds_avec_notes = notes[notes[acronyme].notnull()].index
|
||||
etudids_communs = list(
|
||||
notes_df.index.intersection(etuds_avec_notes)
|
||||
)
|
||||
notes_df.loc[etudids_communs, competence] = notes.loc[
|
||||
etudids_communs, acronyme
|
||||
]
|
||||
|
||||
# Les coeffs
|
||||
etuds_avec_coeffs = coeffs[coeffs[acronyme].notnull()].index
|
||||
etudids_communs = list(
|
||||
coeffs_df.index.intersection(etuds_avec_coeffs)
|
||||
)
|
||||
coeffs_df.loc[etudids_communs, competence] = coeffs.loc[
|
||||
etudids_communs, acronyme
|
||||
]
|
||||
# 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 self.sxstags_aggreges
|
||||
]
|
||||
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):
|
||||
"""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: list[int],
|
||||
# competences_sorted: list[str],
|
||||
# sxstags: dict[(str, int) : pe_sxtag.SxTag],
|
||||
|
||||
coeffs_dfs = {}
|
||||
|
||||
for sxtag_id, sxtag in self.sxstags_aggreges.items():
|
||||
# Partant d'un dataframe vierge
|
||||
coeffs_df = pd.DataFrame(
|
||||
np.nan, index=self.etudids_sorted, columns=self.competences_sorted
|
||||
)
|
||||
if tag in sxtag.moyennes_tags:
|
||||
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
|
||||
]
|
||||
|
||||
# Stocke les dfs
|
||||
coeffs_dfs[sxtag_id] = coeffs_df
|
||||
|
||||
"""Réunit les coeffs sous forme d'un cube etudids x competences x semestres"""
|
||||
sxtag_x_etudids_x_comps = [
|
||||
coeffs_dfs[sxtag_id] for sxtag_id in self.sxstags_aggreges
|
||||
]
|
||||
coeffs_etudids_x_comps_x_sxtag = np.stack(sxtag_x_etudids_x_comps, axis=-1)
|
||||
|
||||
return coeffs_dfs, coeffs_etudids_x_comps_x_sxtag
|
||||
|
||||
def compute_inscriptions_comps_cube(
|
||||
self,
|
||||
tag,
|
||||
):
|
||||
"""Pour un tag donné, construit
|
||||
le cube etudid x competences x SxTag traduisant quels sxtags est à prendre
|
||||
en compte pour chaque étudiant.
|
||||
Contient des 0 et des 1 pour indiquer la prise en compte.
|
||||
|
||||
Args:
|
||||
tag: Le tag visé
|
||||
"""
|
||||
# etudids_sorted: list[int],
|
||||
# competences_sorted: list[str],
|
||||
# sxstags: dict[(str, int) : pe_sxtag.SxTag],
|
||||
# Initialisation
|
||||
inscriptions_dfs = {}
|
||||
|
||||
for sxtag_id, sxtag in self.sxstags_aggreges.items():
|
||||
# Partant d'un dataframe vierge
|
||||
inscription_df = pd.DataFrame(
|
||||
0, index=self.etudids_sorted, columns=self.competences_sorted
|
||||
)
|
||||
|
||||
# Les étudiants dont les résultats au sxtag ont été calculés
|
||||
etudids_sxtag = sxtag.etudids_sorted
|
||||
|
||||
# Les étudiants communs
|
||||
etudids_communs = sorted(set(self.etudids_sorted) & set(etudids_sxtag))
|
||||
|
||||
# Acte l'inscription
|
||||
inscription_df.loc[etudids_communs, :] = 1
|
||||
|
||||
# Stocke les dfs
|
||||
inscriptions_dfs[sxtag_id] = inscription_df
|
||||
notes_dfs[sxtag_id] = notes_df
|
||||
coeffs_dfs[sxtag_id] = coeffs_df
|
||||
|
||||
"""Réunit les inscriptions sous forme d'un cube etudids x competences x semestres"""
|
||||
sxtag_x_etudids_x_comps = [
|
||||
@ -344,7 +278,26 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
sxtag_x_etudids_x_comps, axis=-1
|
||||
)
|
||||
|
||||
return inscriptions_dfs, inscriptions_etudids_x_comps_x_sxtag
|
||||
"""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 self.sxstags_aggreges
|
||||
]
|
||||
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[sxtag_id] for sxtag_id in self.sxstags_aggreges
|
||||
]
|
||||
coeffs_etudids_x_comps_x_sxtag = np.stack(sxtag_x_etudids_x_comps, axis=-1)
|
||||
|
||||
return (
|
||||
inscriptions_dfs,
|
||||
inscriptions_etudids_x_comps_x_sxtag,
|
||||
notes_dfs,
|
||||
notes_etudids_x_comps_x_sxtag,
|
||||
coeffs_dfs,
|
||||
coeffs_etudids_x_comps_x_sxtag,
|
||||
)
|
||||
|
||||
def _do_taglist(self) -> list[str]:
|
||||
"""Synthétise les tags à partir des Sxtags aggrégés.
|
||||
@ -370,7 +323,9 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
dict_competences |= sxtag.acronymes_ues_to_competences
|
||||
return dict_competences
|
||||
|
||||
def compute_notes_competences(self, set_cube: np.array, inscriptions: np.array):
|
||||
def compute_notes_et_coeffs_competences(
|
||||
self, notes_cube: np.array, coeffs_cube: np.array, inscr_mask: np.array
|
||||
):
|
||||
"""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
|
||||
@ -379,9 +334,11 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
par aggrégat de plusieurs semestres.
|
||||
|
||||
Args:
|
||||
set_cube: notes moyennes aux compétences ndarray
|
||||
notes_cube: notes moyennes aux compétences ndarray
|
||||
(etuds x UEs|compétences x sxtags), des floats avec des NaN
|
||||
inscriptions: inscrptions aux compétences ndarray
|
||||
coeffs_cube: coeffs appliqués aux compétences
|
||||
(etuds x UEs|compétences x sxtags), des floats avec des NaN
|
||||
inscr_mask: inscrptions aux compétences ndarray
|
||||
(etuds x UEs|compétences x sxtags), des 0 et des 1
|
||||
Returns:
|
||||
Un DataFrame avec pour columns les moyennes par tags,
|
||||
@ -389,78 +346,45 @@ class RCSemXTag(pe_tabletags.TableTag):
|
||||
"""
|
||||
# etudids_sorted: liste des étudiants (dim. 0 du cube)
|
||||
# competences_sorted: list (dim. 1 du cube)
|
||||
nb_etuds, nb_comps, nb_semestres = set_cube.shape
|
||||
nb_etuds, nb_comps, nb_semestres = notes_cube.shape
|
||||
# assert nb_etuds == len(etudids_sorted)
|
||||
# assert nb_comps == len(competences_sorted)
|
||||
|
||||
# Applique le masque d'inscriptions
|
||||
set_cube_significatif = set_cube * inscriptions
|
||||
# Applique le masque d'inscriptions aux notes et aux coeffs
|
||||
notes_significatives = notes_cube * inscr_mask
|
||||
coeffs_significatifs = coeffs_cube * inscr_mask
|
||||
|
||||
# Quelles entrées du cube contiennent des notes ?
|
||||
mask = ~np.isnan(set_cube_significatif)
|
||||
|
||||
# Enlève les NaN du cube de notes pour les entrées manquantes
|
||||
set_cube_no_nan = np.nan_to_num(set_cube_significatif, nan=0.0)
|
||||
# Enlève les NaN des cubes pour les entrées manquantes
|
||||
notes_no_nan = np.nan_to_num(notes_significatives, nan=0.0)
|
||||
coeffs_no_nan = np.nan_to_num(coeffs_significatifs, 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)
|
||||
mask = ~np.isnan(
|
||||
notes_significatives
|
||||
) # Quelles entrées contiennent des notes ?
|
||||
etud_moy_tag = np.sum(notes_no_nan, axis=2) / np.sum(mask, axis=2)
|
||||
|
||||
coeffs_pris_en_compte = coeffs_no_nan * mask
|
||||
coeff_tag = np.sum(coeffs_pris_en_compte, axis=2)
|
||||
|
||||
inscr_prise_en_compte = inscr_mask * mask
|
||||
inscr_prise_en_compte = np.nan_to_num(inscr_prise_en_compte, nan=-1.0)
|
||||
inscr_tag = np.max(inscr_prise_en_compte, axis=2)
|
||||
inscr_tag[inscr_tag < 0] = np.NaN # fix les max non calculés (-1) -> Na?
|
||||
|
||||
# Le dataFrame des notes moyennes
|
||||
etud_moy_tag = etud_moy_tag * inscr_tag
|
||||
etud_moy_tag_df = pd.DataFrame(
|
||||
etud_moy_tag,
|
||||
index=self.etudids_sorted, # les etudids
|
||||
columns=self.competences_sorted, # les competences
|
||||
)
|
||||
etud_moy_tag_df.fillna(np.nan)
|
||||
|
||||
return etud_moy_tag_df
|
||||
|
||||
def compute_coeffs_competences(
|
||||
self,
|
||||
coeff_cube: np.array,
|
||||
inscriptions: np.array,
|
||||
set_cube: np.array,
|
||||
):
|
||||
"""Calcule les coeffs à utiliser pour la moyenne générale (toutes compétences
|
||||
confondues), en fonction des inscriptions.
|
||||
|
||||
Args:
|
||||
coeffs_cube: coeffs impliqués dans la moyenne générale (semestres par semestres)
|
||||
inscriptions: inscriptions aux UES|Compétences ndarray
|
||||
(etuds x UEs|compétences x sxtags), des 0 ou des 1
|
||||
set_cube: les notes
|
||||
|
||||
|
||||
Returns:
|
||||
Un DataFrame de coefficients (etudids_sorted x compétences_sorted)
|
||||
"""
|
||||
# etudids_sorted: liste des étudiants (dim. 0 du cube)
|
||||
# competences_sorted: list (dim. 1 du cube)
|
||||
nb_etuds, nb_comps, nb_semestres = inscriptions.shape
|
||||
# assert nb_etuds == len(etudids_sorted)
|
||||
# assert nb_comps == len(competences_sorted)
|
||||
|
||||
# Applique le masque des inscriptions aux coeffs et aux notes
|
||||
coeffs_significatifs = coeff_cube * inscriptions
|
||||
|
||||
# Enlève les NaN du cube de notes pour les entrées manquantes
|
||||
coeffs_cube_no_nan = np.nan_to_num(coeffs_significatifs, nan=0.0)
|
||||
|
||||
# Quelles entrées du cube contiennent des notes ?
|
||||
mask = ~np.isnan(set_cube)
|
||||
|
||||
# Retire les coefficients associés à 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
|
||||
coeff_tag = coeff_tag * inscr_tag # Réapplique le masque des inscriptions
|
||||
coeffs_df = pd.DataFrame(
|
||||
coeff_tag, index=self.etudids_sorted, columns=self.competences_sorted
|
||||
)
|
||||
# Remet à Nan les coeffs à 0
|
||||
coeffs_df = coeffs_df.fillna(np.nan)
|
||||
|
||||
return coeffs_df
|
||||
return etud_moy_tag_df, coeffs_df
|
||||
|
@ -98,8 +98,10 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
self.parcours += [None]
|
||||
|
||||
# Les UEs en fonction des parcours
|
||||
self.ues_inscr_parcours_df = self.load_ues_inscr_parcours()
|
||||
"""Inscription des étudiants aux UEs des parcours"""
|
||||
self.ues_inscr_parcours_df = (
|
||||
self.load_ues_inscr_parcours()
|
||||
) # peut contenir du sport
|
||||
"""Inscription des étudiants aux UEs des parcours (etudids x ue_ids)"""
|
||||
|
||||
# Les acronymes des UEs
|
||||
self.ues_to_acronymes = {ue.id: ue.acronyme for ue in self.ues_standards}
|
||||
@ -144,6 +146,12 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
f"--> Moyenne générale calculée avec pour coeffs d'UEs : {profils_aff}"
|
||||
)
|
||||
|
||||
# Les inscriptions aux acronymes d'ues
|
||||
self.acro_ues_inscr_parcours = self._get_acro_ues_inscr_parcours(
|
||||
self.ues_inscr_parcours_df, self.ues_standards
|
||||
)
|
||||
"""DataFrame indiquant à quelles UEs (données par leurs acronymes) sont inscrits les étudiants)"""
|
||||
|
||||
# Les capitalisations (mask etuids x acronyme_ue valant True si capitalisée, False sinon)
|
||||
self.capitalisations = self._get_capitalisations(self.ues_standards)
|
||||
"""DataFrame indiquant les UEs capitalisables d'un étudiant (etudids x )"""
|
||||
@ -167,7 +175,7 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
)
|
||||
|
||||
# Ajoute les moyennes par UEs + la moyenne générale (but)
|
||||
moy_gen = self.compute_moy_gen()
|
||||
moy_gen = self.compute_moy_gen(self.acro_ues_inscr_parcours)
|
||||
self.moyennes_tags["but"] = pe_moytag.MoyennesTag(
|
||||
"but",
|
||||
pe_moytag.CODE_MOY_UE,
|
||||
@ -240,6 +248,31 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
matrice_coeffs_moy_gen = matrice_coeffs_moy_gen.sort_index(axis=1)
|
||||
return matrice_coeffs_moy_gen
|
||||
|
||||
def _get_acro_ues_inscr_parcours(
|
||||
self, ues_inscr_parcours_df: pd.DataFrame, ues_standards: list[UniteEns]
|
||||
) -> pd.DataFrame:
|
||||
"""Renvoie un dataFrame donnant les inscriptions (Nan ou 1) des
|
||||
étudiants aux UEs définies par leur acronyme, en fonction de leur parcours
|
||||
(cf. ues_inscr_parcours_df) et en limitant les données aux UEs standards (hors sport=
|
||||
|
||||
Args:
|
||||
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
|
||||
"""
|
||||
matrice_inscription = ues_inscr_parcours_df * [
|
||||
1 for ue in ues_standards # if ue.type != UE_SPORT <= déjà supprimé
|
||||
]
|
||||
matrice_inscription.columns = [
|
||||
self.ues_to_acronymes[ue.id] for ue in ues_standards
|
||||
]
|
||||
# Tri par etudids (dim 0) et par acronymes (dim 1)
|
||||
matrice_inscription = matrice_inscription.sort_index()
|
||||
matrice_inscription = matrice_inscription.sort_index(axis=1)
|
||||
return matrice_inscription
|
||||
|
||||
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).
|
||||
@ -342,6 +375,9 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
colonnes = [ue.id for ue in self.ues_standards]
|
||||
moyennes_ues_tag = moyennes_ues_tag[colonnes]
|
||||
|
||||
# Met à zéro les moyennes non calculées/calculables
|
||||
moyennes_ues_tag.fillna(0.0, inplace=True)
|
||||
|
||||
# Applique le masque d'inscription aux UE pour ne conserver que les UE dans lequel l'étudiant est inscrit
|
||||
moyennes_ues_tag = moyennes_ues_tag[colonnes] * ues_inscr_parcours_df[colonnes]
|
||||
|
||||
@ -355,7 +391,7 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
|
||||
return moyennes_ues_tag
|
||||
|
||||
def compute_moy_gen(self):
|
||||
def compute_moy_gen(self, acro_ues_inscr_parcours):
|
||||
"""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)
|
||||
"""
|
||||
@ -368,6 +404,12 @@ class ResSemBUTTag(ResultatsSemestreBUT, pe_tabletags.TableTag):
|
||||
acronymes = [self.ues_to_acronymes[col] for col in colonnes]
|
||||
df_ues.columns = acronymes
|
||||
|
||||
# Met à zéro les moyennes non calculées/calculables
|
||||
df_ues.fillna(0.0, inplace=True)
|
||||
|
||||
# Réapplique le mask d'inscription
|
||||
df_ues = df_ues * acro_ues_inscr_parcours
|
||||
|
||||
# Tri par ordre aphabétique de colonnes
|
||||
df_ues.sort_index(axis=1)
|
||||
|
||||
|
@ -141,6 +141,10 @@ class SxTag(pe_tabletags.TableTag):
|
||||
aff = pe_affichage.repr_asso_ue_comp(self.acronymes_ues_to_competences)
|
||||
pe_affichage.pe_print(f"--> UEs/Compétences : {aff}")
|
||||
|
||||
# Les inscriptions des étudiants aux UEs (donnée par leur acronyme)
|
||||
# par report de celle du ressemfinal
|
||||
self.acro_ues_inscr_parcours = self.ressembuttag_final.acro_ues_inscr_parcours
|
||||
|
||||
# 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
|
||||
@ -178,7 +182,7 @@ class SxTag(pe_tabletags.TableTag):
|
||||
pe_affichage.pe_print(f" > MoyTag 👜{tag}")
|
||||
|
||||
# Masque des inscriptions aux UEs (extraits de la matrice de coefficients)
|
||||
inscr_mask: np.array = ~np.isnan(self.matrice_coeffs_moy_gen.to_numpy())
|
||||
# inscr_mask: np.array = ~np.isnan(self.matrice_coeffs_moy_gen.to_numpy())
|
||||
|
||||
# Moyennes (tous modules confondus)
|
||||
if not self.has_notes_tag(tag):
|
||||
@ -194,6 +198,7 @@ class SxTag(pe_tabletags.TableTag):
|
||||
notes_df_gen, notes_cube_gen = self.compute_notes_ues_cube(tag)
|
||||
|
||||
# DataFrame des moyennes (tous modules confondus)
|
||||
inscr_mask = self.acro_ues_inscr_parcours.to_numpy()
|
||||
matrice_moys_ues = self.compute_notes_ues(
|
||||
notes_cube_gen, masque_cube, inscr_mask
|
||||
)
|
||||
@ -289,7 +294,7 @@ class SxTag(pe_tabletags.TableTag):
|
||||
def compute_notes_ues(
|
||||
self,
|
||||
set_cube: np.array,
|
||||
masque_cube: np.array,
|
||||
cap_mask_3D: np.array,
|
||||
inscr_mask: np.array,
|
||||
) -> pd.DataFrame:
|
||||
"""Calcule la moyenne par UEs à un tag donné en prenant la note maximum (UE
|
||||
@ -298,7 +303,8 @@ class SxTag(pe_tabletags.TableTag):
|
||||
Args:
|
||||
set_cube: notes moyennes aux modules ndarray
|
||||
(semestre_ids x etudids x UEs), des floats avec des NaN
|
||||
masque_cube: masque indiquant si la note doit être prise en compte ndarray
|
||||
cap_mask_3D
|
||||
: masque indiquant si la note doit être prise en compte ndarray
|
||||
(semestre_ids x etudids x UEs), des 1.0 ou des 0.0
|
||||
inscr_mask: masque etudids x UE traduisant les inscriptions des
|
||||
étudiants aux UE (du semestre terminal)
|
||||
@ -320,10 +326,7 @@ class SxTag(pe_tabletags.TableTag):
|
||||
set_cube = set_cube * inscr_mask_3D
|
||||
|
||||
# Entrées à garder en fonction des UEs capitalisées ou non
|
||||
set_cube = set_cube * masque_cube
|
||||
|
||||
# Quelles entrées du cube contiennent des notes ?
|
||||
mask = ~np.isnan(set_cube)
|
||||
set_cube = set_cube * cap_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)
|
||||
@ -332,9 +335,12 @@ class SxTag(pe_tabletags.TableTag):
|
||||
# TODO: Pour l'instant un max sans prise en compte des UE capitalisées
|
||||
etud_moy = np.max(set_cube_no_nan, axis=2)
|
||||
|
||||
# Fix les max non calculé -1 -> NaN
|
||||
# Fix les max non calculés (-1) -> NaN
|
||||
etud_moy[etud_moy < 0] = np.NaN
|
||||
|
||||
# Réapplique le masque d'inscription (dans le doute)
|
||||
etud_moy = etud_moy * inscr_mask
|
||||
|
||||
# Le dataFrame
|
||||
etud_moy_tag_df = pd.DataFrame(
|
||||
etud_moy,
|
||||
|
@ -9,6 +9,7 @@
|
||||
from flask import g
|
||||
from app import log
|
||||
from app.pe.rcss import pe_rcs
|
||||
import app.pe.pe_comp as pe_comp
|
||||
|
||||
PE_DEBUG = False
|
||||
|
||||
@ -135,23 +136,45 @@ def aff_tags_par_categories(dict_tags):
|
||||
aff_tags_auto = ", ".join([f"👜{nom}" for nom in noms_tags_auto])
|
||||
return f"Tags automatiques {aff_tags_auto} (aucun tag personnalisé)"
|
||||
|
||||
# Affichage
|
||||
|
||||
def repr_jeune(etudid, etudiants):
|
||||
"""Renvoie la représentation d'un étudiant"""
|
||||
etat = "⛔" if etudid in etudiants.abandons_ids else "✅"
|
||||
jeune = f"{etat} {etudiants.identites[etudid].nomprenom} (#{etudid})"
|
||||
return jeune
|
||||
|
||||
|
||||
def aff_trajectoires_suivies_par_etudiants(etudiants):
|
||||
"""Affiche les trajectoires (regroupement de (form)semestres)
|
||||
amenant un étudiant du S1 à un semestre final"""
|
||||
amenant un étudiant du S1 à un semestre final,
|
||||
en regroupant les étudiants par profil de trajectoires"""
|
||||
|
||||
# Affichage pour debug
|
||||
etudiants_ids = etudiants.etudiants_ids
|
||||
jeunes = list(enumerate(etudiants_ids))
|
||||
for no_etud, etudid in jeunes:
|
||||
etat = "⛔" if etudid in etudiants.abandons_ids else "✅"
|
||||
|
||||
pe_print(f"--> {etat} {etudiants.identites[etudid].nomprenom} (#{etudid}) :")
|
||||
profils_traj = {}
|
||||
|
||||
for no_etud, etudid in jeunes:
|
||||
jeune = repr_jeune(etudid, etudiants)
|
||||
|
||||
# La trajectoire du jeune
|
||||
trajectoires = etudiants.trajectoires[etudid]
|
||||
profil_traj = []
|
||||
for nom_rcs, rcs in trajectoires.items():
|
||||
if rcs:
|
||||
pe_print(f" > RCS ⏯️{nom_rcs}: {rcs.get_repr()}")
|
||||
profil_traj += [f" > RCS ⏯️{nom_rcs}: {rcs.get_repr()}"]
|
||||
aff_profil_traj = "\n".join(profil_traj)
|
||||
if aff_profil_traj not in profils_traj:
|
||||
profils_traj[aff_profil_traj] = []
|
||||
|
||||
profils_traj[aff_profil_traj] += [jeune]
|
||||
|
||||
# Affichage final
|
||||
for profil, jeunes in profils_traj.items():
|
||||
pe_print(f"--> Trajectoire suivie par : ")
|
||||
pe_print("\n".join([" " + jeune for jeune in jeunes]))
|
||||
pe_print(profil)
|
||||
|
||||
|
||||
def aff_semXs_suivis_par_etudiants(etudiants):
|
||||
@ -198,13 +221,11 @@ def aff_capitalisations(etuds, ressembuttags, fid_final, acronymes_sorted, masqu
|
||||
|
||||
def repr_comp_et_ues(acronymes_ues_to_competences):
|
||||
"""Affichage pour debug"""
|
||||
asso_comp_to_ues = pe_comp.asso_comp_to_accronymes(acronymes_ues_to_competences)
|
||||
aff_comp = []
|
||||
competences_sorted = sorted(acronymes_ues_to_competences.keys())
|
||||
competences_sorted = sorted(asso_comp_to_ues.keys())
|
||||
for comp in competences_sorted:
|
||||
liste = []
|
||||
for acro in acronymes_ues_to_competences:
|
||||
if acronymes_ues_to_competences[acro] == comp:
|
||||
liste += ["📍" + acro]
|
||||
liste = ["📍" + accro for accro in asso_comp_to_ues[comp]]
|
||||
aff_comp += [f" 💡{comp} (⇔ {', '.join(liste)})"]
|
||||
return "\n".join(aff_comp)
|
||||
|
||||
|
@ -337,3 +337,21 @@ def get_dernier_semestre_en_date(semestres: dict[int, FormSemestre]) -> FormSeme
|
||||
dernier_semestre = semestres[fid]
|
||||
return dernier_semestre
|
||||
return None
|
||||
|
||||
|
||||
def asso_comp_to_accronymes(accro_ues_to_competences):
|
||||
"""Partant d'un dictionnaire ``{nom_ue: compétence}`` associant des
|
||||
accronymes d'UEs à des compétences, renvoie l'association d'une compétence
|
||||
à ou aux UEs qui l'adresse : ``{competence: [liste_nom_ue]}``
|
||||
|
||||
Args:
|
||||
accro_ues_to_competences: Dictionnaire ``{nom_ue: compétence}``
|
||||
Return:
|
||||
Le dictionnaire ``{competence: [liste_nom_ue]}``
|
||||
"""
|
||||
asso = {}
|
||||
for accro, comp in accro_ues_to_competences.items():
|
||||
if comp not in asso:
|
||||
asso[comp] = []
|
||||
asso[comp].append(accro)
|
||||
return asso
|
||||
|
@ -705,7 +705,7 @@ class JuryPE(object):
|
||||
tag, aggregat=aggregat, type_colonnes=False, options=self.options
|
||||
)
|
||||
if not df_groupe.empty:
|
||||
aff_aggregat += [aggregat]
|
||||
aff_aggregat += [aggregat + " (Groupe)"]
|
||||
df = df.join(df_groupe)
|
||||
|
||||
# Le dataframe du classement sur la promo
|
||||
@ -718,7 +718,7 @@ class JuryPE(object):
|
||||
)
|
||||
|
||||
if not df_promo.empty:
|
||||
aff_aggregat += [aggregat]
|
||||
aff_aggregat += [aggregat + " (Promo)"]
|
||||
df = df.join(df_promo)
|
||||
|
||||
if aff_aggregat:
|
||||
|
@ -15,7 +15,7 @@ from app.pe.rcss import pe_rcs, pe_trajectoires
|
||||
|
||||
|
||||
class RCSemX(pe_rcs.RCS):
|
||||
"""Modélise un regroupement cohérent de SemX (en même regroupant
|
||||
"""Modélise un regroupement cohérent de SemX (en regroupant
|
||||
des semestres Sx combinés pour former les résultats des étudiants
|
||||
au semestre de rang x) dans le but de synthétiser les résultats
|
||||
du S1 jusqu'au semestre final ciblé par le RCSemX (dépendant de l'aggrégat
|
||||
|
Loading…
x
Reference in New Issue
Block a user