Файл: Методические указания по выполнению лабораторных работ для студентов, обучающихся с применением.pdf
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 05.12.2023
Просмотров: 136
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
52
import
os
for
dirname, _, filenames
in
os walk(
'/kaggle/input'
):
for
filename
in
filenames:
(os path join(dirname, filename))
# Any results you write to the current directory are saved as output.
import
pandas
as
pd
master
=
pd read_csv(
"../input/suicide-rates-overview-1985-to-2016/master.csv"
)
Печать таблицы на экран покажет нам столбцы (поля), которые содержит таблица, первые и последние строки таблицы.
(master)
В таблице указаны пол и возраст людей, годы, страна, население, количе- ство случаев на 100 тыс. населения, GDP (Gross domestic product – внутренний валовый продукт), HDI (Human Development Index – Индекс развития человече- ского капитала, разработан ООН для оценки качества жизни людей). Кроме то- го, где-то есть пропуски данных Nan.
Попробуем провести какой-либо анализ указанных данных.
(master describe())
Для каждого поля DataFrame описаны различные характеристики, вклю- чая среднее, среднеквадратическое отклонение, максимальное, минимальное значение, квантили. Посмотрев на характеристики поля «Количество случаев на 100 тыс. населения», можно сделать простые выводы о среднем количестве случаев, о максимальном и минимальном. И сразу возникает простой вопрос, каково население страны, если максимальное – 43 млн. Посмотрим, какие стра- ны присутствуют в списке, получив только уникальные названия стран, и поме- стим их в новый список.
(pd unique(master[
'country'
])
tolist())
Хотя здесь явно присутствуют не все страны, сразу возникает сомнение, так как, например, население Японии в 2019 г. составляло порядка 125 млн.
Попробуем уточнить данные, которые имеются по Японии. df
=
master
(df[df[
'country'
]
==
'Japan'
])
53
И действительно, данные содержат отдельные строки по полу и возрас- там. Таким образом, при вызове describe мы получили максимальное количе- ство людей какого-то возраста в какой-то стране, какого-то пола в каком-то году.
Попробуем получить данные по населению стран. Для этого нам понадо- бится осуществить группировку данных по какому-либо полю (по стране и го- ду) и выполнить агрегированную функцию, в данном случае суммы. Таким об- разом, мы получим информацию по случаям в данной стране за данный год, по всем группам населения независимо от пола и возраста. Следует учесть, что тогда поле, которое считалось, как отношение случаев на 100 тыс. населения, будет уже неверным, так как оно соотносилось с количеством людей в опреде- ленной группе.
# получить данные с отсутствием повторения по группированному полю
# Группировка по странам и годам, суммирование
#
поле как индекс
dfcy
=
df groupby([
'country'
,
'year'
],as_index
=
True
)
sum()
(dfcy)
(dfcy describe())
# получить данные с повторениями по группированному полю
#
в стиле SQL
dfcy
=
df groupby([
'country'
,
'year'
],as_index
=
False
)
sum()
(dfcy)
(dfcy describe())
# получить данные по Японии за все годы
(dfcy[dfcy[
'country'
]
==
'Japan'
])
Попробуем построить графики так, чтобы на них отображалась информация по годам о коли- честве населения в каких-либо странах. dfcy
=
df groupby([
'country'
,
'year'
],as_index
=
False
)
sum()
#
выбираем страны из сгруппированной таблицы
dfj
=
dfcy[dfcy[
'country'
]
isin([
'Japan'
,
'Uzbekistan'
,
'Russian Federation'
])]
# устанавливаем в качестве индекса (первичного ключа) страну и год
# чтобы можно было преобразовать таблицу со столбцами
# по Узбекистану и Японии отдельно
dfj
=
dfj set_index([
'country'
,
'year'
])
# печатаем полученную таблицу
54
(dfj)
# преобразуем таблицу так, чтобы были отдельные столбцы по странам
dfun
=
dfj unstack(
'country'
)
# печатаем полученные столбцы
(
list
(dfun))
Вот такие получились у нас имена столбцов. Как видите, они являются словарями.
[(
'suicides_no'
,
'Japan'
), (
'suicides_no'
,
'Uzbekistan'
),
(
'population'
,
'Japan'
), (
'population'
,
'Uzbekistan'
),
(
'suicides/100k pop'
,
'Japan'
), (
'suicides/100k pop'
,
'Uzbekistan'
),
(
'HDI for year'
,
'Japan'
), (
'HDI for year'
,
'Uzbekistan'
),
(
'gdp_per_capita ($)'
,
'Japan'
), (
'gdp_per_capita ($)'
,
'Uzbekistan'
)]
Если изучить таблицу, то обнаружим, что в ней отсутствуют некоторые данные, они обозначены как Nan. Если вы уже изучали базы данных, вам это будет понятно.
Теперь попробуем отобразить полученную таблицу на графике. Очевид- но, если ее отобразить как dfun.plot(), на графике будут присутствовать как данные по населению, так и различные данные по случаям и внутреннему вало- вому продукту двух стран. Нам нужны данные только по населению.
# получаем список имен столбцов таблицы
newdf
=
list
(dfun)
# выбираем только те столбцы, где есть столбец население
newcols
=
[item
for
item
in
newdf
if
item[
0
]
==
'population'
]
# строим новую таблицу из столбцов с населением Узбекистана
# и Японии
dpop
=
dfun[newcols]
# выводим наш график
dpop plot()
Получаем два графика (рис. 1.30).
55
Рис. 1.30 – График случаев по годам для двух стран
Попробуем сделать более сложный анализ, например, коррелируют ли происходящие случаи с каким-либо индексом человеческого развития или внутренним валовым продуктом (приложение А, рис. А.1–А.3).
#
выводим наш график
%
matplotlib inline
import
matplotlib.pyplot
as
plt
# как будут расположены графики на панно, в ячейках 2*2
# размер графиков
fig, axv
=
plt subplots(nrows
=
2
,ncols
=
2
,figsize
=
(
10
,
10
))
# пространство между графиками
plt subplots_adjust(hspace
=
0.5
) plt subplots_adjust(wspace
=
0.5
)
# способ определения соотношения сторон
axv[
0
][
0
]
set_aspect(aspect
=
'auto'
) axv[
1
][
0
]
set_aspect(aspect
=
'equal'
) axv[
1
][
1
]
set_aspect(aspect
=
'equal'
)
# график по населению
dpop plot(ax
=
axv[
0
][
0
])
import
seaborn
as
sns
(
list
(df)) corr
=
df corr() corr1
=
dfcy corr()
# цветовая карта корреляций
sns heatmap(corr,ax
=
axv[
1
][
0
])
56 sns heatmap(corr1,ax
=
axv[
1
][
1
])
# пары соотношений данных по полу и возрастам
sns pairplot(data
=
df,hue
=
'sex'
) sns pairplot(data
=
df,hue
=
'age'
)
По графикам, представленным на рисунках можно сделать вывод, что у мужчин случаев самоубийств на 100 тыс. населения больше, чем у женщин.
Рост ВВП уменьшает количество случаев, но при этом средний уровень разви- тия человеческого капитала приводит к печальным последствиям чаще, а вот низкий или высокий, наоборот. Интересно было бы сравнить с уровнем убийств. Количество суицида среди населения старшего возраста выше, чем у молодых. Начиная с 1980-х гг. население старше 35 лет растет, а с 2005 г. начинает снижаться, оно составляет большую часть населения представленных стран.
Попробуем проанализировать страны по количеству случаев на
100 тыс. населения. Как было сказано выше, использовать непосредственно по- ле, присутствующее в таблице, уже нельзя, мы его агрегировали.
Таким образом, применим два подхода, с использованием seaborn и «в лоб», будем выводить упорядоченные усредненные данные по десяткам лет. Исполь- зуем поле suicides_no, указывающее на количество случаев за год в данной стране, начиная с 1986 до 2016 г. (приложение А, рис. А.4).
%
matplotlib inline
import
matplotlib.pyplot
as
plt
# как будут расположены графики на панно, в ячейках 2*2
# размер графиков
fig, axv
=
plt subplots(nrows
=
3
,ncols
=
1
,figsize
=
(
20
,
20
))
# пространство между графиками
plt subplots_adjust(hspace
=
0.7
) plt subplots_adjust(wspace
=
0.5
)
# способ определения соотношения сторон
axv[
0
]
set_aspect(aspect
=
'auto'
) axv[
1
]
set_aspect(aspect
=
'auto'
) axv[
2
]
set_aspect(aspect
=
'auto'
)
# график по населению
dpop plot(ax
=
axv[
0
])
57
import
seaborn
as
sns
(
list
(df))
#
определяем несколько DataFrame c усреднением по годам
# в десять лет
dfcl
=
[] dfcl append(dfcy[(dfcy[
'year'
]
>=1980
)
&
(dfcy[
'year'
]
<1990
)]) dfcl append(dfcy[(dfcy[
'year'
]
>=1990
)
&
(dfcy[
'year'
]
<2000
)]) dfcl append(dfcy[(dfcy[
'year'
]
>=2000
)
&
(dfcy[
'year'
]
<2010
)]) dfcl append(dfcy[(dfcy[
'year'
]
>=2010
)
&
(dfcy[
'year'
]
<2020
)]) dfall
=
[]
# цикл, в котором создаем группированные по странам выборки
for
i
in
range
(
4
): dfcymean
=
dfcl[i]
groupby(
'country'
,as_index
=
False
)
mean()
# делим количество случаев на население
dfcymean[
'suon1'
]
=
\ dfcymean[
'suicides_no'
]
divide(dfcymean[
'population'
], fill_value
=0.0
)
# умножаем на 100000, чтобы получить количество
# случаев на 100 тыс.
dfcymean[
'suon1'
]
=
dfcymean[
'suon1'
]
*1e+5
# добавляем в список фреймов
dfall append(dfcymean)
#
объединяем фреймы между собой
res
=
pd concat(dfall,keys
=
[
'if1'
,
'if2'
,
'if3'
,
'if4'
])
# поворачиваем таблицу, чтобы условия были в столбцах
resv
=
res unstack(level
=0
)
# сортируем по последнему десятку лет и по количеству
# c
лучаев за год
resv
=
resv sort_values(by
=
[(
'suon1'
,
'if4'
)], ascending
=
False
)
# создаем скаттер графики на которых будут
# отображены случаи по убыванию по странам
ax1
=
sns scatterplot(x
=
(
'country'
,
'if4'
), y
=
(
'suon1'
,
'if4'
), data
=
resv, ax
=
axv[
1
],label
=
"2010-2020"
) sns scatterplot(x
=
(
'country'
,
'if3'
), y
=
(
'suon1'
,
'if3'
), data
=
resv, ax
=
axv[
1
],label
=
"2000-2010"
) sns scatterplot(x
=
(
'country'
,
'if2'
), y
=
(
'suon1'
,
'if2'
), data
=
resv, ax
=
axv[
1
],label
=
"1990-2000"
) sns scatterplot(x
=
(
'country'
,
'if1'
), y
=
(
'suon1'
,
'if1'
),
58 data
=
resv, ax
=
axv[
1
],label
=
"1980-1990"
)
#
вращаем подписи к графику
for
item
in
ax1
get_xticklabels(): item set_rotation(
90
)
# попробуем сделать примерно то же самое парой строчек кода
# сортируем по количеству случаев DataFrame
# c количеством случаев на 100 тыс. населения
res
=
res sort_values(by
=
'suon1'
, ascending
=
False
)
# строим график с отклонениями от среднего
ax2
=
sns lineplot(x
=
'country'
,y
=
'suon1'
, data
=
res, sort
=
False
, ax
=
axv[
2
])
for
item
in
ax2
get_xticklabels(): item set_rotation(
90
)
Например, по указанным на рисунке А.4 графикам можно сделать вывод, что в России ситуация в 1990–2000-е гг. ухудшилась, как и во многих других странах бывшего СССР, а с 2010 г. начала улучшаться.
1.7.3
Изучение возможностей доступа к API сервиса data.gov.ru
Обычно подобные data.gov.ru сервисы предоставляют API доступ и пере- дачу данных приложению клиенту в форматах json, xml, csv, по протоколу
HTTP.
Получить информацию по предоставляемым возможностям можно, например, здесь:
Руководство по порталу data.gov.ru
Зарегистрируйтесь на сайте https://data.gov.ru/
. Мировым аналогом явля- ется, например, https://data.world/
На странице https://data.gov.ru/get-api-key получите ключ API и скопируй- те его в приложение Colab.
Строка запроса для получения данных с учетом полученного токена: https://data.gov.ru/api/json/dataset/?access_token=YOUR_TOKEN_REPLAC
E&search=2019.
Для получения доступа к API воспользуемся компонентом http.client, поз- воляющим выполнять HTTP-запросы и получать ответы.
59
Используем основной тип запроса для получения данных с сервера GET, далее указываем URL и протокол с версией. Затем идут заголовки запроса.
С помощью GET можно и передавать данные на сервер, после URL ста- вится знак ? затем через амперсанд (&) идут поля атрибут = значение.
В ответ возвращается код ответа, 1xx, 2xx, 3xx, 4xx, 5xx, потом заголовки и тело ответа. Коды ответов: 1 – информационные, 2 – успешные, 3 – перена- правление, 4 – ошибки клиента, 5 – ошибки сервера.
Формат заголовков, имя заголовка: значение.
Например:
HTTP/1.1 200 OK
Date: Mon, 27 Jul 2009 12:28:53 GMT
Server: Apache/2.2.14 (Win32)
Last-Modified: Wed, 22 Jul 2009 19:15:56 GMT
Content-Length: 88
Content-Type: text/html
Connection: Closed
<
html
>
<
body
>
<
h1
>Hello, World!
h1
>
body
>
html
>
Наш код.
import
http.client
as
cl
import
ssl
import
json
conn
=
cl
HTTPSConnection(
'data.gov.ru'
, timeout
=5
, context
=
ssl
_create_unverified_context()) conn request(
"GET"
, \
"https://data.gov.ru/api/json/dataset/?access_token=YOUR_TOKEN&search=2019"
) resp
=
conn getresponse()
(resp status, resp reason)
(resp getheaders())
Теперь можно попытаться проанализировать различные датасеты. data
=
resp read()
decode()
# Можно считать и пропарсить возвращенные данные в объект json.
60
#js_data = json.load(resp)
# Но мы скачаем список датасетов в объект panda DataFrame.
dt
=
pandas read_json(data,typ
=
'frame'
)
(dt)
# Выводим первые 1024 байта скачанного датасета.
(data[
0
:
1024
])
Пример полученных датасетов в формате json.
[
{
"identifier"
:
"7017069388-obincstmsopprone"
,
"title"
:
"Объем инвестиций в основной капитал за счет всех источников финансирования
(без субъектов малого предпринимательства и объемов инвестиций, не наблюдаемых прямыми стати- стическими методами) – всего – в сопоставимых ценах (ПРОГНОЗ 1 вариант)"
,
"organization"
:
"7017069388"
,
"organization_name"
:
"
Администрация Томской области"
,
"topic"
:
"Government"
},
{
"identifier"
:
"7017069388-rgortsopprtwo"
,
"title"
:
"Раздел G: Оптовая и розничная торговля; ремонт автотранспортных средств, мото- циклов, бытовых изделий и предметов личного пользования – в сопоставимых ценах (ПРОГНОЗ 2 вариант)"
,
"organization"
:
"7017069388"
,
"organization_name"
:
"
Администрация Томской области"
,
"topic"
:
"Government"
},
Данных довольно много, поэтому сохраним их, а потом будем читать с диска. Используем формат HDF (Hierarchical Data Format – иерархический формат данных). Это формат файлов, созданный для хранения большого объе- ма цифровой информации. Первоначально был разработан Национальным цен- тром суперкомпьютерных приложений, сейчас поддерживается некоммерче- ской организацией HDF Group.
HDF5 – современная версия формата. Содержит иерархию из двух основ- ных типов объектов.
61
Пример структуры HDF Datasets – наборы данных, многомерные массивы объектов одного типа Groups (группы), являются контейнерами для наборов данных и других групп.
Содержимое файлов HDF5 организовано подобно иерархической файло- вой системе, и для доступа к данным применяются пути, сходные с POSIX- синтаксисом, например, /path/to/resource. Метаданные хранятся в виде набора именованных атрибутов объектов. path_file
=
"mntDrive/My Drive/python/dataf/dataset.hdf5"
dt to_hdf(path_file, key
=
'datasets_2019'
, mode
=
'w'
, format
=
'table'
)
Формат table в отличие от fixed позволяет работать с различными функ- циями поиска, использовать смешанные типы, при этом он более медленный.
Для нашего примера с разными типами fixed работать не будет, поэтому мы ис- пользовали table. Можно, кроме того, добавлять в один и тот же файл разные датафреймы (DataFrame).
# Dt_frame.to_hdf(file_name, key='key_name', mode='a',append= True)
В новом cell считаем наш DataFrame в формате hdf.
import
pandas
fname
=
'mntDrive/My Drive/python/dataf/dataset.hdf5'
dt
=
pandas read_hdf(fname, key
=
'datasets_2019'
)
(dt)
Отфильтруем получены данные, найдем информационные источники по студентам. dt_filt
=
dt[dt[
'title'
]
str contains(
r'
студент'
)]
(dt_filt[
'title'
])
(dt_filt[[
'title'
,
'identifier'
]])
Например:
4057
Принято студентов в государственные и муниципа...
7708234640-fourafouratwoasixaeight
Структура запроса данных требует указывать версию датасета, потому получим версию: conn
=
cl
HTTPSConnection(
'data.gov.ru'
, timeout
=5
, context
=
ssl
_create_unverified_context()) conn request(
"GET"
,
62
"https://data.gov.ru/api/json/dataset/7708234640- fourafouratwoasixaeight/version?access_token=
ваш токен"
) resp
=
conn getresponse() data
=
resp read()
decode()
(data[
0
:
2024
])
Версия
[ {
"created"
:
"20180215T172910"
}]
Как указано в руководстве API, можно узнать структуру набора данных.
Структура запроса:
«/api/
Пример запроса:
/api/json/dataset/7710474375- perechenpodved/version/20131219T130000/structure
К сожалению, ресурс оказался довольно-таки сырым, поэтому получаем пустой ответ. Возможно, нам запрещено получение этих данных.
Разберите код, приведенный ниже. Попытайтесь структурировать его, выделив общие функции.
import
http.client
as
cl
import
ssl
import
json
import
pandas
import
pandas
fname
=
'mntDrive/My Drive/python/dataf/dataset.hdf5'
dt
=
pandas read_hdf(fname, key
=
'datasets_2019'
)
#print(dt)
#dt_filt = dt[dt['title'].str.contains(r'
студент')]
#print(dt_filt[['title','identifier']])
conn
=
cl
HTTPSConnection(
'data.gov.ru'
, timeout
=5
, context
=
ssl
_create_unverified_context())
for
i
in
range
(
20
,
100
):
(
"identifier "
,dt[
'identifier'
]
iloc[i])
(
"title "
,dt[
'title'
]
iloc[i])
# задаем запрос на получение идентификатора версии, который будем использовать
# при получении структуры и контента датасета
request
=
"https://data.gov.ru/api/json/dataset/"
request
=
request
+
dt[
'identifier'
]
iloc[i]
+
\