Мэтиз. Изучаем Python. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
Скачать 6.2 Mb.
|
16 Загрузка данных В этой главе мы загрузим наборы данных из сетевого источника и создадим ра- ботоспособные визуализации этих данных. В интернете можно найти невероятно разнообразную информацию, большая часть которой еще не подвергалась осно- вательному анализу. Умение анализировать данные позволит вам выявить связи и закономерности, не найденные никем другим. В этой главе рассматривается работа с данными в двух популярных форматах, CSV и JSON. Модуль Python csv будет применен для обработки погодных данных в формате CSV (с разделением запятыми) и анализа динамики высоких и низких температур в двух разных местах. Затем библиотека Matplotlib будет использована для построения на базе загруженных данных диаграммы колебания температур в двух разных местах: в Ситке (Аляска) и в Долине Смерти (Калифорния). Позд- нее в этой главе модуль json будет использован для обращения к данным числен- ности населения, хранимым в формате JSON, а при помощи модуля Plotly будет построена карта с данными местоположения и магнитуд недавних землетрясений. К концу этой главы вы будете готовы к работе с разными типами и форматами наборов данных и начнете лучше понимать принципы построения сложных визу- ализаций. Возможность загрузки и визуализации сетевых данных разных типов и форматов крайне важна для работы с разнообразными массивами данных в ре- альном мире. Формат CSV Один из простейших вариантов хранения — запись данных в текстовый файл как серий значений, разделенных запятыми; такой формат хранения получил назва- ние CSV (от Comma Separated Values, то есть «значения, разделенные запятыми»). Например, одна строка погодных данных в формате CSV может выглядеть так: "USW00025333","SITKA AIRPORT, AK US","2018-01-01","0.45",,"48","38" Это погодные данные за 1 января 2018 г. в Ситке (Аляска). В данных указаны максимальная и минимальная температура, а также ряд других показателей за этот день. У человека могут возникнуть проблемы с чтением данных CSV, но этот 348 Глава 16 • Загрузка данных формат хорошо подходит для программной обработки и извлечения значений, а это ускоряет процесс анализа. Начнем с небольшого набора погодных данных в формате CSV, записанного в Ситке; файл с данными можно загрузить по адресу https://www .nostarch .com/ pythoncrashcourse2e/ . Создайте подкаталог с именем data в каталоге, в котором со- храняются программы этой главы. Скопируйте в созданный каталог файл sitka_ weather_07-2018_simple .csv . (После загрузки ресурсов книги в вашем распоряжении появятся все необходимые файлы для этого проекта.) ПРИМЕЧАНИЕ Погодные данные для этого проекта были загружены с сайта https:// ncdc .noaa .gov/cdo-web/ Разбор заголовка файлов CSV Модуль Python csv из стандартной библиотеки разбирает строки файла CSV и позволяет быстро извлечь нужные значения. Начнем с первой строки файла, которая содержит серию заголовков данных. Заголовки описывают информацию, хранящуюся в данных: sitka_highs.py import csv filename = 'data/sitka_weather_07-2018_simple.csv' ❶ with open(filename) as f: ❷ reader = csv.reader(f) ❸ header_row = next(reader) print(header_row) После импортирования модуля csv имя обрабатываемого файла сохраняется в переменной filename . Затем файл открывается, а полученный объект сохраняется в переменной f . Далее программа вызывает метод csv.reader() и передает ему объект файла в аргументе, чтобы создать объект чтения данных для этого файла . Объект чтения данных сохраняется в переменной reader Модуль csv содержит функцию next() , которая возвращает следующую строку файла для полученного объекта чтения данных. В следующем листинге функция next() вызывается только один раз для получения первой строки файла, содержа- щей заголовки . Возвращенные данные сохраняются в header_row . Как видите, header_row содержит осмысленные имена заголовков, которые сообщают, какая информация содержится в каждой строке данных: ['STATION', 'NAME', 'DATE', 'PRCP', 'TAVG', 'TMAX', 'TMIN'] Объект reader обрабатывает первую строку значений, разделенных запятыми, и со- храняет все значения из строки в списке. Заголовок STATION представляет код метео- рологической станции, зарегистрировавшей данные. Позиция заголовка указывает на то, что первым значением в каждой из следующих строк является код метеостанции. Формат CSV 349 Остальные заголовки сообщают, какая информация хранится в соответствующем поле. В данном примере нас интересуют значения даты, высокой температуры ( TMAX ) и низкой температуры ( TMIN ). Мы используем простой набор данных, содержащий информацию только об уровне осадков и температуре. Вы также можете загрузить собственный набор погодных данных и включить в обработку другие показатели: скорость и направление ветра, расширенные данные осадков и т. д. Печать заголовков и их позиций Чтобы читателю было проще понять структуру данных в файле, выведем каждый заголовок и его позицию в списке: sitka_highs.py with open(filename) as f: reader = csv.reader(f) header_row = next(reader) ❶ for index, column_header in enumerate(header_row): print(index, column_header) Функция enumerate() возвращает индекс каждого элемента и его значение при переборе списка . (Обратите внимание: строка print(header_row) удалена ради этой, более подробной версии.) Результат с индексами всех заголовков выглядит так: 0 STATION 1 NAME 2 DATE 3 PRCP 4 TAVG 5 TMAX 6 TMIN Из этих данных видно, что даты и максимальные температуры за эти дни находятся в столбцах 2 и 5. Чтобы проанализировать температурные данные, мы обработаем каждую запись данных в файле sitka_weather_07-2018_simple .csv и извлечем элемен- ты с индексами 2 и 5. Извлечение и чтение данных Итак, нужные столбцы данных известны; попробуем прочитать часть этих данных. Начнем с чтения максимальной температуры за каждый день: sitka_highs.py with open(filename) as f: 350 Глава 16 • Загрузка данных reader = csv.reader(f) header_row = next(reader) # Чтение максимальных температур ❶ highs = [] ❷ for row in reader: ❸ high = int(row[5]) highs.append(high) print(highs) Программа создает пустой список с именем highs и перебирает остальные стро- ки в файле . Объект reader продолжает с того места, на котором он остановился в ходе чтения файла CSV, и автоматически возвращает каждую строку после те- кущей позиции. Так как заголовок уже прочитан, цикл продолжается со второй строки, в которой начинаются фактические данные. При каждом проходе цикла значение с индексом 5 (заголовок TMAX ) присваивается переменной high . Функ- ция int() преобразует данные, хранящиеся в строковом виде, в числовой формат для последующего использования. Значение присоединяется к списку highs В результате будет получен список highs со следующим содержимым: [62, 58, 70, 70, 67, 59, 58, 62, 66, 59, 56, 63, 65, 58, 56, 59, 64, 60, 60, 61, 65, 65, 63, 59, 64, 65, 68, 66, 64, 67, 65] Мы извлекли максимальную температуру для каждого дня и аккуратно сохранили полученные данные в строковом формате в списке. Следующим шагом станет по- строение визуализации этих данных. Нанесение данных на диаграмму Для наглядного представления температурных данных мы сначала создадим про- стую диаграмму дневных максимумов температуры с использованием Matplotlib: sitka_highs.py import csv from matplotlib import pyplot as plt filename = 'data/sitka_weather_07-2018_simple.csv' with open(filename) as f: # Нанесение данных на диаграмму. plt.style.use('seaborn') fig, ax = plt.subplots() ❶ ax.plot(highs, c='red') # Форматирование диаграммы. ❷ plt.title("Daily high temperatures, July 2018", fontsize=24) ❸ plt.xlabel('', fontsize=16) Формат CSV 351 plt.ylabel("Temperature (F)", fontsize=16) plt.tick_params(axis='both', which='major', labelsize=16) plt.show() Мы передаем при вызове plot() список highs и аргумент c='red' для отобра- жения точек красным цветом. (Максимумы будут выводиться красным цветом, а минимумы синим.) Затем указываются другие аспекты форматирования (напри- мер, размер шрифта и метки) , уже знакомые вам по главе 15. Так как даты еще не добавлены, метки для оси x не задаются, но вызов plt.xlabel() изменяет раз- мер шрифта, чтобы метки по умолчанию лучше читались . На рис. 16.1 показана полученная диаграмма: это простой график температурных максимумов за июль 2018 г. в Ситке (штат Аляска). Рис. 16.1. График ежедневных температурных максимумов в июле 2018 г . в Ситке (штат Аляска) Модуль datetime Теперь нанесем даты на график, чтобы с ним было удобнее работать. Первая дата из файла погодных данных хранится во второй строке файла: "USW00025333","SITKA AIRPORT, AK US","2018-07-01","0.25",,"62","50" Данные будут читаться в строковом формате, поэтому нам понадобится способ преобразовать строку '2018-07-1' в объект, представляющий эту дату. Чтобы построить объект, соответствующий 1 июля 2018 г., мы воспользуемся методом strptime() из модуля datetime . Посмотрим, как работает strptime() в терми- нальном окне: 352 Глава 16 • Загрузка данных >>> from datetime import datetime >>> first_date = datetime.strptime('2018-07-01', '%Y-%m-%d') >>> print(first_date) 2018-07-01 00:00:00 Сначала необходимо импортировать класс datetime из модуля datetime . Затем вызывается метод strptime() , первый аргумент которого содержит строку с датой. Второй аргумент сообщает Python, как отформатирована дата. В данном примере значение '%Y-' сообщает Python, что часть строки, предшествующая первому дефису, должна интерпретироваться как год из четырех цифр; '%m-' приказывает Python интерпретировать часть строки перед вторым дефисом как число, представ- ляющее месяц; наконец, '%d' приказывает Python интерпретировать последнюю часть строки как день месяца от 1 до 31. Метод strptime() может получать различные аргументы, которые описывают, как должна интерпретироваться запись даты. В табл. 16.1 перечислены некоторые из таких аргументов. Таблица 16.1. Аргументы форматирования даты и времени из модуля datetime Аргумент Описание %A Название дня недели (например, Monday) %B Название месяца (например, January) %m Порядковый номер месяца (от 01 до 12) %d День месяца (от 01 до 31) %Y Год из четырех цифр (например, 2019) %y Две последние цифры года (например, 19) %H Часы в 24-часовом формате (от 00 до 23) %I Часы в 12-часовом формате (от 01 до 12) %p AM или PM %M Минуты (от 00 до 59) %S Секунды (от 00 до 61) Представление дат на диаграмме Научившись обрабатывать данные в файлах CSV, вы сможете улучшить диаграмму температурных данных. Для этого мы извлечем из файла даты ежедневных макси- мумов и передадим даты и максимумы функции plot() : sitka_highs.py import csv from datetime import datetime from matplotlib import pyplot as plt filename = 'data/sitka_weather_07-2018_simple.csv' with open(filename) as f: Формат CSV 353 reader = csv.reader(f) header_row = next(reader) # Чтение дат и максимальных температур из файла. ❶ dates, highs = [], [] for row in reader: ❷ current_date = datetime.strptime(row[2], "%Y-%m-%d") high = int(row[5]) dates.append(current_date) highs.append(high) # Нанесение данных на диаграмму. plt.style.use('seaborn') fig, ax = plt.subplots() ❸ ax.plot(dates, highs, c='red') # Форматирование диаграммы. plt.title("Daily high temperatures, July 2018", fontsize=24) plt.xlabel('', fontsize=16) ❹ fig.autofmt_xdate() plt.ylabel("Temperature (F)", fontsize=16) plt.tick_params(axis='both', which='major', labelsize=16) plt.show() Мы создаем два пустых списка для хранения дат и температурных максимумов из файла . Затем программа преобразует данные, содержащие информацию даты ( row[2] ), в объект datetime , который присоединяется к dates . Значения дат и температурных максимумов передаются plot() в точке . Вызов fig.autofmt_ xdate() в точке выводит метки дат по диагонали, чтобы они не перекрывались. На рис. 16.2 изображена новая версия графика. Рис. 16.2. График с датами на оси x стал более понятным 354 Глава 16 • Загрузка данных Расширение временного диапазона Итак, график успешно создан. Добавим на него новые данные для получения более полной картины погоды в Ситке. Скопируйте файл sitka_weather_2018_simple .csv , содержащий погодные данные для Ситки за целый год, в каталог с программами этой главы. А теперь мы можем сгенерировать график с погодными данными за год: sitka_highs.py ❶ filename = 'data/sitka_weather_2018_simple.csv' with open(filename) as f: # Форматирование диаграммы. ❷ plt.title("Daily high temperatures - 2018", fontsize=24) plt.xlabel('', fontsize=16) Значение filename было изменено, чтобы в программе использовался новый файл данных sitka_weather_2018_simple .csv , а заголовок диаграммы приведен в соот- ветствие с содержимым . На рис. 16.3 изображена полученная диаграмма. Рис. 16.3. Данные за год Нанесение на диаграмму второй серии данных Обновленный график на рис. 16.3 содержит немало полезной информации, но график можно сделать еще полезнее, добавив на него данные температурных ми- нимумов. Для этого необходимо прочитать температурные минимумы из файла данных и нанести их на график: Формат CSV 355 sitka_highs_lows.py filename = 'sitka_weather_2018_simple.csv' with open(filename) as f: reader = csv.reader(f) header_row = next(reader) # Получение дат, температурных минимумов и максимумов из файла. ❶ dates, highs, lows = [], [], [] for row in reader: current_date = datetime.strptime(row[2], "%Y-%m-%d") high = int(row[5]) ❷ low = int(row[6]) dates.append(current_date) highs.append(high) lows.append(low) # Нанесение данных на диаграмму. plt.style.use('seaborn') fig, ax = plt.subplots() ax.plot(dates, highs, c='red') ❸ plt.plot(dates, lows, c='blue') # Форматирование диаграммы. ❹ plt.title("Daily high and low temperatures - 2018", fontsize=24) В точке создается пустой список lows для хранения температурных минимумов, после чего программа извлекает и сохраняет температурный минимум для каждой даты из седьмой позиции каждой строки данных ( row[6]) . В точке добавляется вызов plot() для температурных минимумов, которые окрашиваются в синий цвет. Затем остается лишь обновить заголовок диаграммы . На рис. 16.4 изображена полученная диаграмма. Рис. 16.4. Две серии данных на одной диаграмме 356 Глава 16 • Загрузка данных Цветовое выделение части диаграммы После добавления двух серий данных можно переходить к анализу диапазона температур по дням. Пора сделать последний штрих в оформлении диаграммы: затушевать диапазон между минимальной и максимальной дневной температурой. Для этого мы воспользуемся методом fill_between() , который получает серию значений x и две серии значений y и заполняет область между двумя значениями y : sitka_highs_lows.py # Нанесение данных на диаграмму. plt.style.use('seaborn') fig, ax = plt.subplots() ❶ ax.plot(dates, highs, c='red', alpha=0.5) ax.plot(dates, lows, c='blue', alpha=0.5) ❷ plt.fill_between(dates, highs, lows, facecolor='blue', alpha=0.1) Аргумент alpha определяет степень прозрачности вывода. Значение 0 означает полную прозрачность, а 1 (по умолчанию) — полную непрозрачность. Со значением alpha=0.5 красные и синие линии на графике становятся более светлыми. В точке fill_between() передается список dates для значений x и две серии значений y highs и lows . Аргумент facecolor определяет цвет закрашиваемой об- ласти; мы назначаем ему низкое значение alpha=0.1 , чтобы заполненная область соединяла две серии данных, не отвлекая зрителя от передаваемой информации. На рис. 16.5 показана диаграмма с закрашенной областью между highs и lows Рис. 16.5. Область между двумя наборами данных закрашена Формат CSV 357 Закрашенная область подчеркивает величину расхождения между двумя наборами данных. Проверка ошибок Программа sitka_highs_lows .py должна нормально работать для погодных данных любого места. Однако некоторые метеорологические станции собирают данные по особым правилам, а на других станциях их не удается собрать из-за сбоев (полно- стью или частично). Отсутствие данных может привести к исключениям; если исключения не будут обработаны, то программа аварийно завершится. Для примера попробуем построить график температур для Долины Смерти (штат Калифорния). Скопируйте файл death_valley_2018_simple .csv в каталог с програм- мами этой главы. Затем выполните следующий код, чтобы просмотреть состав заголовков из файла данных: death_valley_highs_lows.py import csv filename = 'data/death_valley_2018_simple.csv' with open(filename) as f: reader = csv.reader(f) header_row = next(reader) for index, column_header in enumerate(header_row): print(index, column_header) Результат выглядит так: 0 STATION 1 NAME 2 DATE 3 PRCP 4 TMAX 5 TMIN 6 TOBS Дата находится в той же позиции с индексом 2. Но температурные максимумы и минимумы находятся в позициях с индексами 4 и 5, поэтому нам придется из- менить индексы в программе в соответствии с новыми позициями. Вместо того чтобы включать средние показания температуры за день, эта станция регистрирует TOBS — денные за конкретное время наблюдений. Я удалил одно из показаний температуры из файла, чтобы продемонстрировать, что происходит при отсутствии данных в файле. Внесите изменения в sitka_highs_lows . py , чтобы построить график температур для Долины Смерти по только что опре- деленным индексам, и проследите за происходящим: |