Введение
Давайте будем честны: в 2026 году JupyterLab по-прежнему остаётся королём интерактивной разработки в мире дата-сайенс. Да, появились интересные конкуренты — Marimo, Hex, Deepnote — и каждый из них хорош по-своему. Но именно JupyterLab продолжает занимать центральное место в рабочем процессе большинства дата-сайентистов, исследователей и ML-инженеров. Причины? Открытый исходный код, огромная экосистема расширений, поддержка десятков языков программирования и (что немаловажно) постоянное развитие.
Путь от классического Jupyter Notebook до JupyterLab 4.5 был долгим. Классический Notebook предлагал простую однодокументную модель — один ноутбук, один таб. JupyterLab, ставший стабильным в 2018 году, всё изменил: вкладки, панели, файловый менеджер, терминал, расширения. Версия 4.0 (2023) принесла новую архитектуру и ускорение. А текущая 4.5 — это уже совсем другой уровень: интеграция с ИИ, улучшенная производительность и набор инструментов для серьёзной работы.
В этом руководстве мы разберём всё, что нужно знать о JupyterLab 4.5 — от установки до продвинутого профилирования и ИИ-ассистентов. Неважно, только начинаете вы свой путь в дата-сайенс или уже опытный специалист — тут найдутся практические советы для каждого.
Установка и настройка JupyterLab 4.5
Установка через pip
Самый простой способ начать — pip. Только не забудьте про виртуальное окружение, иначе рискуете получить конфликты зависимостей (а это, поверьте, не самое весёлое занятие):
# Создаём виртуальное окружение
python -m venv jupyter-env
source jupyter-env/bin/activate # Linux/macOS
# jupyter-env\Scripts\activate # Windows
# Устанавливаем JupyterLab
pip install jupyterlab==4.5.*
# Проверяем версию
jupyter lab --version
Установка через conda
Если вы из лагеря Anaconda или Miniconda — вот ваш вариант:
# Создаём окружение с нужными библиотеками
conda create -n ds-env python=3.12 jupyterlab=4.5 pandas numpy matplotlib scikit-learn -c conda-forge
# Активируем окружение
conda activate ds-env
# Запускаем JupyterLab
jupyter lab
Начальная настройка
После установки JupyterLab запускается командой jupyter lab и сам откроет браузер на http://localhost:8888. Для удалённой работы добавьте параметры:
# Запуск без автоматического открытия браузера
jupyter lab --no-browser --port=8889 --ip=0.0.0.0
# Генерация конфигурационного файла
jupyter lab --generate-config
# Файл создаётся по пути:
# ~/.jupyter/jupyter_lab_config.py
Вот что стоит подкрутить в конфиге:
# jupyter_lab_config.py
c.ServerApp.port = 8888
c.ServerApp.open_browser = True
c.ServerApp.notebook_dir = '/home/user/projects'
c.ServerApp.token = '' # Только для локальной разработки!
Рекомендуемая структура проекта
Если вы работаете над чем-то серьёзнее, чем одноразовый анализ, вот структура, которая хорошо себя зарекомендовала на практике:
my-ds-project/
├── data/
│ ├── raw/ # Исходные данные (не трогаем!)
│ ├── processed/ # Обработанные данные
│ └── external/ # Данные из внешних источников
├── notebooks/
│ ├── 01_exploration.ipynb
│ ├── 02_preprocessing.ipynb
│ └── 03_modeling.ipynb
├── src/
│ ├── __init__.py
│ ├── data_loading.py
│ ├── features.py
│ └── models.py
├── tests/
├── requirements.txt
├── environment.yml
└── README.md
Новые возможности JupyterLab 4.5
Версия 4.5 — не просто багфикс-релиз. Тут действительно есть вещи, ради которых стоит обновиться.
Режим contentVisibility для производительности
Пожалуй, самое заметное улучшение — новый режим виртуализации на основе CSS-свойства contentVisibility. Раньше полная виртуализация ломала поиск по Ctrl+F и создавала другие неприятности. Теперь браузер сам решает, как оптимизировать рендеринг ячеек за пределами экрана. Результат — ноутбуки с сотнями ячеек летают, а поиск работает как положено.
Включается просто: Settings → Notebook → Windowing mode → content-visibility.
Миникарта для ноутбуков
Знаете миникарту из VS Code? Теперь она есть и в JupyterLab. Компактное визуальное представление всего ноутбука в боковой панели — можно быстро перемещаться между секциями одним кликом. Особенно выручает, когда ноутбук разросся до сотни ячеек. Активируется через View → Show Minimap.
Subshell-консоли
Вот это реально крутая штука для тех, кто любит многозадачность. Subshell-консоли позволяют запускать несколько консолей, привязанных к одному ядру, но работающих независимо. Запустили тяжёлый расчёт в одной консоли — и спокойно исследуете данные в другой, без блокировки. Для работы нужны IPython 9.0+ и ipykernel 7.0+.
Автоматическое переключение тем
Мелочь, а приятно: JupyterLab 4.5 теперь следит за системными настройками и автоматически переключается между светлой и тёмной темами. Если ваша ОС вечером переходит в тёмный режим, JupyterLab последует за ней. Настраивается в Settings → Theme → Theme Synchronisation.
Быстрое сохранение ноутбуков
Механизм сохранения полностью переработали — теперь используется потоковая загрузка. Разница ощутима на больших ноутбуках с кучей графиков. Если ваш ноутбук весит больше 50 МБ, вы заметите ускорение сразу.
Открытие ноутбуков без запуска ядра
Наконец-то! Можно открыть ноутбук просто для просмотра, без запуска ядра. Экономит ресурсы и время. Особенно полезно при код-ревью или когда вы просто хотите посмотреть чужой ноутбук, не запуская весь стек вычислений.
CodeMirror 6 и MathJax 3
Под капотом — CodeMirror 6 с современной подсветкой синтаксиса и продвинутым поиском. А MathJax 3 значительно ускоряет рендеринг формул в Markdown-ячейках. Если вы работаете с научными ноутбуками, где много LaTeX, разница будет ощутимой.
Магические команды для дата-сайенс
Магические команды — это, честно говоря, одна из тех вещей, ради которых стоит использовать IPython. Они позволяют профилировать код, управлять окружением и делать кучу полезных вещей прямо из ячеек ноутбука.
Бенчмаркинг с %timeit и %%timeit
Если вы хоть раз измеряли время через time.time() — забудьте об этом. Команды %timeit (для одной строки) и %%timeit (для всей ячейки) делают это намного надёжнее:
import numpy as np
import pandas as pd
# Строчная магия — измеряет одну строку
%timeit np.random.randn(1000000)
# Ячеечная магия — измеряет всю ячейку
%%timeit
df = pd.DataFrame(np.random.randn(100000, 10))
df.sum(axis=1)
На выходе получите что-то вроде: 3.45 ms ± 127 µs per loop (mean ± std. dev. of 7 runs, 100 loops each). Статистически корректно и без лишних телодвижений.
Профилирование с %prun и %lprun
Когда нужен более детальный анализ, на помощь приходят %prun (профилировщик на уровне функций) и %lprun (построчный профилировщик):
# Профилирование функции с помощью cProfile
def process_data(n):
df = pd.DataFrame(np.random.randn(n, 20), columns=[f'col_{i}' for i in range(20)])
df_normalized = (df - df.mean()) / df.std()
correlations = df_normalized.corr()
return correlations
%prun process_data(100000)
# Построчное профилирование (требует установки line_profiler)
# pip install line_profiler
%load_ext line_profiler
%lprun -f process_data process_data(100000)
Профилирование памяти с %memit и %mprun
Утечки памяти — бич работы с большими данными. Расширение memory_profiler помогает понять, куда уходит RAM:
# pip install memory_profiler
%load_ext memory_profiler
# Измерение пикового потребления памяти
%memit pd.read_csv('large_dataset.csv')
# Построчное профилирование памяти (функция должна быть в .py файле)
# %%writefile mem_example.py
# import pandas as pd
# def load_and_process():
# df = pd.read_csv('large_dataset.csv')
# df_filtered = df[df['value'] > 0]
# return df_filtered.groupby('category').mean()
# from mem_example import load_and_process
# %mprun -f load_and_process load_and_process()
Отладка с %debug
Когда ячейка падает с ошибкой, не паникуйте. Просто напишите %debug в следующей ячейке — и получите интерактивный отладчик, где можно покопаться в переменных прямо в момент сбоя:
# После возникновения ошибки в предыдущей ячейке:
%debug
# Или можно включить автоматический вызов отладчика при ошибках:
%pdb on
Другие полезные магические команды
# Встраивание графиков matplotlib в ноутбук
%matplotlib inline
# Для интерактивных графиков (масштабирование, панорамирование)
%matplotlib widget
# Сохранение переменных между сессиями
%store my_dataframe
# В новой сессии:
%store -r my_dataframe
# Запись содержимого ячейки в файл
%%writefile utils.py
def clean_data(df):
return df.dropna().drop_duplicates()
# Загрузка содержимого файла в ячейку
%load utils.py
Практический пример: профилирование pandas
Вот конкретный пример, который показывает, почему важно знать «правильный» способ агрегации в pandas:
import pandas as pd
import numpy as np
# Создаём тестовый датасет
np.random.seed(42)
n = 500_000
df = pd.DataFrame({
'user_id': np.random.randint(1, 10000, n),
'category': np.random.choice(['A', 'B', 'C', 'D', 'E'], n),
'amount': np.random.exponential(100, n),
'timestamp': pd.date_range('2025-01-01', periods=n, freq='min')
})
# Сравниваем два подхода к агрегации
%timeit df.groupby('category')['amount'].apply(lambda x: x.sum())
%timeit df.groupby('category')['amount'].sum()
# Второй подход в 10-50 раз быстрее — избегайте apply() с простыми агрегациями!
Серьёзно, разница бывает в десятки раз. Я сам когда-то потерял кучу времени, пока не понял, что apply() с простыми операциями — это почти всегда плохая идея.
Интерактивные виджеты с ipywidgets
Библиотека ipywidgets — это, по сути, способ превратить ноутбук в мини-приложение. Ползунки, выпадающие списки, чекбоксы — всё это привязывается к функциям и позволяет анализировать данные интерактивно.
Базовое использование interact()
import ipywidgets as widgets
from ipywidgets import interact, interactive
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# Простой пример: интерактивный график
@interact(n_points=(100, 10000, 100), noise=(0.1, 5.0, 0.1))
def plot_data(n_points=1000, noise=1.0):
x = np.linspace(0, 10, n_points)
y = np.sin(x) + np.random.normal(0, noise, n_points)
plt.figure(figsize=(10, 4))
plt.scatter(x, y, alpha=0.3, s=1)
plt.title(f'Точек: {n_points}, шум: {noise}')
plt.show()
Виджеты: ползунки, выпадающие списки, чекбоксы
# Различные типы виджетов
slider = widgets.FloatSlider(value=0.5, min=0, max=1, step=0.01, description='Порог:')
dropdown = widgets.Dropdown(options=['Линейная', 'Полиномиальная', 'RBF'], description='Модель:')
checkbox = widgets.Checkbox(value=True, description='Показать сетку')
text_input = widgets.Text(value='default', description='Название:')
# Вывод виджетов
display(slider, dropdown, checkbox)
Практический пример: интерактивный дашборд
А вот более серьёзный пример — полноценный дашборд фильтрации данных прямо в ноутбуке:
import ipywidgets as widgets
from IPython.display import display, clear_output
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
# Создаём датасет продаж
np.random.seed(42)
df_sales = pd.DataFrame({
'date': pd.date_range('2025-01-01', periods=1000, freq='D'),
'region': np.random.choice(['Москва', 'Санкт-Петербург', 'Новосибирск', 'Екатеринбург'], 1000),
'product': np.random.choice(['Ноутбук', 'Телефон', 'Планшет', 'Наушники'], 1000),
'revenue': np.random.exponential(50000, 1000),
'quantity': np.random.randint(1, 20, 1000)
})
# Виджеты для фильтрации
region_widget = widgets.SelectMultiple(
options=df_sales['region'].unique().tolist(),
value=['Москва'],
description='Регион:',
rows=4
)
product_widget = widgets.Dropdown(
options=['Все'] + df_sales['product'].unique().tolist(),
value='Все',
description='Товар:'
)
date_range_widget = widgets.IntRangeSlider(
value=[0, 999],
min=0, max=999,
step=1,
description='Период:',
style={'description_width': 'initial'},
layout=widgets.Layout(width='500px')
)
output = widgets.Output()
def update_dashboard(change):
with output:
clear_output(wait=True)
# Фильтрация данных
mask = df_sales['region'].isin(region_widget.value)
if product_widget.value != 'Все':
mask &= df_sales['product'] == product_widget.value
start, end = date_range_widget.value
filtered = df_sales.loc[mask].iloc[start:end+1]
if filtered.empty:
print("Нет данных для выбранных фильтров")
return
fig, axes = plt.subplots(1, 2, figsize=(14, 5))
# Выручка по регионам
filtered.groupby('region')['revenue'].sum().plot(
kind='bar', ax=axes[0], color='steelblue'
)
axes[0].set_title('Выручка по регионам')
axes[0].set_ylabel('Выручка (руб.)')
# Динамика продаж
filtered.set_index('date')['revenue'].resample('M').sum().plot(
ax=axes[1], marker='o', color='coral'
)
axes[1].set_title('Помесячная выручка')
plt.tight_layout()
plt.show()
print(f"\nВсего записей: {len(filtered)}")
print(f"Суммарная выручка: {filtered['revenue'].sum():,.0f} руб.")
# Привязываем обработчики
region_widget.observe(update_dashboard, names='value')
product_widget.observe(update_dashboard, names='value')
date_range_widget.observe(update_dashboard, names='value')
# Отображаем дашборд
dashboard = widgets.VBox([
widgets.HBox([region_widget, product_widget]),
date_range_widget,
output
])
display(dashboard)
update_dashboard(None)
Интерактивные графики с ipympl
Если хочется не просто смотреть на график, а масштабировать и крутить его — ставьте ipympl:
# pip install ipympl
%matplotlib widget
import matplotlib.pyplot as plt
import numpy as np
fig, ax = plt.subplots(figsize=(10, 6))
x = np.linspace(0, 20, 1000)
ax.plot(x, np.sin(x) * np.exp(-x/10), linewidth=2)
ax.set_title('Интерактивный график — попробуйте масштабировать!')
ax.grid(True)
plt.show()
Jupyter AI: интеграция ИИ в рабочий процесс
Одно из самых заметных изменений последних лет — глубокая интеграция больших языковых моделей прямо в JupyterLab. Расширение jupyter-ai позволяет общаться с ИИ, не выходя из ноутбука. И знаете что? Это действительно меняет рабочий процесс.
Установка и настройка
# Установка jupyter-ai
pip install jupyter-ai
# Для работы с конкретными провайдерами моделей:
pip install jupyter-ai langchain-anthropic # Для Claude
pip install jupyter-ai langchain-openai # Для GPT-4o
# После установки перезапустите JupyterLab
jupyter lab
Настройка ключей API — через переменные окружения или интерфейс чата:
# В файле .env или в терминале
export ANTHROPIC_API_KEY="sk-ant-..."
export OPENAI_API_KEY="sk-..."
Чат-панель с LLM
После установки в боковой панели появляется иконка чата. Выбираете модель (Claude, GPT-4o, Gemini — что душе угодно), и можно вести диалог прямо в контексте ваших ноутбуков. Модель видит ваш код и помогает с анализом, отладкой, объяснением результатов.
Что умеет чат-панель:
- Выбор модели из списка (Claude Sonnet, Claude Opus, GPT-4o и др.)
- Отправка выделенного кода для анализа
- Генерация кода по описанию задачи
- Объяснение ошибок с предложением исправлений
Магическая команда %%ai
Для быстрого обращения к модели прямо из ячейки есть магия %%ai:
%%ai anthropic:claude-sonnet-4-20250514
Напиши функцию на Python, которая принимает pandas DataFrame с колонками
'date', 'category', 'value' и возвращает DataFrame с скользящим средним
за 7 дней для каждой категории отдельно.
%%ai anthropic:claude-sonnet-4-20250514
Объясни, почему следующий код работает медленно и предложи оптимизацию:
df['result'] = df.apply(lambda row: row['a'] ** 2 + row['b'] ** 2, axis=1)
Автодополнение с ИИ
Jupyter AI поддерживает inline-автодополнение — примерно как GitHub Copilot. Пишете код, а модель предлагает продолжение; нажимаете Tab, чтобы принять. Настраивается в Settings → Inline Completer. На практике экономит заметное количество времени, особенно с boilerplate-кодом.
Notebook Intelligence (NBI) как альтернатива
Есть ещё Notebook Intelligence (NBI) — похожее расширение, но заточенное под GitHub Copilot. Предлагает автодополнение, чат и рефакторинг. Выбор между jupyter-ai и NBI зависит от того, какой провайдер моделей вам ближе.
Расширения JupyterLab для продуктивности
Экосистема расширений — одна из главных суперсил JupyterLab. Вот список must-have расширений на 2026 год (проверено на собственном опыте).
jupyterlab-git: контроль версий
Git прямо в интерфейсе — коммиты, ветки, diff, история. Больше не нужно переключаться в терминал для каждого коммита:
pip install jupyterlab-git
Визуальное сравнение изменений в ноутбуках — это отдельное удовольствие. Гораздо удобнее, чем пытаться разобраться в JSON-diff.
jupyterlab-lsp: интеллектуальное редактирование
Language Server Protocol даёт вам IDE-уровень редактирования: автодополнение, переход к определению, подсказки типов, диагностику ошибок:
pip install jupyterlab-lsp python-lsp-server[all]
После перезапуска получите полноценное автодополнение, включая подсказки по сигнатурам pandas и numpy. Честно, без этого расширения уже трудно работать.
jupyterlab-execute-time: время выполнения ячеек
pip install jupyterlab-execute-time
Показывает время выполнения каждой ячейки прямо под ней. Незаменимо для быстрого обнаружения узких мест — сразу видно, какие ячейки тормозят.
jupyterlab-code-formatter: форматирование кода
pip install jupyterlab-code-formatter black isort
Форматирует код в ячейках через black и isort одним хоткеем. Можно настроить автоформатирование при сохранении в Settings → Code Formatter.
jupyterlab-variableinspector: инспектор переменных
Панель со списком всех переменных — имена, типы, размеры, значения. Когда в памяти висит десяток DataFrame разного размера, это спасение.
jupyterlab-drawio: диаграммы
pip install jupyterlab-drawio
Draw.io прямо в JupyterLab. Рисуете блок-схемы пайплайнов, архитектурные диаграммы — и всё это не покидая рабочего пространства.
Сводная таблица расширений
| Расширение | Назначение | Команда установки |
|---|---|---|
| jupyterlab-git | Контроль версий Git | pip install jupyterlab-git |
| jupyterlab-lsp | Автодополнение и диагностика | pip install jupyterlab-lsp python-lsp-server |
| jupyterlab-execute-time | Время выполнения ячеек | pip install jupyterlab-execute-time |
| jupyterlab-code-formatter | Форматирование кода | pip install jupyterlab-code-formatter |
| jupyterlab-variableinspector | Инспектор переменных | pip install jupyterlab-variableinspector |
| jupyterlab-drawio | Диаграммы Draw.io | pip install jupyterlab-drawio |
Профилирование и оптимизация кода
Умение находить узкие места — навык, который отделяет джуна от синьора. JupyterLab даёт для этого все инструменты, нужно просто знать, как ими пользоваться.
Профилирование с cProfile и line_profiler
import cProfile
import pandas as pd
import numpy as np
def data_pipeline(n_rows=500_000):
"""Имитация пайплайна обработки данных."""
# Генерация данных
df = pd.DataFrame({
'user_id': np.random.randint(1, 50000, n_rows),
'session_duration': np.random.exponential(300, n_rows),
'pages_viewed': np.random.poisson(5, n_rows),
'purchase_amount': np.random.exponential(100, n_rows) * np.random.binomial(1, 0.1, n_rows),
'device': np.random.choice(['mobile', 'desktop', 'tablet'], n_rows, p=[0.6, 0.3, 0.1])
})
# Обработка
df['is_purchaser'] = df['purchase_amount'] > 0
df['engagement_score'] = df['session_duration'] * df['pages_viewed']
# Агрегация
user_stats = df.groupby('user_id').agg(
total_purchases=('purchase_amount', 'sum'),
avg_session=('session_duration', 'mean'),
visit_count=('user_id', 'count'),
conversion_rate=('is_purchaser', 'mean')
).reset_index()
return user_stats
# Профилирование через магическую команду
%prun -s cumulative data_pipeline()
Оптимизация памяти pandas
При работе с большими датасетами оптимизация типов данных — это не роскошь, а необходимость. Вот функция, которую я использую практически в каждом проекте:
import pandas as pd
import numpy as np
def optimize_dataframe(df):
"""Оптимизирует типы данных DataFrame для экономии памяти."""
start_mem = df.memory_usage(deep=True).sum() / 1024**2
for col in df.columns:
col_type = df[col].dtype
if col_type == 'object':
# Категориальные данные с малым числом уникальных значений
num_unique = df[col].nunique()
num_total = len(df[col])
if num_unique / num_total < 0.5:
df[col] = df[col].astype('category')
elif col_type in ['int64', 'int32']:
# Понижение точности целых чисел
c_min, c_max = df[col].min(), df[col].max()
if c_min >= 0:
if c_max < 255:
df[col] = df[col].astype(np.uint8)
elif c_max < 65535:
df[col] = df[col].astype(np.uint16)
elif c_max < 4294967295:
df[col] = df[col].astype(np.uint32)
else:
if c_min > -128 and c_max < 127:
df[col] = df[col].astype(np.int8)
elif c_min > -32768 and c_max < 32767:
df[col] = df[col].astype(np.int16)
elif c_min > -2147483648 and c_max < 2147483647:
df[col] = df[col].astype(np.int32)
elif col_type == 'float64':
df[col] = df[col].astype(np.float32)
end_mem = df.memory_usage(deep=True).sum() / 1024**2
print(f'Память: {start_mem:.1f} МБ → {end_mem:.1f} МБ '
f'(сокращение на {100 * (start_mem - end_mem) / start_mem:.1f}%)')
return df
# Пример использования
df = pd.DataFrame({
'id': np.random.randint(0, 10000, 1_000_000),
'category': np.random.choice(['cat_a', 'cat_b', 'cat_c'], 1_000_000),
'value': np.random.randn(1_000_000),
'flag': np.random.randint(0, 2, 1_000_000)
})
df_optimized = optimize_dataframe(df)
# Вывод: Память: 42.6 МБ → 6.8 МБ (сокращение на 84.0%)
84% экономии памяти — и это на простом примере. На реальных данных бывает ещё внушительнее.
Чтение данных чанками
Когда датасет не влезает в память, читайте его по частям:
# Обработка CSV по частям
chunk_results = []
for chunk in pd.read_csv('huge_dataset.csv', chunksize=100_000):
# Обработка каждого чанка
result = chunk.groupby('category')['amount'].agg(['sum', 'count'])
chunk_results.append(result)
# Объединяем результаты
final_result = pd.concat(chunk_results).groupby(level=0).sum()
final_result['mean'] = final_result['sum'] / final_result['count']
Автоматизированный EDA с ydata-profiling
Если вам лень (или некогда) писать EDA руками — ydata-profiling сделает это за вас. Одна строчка — и готов полноценный отчёт:
# pip install ydata-profiling
from ydata_profiling import ProfileReport
import pandas as pd
df = pd.read_csv('dataset.csv')
# Генерация полного отчёта
profile = ProfileReport(
df,
title='Анализ датасета',
explorative=True,
dark_mode=True
)
# Отображение в ноутбуке
profile.to_notebook_iframe()
# Или сохранение в HTML
profile.to_file('data_report.html')
В отчёте — статистики по каждому столбцу, корреляции, пропуски, дубликаты и интерактивные визуализации. Для больших датасетов добавьте minimal=True, чтобы не ждать вечность.
Marimo как альтернатива: стоит ли переходить?
Итак, поговорим о слоне в комнате. Marimo — реактивный ноутбук нового поколения, и в 2025–2026 его обсуждают буквально везде. Давайте разберёмся, когда он действительно лучше.
Реактивная модель выполнения
Главная фишка Marimo — реактивность. Меняете значение в одной ячейке, и все зависимые ячейки пересчитываются автоматически. Это решает одну из самых болезненных проблем Jupyter — скрытое состояние, когда результат зависит от порядка выполнения ячеек, а не от их расположения.
# В Marimo изменение переменной x автоматически
# пересчитает все ячейки, использующие x
# Ячейка 1
x = mo.ui.slider(1, 100, value=50, label="Количество точек")
# Ячейка 2 — автоматически обновится при движении ползунка
import numpy as np
data = np.random.randn(x.value, 2)
mo.md(f"Сгенерировано {len(data)} точек")
Хранение в формате .py
Marimo сохраняет ноутбуки как обычные .py файлы. Для Git это подарок — нормальные diff, понятные merge-конфликты. Для сравнения: diff ноутбуков Jupyter в .ipynb — это нечитаемое месиво JSON. Если вы когда-нибудь пытались ревьюить .ipynb на GitHub, вы понимаете, о чём я.
Когда использовать Marimo, а когда Jupyter
| Критерий | JupyterLab | Marimo |
|---|---|---|
| Экосистема расширений | Огромная, зрелая | Растущая, но ограниченная |
| Воспроизводимость | Требует дисциплины | Встроена в архитектуру |
| Git-дружественность | Плохая (JSON) | Отличная (.py) |
| Интерактивные виджеты | ipywidgets (зрелые) | Встроенные (mo.ui) |
| Поддержка языков | Python, R, Julia, 40+ | Только Python |
| Командная работа | JupyterHub, Binder | Ограничена |
| Деплой как приложение | Voilà, Panel | Встроенный (marimo run) |
| Скрытое состояние | Частая проблема | Невозможно |
Текущие ограничения Marimo
При всех плюсах, есть ряд моментов, которые нужно учитывать:
- Только Python — нет ядер для R, Julia и других языков
- Экосистема расширений пока значительно скромнее
- Нет аналога JupyterHub для корпоративного развёртывания
- Миграция существующих Jupyter-ноутбуков может потребовать серьёзной переработки
- Реактивность иногда играет злую шутку — случайно дёрнули параметр, и пошла цепочка тяжёлых пересчётов
- Менее развитая поддержка удалённых вычислительных ресурсов
Мой совет: используйте Marimo для интерактивных отчётов и небольших проектов, где важна воспроизводимость. Для основной работы — ML-экспериментов, командных проектов, тяжёлого анализа — JupyterLab пока остаётся более надёжным выбором.
Лучшие практики работы с Jupyter
Ноутбуки часто ругают за то, что они «поощряют спагетти-код». И отчасти это справедливо. Но при правильном подходе JupyterLab — отличный инструмент для создания воспроизводимых проектов.
Модульная структура ноутбуков
Каждый ноутбук должен иметь чёткую структуру. Это не занудство — это спасение, когда вы откроете свой ноутбук через три месяца:
# Рекомендуемая структура ноутбука:
# 1. Заголовок и описание (Markdown)
# 2. Импорт библиотек
# 3. Конфигурация и константы
# 4. Загрузка данных
# 5. Исследовательский анализ (EDA)
# 6. Предобработка
# 7. Моделирование / Анализ
# 8. Визуализация результатов
# 9. Выводы (Markdown)
# Пример первых ячеек:
# --- Ячейка 1: Импорты ---
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from pathlib import Path
# --- Ячейка 2: Конфигурация ---
DATA_DIR = Path('../data/raw/')
OUTPUT_DIR = Path('../data/processed/')
RANDOM_STATE = 42
TARGET_COLUMN = 'target'
plt.style.use('seaborn-v0_8-whitegrid')
pd.set_option('display.max_columns', 50)
Воспроизводимость окружения
Фиксируйте зависимости. Всегда. Будущий вы скажет спасибо:
# Генерация requirements.txt
pip freeze > requirements.txt
# Или более избирательно — только явно установленные пакеты
pip install pipreqs
pipreqs . --force
# environment.yml для conda
name: ds-project
channels:
- conda-forge
- defaults
dependencies:
- python=3.12
- jupyterlab=4.5
- pandas=2.2
- numpy=2.1
- scikit-learn=1.6
- matplotlib=3.10
- seaborn=0.13
- pip:
- ydata-profiling
- jupyter-ai
Когда выносить код в .py-модули
Извлекайте код в отдельные модули, когда:
- Функция нужна в нескольких ноутбуках
- Функция достаточно сложна и требует тестирования
- Код готов к продакшену
- Ноутбук стал слишком длинным и нечитаемым
# src/features.py
import pandas as pd
import numpy as np
def create_time_features(df: pd.DataFrame, date_col: str = 'date') -> pd.DataFrame:
"""Создаёт временные признаки из столбца с датой."""
df = df.copy()
df[date_col] = pd.to_datetime(df[date_col])
df['day_of_week'] = df[date_col].dt.dayofweek
df['month'] = df[date_col].dt.month
df['quarter'] = df[date_col].dt.quarter
df['is_weekend'] = df['day_of_week'].isin([5, 6]).astype(int)
df['day_of_year'] = df[date_col].dt.dayofyear
return df
def compute_rfm(df: pd.DataFrame, user_col: str, date_col: str,
amount_col: str, reference_date=None) -> pd.DataFrame:
"""Вычисляет RFM-метрики для каждого пользователя."""
if reference_date is None:
reference_date = df[date_col].max() + pd.Timedelta(days=1)
rfm = df.groupby(user_col).agg(
recency=(date_col, lambda x: (reference_date - x.max()).days),
frequency=(date_col, 'count'),
monetary=(amount_col, 'sum')
).reset_index()
return rfm
# В ноутбуке:
import sys
sys.path.insert(0, '../src')
from features import create_time_features, compute_rfm
df = pd.read_csv('../data/raw/transactions.csv')
df = create_time_features(df)
rfm = compute_rfm(df, 'user_id', 'date', 'amount')
Экспорт ноутбуков с nbconvert
Утилита nbconvert конвертирует ноутбуки в разные форматы — HTML, PDF, скрипты:
# Конвертация в HTML
jupyter nbconvert --to html analysis.ipynb
# Конвертация в PDF (требуется LaTeX)
jupyter nbconvert --to pdf analysis.ipynb
# Конвертация в Python-скрипт
jupyter nbconvert --to script analysis.ipynb
# Выполнение ноутбука и сохранение с результатами
jupyter nbconvert --execute --to notebook --output executed_analysis.ipynb analysis.ipynb
# Конвертация без кода (только результаты) — отлично для отчётов
jupyter nbconvert --to html --no-input analysis.ipynb
Стратегии контроля версий
Работа с ноутбуками в Git — отдельная боль. Но есть проверенные подходы.
1. Очистка выходных данных перед коммитом:
# Установка nbstripout — автоматическая очистка выводов при коммите
pip install nbstripout
nbstripout --install # Устанавливает git-фильтр для текущего репозитория
# Теперь при git add *.ipynb выводы ячеек автоматически удаляются
2. Jupytext для парного хранения:
# pip install jupytext
# Jupytext автоматически синхронизирует .ipynb с .py файлом
# Настройка в jupyter_lab_config.py или jupytext.toml:
# formats = "ipynb,py:percent"
# Результат: каждый ноутбук хранится и как .ipynb, и как .py
# В git отслеживается .py (читаемый diff), а .ipynb добавляется в .gitignore
3. Правильный .gitignore:
# .gitignore для проекта с ноутбуками
*.ipynb_checkpoints/
data/raw/* # Исходные данные не коммитим
data/processed/* # Обработанные данные тоже
!data/raw/.gitkeep
!data/processed/.gitkeep
.env
__pycache__/
*.pyc
4. Рецензирование ноутбуков: попробуйте ReviewNB — инструмент для визуального code review ноутбуков на GitHub. Показывает ноутбуки в отрендеренном виде вместо raw JSON. Заметно упрощает ревью.
Ещё несколько рекомендаций
- Перезапускайте ядро и выполняйте все ячейки (Kernel → Restart & Run All) перед финальным сохранением — это проверка на воспроизводимость
- Нумеруйте ноутбуки:
01_data_loading.ipynb,02_eda.ipynb,03_modeling.ipynb - Забудьте об абсолютных путях — используйте
pathlib.Pathи относительные пути - Документируйте решения в Markdown-ячейках: почему выбран этот подход, какие альтернативы рассматривали
- Устанавливайте random seed везде, где есть стохастика
- Если ноутбук больше 30–40 ячеек — подумайте о разделении или выносе логики в модули
Заключение
JupyterLab 4.5 в 2026 году — зрелый и мощный инструмент, который заслуженно остаётся стандартом индустрии. Режим contentVisibility, ИИ-интеграция через jupyter-ai, subshell-консоли — всё это делает его ещё удобнее для повседневной работы.
Что стоит вынести из этого руководства:
- Установка — виртуальные окружения и правильная структура проекта с первого дня
- Магические команды —
%timeit,%prun,%memit,%debug— ваш ежедневный арсенал - ipywidgets — превращают ноутбуки в интерактивные инструменты без написания UI
- ИИ-интеграция — jupyter-ai и
%%aiреально ускоряют работу - Расширения — jupyterlab-git, jupyterlab-lsp, jupyterlab-execute-time — поставьте первым делом
- Профилирование — регулярно профилируйте и оптимизируйте типы данных
- Marimo — следите за проектом, но для большинства задач JupyterLab пока надёжнее
- Практики — модульность, воспроизводимость, грамотный Git — основа профессионализма
Экосистема Jupyter продолжает развиваться — коллаборативное редактирование в реальном времени, интеграция с облаком, расширение ИИ-возможностей. Навыки работы с JupyterLab останутся актуальными ещё очень долго.
Так что ставьте JupyterLab 4.5, настраивайте расширения, подключайте jupyter-ai — и ваша продуктивность выйдет на новый уровень. Удачи!