<jupyter_start><jupyter_text>Jupyter Notebook О чём этот ноутбук**В ноутбуке есть интерактивный контент, в связи с чем мы рекомендуем просматривать его в `jupyter notebook/lab`.**<img src="images/jupyter_art.png" alt="Jupyter Notebook"	title="Jupyter Notebook" width="600"/>    ["Why Jupyter is data scientists’ computational notebook of choice"](https://www.nature.com/articles/d41586-018-07196-1) — статья с таким заголовком вышла в октябрьском номере `Nature` в 2018 году (почитайте, там интересно). Она посвящена `Jupyter Notebook` — опенсорсному веб-приложению для интерактивной разработки, которое за последние несколько лет покорило сердца миллионов и стало де-факто стандартом в аналитике, науке о данных, машинном обучении и много где ещё. Количество `.ipynb`-файлов на `GitHub` выросло с $2 \cdot 10^5$ в 2015 году до $2.5 \cdot 10^6$ в 2018. Ниже мы разберём основные причины такой взрывной популярности: Лабораторный журнал 21 векаРабота аналитика или учёного отличается от индустриальной разработки отсутствием чёткого техзадания. В этих сферах правильная постановка задачи это уже половина решения.  На начальную фазу — тщательный анализ исходных данных (`exploratory data analysis (EDA)`) и последующую постановку гипотез — уходит много времени. Как следствие, до самого конца неясно, как организовать процесс разработки: что в итоге важно, а о чём можно будет забыть. В таких условиях тратить силы на скурпулёзное написание кода бессмысленно — на первый план выходит умение быстро прототипировать, ставить эксперименты. Кроме того, свои результаты приходится постоянно презентовать как коллегам, там и заказчику или начальству. `Jupyter Notebook` убивает этих двух зайцев одним выстрелом:   <img src="images/jupyter_lab.png" alt="Jupyter Lab"title="Jupyter Lab — будущее Jupyter Notebook и 'убийца RStudio' (still in beta)" width="900"/>По своей сути `Jupyter` это интерактивный лабораторный журнал: он позволяет писать код прямо в отчёте (`markdown` с формулами из `latex`), дополнять его иллюстрациями (в том числе интерактивными), пересчитывать всё на лету и обмениваться результатами в читаемом формате. Это дало новую жизнь парадигме **reproducible research** — в формате `.ipynb` или `R-Markdown` пишут [статьи](https://github.com/jupyter/jupyter/wiki/A-gallery-of-interesting-Jupyter-Notebooksreproducible-academic-publications) и [даже книги](https://github.com/jupyter/jupyter/wiki/A-gallery-of-interesting-Jupyter-Notebooksentire-books-or-other-large-collections-of-notebooks-on-a-topic), где заинтересованный читатель может сразу же воспроизводить описанные результаты. Автор не уверен, что впечатляет его больше — потенциальный полёт человечества к Юпитеру или то, насколько более демократичной `Jupyter Notebook` сделал высокую науку (которая, к слову, страдает от того, что [70% учёных не смогли воспроизвести чужие результаты, а ещё 50% — свои](https://www.nature.com/news/1-500-scientists-lift-the-lid-on-reproducibility-1.19970) согласно опросу в `Nature`). Нелинейная последовательность исполнения`Jupyter` позволяет запускать клетки с кодом в произвольном порядке и, в отличие от `IPython`, в нём это делать удобно. Да, это повышает требования к разработчику (который должен помнить, какая конкретно последовательность ячеек решает задачу) и провоцирует писать очень плохой код, но в реалиях, когда полный перезапуск пайплайна требует нескольких часов на суперкомпьютере, это не прихоть, а необходимость. Вавилонская башня от программированияВопреки расхожему мнению, `Jupyter` поддерживает не только `Julia`, `Python` и `R` (`Ju`-`Py`-`teR`, именно потому), но [более 40 языков](https://jupyter.org), включая `C++` (да-да, компилируемый язык, [check it out](https://quantstack.net/index.html)). Более того, для того, чтобы писать код на нескольких языках одновременно (обычно это `Bash`, `Python` и `R`) не нужно создавать разные ноутбуки (об этом мы поговорим ниже). Это инструмент, который не ограничивает возможности разработчика. Переносимость и платформонезависимость`Jupyter` позволяет развернуть дружелюбный интерфейс на любой удалённой машине, от учебного сервера до гигантской распределённой `map-reduce` сети в духе Яндексовского `YT`. Учитывая, что работать с данными на своём ноутбуке почти никогда не приходится (либо по закону нельзя, либо в оперативку не влезает), возможность оставить в прошлом сумрачную серверную консоль многие восприняли с облегчением. В сочетании с инструментами в духе `conda`, `jupyter` позволяет развернуть привычное и настроенное под себя окружение, не задумываясь о том, с каким железом и в какой системе приходится работать. Более того, `Jupyter Hub` позволяет создать точку входа, через которую над проектом могут совместно работать несколько человек. Это позволяет специалисту настроить окружение один раз, после чего им смогут пользоваться сотни человек. Неудивительно, что многие онлайн-курсы переходят на формат `jupyter`-ноутбуков. Возможно, нас это тоже ждёт. Вывод`Jupyter`-ноутбуки это мощный инструмент, который облегчит вашу жизнь. Тем не менее, работа с ним требует дисциплины. Мы разберём как `best practices`, так и распространённые антипаттерны, которых следует избегать. Мы верим, что это сделает мир лучше.Мы разберём такие темы как:1. `jupyter_contrib_nbextensions` — плагины, которые превращают `jupyter` в удобный кодовый редактор;2. основы работы с командной строкой (здесь `jupyter` похож на `vim`);3. `jupyter magics` — метаязык, который позволяет навешивать триггеры на клетки и интерактивно менять переменные окружения. Если простыми словами, то эта штука позволяет засекать время исполнения клеток, менять формат отображения графиков, запускать внешние скрипты и многое другое, что обычно делают через терминал. Очень удобно;4. запуск `jupyter`-сервера на удалённой машине;5. полезные мелочи, которые сделают ваши ноутбуки опрятнее;  ОсновыУстановка всего необходимого в `conda-env` обсуждалась в прошлом ноутбуке.  Для того, чтобы поднять `jupyter`-сервер, активируйте `conda-env` и наберите в терминале:```bashjupyter notebook```Когда вы откроете `jupyter`-ноутбук, в меню `Help` можно будет найти интерактивные вводные руководства.  Советуем ознакомиться с ними, если интерфейс вам вновинку.  Всего ячейки бывают трёх типов:- `code` — собственно, код- `markdown` — текст с формулами на `latex` (в одинарных или двойных $)- `raw` — неформатированный текстИзменить тип можно либо в меню (`Cell` —> `Cell Type`), либо с помощью клавиатурных сокращений (см. ниже).  В целом, базовый интерфейс довольно интуитивный, в нём полезно разобраться самостоятельно.  ПлагиныВстроенный редактор довольно удобный, но с плагинами он становится по-настоящему хорош.  Установка библиотеки `jupyter_contrib_nbextensions`, которая отвечает за поддержку плагинов, освещалась в прошлом ноутбуке.  Давайте разберёмся, какие плагины из стандартного списка наиболее полезны:- `Ruler` — отображает красным границу в 80 символов в строке. **Этот плагин нужно поставить обязательно,** чтобы не расстраивать проверяющих тем, что при конвертации в pdf у вас опять что-то не влезло в одну строку.- `Codefolding`, `Codefolding in editor` — незаменимый плагин, который позволяет сворачивать код для лучшей читаемости.- `ExecuteTime` — автоматически запоминает, когда ячейка начала выполняться и сколько времени это заняло- `Notify` — посылает `push`-уведомление в браузере, когда ячейка закончила выполняться (если она отрабатывала достаточно долго)- `Move selected cells` — позволяет одновременно перемещать выделенные ячейки вверх или вниз- `Limit Output` — ограничивает размер вывода ячейки. С этим плагином всё не упадёт, если из-за ошибки в коде вы решите распечатать многогигабайтную таблицу прямо в окошке браузера (бывает чаще, чем хотелось бы).Этим список плагинов не исчерпывается, остальные можете выбрать на свой вкус.  Работа с командной строкой `Jupyter` Command modeВ `jupyter` есть `command mode` — режим, где можно вводить команды для быстрого редактирования текста. Как и в `vim`, из которого эта концепция была позаимствована, его можно активировать кнопкой `Esc`, после чего возможны варианты. `Esc + h` откроет справку:<img src="images/command_mode.png" alt="command mode shortcuts"	title="command mode shortcuts" width="600"/> В ней перечислено много команд, из которых чаще всего используются такие:- `Esc + F` — найти и заменить- `Esc + I` — прервать исполнение- `Esc + 0` — перезапустить ядро- `Esc + Shift + ↑↓` — выделить ячейку выше/ниже текущей- `Esc + Ctrl + Enter` — запустить выделенные ячейки (в естественном порядке)- `Esc + D + D` — удалить все выделенные ячейки (включая текущую)- `Esc + Z` — отменить удаление ячеек- `Esc + C` — скопировать выделенные ячейки- `Esc + X` — вырезать выделенные ячейки- `Esc + V` — вставить ранее скопированные ячейки- `Esc + A` — вставить ячейку выше- `Esc + B` — вставить ячейку ниже- `Esc + Shift + M` — объединить выделенные ячейки (или текущую ячейку с нижней)- `Esc + M` — заменить код на markdown- `Esc + Y` — наоборот, markdown —> код  Edit modeЭти сокращения доступны в редакторе. Здесь всё стандартно. Если вы не привыкли пользоваться такими сокращениями, то настоятельно рекомендуем потратить время и научиться: это сэкономит вам много времени в будущем.<img src="images/edit_mode.png" alt="edit mode shortcuts"	title="edit mode shortcuts" width="600"/> Самые полезные команды (кроме очевидных) таковы:- `Shift + Tab` — показать описание функции (курсор должен стоять сразу после открывающей скобки)- `Ctrl + /` — закомментировать строку- `Ctrl + D` — удалить строку- `Ctrl + ↑` — перейти к началу ячейки- `Ctrl + ↓` — перейти к концу ячейки- `Ctrl + Shift + -` — разбить ячейку по текущей строке- `Shift + ↑↓` — выделить ячейку выше/ниже текущей- `Ctrl + Enter` — запустить выделенные ячейки- `Shift + Enter` — запустить ячейку и перейти на одну ниже (удобно, когда последовательно запускаете сразу много)  Магия `Jupyter`<img src="images/jupyter_magics.jpg" alt="It's a kind of magic"	title="It's a kind of magic" width="400"/>`jupyter magics` — метаязык (как макросы в Си), команды которого обычно начинаются с `%` или `%%` (зависит от контекста). Работают они или нет — зависит от реализации. Стандартные `jupyter-magics` поставляются с ядром `IPython` (потому вы можете выучить их один раз, а потом пользоваться и там, и там). Для других языков или ядер набор команд может быть другим.  Давайте посмотрим, какие команды есть.  *P.S. Если вам захочется узнать больше, можете посмотреть [замечательный доклад с PyCon Canada](https://www.youtube.com/watch?v=zxkdO07L29Q).*<jupyter_code>%lsmagic<jupyter_output><empty_output><jupyter_text>А если вы хотите почитать краткую справку по `IPython` (по сути, краткий конспект этого раздела), используйте команду<jupyter_code>%quickref<jupyter_output><empty_output><jupyter_text>Видно, что команды делятся на два типа: `line magics` и `cell magics`. Как следует из названия, разница между ними в том, что `cell magics` влияют на состояние всей ячейки (и работают только если написаны в самом её начале), в то время как `line magics` могут быть написаны в любом месте и либо влияют на строку с кодом (скажем, замеряют время исполнения, как `%timeit`), либо выполняют какую-то системную команду (как `%ls`). Если вы забыли, что делает конкретная команда, то добавьте перед ней знак вопроса — откроется справка.<jupyter_code>?%time<jupyter_output><empty_output><jupyter_text>К слову, таким же образом можно вызвать справку для произвольной функции. Синтаксис привычен тем, кто работал с `R`:<jupyter_code>?range<jupyter_output><empty_output><jupyter_text>Давайте посмотрим на эти команды поближе:  `%load_ext`, `%autoreload``%load_ext` позволяет загружать сторонние модули (например, `Cython`).  Нам важно, что с её помощью можно активировать самую важную команду — `%autoreload`. Без неё вам пришлось бы перезапускать ядро каждый раз, когда вы меняете библиотеки со своим кодом. `autoreload` делает это за вас, в больших проектах это незаменимо.<jupyter_code>%load_ext autoreload
# здесь 2 означает, что все библиотеки будут подгружаться заново,
# если только явно не указано иное
%autoreload 2 

import jupyter_lesson<jupyter_output>The autoreload extension is already loaded. To reload it, use:
  %reload_ext autoreload<jupyter_text>`%matplotlib`Скорее всего, эту команду вам придётся писать в начале каждого домашнего задания.  Она определяет, каким образом будут отображаться ваши графики. Есть два основных варианта: `inline` и `notebook`.  Разберёмся, в чём между ними разница:<jupyter_code>%matplotlib notebook 

jupyter_lesson.plot_batman()<jupyter_output><empty_output><jupyter_text>Видно, что открылось интерактивное окошко, в котором можно масштабировать участки графика по своему усмотрению. Это удобно, когда хочется рассмотреть детали, но требовательно к ресурсам при сложных визуализациях. А ещё работает не всегда.<jupyter_code>%matplotlib inline

jupyter_lesson.plot_batman()<jupyter_output><empty_output><jupyter_text>В этом режиме в ноутбук просто вставляется статическая картинка.  Именно этим режимом вы будете пользоваться чаще всего. **Раздел со звёздочкой:** На удалённых машинах часто нет графического интерфейса. В связи с этим набор предустановленных инструментов для работы с графикой там ограничен. Часто обнаруживается только какой-то конкретный бэкенд для отрисовки графики (скажем, `qt`). В таких случаях нужно явно потребовать, чтобы `matplotlib` использовал именно его. Посмотреть список доступных бэкендов можно с помощью<jupyter_code>%matplotlib --list<jupyter_output>Available matplotlib backends: ['tk', 'gtk', 'gtk3', 'wx', 'qt4', 'qt5', 'qt', 'osx', 'nbagg', 'notebook', 'agg', 'svg', 'pdf', 'ps', 'inline', 'ipympl', 'widget']<jupyter_text>Как вы видите, `notebook` и `inline` это тоже варианты бэкенда.   `%time`, `%timeit`, `%%time`Эти три команды замеряют, как долго исполняется код.  `%timeit` запускает команду несколько раз. По результатам вычисляется среднее и стандартное отклонение. Это уместно, если функция зависит от случайных битов. Для примера напишем функцию, которая генерирует случайное число и засыпает на одну секунду, если оно нечётное.<jupyter_code>import time

def sleep_if_odd():
    rvs = np.random.randint(low=0, high=int(1e9)) 
    randbit = rvs % 2
    if randbit % 2 == 1:
        time.sleep(1)
%time sleep_if_odd()<jupyter_output>CPU times: user 1.36 ms, sys: 423 µs, total: 1.78 ms
Wall time: 1 s<jupyter_text>При использовании `%timeit` можно указать, сколько раз нужно запустить функцию. Синтаксис — `%timeit -n` Дефолтное значение — 7.<jupyter_code>%timeit -n 10 sleep_if_odd()<jupyter_output>487 ms ± 125 ms per loop (mean ± std. dev. of 7 runs, 10 loops each)<jupyter_text>Видно, что только результаты `%timeit` отражают реальное поведение функции. Это стоит иметь в виду при тестировании кода.  `%system`, `%%bash`Позволяет выполнять системные команды так, будто вы работаете в терминале.<jupyter_code>%system date<jupyter_output><empty_output><jupyter_text>Отметим, что для этого есть удобный альтернативный синтаксис:<jupyter_code>!date<jupyter_output>Ср окт  9 21:09:00 MSK 2019<jupyter_text>С помощью команды `%%bash` можно вызвать многострочный скрипт на баше:<jupyter_code>%%bash

for word in {'IPython', 'and', 'bash' 'are', 'friends!'}
do
    echo $word
done<jupyter_output>{IPython,
and,
bash
are,
friends!}<jupyter_text>`%debug`Мало кто знает, что в `IPython` (а следовательно и в `jupyter`) есть встроенный дебаггер.  Об этом есть замечательная [ветка сообщений в Twitter](https://twitter.com/radekosmulski/status/945739571735748609), мы кратко воспроизведём её здесь.  Напишем злободневную функцию и целенаправленно её сломаем:<jupyter_code>from datetime import date, datetime, timedelta

deadline = datetime.combine(date.today(), datetime.max.time())
def submit_stats_homework(submission_time, deadline=deadline):
    good_student = True
    if submission_time > deadline: 
        good_student = False
        raise ValueError(
            "Вы сдали задание после дедлайна! 0 баллов! ¯\_(ツ)_/¯\n"
            "Впредь будьте аккуратнее!"
        )
submission_time = deadline + timedelta(seconds=1)
submit_stats_homework(submission_time)<jupyter_output><empty_output><jupyter_text>Вызов команды `%debug` вернёт вас к тому моменту исполнения, когда код упал с ошибкой. В консоли интерпретатора вы сможете посмотреть значение локальных переменных. Дебаггер становится незаменим, если функция работает долго или ошибку трудно воспроизвести.<jupyter_code>%debug<jupyter_output>> [0;32m<ipython-input-125-ab85f7c267de>[0m(9)[0;36msubmit_stats_homework[0;34m()[0m
[0;32m      7 [0;31m        [0mgood_student[0m [0;34m=[0m [0;32mFalse[0m[0;34m[0m[0;34m[0m[0m
[0m[0;32m      8 [0;31m        raise ValueError(
[0m[0;32m----> 9 [0;31m            [0;34m"Вы сдали задание после дедлайна! 0 баллов! ¯\_(ツ)_/¯\n"[0m[0;34m[0m[0;34m[0m[0m
[0m[0;32m     10 [0;31m            [0;34m"Впредь будьте аккуратнее!"[0m[0;34m[0m[0;34m[0m[0m
[0m[0;32m     11 [0;31m        )
[0m
ipdb> help

Documented commands (type help <topic>):
========================================
EOF    cl         disable  interact  next    psource  rv         unt   
a      clear      display  j         p       q        s          until 
alias  commands   down     jump      pdef    quit     source     up    
args   condition  enable   l         pdoc    r        step       w     
b      cont       exit     list      pfile   restart  tbreak     whatis
break  continue   h  [...]<jupyter_text>`%%writefile`, `%pycat`Эти функции позволяют вам сохранить ячейку с кодом в питоновский файл и вывести его содержимое с подсветкой синтаксиса.  Это пригодится вам при работе с `Google Colab` весной (там нельзя менять `.py`-файлы, только перезаписывать).<jupyter_code>%%writefile test.py
print("Hello, World!")
%pycat test.py
!rm test.py<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.08826990976853669, 'fraction_numerical': 0.014235274337275122, 'mean_word_length': 5.37513397642015, 'pattern_counts': {'":': 0, '<': 65, '<?xml version=': 0, '>': 71, 'https://': 8, 'lorem ipsum': 0, 'www.': 3, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '16', 'dir': 'jupyter-structured-clean-dedup', 'id': '526349', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 7342, 'n_tokens_neox': 8284, 'n_words': 2088, 'path': 'notebooks/Introduction_to_DS/02-to-jupyter-and-back.ipynb', 'repo_name': 'TopCoder2K/DS-introduction', 'size': '17843'}