Etat intermédiaire

This commit is contained in:
Cléo Baras 2024-03-07 19:41:30 +01:00
parent 1bed4bb720
commit c91ab67951
2 changed files with 96 additions and 58 deletions

View File

@ -55,8 +55,7 @@ class RCSemXTag(pe_tabletags.TableTag):
semXs_suivis: dict[int, dict], semXs_suivis: dict[int, dict],
): ):
"""Calcule les moyennes par tag (orientées compétences) """Calcule les moyennes par tag (orientées compétences)
d'un regroupement de SxTag d'un regroupement de SxTag, pour extraire les classements par tag pour un
(RCRCF), pour extraire les classements par tag pour un
groupe d'étudiants donnés. Le groupe d'étudiants est formé par ceux ayant tous groupe d'étudiants donnés. Le groupe d'étudiants est formé par ceux ayant tous
participé au même semestre terminal. participé au même semestre terminal.
@ -139,13 +138,13 @@ class RCSemXTag(pe_tabletags.TableTag):
# en "aggrégant" les données des sxstags, compétence par compétence # en "aggrégant" les données des sxstags, compétence par compétence
( (
inscr_df, inscr_df,
inscr_cube, inscr_cube, # données d'inscriptions
notes_df, notes_df,
notes_cube, notes_cube, # notes
coeffs_df, coeffs_df,
coeffs_cube, coeffs_cube, # coeffs pour la moyenne générale (par UEs)
coeffs_rcues_df, coeffs_rcues_df,
coeffs_rcues_cube, coeffs_rcues_cube, # coeffs pour la moyenne de regroupement d'UEs
) = self.assemble_cubes(tag) ) = self.assemble_cubes(tag)
# Calcule les moyennes, et synthétise les coeffs # Calcule les moyennes, et synthétise les coeffs
@ -363,67 +362,92 @@ class RCSemXTag(pe_tabletags.TableTag):
coeffs_rcue: np.array, coeffs_rcue: np.array,
inscr_mask: np.array, inscr_mask: np.array,
): ):
"""Calcule la moyenne par compétences (à un tag donné) sur plusieurs semestres (partant du set_cube). """Calcule la moyenne par UEs|Compétences en moyennant sur les semestres et renvoie les résultats (notes
et coeffs) sous la forme de DataFrame"""
(etud_moy_tag, coeff_tag) = compute_moyennes_par_RCS(
notes_cube, coeffs_cube, coeffs_rcue, inscr_mask
)
La moyenne est un nombre (note/20), ou NaN si pas de notes disponibles
*Remarque* : Adaptation de moy_ue.compute_ue_moys_apc au cas des moyennes de tag
par aggrégat de plusieurs semestres.
Args:
notes_cube: notes moyennes aux compétences ndarray
(etuds x UEs|compétences x sxtags), des floats avec des NaN
coeffs_cube: coeffs appliqués aux compétences
(etuds x UEs|compétences x sxtags) dans le calcul des moyennes générales,
des floats avec des NaN
coeffs_rcue_cube: coeffs des RCUE appliqués dans les moyennes de RCS
inscr_mask: inscriptions 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,
et pour rows les etudid
"""
# etudids_sorted: liste des étudiants (dim. 0 du cube)
# competences_sorted: list (dim. 1 du cube)
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 aux notes et aux coeffs
notes_significatives = notes_cube * inscr_mask
coeffs_significatifs = coeffs_cube * inscr_mask
# 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)
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_df = pd.DataFrame(
etud_moy_tag, etud_moy_tag,
index=self.etudids_sorted, # les etudids index=self.etudids_sorted, # les etudids
columns=self.competences_sorted, # les competences columns=self.competences_sorted, # les competences
) )
# Le dataFrame des coeffs
coeff_tag = coeff_tag * inscr_tag # Réapplique le masque des inscriptions
coeffs_df = pd.DataFrame( coeffs_df = pd.DataFrame(
coeff_tag, index=self.etudids_sorted, columns=self.competences_sorted coeff_tag, index=self.etudids_sorted, columns=self.competences_sorted
) )
return etud_moy_tag_df, coeffs_df return etud_moy_tag_df, coeffs_df
def compute_moyennes_par_RCS(
notes_cube: np.array,
coeffs_cube: np.array,
coeffs_rcue: np.array,
inscr_mask: np.array,
):
"""Partant d'une série de notes (fournie sous forme d'un cube
etudids_sorted x UEs|Compétences x semestres)
chaque note étant pondérée par un coeff dépendant du semestre (fourni dans coeffs_rcue),
et pondérée par un coeff dépendant de l'UE|Compétence pour calculer une moyenne générale
(fourni dans coeffs_cube),
calcule :
* la moyenne par UEs|Compétences sur plusieurs semestres (partant du set_cube).
* les coeffs "cumulés" à appliquer pour le calcul de la moyenne générale
La moyenne est un nombre (note/20), ou NaN si pas de notes disponibles
Args:
notes_cube: notes moyennes aux compétences ndarray
(etuds_sorted x UEs|compétences x sxtags),
des floats avec des NaN
coeffs_cube: coeffs appliqués aux compétences dans le calcul des moyennes générales,
(etuds_sorted x UEs|compétences x sxtags),
des floats avec des NaN
coeffs_rcue_cube: coeffs des RCUE appliqués dans les moyennes de RCS
inscr_mask: inscriptions aux compétences ndarray
(etuds_sorted x UEs|compétences x sxtags),
des 0 et des 1
Returns:
Un DataFrame avec pour columns les moyennes par tags,
et pour rows les etudid
"""
# Applique le masque d'inscriptions aux notes et aux coeffs
notes_significatives = notes_cube * inscr_mask
coeffs_moy_gen_significatifs = coeffs_cube * inscr_mask
coeffs_rcues_significatifs = coeffs_rcue * inscr_mask
# 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_moy_gen_significatifs, nan=0.0)
# Les moyennes par tag
with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN)
# Quelles entrées contiennent des notes et des coeffs?
mask = ~np.isnan(notes_significatives) & ~np.isnan(coeffs_rcues_significatifs)
# La moyenne (pondérée) sur le regroupement cohérent de semestres
coeffs_rcues_non_nan = np.nan_to_num(coeffs_rcues_significatifs * mask, nan=0.0)
notes_ponderes = notes_no_nan * coeffs_rcues_non_nan
etud_moy_tag = np.sum(notes_ponderes, axis=2) / np.sum(
coeffs_rcues_non_nan, axis=2
)
# Les coeffs pour la moyenne générale
coeffs_pris_en_compte = coeffs_moy_gen_significatifs * mask
coeffs_no_nan = np.nan_to_num(coeffs_pris_en_compte, nan=0.0)
coeff_tag = np.sum(coeffs_no_nan, axis=2)
# Le masque des inscriptions prises en compte
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, en réappliquant le masque des inscriptions
etud_moy_tag = etud_moy_tag * inscr_tag
# Le dataFrame des coeffs pour la moyenne générale, en réappliquant le masque des inscriptions
coeff_tag = coeff_tag * inscr_tag # Réapplique le masque des inscriptions
return (etud_moy_tag, coeff_tag)

14
tests/unit/test_pe.py Normal file
View File

@ -0,0 +1,14 @@
"""
Test calcul moyennes pour les poursuites d'études
"""
import numpy as np
from tests.unit import setup
from app import db
import app.pe.moys.pe_rcstag as pe_rcstag
def test_compute_moyennes_par_RCS:
"""Test"""
pass