Skip to content
Snippets Groups Projects
Commit c2d94629 authored by Christopher Bohn's avatar Christopher Bohn :thinking:
Browse files

Improved performance by memorizing scores to reduce network accesses

parent 67c3829c
Branches
No related tags found
No related merge requests found
...@@ -49,7 +49,9 @@ def create_semester_filter() -> str: ...@@ -49,7 +49,9 @@ def create_semester_filter() -> str:
return f'1{str(year)[-2:]}{month}' # introducing a y2.1k problem return f'1{str(year)[-2:]}{month}' # introducing a y2.1k problem
def select_students_for_material_collection(assignment, student_subset) -> Tuple[CanvasUser, CanvasUser, CanvasUser]: def select_students_for_material_collection(assignment,
scores: Dict[CanvasUser, Optional[float]],
student_subset) -> Tuple[CanvasUser, CanvasUser, CanvasUser]:
points_possible: float = assignment.get_points_possible() points_possible: float = assignment.get_points_possible()
grade_thresholds: Dict[str, float] = { grade_thresholds: Dict[str, float] = {
'A': 0.93 * points_possible, 'A': 0.93 * points_possible,
...@@ -66,37 +68,39 @@ def select_students_for_material_collection(assignment, student_subset) -> Tuple ...@@ -66,37 +68,39 @@ def select_students_for_material_collection(assignment, student_subset) -> Tuple
c_student: Optional[CanvasUser] = None c_student: Optional[CanvasUser] = None
candidates_for_material_collection: Set[CanvasUser] = \ candidates_for_material_collection: Set[CanvasUser] = \
{student for student in student_subset {student for student in student_subset
if assignment.get_score(student) is not None if scores[student] is not None
and assignment.get_score(student) >= grade_thresholds['A']} and scores[student] >= grade_thresholds['A']}
if len(candidates_for_material_collection) == 0: if len(candidates_for_material_collection) == 0:
candidates_for_material_collection = \ candidates_for_material_collection = \
{student for student in student_subset {student for student in student_subset
if assignment.get_score(student) is not None if scores[student] is not None
and assignment.get_score(student) >= grade_thresholds['A-']} and scores[student] >= grade_thresholds['A-']}
if len(candidates_for_material_collection) > 0: if len(candidates_for_material_collection) > 0:
a_student = candidates_for_material_collection.pop() a_student = candidates_for_material_collection.pop()
candidates_for_material_collection = \ candidates_for_material_collection = \
{student for student in student_subset if assignment.get_score(student) is not None {student for student in student_subset if scores[student] is not None
and grade_thresholds['B'] <= assignment.get_score(student) < grade_thresholds['B+']} and grade_thresholds['B'] <= scores[student] < grade_thresholds['B+']}
if len(candidates_for_material_collection) == 0: if len(candidates_for_material_collection) == 0:
candidates_for_material_collection = \ candidates_for_material_collection = \
{student for student in student_subset if assignment.get_score(student) is not None {student for student in student_subset if scores[student] is not None
and grade_thresholds['B-'] <= assignment.get_score(student) < grade_thresholds['A-']} and grade_thresholds['B-'] <= scores[student] < grade_thresholds['A-']}
if len(candidates_for_material_collection) > 0: if len(candidates_for_material_collection) > 0:
b_student = candidates_for_material_collection.pop() b_student = candidates_for_material_collection.pop()
candidates_for_material_collection = \ candidates_for_material_collection = \
{student for student in student_subset if assignment.get_score(student) is not None {student for student in student_subset if scores[student] is not None
and grade_thresholds['C'] <= assignment.get_score(student) < grade_thresholds['C+']} and grade_thresholds['C'] <= scores[student] < grade_thresholds['C+']}
if len(candidates_for_material_collection) == 0: if len(candidates_for_material_collection) == 0:
candidates_for_material_collection = \ candidates_for_material_collection = \
{student for student in student_subset if assignment.get_score(student) is not None {student for student in student_subset if scores[student] is not None
and grade_thresholds['C-'] <= assignment.get_score(student) < grade_thresholds['B-']} and grade_thresholds['C-'] <= scores[student] < grade_thresholds['B-']}
if len(candidates_for_material_collection) > 0: if len(candidates_for_material_collection) > 0:
c_student = candidates_for_material_collection.pop() c_student = candidates_for_material_collection.pop()
return a_student, b_student, c_student return a_student, b_student, c_student
def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], def print_sample_scores(assignment: CanvasAssignment,
scores: Dict[CanvasUser, Optional[float]],
majors: Set[Major],
major_partitions: Dict[Major, Set[CanvasUser]], major_partitions: Dict[Major, Set[CanvasUser]],
students: Optional[List[CanvasUser]] = None) -> None: students: Optional[List[CanvasUser]] = None) -> None:
points_possible: float = assignment.get_points_possible() points_possible: float = assignment.get_points_possible()
...@@ -104,7 +108,7 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], ...@@ -104,7 +108,7 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major],
b_student: Optional[CanvasUser] = None b_student: Optional[CanvasUser] = None
c_student: Optional[CanvasUser] = None c_student: Optional[CanvasUser] = None
for major in majors: for major in majors:
student_subset: Set[CanvasUser] = major_partitions[major] if students is None \ student_subset: Set[CanvasUser] = major_partitions[major].copy() if students is None \
else major_partitions[major].intersection(students) else major_partitions[major].intersection(students)
selected_students: Set[CanvasUser] = set() selected_students: Set[CanvasUser] = set()
if len(student_subset) == 0: if len(student_subset) == 0:
...@@ -112,12 +116,14 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], ...@@ -112,12 +116,14 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major],
elif len(student_subset) <= 30: elif len(student_subset) <= 30:
print(f'{major.name} has {len(student_subset)} students: reporting scores for all students.') print(f'{major.name} has {len(student_subset)} students: reporting scores for all students.')
selected_students = student_subset selected_students = student_subset
a_student, b_student, c_student = select_students_for_material_collection(assignment, student_subset) a_student, b_student, c_student = select_students_for_material_collection(assignment, scores,
student_subset)
else: else:
print( print(
f'{major.name} has {len(student_subset)} students: reporting scores for 30 randomly-selected students.') f'{major.name} has {len(student_subset)} students: reporting scores for 30 randomly-selected students.')
# let's make sure there are an 'A', a 'B', and a 'C' student in the mix # let's make sure there are an 'A', a 'B', and a 'C' student in the mix
a_student, b_student, c_student = select_students_for_material_collection(assignment, student_subset) a_student, b_student, c_student = select_students_for_material_collection(assignment, scores,
student_subset)
for student in (a_student, b_student, c_student): for student in (a_student, b_student, c_student):
if student is not None: if student is not None:
student_subset.remove(student) student_subset.remove(student)
...@@ -127,27 +133,29 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major], ...@@ -127,27 +133,29 @@ def print_sample_scores(assignment: CanvasAssignment, majors: Set[Major],
selected_students.add(student) selected_students.add(student)
i = 1 i = 1
for student in selected_students: for student in selected_students:
print(f'Student {i:>2} -- raw score: {assignment.get_score(student)}' print(f'Student {i:>2} -- raw score: {scores[student]}'
f'\tscaled score: {100 * assignment.get_score(student) / points_possible}') f'\tscaled score: {100 * scores[student] / points_possible}')
print('Collect sample materials --')
print(f'"A" student: {a_student.get_name()}')
print(f'"B" student: {b_student.get_name()}')
print(f'"C" student: {c_student.get_name()}')
i += 1 i += 1
print('Collect sample materials --')
print(f'"A" student: {a_student.get_name() if a_student is not None else a_student}')
print(f'"B" student: {b_student.get_name() if b_student is not None else b_student}')
print(f'"C" student: {c_student.get_name() if c_student is not None else c_student}')
print() print()
def print_statistics_for_some_majors(assignment: CanvasAssignment, majors: Set[Major], def print_statistics_for_some_majors(assignment: CanvasAssignment,
scores: Dict[CanvasUser, Optional[float]],
majors: Set[Major],
major_partitions: Dict[Major, Set[CanvasUser]], major_partitions: Dict[Major, Set[CanvasUser]],
students: Optional[List[CanvasUser]] = None) -> None: students: Optional[List[CanvasUser]] = None) -> None:
points_possible: float = assignment.get_points_possible() points_possible: float = assignment.get_points_possible()
for major in majors: for major in majors:
student_subset: Set[CanvasUser] = major_partitions[major] if students is None \ student_subset: Set[CanvasUser] = major_partitions[major] if students is None \
else major_partitions[major].intersection(students) else major_partitions[major].intersection(students)
scores: List[float] = [assignment.get_score(student) for student in student_subset valued_scores: List[float] = [scores[student] for student in student_subset
if assignment.get_score(student) is not None] if scores[student] is not None]
try: try:
average_score: float = statistics.mean(scores) average_score: float = statistics.mean(valued_scores)
scaled_average_score: float = 100 * average_score / points_possible scaled_average_score: float = 100 * average_score / points_possible
print(f'{major.name:27}students:{len(major_partitions[major]):>3} ' print(f'{major.name:27}students:{len(major_partitions[major]):>3} '
f'scaled mean score: {scaled_average_score:.2f}%') f'scaled mean score: {scaled_average_score:.2f}%')
...@@ -155,20 +163,24 @@ def print_statistics_for_some_majors(assignment: CanvasAssignment, majors: Set[M ...@@ -155,20 +163,24 @@ def print_statistics_for_some_majors(assignment: CanvasAssignment, majors: Set[M
print(f'{major.name:27}students:{len(major_partitions[major]):>3} no mean score computed: {exception}') print(f'{major.name:27}students:{len(major_partitions[major]):>3} no mean score computed: {exception}')
def print_statistics(assignment: CanvasAssignment, major_partitions: Dict[Major, Set[CanvasUser]]) -> None: def print_statistics(assignment: CanvasAssignment,
scores: Dict[CanvasUser, Optional[float]],
major_partitions: Dict[Major, Set[CanvasUser]]) -> None:
if assignment.get_points_possible() == 0: if assignment.get_points_possible() == 0:
print(f'WARNING: {assignment} is a 0-point assignment; cannot compute scaled mean score.') print(f'WARNING: {assignment} is a 0-point assignment; cannot compute scaled mean score.')
else: else:
print(f'Statistics for {assignment}:') print(f'Statistics for {assignment}:')
computing_majors: Set[Major] = {major for major in Major.majors if major.is_computing_major} computing_majors: Set[Major] = {major for major in Major.majors if major.is_computing_major}
non_computing_majors: Set[Major] = {major for major in major_partitions.keys() if not major.is_computing_major} non_computing_majors: Set[Major] = {major for major in major_partitions.keys() if not major.is_computing_major}
print_statistics_for_some_majors(assignment, computing_majors, major_partitions) print_statistics_for_some_majors(assignment, scores, computing_majors, major_partitions)
print_statistics_for_some_majors(assignment, non_computing_majors, major_partitions) print_statistics_for_some_majors(assignment, scores, non_computing_majors, major_partitions)
print() print()
print_sample_scores(assignment, computing_majors, major_partitions) print_sample_scores(assignment, scores, computing_majors, major_partitions)
def print_statistics_by_section(course: CanvasCourse, assignment: CanvasAssignment, def print_statistics_by_section(course: CanvasCourse,
assignment: CanvasAssignment,
scores: Dict[CanvasUser, Optional[float]],
major_partitions: Dict[Major, Set[CanvasUser]]) -> None: major_partitions: Dict[Major, Set[CanvasUser]]) -> None:
print(f'Statistics for {assignment}:') print(f'Statistics for {assignment}:')
computing_majors: Set[Major] = {major for major in Major.majors if major.is_computing_major} computing_majors: Set[Major] = {major for major in Major.majors if major.is_computing_major}
...@@ -182,10 +194,10 @@ def print_statistics_by_section(course: CanvasCourse, assignment: CanvasAssignme ...@@ -182,10 +194,10 @@ def print_statistics_by_section(course: CanvasCourse, assignment: CanvasAssignme
for student in students: for student in students:
non_computing_majors.update({major for major in all_non_computing_majors non_computing_majors.update({major for major in all_non_computing_majors
if student in major_partitions[major]}) if student in major_partitions[major]})
print_statistics_for_some_majors(assignment, computing_majors, major_partitions, students) print_statistics_for_some_majors(assignment, scores, computing_majors, major_partitions, students)
print_statistics_for_some_majors(assignment, non_computing_majors, major_partitions, students) print_statistics_for_some_majors(assignment, scores, non_computing_majors, major_partitions, students)
print() print()
print_sample_scores(assignment, computing_majors, major_partitions, students) print_sample_scores(assignment, scores, computing_majors, major_partitions, students)
print() print()
...@@ -197,10 +209,18 @@ def assess_assignments(course: CanvasCourse, major_partitions: Dict[Major, Set[C ...@@ -197,10 +209,18 @@ def assess_assignments(course: CanvasCourse, major_partitions: Dict[Major, Set[C
assignment_group: CanvasAssignmentGroup = \ assignment_group: CanvasAssignmentGroup = \
select_from_list(course.get_assignment_groups(), 'assignment group') select_from_list(course.get_assignment_groups(), 'assignment group')
oat_assignment: CanvasAssignment = select_from_list(assignment_group.get_assignments(), 'assignment') oat_assignment: CanvasAssignment = select_from_list(assignment_group.get_assignments(), 'assignment')
assignment_scores: Dict[CanvasUser, Optional[float]] = {}
print('Retrieving scores ', end='')
sys.stdout.flush()
for student in course.get_students():
print('.', end='')
sys.stdout.flush()
assignment_scores[student] = oat_assignment.get_score(student)
print()
if not print_section_statistics: if not print_section_statistics:
print_statistics(oat_assignment, major_partitions) print_statistics(oat_assignment, assignment_scores, major_partitions)
else: else:
print_statistics_by_section(course, oat_assignment, major_partitions) print_statistics_by_section(course, oat_assignment, assignment_scores, major_partitions)
print() print()
answer = input('Assess additional assignments? [Y/n] ') answer = input('Assess additional assignments? [Y/n] ')
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment