Среднее средних — не среднее
Почему нельзя усреднять усреднённое и как это тихо портит отчёты.
Пример
У Иванова одна пятёрка. У Петрова десять троек.
srednie = [5.0, 3.0]
sum(srednie) / len(srednie) # 4.0
А честное среднее по всем оценкам:
vse = [5] + [3] * 10
sum(vse) / len(vse) # 3.18
Разница почти в балл, и она не случайна: усреднение средних даёт каждому ученику одинаковый вес независимо от числа оценок.
Когда что верно
Среднее по всем — когда важен каждый случай: средний балл класса, средний чек, средняя длительность звонка.
Среднее средних — когда важен каждый объект: средняя успеваемость ученика по классу, где ученик с одной оценкой и с сотней равны по значимости. Так тоже бывает, но это должно быть решением, а не случайностью.
Почему ошибка живучая
Отчёт собирается, число получается, выглядит правдоподобно. Заметить можно только сверив с честным расчётом — а для этого надо заподозрить.
Как считать правильно
Собрать все значения, а не средние:
vse_ocenki = []
for ocenki in ucheniki.values():
vse_ocenki.extend(ocenki)
srednee = sum(vse_ocenki) / len(vse_ocenki) if vse_ocenki else 0
Если хранить все значения дорого, копите сумму и количество:
summa = kolichestvo = 0
for ocenki in ucheniki.values():
summa += sum(ocenki)
kolichestvo += len(ocenki)
Родственная ловушка
Проценты складывать тоже нельзя. Скидка 10%, потом ещё 10% — это не 20%, а 19%.