1
0
forked from ScoDoc/ScoDoc

Optimize compute_module_moy

This commit is contained in:
Emmanuel Viennet 2021-11-26 17:26:34 +01:00
parent 83ba9cf186
commit 5a3c25e67f
2 changed files with 33 additions and 32 deletions

View File

@ -121,8 +121,8 @@ def df_load_modimpl_notes(moduleimpl_id: int) -> pd.DataFrame:
def compute_module_moy( def compute_module_moy(
evals_notes: pd.DataFrame, evals_notes_df: pd.DataFrame,
evals_poids: pd.DataFrame, evals_poids_df: pd.DataFrame,
evaluations: list, evaluations: list,
) -> pd.DataFrame: ) -> pd.DataFrame:
"""Calcule les moyennes des étudiants dans ce module """Calcule les moyennes des étudiants dans ce module
@ -140,34 +140,35 @@ def compute_module_moy(
ou NaN si les évaluations (dans lesquelles l'étudiant à des notes) ou NaN si les évaluations (dans lesquelles l'étudiant à des notes)
ne donnent pas de coef vers cette UE. ne donnent pas de coef vers cette UE.
""" """
nb_etuds = len(evals_notes) nb_etuds, nb_evals = evals_notes_df.shape
nb_ues = evals_poids.shape[1] nb_ues = evals_poids_df.shape[1]
etud_moy_module_arr = np.zeros((nb_etuds, nb_ues)) assert evals_poids_df.shape[0] == nb_evals # compat notes/poids
evals_poids_arr = evals_poids.to_numpy().transpose() * [ evals_coefs = np.array([e.coefficient for e in evaluations], dtype=float).reshape(
e.coefficient for e in evaluations -1, 1
] )
# -> evals_poids_arr shape : (nb_ues, nb_evals) evals_poids = evals_poids_df.values * evals_coefs
# -> evals_poids_arr shape : (nb_evals, nb_ues)
assert evals_poids.shape == (nb_evals, nb_ues)
# Remet les notes sur 20 (sauf notes spéciales <= -1000): # Remet les notes sur 20 (sauf notes spéciales <= -1000):
evals_notes_arr = np.where(evals_notes.values > -1000, evals_notes.values, 0.0) / [ evals_notes = np.where(
e.note_max / 20.0 for e in evaluations evals_notes_df.values > -1000, evals_notes_df.values, 0.0
] ) / [e.note_max / 20.0 for e in evaluations]
for i in range(nb_etuds): # Les poids des évals pour les étudiant: là où il a des notes non neutralisées
# note_vect: array [note_ue1, note_ue2, ...] de l'étudiant i
note_vect = evals_notes_arr[i]
# Les poids des évals pour cet étudiant: là où il a des notes non neutralisées
# Attention: les NaN (codant les absents) sont remplacés par des 0 dans # Attention: les NaN (codant les absents) sont remplacés par des 0 dans
# evals_notes_arr mais pas dans evals_poids_etud_arr # evals_notes_arr mais pas dans evals_poids_etuds_arr
# (la comparaison est toujours false face à un NaN) # (la comparaison est toujours false face à un NaN)
evals_poids_etud_arr = np.where( # shape: (nb_etuds, nb_evals, nb_ues)
evals_notes.values[i] <= -1000, 0, evals_poids_arr poids_stacked = np.stack([evals_poids] * nb_etuds)
evals_poids_etuds = np.where(
np.stack([evals_notes_df.values] * nb_ues, axis=2) <= -1000.0, 0, poids_stacked
) )
# Calcule la moyenne pondérée sur les notes disponibles # Calcule la moyenne pondérée sur les notes disponibles
evals_notes_stacked = np.stack([evals_notes] * nb_ues, axis=2)
with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN) with np.errstate(invalid="ignore"): # ignore les 0/0 (-> NaN)
etud_moy_module_arr[i] = (note_vect * evals_poids_etud_arr).sum( etud_moy_module = np.sum(
axis=1 evals_poids_etuds * evals_notes_stacked, axis=1
) / evals_poids_etud_arr.sum(axis=1) ) / np.sum(evals_poids_etuds, axis=1)
etud_moy_module_df = pd.DataFrame( etud_moy_module_df = pd.DataFrame(
etud_moy_module_arr, index=evals_notes.index, columns=evals_poids.columns etud_moy_module, index=evals_notes_df.index, columns=evals_poids_df.columns
) )
return etud_moy_module_df return etud_moy_module_df

View File

@ -234,7 +234,7 @@ def test_module_moy_elem(test_client):
"EVAL2": np.NaN, # et une ABS "EVAL2": np.NaN, # et une ABS
}, },
] ]
evals_notes = pd.DataFrame( evals_notes_df = pd.DataFrame(
data, index=["etud1", "etud2", "etud3", "etud4", "etud5"] data, index=["etud1", "etud2", "etud3", "etud4", "etud5"]
) )
# Poids des évaluations (1 ligne / évaluation) # Poids des évaluations (1 ligne / évaluation)
@ -242,13 +242,13 @@ def test_module_moy_elem(test_client):
{"UE1": 1, "UE2": 0, "UE3": 0}, {"UE1": 1, "UE2": 0, "UE3": 0},
{"UE1": 2, "UE2": 5, "UE3": 0}, {"UE1": 2, "UE2": 5, "UE3": 0},
] ]
evals_poids = pd.DataFrame(data, index=["EVAL1", "EVAL2"], dtype=float) evals_poids_df = pd.DataFrame(data, index=["EVAL1", "EVAL2"], dtype=float)
evaluations = [ evaluations = [
Evaluation(note_max=20.0, coefficient=1.0), Evaluation(note_max=20.0, coefficient=1.0),
Evaluation(note_max=20.0, coefficient=1.0), Evaluation(note_max=20.0, coefficient=1.0),
] ]
etud_moy_module_df = moy_mod.compute_module_moy( etud_moy_module_df = moy_mod.compute_module_moy(
evals_notes.fillna(0.0), evals_poids, evaluations evals_notes_df.fillna(0.0), evals_poids_df, evaluations
) )
NAN = 666.0 # pour pouvoir comparer NaN et NaN (car NaN != NaN) NAN = 666.0 # pour pouvoir comparer NaN et NaN (car NaN != NaN)
r = etud_moy_module_df.fillna(NAN) r = etud_moy_module_df.fillna(NAN)