Быстрая навигация:
От автора
Цитата автора
Светлана Овсянникова
Ex-разработчик в Яндекс Образовании
Привет!
Я Света, разработчик в Яндекс Образовании. Ниже разберу, как мы смогли формализовать очень абстрактную задачу, с которой столкнулись на работе. А затем покажу её решение. Приглашаю вас пройти этот путь вместе со мной.
Нюансы
Ежегодно компания проводит курс «Программирование на Python» для школьников и студентов средних учебных заведений.
Чтобы с каждым запуском образовательной программы ученики достигали более высоких результатов, анализируем опыт прохождения и делаем изменения часто даже по ходу программы. Таким образом нам нужно было собрать данные и провести анализ, чтобы сделать вывод, хорошо или плохо проходит курс и на что стоит обратить внимание.
В первом приближении задача выглядела следующим образом:
|
|
|
Данные о курсе
|
Курс проходит хорошо или плохо
|
В текущем виде абсолютно непонятно: какие данные приходят на вход, как их нужно обрабатывать, из чего в целом формируется вывод. А значит, надо разбираться, запрашивать, как всё устроено и в каком виде ожидают результат.
Начинаем погружение!
Аналитика образовательной программы
В первую очередь я решила уточнить, что значит «курс проходит хорошо или плохо»? Пообщалась с руководителем. Оказывается, он имел в виду, что «хорошо или плохо» — это интерпретация статистики по успеваемости учеников на курсе. Если у участников программы получается набирать больше определённого процента всех возможных баллов (например, больше 50%), значит, всё «хорошо», иначе — «плохо».
При этом важно не забывать о разбросе данных об успеваемости, чтобы определять ситуации, когда небольшим количеством прилежных учеников достигается высокий средний рейтинг. Порекомендовал собрать ещё максимальный и минимальный рейтинг ученика на программе, а также посмотреть на рейтинги лучших. Так будет собираться более полная картинка о реальном состоянии дел.
Ещё он подробнее рассказал про саму программу, для которой мы решаем задачу:
-
У задачи глобальное применение. На данный момент обучение проводится очно в более чем в 20 городах России. То есть мы делаем дополнительный функционал, которым будут пользоваться одновременно 20+ образовательных программ.
-
Есть конкретная структура обучения, из которой формируется успеваемость/рейтинг учеников. Обучение состоит из четырёх активностей, каждая из которых вносит свой вклад в рейтинг:
- Каждое занятие включает в себя теоретическую часть, где преподаватель объясняет новый материал.
- И практическую часть, в ходе которой ученики пишут код и выполняют задания в определённой системе.
- Для закрепления материала выдаются домашние задания.
- Для проверки знаний проводятся контрольные работы.
Далее, получив больше подробностей о задаче и образовательной программе, я задумалась, а какие данные и в каком виде мы собираем? С этим запросом обратилась к команде, которая запускала курс.
Оказалось, что команда использовала аналитическую систему, которая уже собирала и хранила данные с программ. В том числе и необходимые нам для расчёта успеваемости.
|
Блок
|
Что хранится
|
|
Успеваемость
|
- Оценки за активность на занятии
- Оценки за самостоятельную работу
- Оценки за домашние задания
- Оценки за контрольные работы
- Оценки за другие виды деятельности
(на некоторых программах есть дополнительные активности)
- Рейтинги
|
|
Посещаемость
|
- Количество посещённых занятий
- Количество пропущенных занятий
- Причины пропусков
|
|
Вовлечённость
|
- Количество ответов на занятиях
- Участие в дискуссиях
- Количество решений необязательных заданий
- Вопросы, задаваемые преподавателю
- Изучение дополнительных учебных материалов
|
|
Фидбэк
|
- Оценки курса учениками
- Комментарии к материалам курса
- Отзывы о преподавателях
- Сложные и лёгкие темы (по мнению учеников)
- Предложения по улучшению программы
|
Меня предупредили, что очистка и обработка данных пока настраивается, поэтому данные по успеваемости могут содержать ошибки и стоит их лишний раз проверять.
В результате я уточнила задачу, нашла готовые данные и поняла, как моя задача встраивается в глобальный контекст. Теперь можем составить рабочую формулировку!
Давайте соединим все детали и соберём формулировку задачи.
Что нужно посчитать:
- Рейтинг трёх лучших учеников.
- Общие статистические параметры программы (минимальный, средний, максимальный рейтинг учеников).
- Усвояемость программы. Если средний рейтинг будет больше 50% от максимального, сделаем вывод «Курс усваивается». Если меньше или равен 50% — «Курс не усваивается».
Ключевое:
- Ученик получает оценки для рейтинга за четыре вида активности по каждому занятию:
- за активность на занятии (classwork_grade);
- практику (selfwork_grade);
- домашнюю работу (homework_grade);
- и контрольные работы (testwork_grade).
- Рейтинг формируется из сумм оценок по каждому занятию по активностям, взятым с определённым весом (коэффициентом).
Рейтинг ученика = Сумма баллов по всем занятиям
Баллы за одно занятие = (
Оценка за активность • Коэффициент за активность
+ Оценка за практику • Коэффициент за практику
+ Оценка за домашнюю работу • Коэффициент за домашнюю работу
+ Оценка за контрольную работу • Коэффициент за контрольную работу
)
- Входные данные и итоговые расчёты нужно будет проверять на предмет возможных ошибок.
- Если ученика не было на занятии, или он не проявил себя, или не было этой активности, то оценка за активность будет равняться 0.
С учётом всех деталей задача преобразовалась в следующую:
|
Условие задачи:
|
|
Недавно начался очередной годовой курс «Программирование на Python». Прошла пара недель — и настало время подвести первые итоги: насколько курс усваивается учениками и нужно ли в нём что-то менять. Вас попросили собрать статистику по успеваемости учеников на курсе.
Для возможности принимать решения в рамках статистики необходимо:
-
Вывести общие показатели учеников программы: максимальное, среднее и минимальное значение рейтинга в процентах от максимально возможного.
-
Округлить результаты до целого значения по правилам математического округления: round().
-
Вывести лучших учеников: топ-3 лидера по рейтингу, их фамилии в порядке убывания рейтинга и заработанный процент от максимального количества баллов. Если у студентов равный рейтинг, они идут в порядке их ввода. Фамилии учеников уникальны.
-
На основе данных сделать предварительный вывод, насколько усваивается курс:
Также нужно проверить правильность введённых данных и расчётов.
Если есть ошибки, выводим «Во введённых данных ошибка».
Комментарии по вводу:
-
N (num_students) — число учеников в курсе.
-
M (num_lessons) — количество занятий в курсе.
-
Q (max_rating) — максимальный рейтинг.
-
cw (classwork_coefficient) — коэффициент для активности на занятии.
-
sw (selfwork_coefficient) — коэффициент для практики.
-
hw (homework_coefficient) — коэффициент для домашней работы.
-
tw (testwork_coefficient) — коэффициент для контрольной работы.
-
a (classwork_grade) — оценка за активность на занятии.
-
b (selfwork_grade) — оценка за практику на занятии.
-
c (homework_grade) — оценка за домашнюю работу на занятии.
-
d (testwork_grade) — оценка за контрольную работу на занятии.
Если не было активности, ученик отсутствовал либо не проявил себя на занятии — значение за активность будет 0.
Ограничения, которые следует учесть в работе программы:
-
N >= 3 (количество учеников больше или равно 3)
-
M > 0 (количество проведённых занятий 1 и больше)
-
cw, sw, hw, tw > 0 (все активности учитываются в рейтинге)
-
Рассчитанный максимальный рейтинг ученика на программе не должен превышать Q.
|
Ввод:
|
Вывод:
|
|
Строка с общими данными по программе
N M Q cw sw hw tw
Далее построчно вводятся оценки учеников в формате:
Фамилия
aᵢ,bᵢ,cᵢ,dᵢ
|
Max Average Min (максимальный, средний и минимальный рейтинг учеников программы)
Фамилия_1 Rating_1% (top-1)
Фамилия_2 Rating_2% (top-2)
Фамилия_3 Rating_3% (top-3)
Курс усваивается хорошо/плохо
|
|
4 5 190 1 2 4 6
Иванов
2,3,0,0
0,4,0,1
0,0,9,0
0,3,0,0
4,0,0,2
Петров
0,0,0,2
2,0,0,0
0,0,10,0
5,6,0,0
3,0,0,0
Сидоров
1,4,0,1
0,5,0,0
0,0,6,0
0,0,0,0
0,0,0,8
Сергеев
0,6,3,0
1,4,0,0
0,0,3,0
0,4,0,0
0,0,0,5
|
51 44 39
Сидоров 51%
Сергеев 44%
Иванов 42%
Курс усваивается плохо
Пояснение:
Все граничные условия выполнены. С данными всё в порядке.
Для Иванова рейтинг
6 ⋅ 1 + 10 ⋅ 2 + 9 ⋅ 4 + 3 ⋅ 6 = 80
округление 80 ∶ 190 = 42%
Для Петрова рейтинг
10 ⋅ 1 + 6 ⋅ 2 + 10 ⋅ 4 + 2 ⋅ 6 = 74
округление 74 ∶ 190 = 39%
У Сидорова = 51%
У Сергеева = 44%
Итого среднее (42 + 39 + 51 + 44) ∶ 4 = 44
|
|
2 5 210 3 4 7 8
Иванов
5,7,0,0
0,4,0,0
0,0,9,0
7,8,0,0
0,0,0,9
Петров
0,10,0,0
2,10,0,0
0,0,10,0
8,9,0,0
0,0,0,10
|
Во введённых данных ошибка
Пояснение:
Проверяем граничные условия. Количество учеников на курсе не больше или равно 3. Выводим ошибку.
|
|
Обратите внимание
Возможно, вы заметили, что ввод данных отличается от ввода данных в предыдущих задачах главы. Ранее вы считывали построчно — на каждой строчке были отдельные данные. А теперь несколько данных лежат в одной строчке, разделенные пробелом. и непонятно, как их считывать. Это нормально — так обычно бывает, когда начинаешь работать над новой для себя задачей и чего-то не знаешь. На практике программисты обычно либо советуются с более опытными коллегами, либо читают документацию, либо обращаются к GPT. Мы же дадим небольшую подсказку.
В данном случае для считывания данных из строчки мы будем использовать связку функции map() и метода .split().
Представим себе, что на вход подаются часы, минуты, секунды через пробел. Хотим эти данные считать в разные переменные.
14 30 45
Сделать можете это следующим образом.
1
2hours, minutes, seconds = map(int, input().split())
3
4
5print("Часы:", hours)
6print("Минуты:", minutes)
7print("Секунды:", seconds)
В данном случае .split() разбивает строку на три части, игнорируя пробелы:
А map(int, …) превращает их в числа:
А дальше происходит присваивание переменных:
1hours = 14
2minutes = 30
3seconds = 45
Теперь представим, что входные данные у нас идут с другим разделителем, запятой “,”:
14,30,45
В таком случае в методе .split() надо указать, какой разделитель у данных. Получится .split(“,”). Код изменится на следующий:
1
2hours, minutes, seconds = map(int, input().split(“,”))
3
4
5print("Часы:", hours)
6print("Минуты:", minutes)
7print("Секунды:", seconds)
Пользуйтесь этой связкой для считывания данных в рамках задачи.
Теперь у вас есть всё необходимое для решения задачи. Удачи!