Я пришел в Data Science не сразу. Учился в магистратуре по вечерам, работая в совершенно другой сфере (строительство). Осваивать машинное обучение и анализ данных было интересно, но один из самых неожиданных вопросов, который возник буквально сразу - в какой среде писать код?

На первый взгляд кажется, что Jupyter Notebook, Google Colab, Kaggle и сравнительно новая Marimo - это одно и то же, ноутбук с ячейками и Python (так же поддерживаются другие языки программирования). Но на практике каждая из этих сред подходит для разных задач, где-то удобнее учиться, а где-то работать командой.

Эта статья - результат моего практического сравнения сред, которое я проводил во время обучения и выполнения исследовательских задач, связанных с анализом и подготовкой данных, моделированием и машинным обучением.

Статья будет полезна:

  • начинающим специалистам, выбирающим инструмент для первых проектов;

  • студентам и исследователям;

  • тем, кто учится самостоятельно и хочет понимать, не «что популярно», а когда что использовать.

Я не претендую на экспертный вердикт - цель статьи не «выбрать лучшего», а показать особенности каждой среды и помочь другим избежать тех же вопросов, на которые мне пришлось тратить время. Более того, результат появление этой статьи на Хабре, работа цензора научного издания с формулировкой: «Рассматриваемый текст, это скорее некоторый набор демонстрационных примеров, которому место, например, в методичке к лабораторной работе или на Хабре».

Сравнение построено на выполнении одного и того же кода во всех средах, от базовых операций Python до задач оптимизации и машинного обучения. Это позволяет объективно оценить удобство, особенности интерфейса, работу с ресурсами и возможности для обучения и совместной работы.

Введение

Интерактивные вычислительные среды становятся стандартным инструментарием для исследователей в области науки о данных, искусственного интеллекта и машинного обучения. Данные платформы предоставляют интегрированные решения для написания, тестирования и совместного использования кода, а также визуализации результатов и коллаборации. В условиях возрастающей потребности в аналитике данных во всех отраслях критически важным становится обоснованный выбор вычислительной среды для решения конкретных задач, особенно в контексте ограниченного доступа к определенным программным продуктам. Правильно подобранная платформа может упростить рабочие процессы, повысить эффективность вычислений и улучшить взаимодействие между командами, что делает процесс отбора критически важным для профессионалов в этих областях.

Как проводился эксперимент

Для сравнения во всех средах выполнялся один и тот же код, включающий:

  1. Основные операции Python (циклы, условия, типы данных);

  2. NumPy и структуры данных;

  3. Визуализация (Matplotlib, Seaborn);

  4. Численные вычисления;

  5. Оптимизационные задачи (PuLP и SciPy);

  6. Машинное обучение (SVM, Decision Trees, генетические алгоритмы);

  7. Моделирование цепей Маркова (моделирование эффективности продаж).

Для измерения времени выполнения использовал модуль time.

На каждой платформе создавался новый ноутбук, за исключением сред Google Colab и Kaggle для которых был импортирован предварительно подготовленный ноутбук из Jupyter Notebook с необходимыми модификациями для обеспечения совместимости с поддерживаемыми версиями библиотек.

Экспериментальный набор кода был применен для отражения различных аспектов применения интерактивных сред в современных образовательных и исследовательских задачах:

1.Основы программирования. Основные операции Python (переменные, циклы, условия), структуры данных (списки, словари) - эти элементы составляют основу обучения программированию, позволяя новичкам постичь синтаксис, логику и алгоритмическое мышление.

Рисунок 1. Ошибка повторного использования переменной в среде Marino
Рисунок 1. Ошибка повторного использования переменной в среде Marino

Например, реактивность Marimo предоставляет мгновенную визуальную обратную связь (Рисунок 1. Ошибка повторного использования переменной в среде Marino). Выполнение задач в Jupyter Notebook на основе ячеек позволяет постепенно углублять понимание, а постоянное хранение данных в Google Colab через интеграцию с Google Drive гарантирует, что работа не будет потеряна между сессиями. Встроенная система подсказок Kaggle обеспечивает контекстную помощь новичкам, испытывающим трудности с логическими конструкциями.

