{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Python для сбора данных\n", "\n", "*Алла Тамбовцева, НИУ ВШЭ*\n", "\n", "### Семинар 5 по теме: группировка и агрегирование" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 1: загрузка и преобразование файла JSON\n", "\n", "В рамках этого семинара мы поработаем с файлом в формате JSON. \n", "\n", "JSON расшифровывается как *JavaScript Object Notation*. Изначально этот формат хранения данных использовался в языке JavaScript, но теперь он потерял привязку к конкретному языку программирования и стал универсальным. С форматом JSON можно столкнуться при обращении к API, базам данных; формат часто применяется для хранения информации на сервере, к которому обращается сайт, например, в зависимости от запросов пользователей. *Object* здесь можно понимать как некоторую структуру хранения данных (список, кортеж, словарь), которая записывается в специальном виде, внешне напоминающим обычную строку.\n", "\n", "Импортируем модуль `json`:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [], "source": [ "import json" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Начнём работать с реальными данными. Зайдём на [Портал открытых данных](https://data.mos.ru/opendata) Правительства Москвы в раздел Образование и выберем набор данных **Победители олимпиад**. Кликнем *Экспорт* и скачаем файл в формате `json`. Скачается, правда, zip-архив, но его можно распаковать. Сохраним название файла (или путь к нему) в переменную `name`:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "name = \"data-27257-2020-03-02.json\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Теперь загрузим содержимое файла в Python. Вообще при работе с json-файлами выделяют две операции: десериализация и сериализация. Десериализация – это преобразование объекта JSON в другую структуру данных (например, в питоновский словарь или список), а сериализация – это запись данных в формат JSON. Десериализуем:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "with open(name, \"r\", encoding=\"Windows-1251\") as read_file:\n", " data = json.load(read_file)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Запись с `with open()` as `read_file` эквивалентна созданию переменной `read_file` и присваиванию ей значения из `open()`. Плюс, так как текст в файле на кириллице, при загрузке файла имеет смысл указать кодировку (здесь это `Windows-1251`), иначе файл может не открыться или открыться, но с крокозябрами вместо букв.\n", "\n", "Посмотрим на `data`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "data" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "В переменной `data` сохранён список словарей. Можем посмотреть на первый элемент списка:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{'global_id': 4472939,\n", " 'Year': '2012/2013',\n", " 'ShortName': 'ГБОУ лицей «Вторая школа»',\n", " 'OlympiadType': 'Всероссийская олимпиада',\n", " 'Stage': '3',\n", " 'Class': '11',\n", " 'Subject': 'Иностранный язык (английский язык)',\n", " 'Status': 'призёр',\n", " 'FullName': 'Государственное бюджетное общеобразовательное учреждение города Москвы «Лицей «Вторая школа»'}" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "data[0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Если привести данные в таком формате к привычному табличному виду, то получится, что в таблице у нас есть 9 столбцов (с `global_id` по `FullName`), а каждая строка таблицы описывается словарём как в ячейке выше. Данные в таком формате удобно хранить, к ним удобно писать запросы, выбирая значения по ключам в словарях, но иногда логичнее поместить их в таблицу. Для этого нам понадобится библиотека `pandas`:" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "import pandas as pd" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Превратим список словарей `data` в таблицу (датафрейм `pandas`):" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "olymp = pd.DataFrame(data)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Посмотрим на первые несколько строк:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
global_idYearShortNameOlympiadTypeStageClassSubjectStatusFullName
044729392012/2013ГБОУ лицей «Вторая школа»Всероссийская олимпиада311Иностранный язык (английский язык)призёрГосударственное бюджетное общеобразовательное ...
144729402012/2013ГБОУ лицей «Вторая школа»Всероссийская олимпиада311Иностранный язык (английский язык)призёрГосударственное бюджетное общеобразовательное ...
244729412012/2013ГБОУ лицей «Вторая школа»Всероссийская олимпиада310Иностранный язык (английский язык)призёрГосударственное бюджетное общеобразовательное ...
344729422012/2013ГБОУ СОШ № 26Всероссийская олимпиада411Иностранный язык (английский язык)победительГосударственное бюджетное образовательное учре...
444729432012/2013ГБОУ СОШ № 26Всероссийская олимпиада311Иностранный язык (английский язык)призёрГосударственное бюджетное образовательное учре...
\n", "
" ], "text/plain": [ " global_id Year ShortName OlympiadType \\\n", "0 4472939 2012/2013 ГБОУ лицей «Вторая школа» Всероссийская олимпиада \n", "1 4472940 2012/2013 ГБОУ лицей «Вторая школа» Всероссийская олимпиада \n", "2 4472941 2012/2013 ГБОУ лицей «Вторая школа» Всероссийская олимпиада \n", "3 4472942 2012/2013 ГБОУ СОШ № 26 Всероссийская олимпиада \n", "4 4472943 2012/2013 ГБОУ СОШ № 26 Всероссийская олимпиада \n", "\n", " Stage Class Subject Status \\\n", "0 3 11 Иностранный язык (английский язык) призёр \n", "1 3 11 Иностранный язык (английский язык) призёр \n", "2 3 10 Иностранный язык (английский язык) призёр \n", "3 4 11 Иностранный язык (английский язык) победитель \n", "4 3 11 Иностранный язык (английский язык) призёр \n", "\n", " FullName \n", "0 Государственное бюджетное общеобразовательное ... \n", "1 Государственное бюджетное общеобразовательное ... \n", "2 Государственное бюджетное общеобразовательное ... \n", "3 Государственное бюджетное образовательное учре... \n", "4 Государственное бюджетное образовательное учре... " ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "olymp.head() " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Часть 2: группировка и агрегирование\n", "\n", "Все задания выполняются на основе датафрейма `olymp`, полученного в предыдущей части." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 1\n", "\n", "Приведите столбец `Class` к целочисленному типу." ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "RangeIndex: 66122 entries, 0 to 66121\n", "Data columns (total 9 columns):\n", "global_id 66122 non-null int64\n", "Year 66122 non-null object\n", "ShortName 66122 non-null object\n", "OlympiadType 66122 non-null object\n", "Stage 41702 non-null object\n", "Class 66122 non-null int64\n", "Subject 66122 non-null object\n", "Status 66122 non-null object\n", "FullName 66122 non-null object\n", "dtypes: int64(2), object(7)\n", "memory usage: 4.5+ MB\n" ] } ], "source": [ "olymp[\"Class\"] = olymp[\"Class\"].astype(int)\n", "olymp.info() # проверим" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 2\n", "\n", "Выведите уникальные значения в столбце `OlympiadType`. " ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array(['Всероссийская олимпиада', 'Московская олимпиада'], dtype=object)" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "olymp[\"OlympiadType\"].unique()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 3\n", "\n", "Сгруппируйте строки в соответствии со значениями в столбце `OlympiadType` и сохраните в отдельные csv-файл данные по Всероссийской олимпиаде и по Московской олимпиаде. Файлы должны называться `Всероссийская олимпиада.csv` и `Московская олимпиада.csv`." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [], "source": [ "for name, dat in olymp.groupby(\"OlympiadType\"):\n", " dat.to_csv(name + \".csv\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 4\n", "\n", "Выведите таблицу с числом участников олимпиад с группировкой по типу олимпиады и статусу участника. Сохраните полученный результат в переменную `res`." ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
global_idYearShortNameStageClassSubjectFullName
OlympiadTypeStatus
Всероссийская олимпиадапобедитель4581458145814581458145814581
призёр37121371213712137121371213712137121
Московская олимпиадапобедитель4840484048400484048404840
призёр1958019580195800195801958019580
\n", "
" ], "text/plain": [ " global_id Year ShortName Stage Class \\\n", "OlympiadType Status \n", "Всероссийская олимпиада победитель 4581 4581 4581 4581 4581 \n", " призёр 37121 37121 37121 37121 37121 \n", "Московская олимпиада победитель 4840 4840 4840 0 4840 \n", " призёр 19580 19580 19580 0 19580 \n", "\n", " Subject FullName \n", "OlympiadType Status \n", "Всероссийская олимпиада победитель 4581 4581 \n", " призёр 37121 37121 \n", "Московская олимпиада победитель 4840 4840 \n", " призёр 19580 19580 " ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res = olymp.groupby([\"OlympiadType\", \"Status\"]).agg('count')\n", "res" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 5\n", "\n", "a) Используя результат в переменной `res`, выведите на экран число победителей и призеров только Всероссийской олимпиады.\n", "\n", "b) Используя результат в переменной `res`, выведите на экран число победителей и призеров только Московской олимпиады.\n", "\n", "c) Используя результат в переменной `res`, выведите на экран число победителей Всероссийской олимпиады. Это должно быть одно число." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
global_idYearShortNameStageClassSubjectFullName
Status
победитель4581458145814581458145814581
призёр37121371213712137121371213712137121
\n", "
" ], "text/plain": [ " global_id Year ShortName Stage Class Subject FullName\n", "Status \n", "победитель 4581 4581 4581 4581 4581 4581 4581\n", "призёр 37121 37121 37121 37121 37121 37121 37121" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# a\n", "res.xs(\"Всероссийская олимпиада\", level = \"OlympiadType\")" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
global_idYearShortNameStageClassSubjectFullName
Status
победитель4840484048400484048404840
призёр1958019580195800195801958019580
\n", "
" ], "text/plain": [ " global_id Year ShortName Stage Class Subject FullName\n", "Status \n", "победитель 4840 4840 4840 0 4840 4840 4840\n", "призёр 19580 19580 19580 0 19580 19580 19580" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# b\n", "res.xs(\"Московская олимпиада\", level = \"OlympiadType\")" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4581" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# c\n", "res.iloc[0, 1]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 6\n", "\n", "Выведите медианное значение класса для каждого типа олимпиады и статуса участника, используя группировку и метод для агрегирования. Сохраните результат в переменную `res2`. Удалите в `res2` столбец `global_id`, переименуйте столбец `Class` в `Класс (медиана)`." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
global_idClass
OlympiadTypeStatus
Всероссийская олимпиадапобедитель425397348.010.0
призёр425105693.010.0
Московская олимпиадапобедитель425405397.58.0
призёр425404716.58.0
\n", "
" ], "text/plain": [ " global_id Class\n", "OlympiadType Status \n", "Всероссийская олимпиада победитель 425397348.0 10.0\n", " призёр 425105693.0 10.0\n", "Московская олимпиада победитель 425405397.5 8.0\n", " призёр 425404716.5 8.0" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res2 = olymp.groupby([\"OlympiadType\", \n", " \"Status\"]).agg('median')\n", "res2" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Class
OlympiadTypeStatus
Всероссийская олимпиадапобедитель10.0
призёр10.0
Московская олимпиадапобедитель8.0
призёр8.0
\n", "
" ], "text/plain": [ " Class\n", "OlympiadType Status \n", "Всероссийская олимпиада победитель 10.0\n", " призёр 10.0\n", "Московская олимпиада победитель 8.0\n", " призёр 8.0" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# удаляем столбец\n", "\n", "res2.drop(columns=[\"global_id\"], inplace = True)\n", "res2" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
Класс (медиана)
OlympiadTypeStatus
Всероссийская олимпиадапобедитель10.0
призёр10.0
Московская олимпиадапобедитель8.0
призёр8.0
\n", "
" ], "text/plain": [ " Класс (медиана)\n", "OlympiadType Status \n", "Всероссийская олимпиада победитель 10.0\n", " призёр 10.0\n", "Московская олимпиада победитель 8.0\n", " призёр 8.0" ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# переименовываем\n", "res2.rename(columns = {'Class':'Класс (медиана)'}, \n", " inplace = True)\n", "res2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Задание 7\n", "\n", "Получите код HTML для объекта `res2`, используя метод `.to_html()`. Скопируйте полученный код [сюда](https://www.w3schools.com/html/tryit.asp?filename=tryhtml_default), поместив его между тэгами `` и ``, кликните *Run*. Порефлексируйте над полученным результатом – знание устройства html-файлов очень поможет потом при парсинге файлов из интернета." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'\\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n \\n
Класс (медиана)
OlympiadTypeStatus
Всероссийская олимпиадапобедитель10.0
призёр10.0
Московская олимпиадапобедитель8.0
призёр8.0
'" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "res2.to_html()" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.4" } }, "nbformat": 4, "nbformat_minor": 2 }