
Как превратить Jupyter Notebook в рабочий процесс по обработке данных
1. Введение
Jupyter Notebook — это «золотой стандарт» в разведочном анализе данных (EDA-анализ) и отличный инструмент для документирования data science проектов. В основном аналитики работают в блокнотах итерационно, а не идут сверху вниз по ячейкам. Несмотря на это, в Jupyter Notebook можно воспроизвести пошаговый анализ данных, запуская ячейки с первой по последнюю.
Единственная проблема Jupyter Notebook при выполнении повторяющихся задач и ETL‑операций, — это скудная автоматизация и отсутствие функций логирования. То есть вам нужно каждый раз открывать нужный блокнот и запускать его вручную. Кроме того, в процессе выполнения ячейки вы не можете отслеживать возможные ошибки и исключения.
1.1. Знакомство с Papermill
Papermill — это инструмент для параметризации и запуска блокнотов. Он превращает Jupyter Notebook в своего рода рабочий процесс, способный последовательно выполнять каждую ячейку без открытия JupyterLab (или Notebook). Пробелы по части логирования и автоматизации Papermill с лихвой восполняет запуском блокнотов в виде файлов и созданием отчетов для каждого выполнения.
ЦЕЛЬЮ данной статьи является интеграция Papermill и Jupyter Notebook для создания рабочего процесса обработки данных. Для наглядности мы создадим Python Notebook. В этом блокноте мы проведем простой анализ данных по метеопрогнозу через API (PyOWM), выполним первичную обработку данных, создадим несколько визуализаций и сформируем итоговый отчет.
Jupyter Notebook и другие необходимые файлы можно найти в репозитории проекта на GitHub. Если вы хотите повторить все сами, то установите библиотеки из papermill_env.yaml.
2. Настройка среды разработки
2.1. Установка Papermill и JupyterLab
Для начала создадим среду разработки в Conda (1, 2) и установим JupyterLab со всеми нужными библиотеками (3).
# 1) Создадим conda среду conda create -n papermill python=3.7 # 2) Активируем ее conda activate papermill # 3) Установим библиотеки через pip (или conda) pip install papermill pyowm jupyterlab pandas seaborn boto3 pdfkit После установки Papermill мы видим подробную информацию в терминале (4). # 4) Документация по Papermill papermill -h Использование: papermill [OPTIONS] NOTEBOOK_PATH OUTPUT_PATH. Эта утилита выполняет по одному блокноту в подпроцессе. Papermill берет исходный блокнот, применяет к нему параметры, выполняет (4) блокнот с указанным ядром и сохраняет результат в конечном блокноте. NOTEBOOK_PATH и OUTPUT_PATH теперь можно заменить на `-` (представление stdout и stderr) или input/output между вертикальными слешами. То есть `<generate input>... | papermill | ...<process output>` с `papermill - -`, заключенной в вертикальные слеши, прочитает блокнот из stdin и запишет его в stdout. Опции: -p, --parameters TEXT... — Параметры для передачи в ячейку параметров. -r, --parameters_raw TEXT... — Параметры для чтения в виде неотформатированной строки. -f, --parameters_file TEXT — Путь к YAML-файлу с параметрами -y, --parameters_yaml TEXT — YAML-строка для использования в качестве параметров. -b, --parameters_base64 TEXT — YAML-строка в кодировке Base64 для использования в качестве параметров. --inject-input-path — Добавляет путь к входному блокноту PAPERMILL_INPUT_PATH в качестве параметра блокнота. --inject-output-path — Добавляет путь к блокноту вывода PAPERMILL_OUTPUT_PATH в качестве параметра блокнота. --inject-paths — Добавляет пути к входному/выходному блокноту PAPERMILL_INPUT_PATH/PAPERMILL_OUTPUT_PATH в качестве параметров блокнота --engine TEXT — Название механизма выполнения, используемого при анализе блокнота. --request-save-on-cell-execute / --no-request-save-on-cell-execute — Запрос на сохранение блокнота после выполнения каждой ячейки --prepare-only / --prepare-execute — Флажок для вывода блокнота без выполнения, но с применением параметров -k, --kernel TEXT — Название ядра для запуска --cwd TEXT — Рабочая директория для запуска блокнота --progress-bar / --no-progress-bar — Флажок для включения индикатора выполнения --log-output / --no-log-output — Флажок для записи результата блокнота в настроенный журнал --stdout-file FILENAME — Файл для записи результата stdout --stderr-file FILENAME — Файл для записи результата stderr --log-level [NOTSET|DEBUG|INFO|WARNING|ERROR|CRITICAL] — Установка уровня записи --start_timeout INTEGER — Время (сек.) ожидания запуска ядра --report-mode / --no-report-mode — Флажок для скрытия входных данных. --version — Флажок для отображения версии -h, --help — Показать это сообщение и выйти
Судя по документации, в основных функциях Papermill ничего сложного нет. Мы просто указываем путь к нужному Jupyter Notebook и задаем имя для блокнота вывода (он выполняет функцию журнала). К ряду других полезных опций мы вернемся позже.
2.2. Установка Jupyter Kernel
Несмотря на то, что Jupyter Notebook чаще всего ассоциируется с запуском на Python, он работает практически под любым языком программирования при установке нужного ядра. Papermill в сочетании с подходящим ядром позволяет запускать блокноты в различных средах, избегая проблем с отсутствующими библиотеками (5).
# 5) Установка ядра Jupyter для среды Papermill pip install ipykernelipython kernel install --user --name=papermill-tutorial
3. Создание рабочего процесса
Мы воспользуемся Jupyter Notebook для анализа метеорологических данных. Суть вот в чем: мы извлечем данные по определенному городу через PyOWM (Python API), выполним первичную обработку данных, создадим графики и представим структурированную информацию в PDF-отчете.
3.1. Работа с метеорологическим PyOWM API
Как говорится на главной странице библиотеки, PyOWM — это клиентская обертка Python-библиотеки для Web API OpenWeatherMap. Она упрощает доступ к метеорологическим данным, предлагая «простую объектную модель». Единственное требование к использованию данной библиотеки — API-ключ, который можно бесплатно получить на OpenWeather.
3.2. Рабочий процесс. Часть 1: получение метеоданных через PyOWM API
В первой части рабочего процесса мы используем библиотеку PyOWM для получения информации об уже заданном городе city (в исходном блокноте — это Сан-Паулу, Бразилия). Мы перебираем объект forecast и структурируем возвращаемую информацию в DataFrame, чем существенно облегчаем себе жизнь в дальнейшем.
1. Доступ к pyown API
На первом этапе анализа мы получаем метеоданные по выбранному городу через pyown API.
Эта информация структурируется в словаре, а затем загружается в виде DataFrame Pandas для выполнения первичной обработки.
[1] #импорт библиотек
import pyowm import pandas as pd import seaborn as sns import matplotlib.pyplot as plt import pdfkit
1.1. Установка API-ключа PyOWM и определение переменных
Здесь мы определяем API-ключ для доступа к сервису OpenWeather, а также ячейку с параметром city , которая прописывается в Papermill.
In [2] # Установка API-ключа:
owm = pyowm.OWM('xxxxxxxxxxxPyOWM-API-keyxxxxxxxx')
In [3] # Определение параметров по умолчанию:
city = ‘Sao Paulo,BR’
1.2. Получение метеоданных по определенному городу
На данном этапе мы используем PyOWM для получения данных о городе и структурирования их сначала в словаре, а затем в DataFrame.
In [4] # Инстанцирование объекта forecast и получение метеоданных о городе:
fc = owm.three_hours_forecast(city) forecast = fc.get_forecast()
In [5] # Создание словаря для структурирования метеоданных по выбранному городу:
dict_forecast = { ‘datetime’:[], ‘clouds’:[], ‘humidity’:[], ‘temp’:[], ‘temp_max’:[], ‘temp_min’:[], ‘detailed_status’:[], ‘icon_url’:[], ‘rain_vol’:[] }
In [6] # Перебор объекта forecast для доступа к метеорологическим характеристикам (опциям):
for weather in forecast: dict_forecast['datetime'].append(str(weather.get_reference_time(timeformat='iso'))) dict_forecast['clouds'].append(weather.get_clouds()) dict_forecast['humidity'].append(weather.get_humidity()) dict_forecast['temp'].append(weather.get_temperature(unit='celsius').get('temp')) dict_forecast['temp_max'].append(weather.get_temperature(unit='celsius').get('temp_max')) dict_forecast['temp_min'].append(weather.get_temperature(unit='celsius').get('temp_min')) dict_forecast['detailed_status'].append(weather.get_detailed_status()) dict_forecast['icon_url'].append(weather.get_weather_icon_url()) if '3h' in weather.get_rain().keys(): dict_forecast['rain_vol'].append(weather.get_rain().get('3h')) else: dict_forecast['rain_vol'].append(0)
In [7] # Создание Dataframe из словаря:
df = pd.DataFrame.from_dict(dict_forecast) df.head()
Out [7]

