Учебная часть прислала оценки за год и просит отчёт для кафедры. В файле data/grades.csv — 30 студентов
трёх групп, пять предметов, два семестра; баллы от 0 до 100, зачёт — от 50. Одна строка — одна оценка.
Новых методов в проекте нет.
import pandas as pd
grades = pd.read_csv("data/grades.csv")
print(grades.shape)
grades.head(4)(300, 5)
| student | group | subject | term | score | |
|---|---|---|---|---|---|
| 0 | Анна А. | ИТ-21 | Математика | 1 | 68 |
| 1 | Анна А. | ИТ-21 | Математика | 2 | 71 |
| 2 | Анна А. | ИТ-21 | Физика | 1 | 49 |
| 3 | Анна А. | ИТ-21 | Физика | 2 | 60 |
Шаг 1. Годовая ведомость
Данные в длинном формате удобны для расчётов, но преподаватели привыкли к ведомости: студенты в строках, предметы в столбцах. У каждого студента по каждому предмету две оценки — значит, их нужно свести в одну.
Сохраните в sheet сводную таблицу: студенты в строках, предметы в столбцах, в ячейках — средний балл
за два семестра, округлённый до одного знака.
grades.pivot_table(values="score", index="student", columns="subject", aggfunc="mean").round(1).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
sheet = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
sheet = grades.pivot_table(values="score", index="student", columns="subject", aggfunc="mean").round(1)sheet.head(5)| subject | Английский | История | Математика | Программирование | Физика |
|---|---|---|---|---|---|
| student | |||||
| Алексей Я. | 97.5 | 76.5 | 85.0 | 98.5 | 92.0 |
| Андрей Б. | 56.0 | 65.0 | 51.0 | 83.0 | 68.5 |
| Анна А. | 78.0 | 80.5 | 69.5 | 66.5 | 54.5 |
| Анна Л. | 65.5 | 86.0 | 80.5 | 70.5 | 86.0 |
| Дмитрий К. | 63.0 | 76.0 | 66.0 | 76.0 | 65.0 |
Шаг 2. Лучшие студенты
Сохраните в student_avg средний балл каждого студента по всем оценкам за год. В top3 — трёх студентов
с наибольшим средним баллом; баллы округлите до одного знака.
grades.groupby("student")["score"].mean().student_avg.nlargest(3).round(1).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
student_avg = ...
top3 = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
student_avg = grades.groupby("student")["score"].mean()
top3 = student_avg.nlargest(3).round(1)Шаг 3. Группы и предметы
Сохраните в group_subject сводную таблицу средних баллов: группы в строках, предметы в столбцах, с итоговой
строкой и столбцом «Все», округление до одного знака. В math_leader сохраните группу с лучшим средним
баллом по математике.
pivot_table добавьте margins=True, margins_name="Все".group_subject["Математика"].idxmax().Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
group_subject = ...
math_leader = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
group_subject = grades.pivot_table(values="score", index="group", columns="subject", aggfunc="mean", margins=True, margins_name="Все").round(1)
math_leader = group_subject["Математика"].idxmax()group_subject| subject | Английский | История | Математика | Программирование | Физика | Все |
|---|---|---|---|---|---|---|
| group | ||||||
| ИТ-21 | 67.2 | 71.8 | 63.2 | 65.0 | 64.9 | 66.4 |
| ИТ-22 | 64.2 | 65.4 | 69.0 | 77.4 | 69.7 | 69.2 |
| ИТ-23 | 67.2 | 70.6 | 71.8 | 67.0 | 69.0 | 69.1 |
| Все | 66.2 | 69.2 | 68.0 | 69.8 | 67.8 | 68.2 |
У группы ИТ-22 заметный отрыв по программированию — 77.4 против 65–67 у остальных. Заметна и разница по математике: ИТ-21 отстаёт от двух других групп на 6–9 баллов. А по английскому группы почти равны.
Шаг 4. Первый семестр против второго
Сохраните в by_term сводную таблицу: предметы в строках, семестры в столбцах, в ячейках — средний балл.
Добавьте столбец growth — разность второго и первого семестра. В grew_most сохраните предмет, по которому
баллы выросли сильнее всего, в fell — строки предметов, по которым баллы упали.
by_term[2] - by_term[1].by_term["growth"].idxmax(); упавшие — фильтр by_term["growth"] < 0.Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
by_term = ...
# добавьте в by_term столбец growth
grew_most = ...
fell = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
by_term = grades.pivot_table(values="score", index="subject", columns="term", aggfunc="mean")
by_term["growth"] = by_term[2] - by_term[1]
grew_most = by_term["growth"].idxmax()
fell = by_term[by_term["growth"] < 0]Шаг 5. Незачёты
Добавьте в grades столбец passed: True, если балл не меньше 50. Сохраните в pass_table таблицу долей:
группы в строках, passed в столбцах, доли внутри строки. В fail_21 сохраните долю незачётов в группе ИТ-21.
pd.crosstab(grades["group"], grades["passed"], normalize="index").False: pass_table.loc["ИТ-21", False].Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
# добавьте в grades столбец passed
pass_table = ...
fail_21 = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
grades["passed"] = grades["score"] >= 50
pass_table = pd.crosstab(grades["group"], grades["passed"], normalize="index")
fail_21 = pass_table.loc["ИТ-21", False]Шаг 6. Обратно в длинную форму
Ведомость sheet широкая. Чтобы найти в ней все высокие баллы разом, её удобнее снова «расплавить».
Студенты сейчас в индексе — melt работает со столбцами, поэтому сначала reset_index.
Переведите sheet в длинный формат и сохраните в year_marks: столбцы student, subject, mean_score.
В stars сохраните строки с годовым баллом от 90, отсортированные по убыванию балла.
sheet.reset_index().melt(id_vars="student", var_name="subject", value_name="mean_score").year_marks["mean_score"] >= 90 и sort_values("mean_score", ascending=False).Заготовка упражнения обновилась с тех пор, как вы сохранили свой код.
Вернуть заготовку? Ваш код в этом упражнении будет удалён.
year_marks = ...
stars = ...Упражнение пока не решено, поэтому для ячеек ниже выполнено эталонное решение — ваш код не изменён.
year_marks = sheet.reset_index().melt(id_vars="student", var_name="subject", value_name="mean_score")
stars = year_marks[year_marks["mean_score"] >= 90].sort_values("mean_score", ascending=False)Отчёт
print("Лучшие студенты:")
print(top3)
print("Лучшая группа по математике:", math_leader)
print("Сильнее всего выросли баллы:", grew_most, "· упали:", list(fell.index))
print("Доля незачётов в ИТ-21:", round(fail_21 * 100), "%")
print("Годовых баллов от 90:", len(stars))Лучшие студенты: student Алексей Я. 89.9 Наталья П. 81.0 Ольга А. 79.3 Name: score, dtype: float64 Лучшая группа по математике: ИТ-23 Сильнее всего выросли баллы: Физика · упали: ['История'] Доля незачётов в ИТ-21: 8 % Годовых баллов от 90: 5
Выводы
- Лучший студент года — Алексей Я. со средним баллом 89.9; на его счету три из пяти годовых результатов от 90 баллов.
- Группа ИТ-22 сильнее остальных в программировании, ИТ-23 — в математике.
- От первого семестра ко второму выросли баллы по физике (+2.2) и программированию; по истории немного упали.
- Незачётов мало: 15 из 300 оценок. Больше всего — в ИТ-21, 8 %.
В этом проекте данные дважды сменили форму: длинная → широкая ведомость → снова длинная. Это обычная работа с таблицами: считать удобнее в длинной форме, смотреть — в широкой.