2.Работа с данными. Понимание данных имеет решающее значение в эпоху, когда доминирует принятие решений на основе данных (Рисунок  2. Пример визуализации данных).

Скрытый текст
import numpy as np
import matplotlib.pyplot as plt

# Генерация данных
y_rand = 200 + 50 * np.random.randn(100)
x = np.arange(len(y_rand))
median_val = np.median(y_rand)  # Вычисляем медиану

# График и заливка
plt.plot(x, y_rand, 'b-', label='Случайные данные')
plt.axhline(median_val, color='gray', linestyle='--', label='Медиана')

# Закрашиваем только верхнюю половину
plt.fill_between(x, y_rand, median_val, 
                where=(y_rand > median_val),
                color='lightgreen', alpha=0.5,
                label='Верхние отклонения')

# Оформление
plt.title('Закрашена верхняя половина отклонений')
plt.xlabel('Индекс')
plt.ylabel('Значение')
plt.legend()
plt.grid(True)
plt.show()
Рисунок  2. Пример визуализации данных.
Рисунок  2. Пример визуализации данных.

3.Решение вычислительных задач. Оценивались возможности сред для выполнения численных вычислений, оптимизации и задач машинного обучения, включая метод опорных векторов и деревья решений (Рисунок  3. Визуализация применения метода опорных векторов (SVM)).

Выявлено преимущество Kaggle в доступе к решениям сообщества содержащих множество примеров и соревнований по сравнению с изолированными средами.

Скрытый текст
import numpy as np
from matplotlib import pyplot as plt
from scipy.optimize import minimize

# Генерация данных
no_samples = 30
np.random.seed(42)  # Для воспроизводимости результатов

# Температура в режиме отказа
temp_readings_failure = 7 * np.random.random_sample((no_samples, 1)) + 29
rpms_failure = 400 * np.random.random_sample((no_samples, 1)) + 2900

# Температура в нормальном режиме
temp_readings_normal = 7 * np.random.random_sample((no_samples, 1)) + 22
rpms_normal = 400 * np.random.random_sample((no_samples, 1)) + 2500

# Подготовка данных для оптимизации (Добавляем столбец единиц для intercept term (theta_0))
X_failure = np.hstack([np.ones((no_samples, 1)), temp_readings_failure, rpms_failure])
X_normal = np.hstack([np.ones((no_samples, 1)), temp_readings_normal, rpms_normal])

# Целевая функция для минимизации (норма вектора theta)
def objective_func(theta):
    return 0.5 * np.sum(theta[1:]**2)  # Игнорируем theta_0 в регуляризации

# Ограничения для классификации
failure_linear_constraints = {
    'type': 'ineq',
    'fun': lambda theta: X_failure @ theta - 1  # y_i(w·x_i + b) >= 1
}

normal_linear_constraints = {
    'type': 'ineq',
    'fun': lambda theta: -X_normal @ theta - 1  # -y_i(w·x_i + b) >= 1
}

# Начальное приближение
theta_hat_0 = np.array([1.0, -57, 4452])

# Оптимизация
linear_constraint = [failure_linear_constraints, normal_linear_constraints]
res = minimize(objective_func, theta_hat_0, constraints=linear_constraint,
               options={"maxiter": 1000, "disp": True})

theta_prime = res.x
print("Оптимальные параметры:", theta_prime)

# Визуализация
fig, ax = plt.subplots(figsize=(10, 6))

# Отображение данных
ax.scatter(temp_readings_failure, rpms_failure, color='red', label='Режим отказа')
ax.scatter(temp_readings_normal, rpms_normal, color='blue', label='Нормальный режим')