3.3. Рабочий процесс. Часть 2: получение метеоданных через PyOWM API
Во второй части рабочего процесса мы объединяем данные по дням, а затем визуализируем информацию на двух графиках. Первый график показывает температурные данные, а второй — осадки, облачность и влажность.
2. Создание визуализации
На этом этапе мы будем создавать графики из структурированных данных через seaborn.
2.1. Температурный график
График показывает метеопрогноз с максимальной, минимальной и средней температурой на ближайшие 5 дней.
In [14] # Создание графика температур на ближайшие 5 дней
fig = plt.figure() sns_plot = sns.lineplot(data=df_temp, style="event",markers=True, dashes=False) sns_plot.set_title(f'Temperature forecast for the next 5 days', fontsize=20) sns_plot.set_xlabel('Date', fontsize=14) sns_plot.set_ylabel('Temperature Celsius', fontsize=14) sns_plot.set_xticklabels(df_temp.index, rotation=20) sns_plot.grid(True) sns_plot.legend(labels=['Min. Temperature', 'Max Temperature', 'Average Temperature']) fig.set_size_inches(12, 6) temperature_plot = f"{city.split(',')[0].replace(' ','_')}_temperature.png" sns_plot.figure.savefig(temperature_plot, dpi=300, facecolor='w',
Out [14]

2.2. График влажности, осадков и облачности
В этом графике мы объединяем данные об осадках и влажности.
In [15] # Создание Dataframe с ожидаемым объемом осадков по дням:
df_rain_per_day = df.resample(‘D’, on=’datetime’).sum()[[‘rain_vol’]] df_rain_per_day.index = df_rain_per_day.index.date
Out [15]

In [17]
fig = plt.figure() # Линейный график влажности и облачности: ax1 = fig.add_subplot(211) ax1 = sns.lineplot(data=df_mean[['clouds', 'humidity']], markers=True, dashes=False) ax1.set_xticks([]) ax1.set_title(f'Expected humidity and rain volume for the next 5 days', fontsize=20) ax1.set_ylabel('Percentage', fontsize=14) ax1.grid(True) # Столбцы с общим объемом осадков по дням: ax2 = fig.add_subplot(212) ax2 = sns.barplot(x=df_rain_per_day.index, y='rain_vol', data=df_rain_per_day, palette="Blues_d") ax2.set_xticklabels(df_temp.index, rotation=30) ax2.set_ylabel('Total Rain Volume in mm', fontsize=14) ax2.set_xlabel('Date', fontsize=14) fig.set_size_inches(12, 6) rain_humidity_plot = f"{city.split(',')[0].replace(' ','_')}_rain_humidity.png" fig.savefig(rain_humidity_plot, dpi=300, facecolor='w',

3.4. Рабочий процесс. Часть 3: создание прогноза погоды в PDF
На последнем этапе рабочего процесса мы создаем общую метеорологическую сводку с использованием данных по городу и информации из графиков. Здесь нам понадобится библиотека pdfkit. С ее помощью мы сможем преобразовать HTML-шаблон в PDF-файл.
3. Создание метеосводки
На этом этапе рабочего процесса мы воспользуемся простым HTML-шаблоном и на его основе создадим итоговый отчет, куда добавим информацию о выбранном городе и наши графики.
In [49] # Задаем начальные и конечные даты для анализа:
today = str(df_mean.index.min()).replace(‘-’, ‘/’) last_day = str(df_mean.index.max()).replace(‘-’, ‘/’)
In [50] # HTML-шаблон для добавления данных и графиков:
report_template = f’’’ <!DOCTYPE html> <html> <head> <meta charset=’utf-8'> <title>Weather Forecast with PyOWM</title> <link rel=’stylesheet’ href=’report.css’> <style> h1 {{ font-family: Arial; font-size: 300%; }} h2 {{ font-family: Arial; font-size: 200%; }} @page {{ size: 7in 9.25in; margin: 27mm 16mm 27mm 16mm; }} </style> </head> <h1 align=”center”>Weather forecast for {city}</h1> <h2 align=”center”>Initial date: {today}</h2> <h2 align=”center”>Final date: {last_day}</h2> <figure> <img src=”{temperature_plot}” width=”1200" height=”600"> </figure> <figure> <img src=”{rain_humidity_plot}” width=”1200" height=”600"> </figure> </html> ‘’’
In [51] # Сохранение HTML-строки в файл:
html_report = f"{city.split(',')[0].replace(' ','_')}_report.html" with open(html_report, "w") as r: r.write(report_template)
In [52] # Использование pdfkit для создания графика в PDF:
pdfkit.from_file(html_report, f”{city.split(‘,’)[0].replace(‘ ‘, ‘_’)}_weather_report_for.pdf”)
3.5. Окончательная проверка перед подключением к Papermill
Сразу после завершения анализа в Jupyter Notebook, рекомендуется протестировать рабочий процесс через перезапуск ядра и запуск всех ячеек (Run > Run all cells). Если мы видим, что все ячейки выполнились успешно, и был получен ожидаемый результат, то наш блокнот готов к интеграции с Papermill. Ожидаемый метеопрогноз, который наш рабочий процесс сгенерировал для Сан-Паулу, представлен на Рис. 2. В дальнейшем мы настроим Jupyter Notebook на принятие любого города в качестве параметра рабочего процесса и его автоматическое выполнение через Papermill.

4. Настройка блокнота для Papermill
Теперь, когда наш блокнот готов для работы, необходимо внести ряд изменений в его настройки для корректной интеграции с Papermill. Вы можете воспользоваться JupyterLab либо интегрировать Jupyter Notebook с Papermill. Настройка ячейки с параметрами разнится для каждой платформы, поэтому на данном этапе будьте предельно внимательны.
4.1. Определение параметров в JupyterLab
При запуске блокнота через JupyterLab мы должны будем создать ячейку параметров рабочего процесса со значениями по умолчанию. Далее мы выделяем ячейку с параметрами, выбираем Notebook Tools(иконка с гаечным ключом на панели настроек слева) и Advanced Tools(Рис. 3).

В поле Cell Metadata добавляем следующее описание:
{ "tags": [ "parameters" ] }
Не забудьте сохранить изменения, нажав на иконку вверху поля. Теперь ваш блокнот в JupyterLab готов к получению параметров из Papermill.
4.2. Определение параметров в Jupyter Notebook
Для настройки ячейки параметров в Jupyter Notebook нужно нажать View > Cell Toolbar > Tags. Далее прописываем и добавляем тег parameters в нужную ячейку блокнота (Рис. 4).

5. Выполнение Papermill
Запустить Papermill можно из командной строки или через Python API. Для запуска Jupyter Notebooks через терминал мы выполним следующую команду (6):
# 6) Запуск Papermill из терминала papermill weather_forecast_using_pyowm.ipynb weather_forecast_using_pyowm_output.ipynb -p city 'Sao Paulo,BR' -k papermill-tutorial
Первые два параметра — это название целевого блокнота (из сессии 3) и название блокнота вывода (выполненная версия ввода). Для перечисления параметров используется -p, поэтому здесь мы описываем название и значение каждого параметра (в нашем случае есть только city). И, наконец, через -k указывается ядро. Тут мы выбираем papermill-tutorial, созданное в шаге 5).
Если бы мы захотели запустить тот же процесс через Python API в Papermill, то написали бы следующее:
import papermill as pm pm.execute_notebook('weather_forecast_using_pyowm.ipynb', 'weather_forecast_using_pyowm_output.ipynb', parameters={'city':'Sao Paulo,BR'}, kernel_name='papermill-tutorial')
5.1. Блокнот вывода
С помощью Python API в Papermill можно при желании объединить выполнение блокнота с другими действиями. Например, если бы в процессе выполнения вдруг возникла ошибка, то мы могли бы проанализировать выходной файл, обнаружить проблему и сохранить информацию в структуре базы данных.
Файлы блокнотов Jupyter (с расширением .ipynb) — это JSON-файлы с информацией о тексте каждой ячейки, исходном коде, выводе и метаданных. Papermill создает файл вывода, который представляет собой блокнот входа, выполненный с пользовательскими параметрами. По сути, здесь присутствует вся нужная информация для обработки документа. То есть мы можем использовать блокнот вывода в качестве некоего журнала логирования данных при выполнении рабочего процесса. Один из способов сохранения выходных JSON-файлов — это использование базы данных «ключ-значение» NoSQL (Amazon DynamoDB, MongoDB, CassandraDB, BigTable и т.д.).
6. Заключение
Papermill — это простой и удобный инструмент, преобразующий Jupyter Notebook в рабочий процесс обработки данных. Он расширяет возможности использования блокнотов, устраняет ограничения среды по визуализации/документации и предлагает готовую к запуску платформу. Papermill можно использовать как быстрое и качественное решение для прототипирования рабочих процессов перед созданием ETL, работающих с более сложными процессами передачи данных (как, например, Airflow или Luigi).
Интеграционные возможности данной платформы безграничны. Мы уверены, что Papermill обзаведется своим сообществом, которое направит развитие проекта в серьезное русло.
Специально для сайта ITWORLD.UZ. Новость взята с сайта NOP::Nuances of programming