На Python можно работать с данными и визуализировать их. Пользуются этим не только программисты, но и ученые: биологи, физики, социологи. Сегодня мы вместе с shwars, куратором нашего курса Python jumpstart for AI, ненадолго превратимся в метеорологов и изучим климат городов России. Из библиотек для визуализации и работы с данными используем Pandas, Matplotlib и Bokeh.
Сами исследования мы проводим в Azure Notebooks — облачной версии Jupyther Notebook. Таким образом для начала работы с Python нам не потребуется ничего устанавливать себе на компьютер и работать можно будет прямо из браузера. Необходимо лишь осуществить вход со своим Microsoft Account, создать библиотеку и в ней — новый ноутбук Python 3. После чего можно брать фрагменты кода из этой статьи и экспериментировать!
Получаем данные
В первую очередь импортируем основные библиотеки, которые нам понадобятся. Pandas — это библиотека для работы с табличными данными, или так называемыми фреймами данных, а pyplot позволит нам строить графики.
import pandas as pd
import matplotlib.pyplot as plt
Исходные данные легко найти в интернете, но мы уже подготовили для вас данные в удобном формате CSV. CSV — это текстовый формат, в котором все столбцы разделены запятыми. Отсюда и название — Comma Separated Values.
Pandas умеет сам открывать CSV-файлы как с локального диска, так и сразу из интернета. Сами данные лежат в нашем репозитории на GitHub, поэтому нам достаточно просто указать правильный URL.
data = pd.read_csv("https://raw.githubusercontent.com/shwars/PythonJump/master/Data/climat_russia_cities.csv")
data
Переименуем столбцы таблицы, чтобы к ним удобнее было обращаться по имени. Также нам необходимо преобразовать строки в численные значения, чтобы оперировать ими. Когда мы попробуем это сделать с помощью функции pd.to_numeric
, то обнаружим, что возникает странная ошибка. Это связано с тем, что вместо минуса в тексте используется знак длинного тире.
data.columns=["City","Lat","Long","TempMin","TempColdest","AvgAnnual","TempWarmest","AbsMax","Precipitation"]
data["TempMin"] = pd.to_numeric(data["TempMin"])
---------------------------------------------------------------------------
ValueError Traceback (most recent call last)
pandas/_libs/src/inference.pyx in pandas._libs.lib.maybe_convert_numeric()
ValueError: Unable to parse string "−38.0"
...
...
...
ValueError: Unable to parse string "−38.0" at position 0
Из этой проблемы следует важная мораль: данные обычно приходят в «грязном» виде, неудобном для использования, и задача data scientist’а в том, чтобы эти данные привести к хорошему виду.
Можно видеть, что некоторые столбцы нашей таблицы имеют тип object
, а не числовой тип float64
. В таких столбцах произведем замену тире на минус и затем преобразуем всю таблицу в числовой формат. Столбцы, которые не могут быть преобразованы (названия городов) останутся в неизменном виде (для этого мы использовали ключ errors=’ignore’
).
print(data.dtypes)
for x in ["TempMin","TempColdest","AvgAnnual"]:
data[x] = data[x].str.replace('−','-')
data = data.apply(pd.to_numeric,errors='ignore')
print(data.dtypes)
City object
Lat float64
Long float64
TempMin object
TempColdest object
AvgAnnual object
TempWarmest float64
AbsMax float64
Precipitation int64
dtype: object
City object
Lat float64
Long float64
TempMin float64
TempColdest float64
AvgAnnual float64
TempWarmest float64
AbsMax float64
Precipitation int64
dtype: object
Исследуем данные
Теперь, когда мы получили чистые данные, можно попробовать построить интересные графики.
Среднегодовая температура
Например, посмотрим, как зависит средняя температура от широты.
ax = data.plot(x="Lat",y="AvgAnnual",kind="Scatter")
ax.set_xlabel("Широта")
ax.set_ylabel("Среднегодовая температура")
Из графика видно, что чем ближе к экватору — тем теплее.
Города-рекордсмены
Теперь взглянем на города, которые являются температурными рекордсменами, и посмотрим, есть ли корреляция между минимальной и максимальной температурой в городе.
ax=data.plot(x="TempMin",y="AbsMax",kind="scatter")
ax.set_xlabel("Рекорд отрицательной температуры")
ax.set_ylabel("Рекорд положительной температуры")
ax.invert_xaxis()
Как можно видеть, в этом случае такой корреляции нет. Есть города как с резко континентальным климатом, так и просто теплые и холодные города. Найдем города с максимальным температурным разбросом, то есть как раз города с резко континентальным климатом.
data['spread'] = data['TempWarmest'] - data['TempColdest']
data.nlargest(3,'spread')
В этот раз мы брали не рекордные показатели, а средние самого теплого и самого холодного месяца. Как и ожидалось, самый большой разброс у городов из Республики Саха (Якутия).
Зимой и летом
Для дальнейшего исследования рассмотрим города в радиусе 300 км от Москвы. Для вычисления расстояния между точками по широте и долготе используем библиотеку geopy, которую предварительно необходимо установить при помощи помощи pip install
.
!pip install geopy
import geopy.distance
Добавим к таблице еще один столбец — расстояние до Москвы.
msk_coords = tuple(data.loc[data["City"]=="Москва"][["Lat","Long"]].iloc[0])
data["DistMsk"] = data.apply(lambda row : geopy.distance.distance(msk_coords,(row["Lat"],row["Long"])).km,axis=1)
data.head()
Используем выражение, чтобы отобрать только интересующие нас строки.
msk = data.loc[data['DistMsk']<300]
msk
Для этих городов построим график минимальной, среднегодовой и максимальной температур.
ax=msk.plot(x="City",y=["TempColdest","AvgAnnual","TempWarmest"],kind="bar",stacked="true")
ax.legend(["Мин","Сред","Макс"],loc='lower right')
В целом в пределах 300 километров вокруг Москвы никаких аномалий не наблюдается. Иваново находится севернее остальных городов, поэтому и температуры там на несколько градусов ниже.
Работа с гео-данными
Теперь попробуем отобразить на карте среднегодовое количество осадков с привязкой к городам и посмотреть, как зависят осадки от географического расположения. Для этого используем другую библиотеку визуализации — Bokeh. Ее также необходимо установить.
Затем вычисляем еще один столбец — размер кружочка, который будет показывать количество осадков. Коэффициент подбираем опытным путем.
!pip install bokeh
from bokeh.io import output_file, output_notebook, show
from bokeh.models import (
GMapPlot, GMapOptions, ColumnDataSource, Circle, LogColorMapper, BasicTicker, ColorBar,
DataRange1d, PanTool, WheelZoomTool, BoxSelectTool, HoverTool
)
from bokeh.models.mappers import ColorMapper, LinearColorMapper
from bokeh.palettes import Viridis5
from bokeh.plotting import gmap
Для работы с картой потребуется ключ Google Maps API. Его необходимо самостоятельно получить на сайте.
Более подробные инструкции по использованию Bokeh для построения графиков на картах можно найти тут и тут.
google_key = "<INSERT YOUR KEY HERE>"
data["PrecipSize"] = data["Precipitation"] / 50.0
map_options = GMapOptions(lat=msk_coords[0], lng=msk_coords[1], map_type="roadmap", zoom=4)
plot = gmap(google_key,map_options=map_options)
plot.title.text = "Уровень осадков в городах России"
source = ColumnDataSource(data=data)
my_hover = HoverTool()
my_hover.tooltips = [('Город', '@City'),('Осадки','@Precipitation')]
plot.circle(x="Long", y="Lat", size="PrecipSize", fill_color="blue", fill_alpha=0.8, source=source)
plot.add_tools(PanTool(), WheelZoomTool(), BoxSelectTool(), my_hover)
output_notebook()
show(plot)
Как можно заметить, наибольшее количество осадков выпадает в приморских городах. Хотя есть достаточно большое количество таких городов, где уровень осадков среднее или даже ниже общероссийского.
Весь код с комментариями, написанный Дмитрием Сошниковым, вы можете самостоятельно посмотреть и запустить здесь.
Итоги
Мы показали возможности языка без использования сложных алгоритмов, специфических библиотек или написания сотни строк кода. Однако даже вооружившись стандартными инструментами можно проанализировать свои данные и сделать какие-то выводы.
Датасеты далеко не всегда бывают идеально составлены, поэтому прежде чем начать работать с визуализацией необходимо привести их в порядок. Качество визуализации будет во многом зависеть от качества используемых данных.
Всевозможных типов диаграмм и графиков огромное количество, и необязательно ограничиваться одними только стандартными библиотеками.
Существует Geoplotlib, Plotly, минималистичный Leather и другие.
Если вы хотите узнать о работе с данными в Python больше, а также познакомиться с искусственным интеллектом, то приглашаем вас на однодневный интенсив от Binary District — Python jumpstart for AI.
Автор: dzakhour