recopytex/recopytex/datalib/on_score_column.py

207 lines
5.7 KiB
Python

#!/usr/bin/env python
# encoding: utf-8
from math import ceil
def is_none_score(x, score_config):
"""Is a score correspond to a None numeric_value which
>>> import pandas as pd
>>> d = {"Eleve":["E1"]*7,
... "score_rate": [1]*7,
... "is_leveled":[0]+[1]*6,
... "score":[0.33, "", ".", "a", 1, 2, 3],
... }
>>> score_config = {
... 'BAD': {'value': 0, 'numeric_value': 0},
... 'FEW': {'value': 1, 'numeric_value': 1},
... 'NEARLY': {'value': 2, 'numeric_value': 2},
... 'GOOD': {'value': 3, 'numeric_value': 3},
... 'NOTFILLED': {'value': '', 'numeric_value': 'None'},
... 'NOANSWER': {'value': '.', 'numeric_value': 0},
... 'ABS': {'value': 'a', 'numeric_value': 'None'}
... }
>>> df = pd.DataFrame(d)
>>> df.apply(lambda x:is_none_score(x, score_config), axis=1)
0 False
1 True
2 False
3 True
4 False
5 False
6 False
dtype: bool
"""
none_values = [
v["value"]
for v in score_config.values()
if str(v["numeric_value"]).lower() == "none"
]
return x["score"] in none_values
def score_to_numeric_score(x, score_config):
"""Convert a score to the corresponding numeric value
>>> import pandas as pd
>>> d = {"Eleve":["E1"]*7,
... "score_rate": [1]*7,
... "is_leveled":[0]+[1]*6,
... "score":[0.33, "", ".", "a", 1, 2, 3],
... }
>>> score_config = {
... 'BAD': {'value': 0, 'numeric_value': 0},
... 'FEW': {'value': 1, 'numeric_value': 1},
... 'NEARLY': {'value': 2, 'numeric_value': 2},
... 'GOOD': {'value': 3, 'numeric_value': 3},
... 'NOTFILLED': {'value': '', 'numeric_value': 'None'},
... 'NOANSWER': {'value': '.', 'numeric_value': 0},
... 'ABS': {'value': 'a', 'numeric_value': 'None'}
... }
>>> df = pd.DataFrame(d)
>>> df.apply(lambda x:score_to_numeric_score(x, score_config), axis=1)
0 0.33
1 None
2 0
3 None
4 1
5 2
6 3
dtype: object
"""
if x["is_leveled"]:
replacements = {v["value"]: v["numeric_value"] for v in score_config.values()}
return replacements[x["score"]]
return x["score"]
def score_to_mark(x, score_max, rounding=lambda x: round(x, 2)):
"""Compute the mark from the score
if the item is leveled then the score is multiply by the score_rate
otherwise it copies the score
:param x: dictionnary with "is_leveled", "score" (need to be number) and "score_rate" keys
:param score_max:
:param rounding: rounding mark function
:return: the mark
>>> import pandas as pd
>>> d = {"Eleve":["E1"]*6 + ["E2"]*6,
... "score_rate":[1]*2+[2]*2+[2]*2 + [1]*2+[2]*2+[2]*2,
... "is_leveled":[0]*4+[1]*2 + [0]*4+[1]*2,
... "score":[1, 0.33, 2, 1.5, 1, 3, 0.666, 1, 1.5, 1.2, 2, 3],
... }
>>> df = pd.DataFrame(d)
>>> df.loc[0]
Eleve E1
score_rate 1
is_leveled 0
score 1.0
Name: 0, dtype: object
>>> score_to_mark(df.loc[0], 3)
1.0
>>> df.loc[10]
Eleve E2
score_rate 2
is_leveled 1
score 2.0
Name: 10, dtype: object
>>> score_to_mark(df.loc[10], 3)
1.33
>>> from .on_value import round_half_point
>>> score_to_mark(df.loc[10], 3, round_half_point)
1.5
>>> df.loc[1]
Eleve E1
score_rate 1
is_leveled 0
score 0.33
Name: 1, dtype: object
>>> score_to_mark(df.loc[1], 3)
0.33
"""
if x["is_leveled"]:
if x["score"] not in list(range(score_max + 1)):
raise ValueError(f"The evaluation is out of range: {x['score']} at {x}")
return rounding(x["score"] * x["score_rate"] / score_max)
return rounding(x["score"])
def score_to_level(x, level_max=3):
"""Compute the level (".",0,1,2,3).
:param x: dictionnary with "is_leveled", "score" and "score_rate" keys
:return: the level
>>> import pandas as pd
>>> d = {"Eleve":["E1"]*6 + ["E2"]*6,
... "score_rate":[1]*2+[2]*2+[2]*2 + [1]*2+[2]*2+[2]*2,
... "is_leveled":[0]*4+[1]*2 + [0]*4+[1]*2,
... "score":[1, 0.33, 0, 1.5, 1, 3, 0.666, 1, 1.5, 1, 2, 3],
... }
>>> df = pd.DataFrame(d)
>>> df
Eleve score_rate is_leveled score
0 E1 1 0 1.000
1 E1 1 0 0.330
2 E1 2 0 0.000
3 E1 2 0 1.500
4 E1 2 1 1.000
5 E1 2 1 3.000
6 E2 1 0 0.666
7 E2 1 0 1.000
8 E2 2 0 1.500
9 E2 2 0 1.000
10 E2 2 1 2.000
11 E2 2 1 3.000
>>> df.apply(score_to_level, axis=1)
0 3
1 1
2 0
3 3
4 1
5 3
6 2
7 3
8 3
9 2
10 2
11 3
dtype: int64
>>> df.apply(lambda x: score_to_level(x, 5), axis=1)
0 5
1 2
2 0
3 4
4 1
5 3
6 4
7 5
8 4
9 3
10 2
11 3
dtype: int64
"""
if x["is_leveled"]:
return int(x["score"])
if x["score"] > x["score_rate"]:
raise ValueError(
f"score is higher than score_rate ({x['score']} > {x['score_rate']}) for {x}"
)
return int(ceil(x["score"] / x["score_rate"] * level_max))
# -----------------------------
# Reglages pour 'vim'
# vim:set autoindent expandtab tabstop=4 shiftwidth=4:
# cursor: 16 del