# Построение разделяющей гиперплоскости
t = np.linspace(22, 37, 100)
# Уравнение: theta_0 + theta_1*t + theta_2*r = 0 => r = (-theta_0 - theta_1*t)/theta_2
r_mms = (-theta_prime[0] - theta_prime[1]*t) / theta_prime[2]

# Границы зазора (margin)
r_mms_max = (-theta_prime[0] - theta_prime[1]*t + 1) / theta_prime[2]
r_mms_min = (-theta_prime[0] - theta_prime[1]*t - 1) / theta_prime[2]

# Построение линий
ax.plot(t, r_mms, 'k-', label='Разделяющая гиперплоскость')
ax.plot(t, r_mms_max, 'k--', label='Граница зазора')
ax.plot(t, r_mms_min, 'k--')

# Настройки графика
ax.set_xlim(21, 37)
ax.set_ylim(2300, 3300)
ax.set_xlabel('$x_1$ (температура в °C)')
ax.set_ylabel('$x_2$ (скорость двигателя в RPM)')
ax.set_title('Классификация состояния двигателя методом SVM')
ax.legend()
ax.grid(True)

plt.tight_layout()
plt.show()

# Проверка минимального расстояния до гиперплоскости
min_distance_failure = np.min(X_failure @ theta_prime)
min_distance_normal = np.min(-X_normal @ theta_prime)
print(f"Минимальное расстояние для класса 'отказ': {min_distance_failure:.2f}")
print(f"Минимальное расстояние для класса 'норма': {min_distance_normal:.2f}")
Рисунок  3. Визуализация применения метода опорных векторов (SVM)
Рисунок  3. Визуализация применения метода опорных векторов (SVM)

4.Моделирование для прикладных исследований. Тестирование включало реализацию генетических алгоритмов и моделирование цепей Маркова.

Отмечены преимущества реактивного интерфейса Marimo для интерактивного моделирования, стабильность сред выполнения Google Colab и система контроля версий Kaggle (Рисунок 4. Визуализация применения генетического алгоритма для решения головоломки Судоку).

Скрытый текст
import numpy as np
from datetime import datetime
from matplotlib import pyplot as plt
from random import sample

# Исходное судоку (0 - пустые клетки)
problem = np.array([
    [8, 0, 6, 2, 0, 9, 0, 1, 5],
    [9, 5, 0, 3, 0, 8, 7, 0, 0],
    [4, 0, 0, 1, 0, 0, 3, 0, 9],
    [7, 9, 3, 4, 8, 5, 0, 0, 0],
    [0, 0, 0, 7, 0, 0, 0, 0, 4],
    [0, 8, 4, 6, 0, 3, 9, 5, 7],
    [0, 0, 0, 0, 3, 4, 2, 0, 0],
    [3, 0, 9, 0, 0, 0, 1, 0, 8],
    [6, 0, 7, 0, 2, 0, 0, 0, 3]
])

# Индексы заданных значений и пустых клеток
clues_idx = np.nonzero(problem)
gaps_idx = np.nonzero(problem == 0)

# Подсчет количества каждой цифры в исходном судоку
digit_count = np.bincount(problem.flatten(), minlength=10)
problem_size = len(gaps_idx[0])  # Количество пустых клеток

# Гиперпараметры алгоритма
in_chromosome_size = problem_size - 2
population_size = 500
num_iter = 1000
num_survivals = 10
reset_it = 10

# Определение недостающих цифр
digits = np.arange(1, 10)
missing_count = 9 - digit_count[1:]  # Игнорируем счетчик для 0

# Создание массива недостающих цифр
candidate_digits = np.array([], dtype='int32')
for digit in digits:
    candidate_digits = np.append(candidate_digits, np.repeat(digit, missing_count[digit-1]))

# Функция проверки, является ли набор перестановкой цифр 1-9
def is_permutation(elements):
    return 9 - len(np.unique(elements))

