JupyterLab 4.5 в 2026: практическое руководство для дата-сайентиста

Полное практическое руководство по JupyterLab 4.5 для дата-сайентистов — от установки и магических команд до ИИ-интеграции, профилирования кода и лучших практик работы с ноутбуками.

Введение

Давайте будем честны: в 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 — и ваша продуктивность выйдет на новый уровень. Удачи!

Об авторе Editorial Team

Our team of expert writers and editors.