# Функция оценки решения
def fitness(solution):
    res = 0
    # Проверка строк
    for i in range(9):
        res += is_permutation(solution[i])
    
    # Проверка столбцов
    for j in range(9):
        res += is_permutation(solution[:, j])
    
    # Проверка блоков 3x3
    for k in range(9):
        row_index = 3 * (k // 3)
        col_index = 3 * (k % 3)
        res += is_permutation(solution[row_index:row_index+3, col_index:col_index+3])
    
    # Проверка на наличие нулей
    res += np.sum(solution == 0)
    return res

# Инициализация популяции
genome = np.zeros((population_size, 9, 9), dtype='int32')
for k in range(population_size):
    np.random.shuffle(candidate_digits)
    genome[k, :, :] = np.copy(problem)
    np.place(genome[k, :, :], genome[k, :, :] == 0, candidate_digits)

# Основной цикл алгоритма
init_time = datetime.now()
iteration_error = np.zeros(num_iter)
it = 0

while it < num_iter:
    # Оценка приспособленности
    fitness_array = np.array([fitness(genome[k]) for k in range(population_size)])
    
    # Отбор лучших решений
    fittest = np.argsort(fitness_array)[:num_survivals]
    iteration_error[it] = fitness_array[fittest[0]]
    
    # Проверка на нахождение решения
    if fitness_array[fittest[0]] == 0:
        break
    
    # Проверка на зацикливание
    if it >= reset_it and np.all(iteration_error[it-reset_it:it] == iteration_error[it]):
        # Реинициализация популяции
        candidate_digits = np.concatenate([np.repeat(digit, missing_count[digit-1]) for digit in digits])
        for k in range(population_size):
            np.random.shuffle(candidate_digits)
            genome[k, :, :] = np.copy(problem)
            np.place(genome[k, :, :], genome[k, :, :] == 0, candidate_digits)
        continue
    
    # Создание нового поколения
    new_genome = np.zeros_like(genome)
    for k in range(population_size):
        parent_a = genome[np.random.choice(fittest)]
        parent_b = genome[np.random.choice(fittest)]
        
        # Создание потомка
        child = np.copy(problem)
        mask = np.random.random(size=(9,9)) > 0.5
        child[gaps_idx] = np.where(mask[gaps_idx], parent_a[gaps_idx], parent_b[gaps_idx])
        
        # Мутация
        if np.random.random() < 0.1:
            swap_pos = np.random.choice(len(candidate_digits), 2, replace=False)
            child[gaps_idx[0][swap_pos[0]], gaps_idx[1][swap_pos[0]]], \
            child[gaps_idx[0][swap_pos[1]], gaps_idx[1][swap_pos[1]]] = \
            child[gaps_idx[0][swap_pos[1]], gaps_idx[1][swap_pos[1]]], \
            child[gaps_idx[0][swap_pos[0]], gaps_idx[1][swap_pos[0]]]
        
        new_genome[k] = child
    
    genome = new_genome
    it += 1

# Вывод результатов
end_time = datetime.now()
duration = end_time - init_time
sol = genome[fittest[0]]
print(f"Решение найдено за {duration.total_seconds():.2f} секунд и {it} итераций:")
print(sol)

# Визуализация сходимости
plt.figure(figsize=(10, 5))
plt.plot(iteration_error[:it])
plt.xlabel('Итерация')
plt.ylabel('Ошибка')
plt.title('Сходимость генетического алгоритма')
plt.grid(True)
plt.show()
Рисунок 4. Визуализация применения генетического алгоритма для решения головоломки Судоку
Рисунок 4. Визуализация применения генетического алгоритма для решения головоломки Судоку
Рисунок 4. Визуализация применения генетического алгоритма для решения головоломки Судоку
Рисунок 4. Визуализация применения генетического алгоритма для решения головоломки Судоку

5. Интеграция образовательных и исследовательских функций.  

Kaggle предлагает соревновательный подход и предоставляет уникальный и мощный механизм для обучения через свои структурированные пути. Этот комплекс взаимосвязанных возможностей создает направленную среду для самостоятельного освоения Data Science, включая иерархию соревнований, интерактивные курсы, наборы данных с задачами, сообщество и обмен знаниями, а также систему достижений и прогресса. Google Colab обеспечивает доступность облачных ресурсов и имеет минимальный порог входа, что делает его особенно привлекательным для новичков. Jupyter отличается гибкостью и расширяемостью. Несмотря на то, что требования к установке могут создавать первые трудности, эта платформа предлагает более широкие возможности настройки под конкретные исследовательские нужды. Marimo демонстрирует когнитивную эффективность благодаря инновационному интерфейсу, который поначалу может смущать пользователей. Однако он показывает значительно более быстрые кривые освоения, особенно для новичков, из-за своей реактивности по сравнению с традиционными блокнотами.

При выборе платформы следует учитывать не только технические требования, но и конкретные стили обучения и потребности целевых пользователей в доступности (Рисунок  5. Пример визуализации синтетических данных, имитирующих показания датчиков двигателя).

Скрытый текст
import numpy as np
import matplotlib.pyplot as plt

n_samples = 500
centers = [(25, 25), (33, 32)]  # Центры кластеров
X, y = make_blobs(n_samples=n_samples, centers=centers, cluster_std=1.5, random_state=42)

# Определение необходимых переменных
y_unique = np.unique(y)  # Уникальные классы
colors = ['blue', 'red']  # Цвета для каждого класса

# Создаем фигуру для графика
plt.figure(figsize=(10, 6))

# Проходим по каждому классу и строим точки
for this_y, color in zip(y_unique, colors):
    this_X = X[y == this_y]  # Выбираем точки текущего класса
    plt.scatter(
        this_X[:, 0],  # Температура по оси X
        this_X[:, 1],  # RPM по оси Y
        c=color,
        alpha=0.5,
        edgecolor="k",
        label=f"Класс {this_y}",
        s=30
    )

# Создаем разделительные линии и заливку
x = np.linspace(20, 37, 1000)
sep1 = 0*x + 29  # Верхняя граница
sep2 = 0*x + 20  # Нижняя граница
sep3 = 0*x + 37  # Верхняя граница расширенная

# Заливка областей
plt.fill_between(x, sep1, sep2, where=x<=30, alpha=0.1, color=colors[0], label='Нормальный режим')
plt.fill_between(x, sep3, sep1, where=x<=30, alpha=0.1, color=colors[1], label='Режим отказа')
plt.fill_between(x, sep3, sep2, where=x>30, alpha=0.1, color=colors[1])

# Настройки графика
plt.legend(loc="best")
plt.ylabel('Скорость двигателя (об/мин / 1000)')
plt.xlabel('Температура (°C)')
plt.title("Показания датчиков двигателя")
plt.grid(True, linestyle='--', alpha=0.5)
plt.xlim(20, 37)
plt.ylim(20, 37)

plt.tight_layout()
plt.show()
Рисунок  5. Пример визуализации синтетических данных, имитирующих показания датчиков двигателя
Рисунок  5. Пример визуализации синтетических данных, имитирующих показания датчиков двигателя

6.Производительность и технические компромиссы.

Google Colab и Kaggle предоставляют доступ к облачным GPU, включая возможность платного расширения ресурсов, при этом на бесплатной сессии имеются таймауты сессий и ограничения GPU. Jupyter Notebook, Marimo поддерживает работу GPU.

7.Совместная работа.

Google Colab и Kaggle демонстрируют превосходные возможности для реализации совместной работы в реальном времени. Jupyter Notebook требует дополнительной настройки и использования Git для контроля версий. Экосистема Kaggle способствует обмену знаниями через публичные блокноты. Исходя из этого следует, что Colab и Kaggle способствуют более частым итерациям и обмену кодом, а Jupyter и Marimo - более глубокому индивидуальному исследованию.

8. Специализация сред.

Каждая платформа демонстрирует преимущества в определенных областях. Jupyter Notebook преимущественно используется для академических исследований, требующих обширной документации и воспроизводимости, и необходимость изолированной исследовательской работы. Доступу к GPU Google Colab и Kaggle является предпочтительной средой для приложений глубокого обучения, особенно для задач компьютерного зрения и обработки естественного языка. Kaggle предоставляет практическое обучение и обмен опытом. Реактивный подход Marimo имеет уникальные преимущества для интерактивных панелей и исследовательского анализа данных (например, эпидемиологическое моделирование).

9. Адаптивность к будущему и новые технологии.

Каждая платформа позволяет пользователям адаптироваться к появляющимся вычислительным методам и обстоятельствам. Богатая экосистема Google предоставляет пользователям Google Colab уникальную гибкость и доступ к широкому спектру встроенных сервисов. Тенденция к усилению взаимосвязи сервисов в экосистеме будет сохраняться. Новые архитектуры на подобие Marimo показали перспективы для приложений с реактивными данными, которые стирают грань между блокнотами и интерактивными приложениями. При выборе платформы должно учитываться не только текущие требования, но и траектории развития своей области, при этом подходы со смешанными средами часто обеспечивают оптимальный баланс между стабильностью и инновационным потенциалом.

Результаты тестирования продемонстрировали, что исследуемые среды не являются прямыми конкурентами, а предлагают взаимодополняющие функциональные возможности для различных контекстов использования. Ни одна среда не является идеальной - выбор зависит от требований проекта, размера команды и аппаратных ограничений.

Особенности, которые проявились в процессе:

Jupyter Notebook - это классика, стандарт де-факто.

Плюсы:

  • Работает локально и нет ограничений по времени;

  • Полный контроль над окружением;

  • Удобно документировать и писать «исследовательский код».

Минусы:

  • установка окружений, зависимостей, библиотек может быть болезненнее, чем «просто открыть Colab»;

  • Если железо слабое, то ограничения по моделям.

Использую когда нужно глубокое исследование, контроль над зависимостями и конфиденциальность данных.

Google Colab - лучший старт при отсутствии мощного железа и необходимости функционала "из коробки".

Плюсы:

  • Бесплатные GPU/TPU;

  • Легкая интеграция с Google Drive;

  • Поддерживает подключение датасетов с Kaggle;

  • Agent на базе Gemini, который помогает с рутиной.

Минусы:

  • Сессия может прерваться;

  • Производительность GPU зависит от нагрузки на сервис;

Использую когда нужен GPU «здесь и сейчас» без оплаты сервера.

Kaggle Notebooks это не просто среда, это экосистема обучения и соревнований.

Плюсы:

  • Готовые датасеты;

  • Обучающие курсы;

  • Публичные ноутбуки с решениями;

  • Соревнования;

  • Можно не только писать код, но и сравнивать себя с другими - очень мотивирует.

Минусы:

  • Сессия может прерваться;

  • Производительность GPU зависит от нагрузки на сервис;

  • Больше порог входа.

Kaggle лучше для обучения на реальных задачах и анализа чужих решений.

Marimo - самая необычная платформа в списке.

Плюсы:

  • Подходит для интерактивных отчетов и визуализаций;

  • Удобен для демонстрации результатов;

  • Встроенный SQL.

Минусы:

  • Если переопределить переменную в другой ячейке, то будет ошибка (за исключением создания локальной переменной путем добавления "_" к имени переменной);

  • Экспорт интерактивных элементов в PDF/HTML требует дополнительной обработки

Использую когда нужно исследовать данные динамически, а не «последовательно сверху вниз».

Резюмируя, если вы входите в Data Science:

  1. Начните с Kaggle или Colab.

  2. Переходите в Jupyter когда необходима локализация (изолированная среда или отсутствует интернет).

  3. Попробуйте Marimo, если хотите строить живые аналитические панели.

Комментарии (0)