Команда Python for Devs подготовила перевод статьи Клауса Вилке о том, почему Python, несмотря на статус языка №1 в data science, вовсе не идеален для анализа данных. Автор показывает на реальных примерах из лабораторной практики, что многие операции в Python оказываются куда более громоздкими, чем в R, — и это не вина программистов, а архитектурные особенности инструментов.
Возможно, Python неплохой язык для data science, но точно не отличный.
Да, я готов разворошить осиное гнездо! Свистать всех в комментарии!
Но на самом деле первое, что я хочу сказать, — вот что: используйте инструмент, который вам знаком. Если это Python — прекрасно, используйте его. И ещё: используйте лучший инструмент для конкретной задачи. Если это Python — отлично, используйте его. И ещё: вполне нормально использовать инструмент для какой-то одной задачи только потому, что вы и так применяете его для множества других и он всегда под рукой. Если вы целый день забиваете гвозди, ничего страшного, если вы тем же молотком открываете бутылку пива или почесываете спину. Так же и с Python: если вы весь день программируете на Python, вполне нормально использовать его и для подбора смешанных линейных моделей. Если вам удобно — замечательно! Продолжайте. Но если вы спотыкаетесь на ровном месте, если всё кажется сложнее, чем должно быть, — эта серия статей может быть для вас.

Мне кажется, роль Python как языка для data science сильно переоценивают. У него есть ограничения, которые, на мой взгляд, нельзя игнорировать. Есть много задач data science, которые я с куда большим удовольствием делаю в R, а не в Python.1 Я считаю, что популярность Python в data science — это историческая случайность, усиленная тем, что он «вроде как неплох почти во всём», а не следствие его особой пригодности к работе с данными.
При этом Python, на мой взгляд, очень хорош для deep learning.2 Не зря PyTorch стал индустриальным стандартом. Когда я здесь говорю о data science, я специально исключаю deep learning. Речь про всё остальное: подготовку данных, разведочный анализ, визуализацию, статистическое моделирование и т. д. И, как я сказал в начале, я прекрасно понимаю, что если вы по веской причине весь день работаете в Python (например, обучаете AI-модели), то вам может захотеться делать в Python и всё остальное. Сам я поступаю так же, когда веду курсы по deep learning. Но это не отменяет того, что работа с данными в мире Python нередко оказывается мучительно громоздкой.
Наблюдения с передовой
Начну с личного опыта, без попыток объяснить, что именно его вызывает. Я руковожу исследовательской лабораторией в области вычислительной биологии уже больше двадцати лет. За это время я работал примерно с тридцатью аспирантами и постдоками — все они очень сильные специалисты по вычислительным методам. В моей лаборатории действует простой принцип: каждый волен пользоваться любым языком программирования и любыми инструментами. Я никому не указываю. И чаще всего люди выбирают Python как основной рабочий язык.
И вот типичная ситуация, которая повторяется снова и снова со студентами, использующими Python. Студент приходит ко мне в кабинет и показывает какой-то результат. Я говорю: «Отлично, а можешь быстро построить график немного по-другому?» или «Можешь быстро посчитать вот эту величину, которую я только что придумал, и показать, как она выглядит на графике?» или что-то в этом роде. Обычно я прошу о вещах, которые сам мог бы сделать в R за несколько минут. Примеры: преобразовать boxplot в violin plot или наоборот, превратить линейный график в тепловую карту, построить оценку плотности вместо гистограммы, выполнить вычисление не по исходным данным, а по ранжированным значениям и так далее. И неизменно студенты, работающие в Python, отвечают: «Это займёт какое-то время. Я вернусь к себе, разберусь и приду обратно». Чтобы не было недопонимания: это отличные студенты. Проблема не в том, что они плохо знают инструменты. Мне действительно кажется, что дело в самих инструментах. Они оказываются настолько громоздкими или запутанными, что даже элементарные просьбы часто перестают быть элементарными.3
Как бы ни объяснять этот феномен, я вынужден заключить: в том, как в Python устроена работа с данными, есть что-то фундаментально сломанное. Возможно, это особенности самого языка; возможно — ограничения библиотек; скорее всего — сочетание того и другого. Но как бы то ни было, последствия вполне реальные, и я сталкиваюсь с ними постоянно. Приведу ещё один пример, если вам вдруг захочется возразить: «Это проблема навыков — нужно брать студентов посильнее». Прошлой осенью я вёл курс по AI-моделям для биологии совместно с опытным дата-сайентистом, который делает всю свою работу в Python. Он знает NumPy, pandas и matplotlib как свои пять пальцев. На занятиях я читал теорию, а он разбирал практические упражнения — в Python. Так что я получил возможность наблюдать, как эксперт проходит через разнообразные примеры. И очень часто, глядя на код, я думал: «Зачем всё так усложнено?» Слишком часто то, что в R заняло бы несколько простых строк, в Python оказывалось куда более длинным и путаным. Я бы точно не смог написать такой код без основательного изучения и полной перенастройки мышления под необходимые шаблоны. Всё выглядело очень чуждым — но не в смысле «необычно, но изящно», а в смысле «необычно, странно и неудобно». И снова: дело не в том, что мой коллега недостаточно силён. Он исключительно хорош в своём деле. Похоже, проблема в архитектурных основах инструментов.
Некоторые общие мысли о том, каким должен быть хороший язык для data science
Давайте немного отступим и рассмотрим базовые критерии выбора языка для data science. Под data science я понимаю разбор и суммирование данных, поиск закономерностей, построение моделей и визуализаций. Короче говоря, то, чем занимаются учёные и другие исследователи4, когда анализируют данные. Эта деятельность отличается от data engineering’а или разработки приложений, даже если приложение обрабатывает большой объём данных.
Data science в моём определении предполагает много интерактивного исследования данных и быстрых разовых анализов или экспериментов. Поэтому язык, подходящий для data science, должен быть интерпретируемым, работать в интерактивной консоли или в формате ноутбуков. Это также означает, что производительность — вторична. Когда вы хотите быстро прогнать линейную регрессию на каком-то наборе данных, вам совершенно не важно, займёт задача 50 миллисекунд или 500 миллисекунд. Вам важно, сможете ли вы просто открыть оболочку, набрать несколько строчек кода и получить результат за минуту-другую, а не настраивать новый проект, писать тонны шаблонного кода ради компилятора и тратить больше времени на компиляцию, чем на выполнение.
Если принять, что возможность работать интерактивно и с минимальными накладными расходами — критически важное свойство языка для data science, то мы сразу приходим к скриптовым языкам вроде Python или специализированным языкам для анализа данных, таким как R, Matlab или Mathematica. Есть ещё Julia, но, честно говоря, я знаю о ней недостаточно, чтобы писать связно. Возможно, это лучший язык для data science из всех. Но я замечаю, что даже у людей, которые много на ней работали, есть сомнения. Так или иначе, обсуждать её я здесь не буду. Я также не рассматриваю проприетарные языки вроде Matlab или Mathematica и малоизвестные решения без развитой экосистемы пакетов, такие как Octave. В итоге остаются два реалистичных варианта — R и Python.5
Прежде чем идти дальше, скажу ещё пару слов о производительности. Производительность почти всегда конфликтует с другими свойствами языка. Если упростить, высокую производительность приходится оплачивать либо дополнительными усилиями программиста (как в Rust), либо повышенным риском странных, трудноуловимых багов (как в C), либо и тем и другим. Для задач data science высокий риск скрытых ошибок или некорректных результатов, на мой взгляд, недопустим, а удобство для программиста важнее сырой скорости. Компьютеры быстрые, а думать больно. Я лучше затрачу меньше умственной энергии на то, чтобы объяснить компьютеру, что нужно сделать, и подожду подольше результата. Чем легче язык делает мою работу, тем лучше. Если в каком-то анализе я действительно упираюсь в производительность, я всегда могу переписать конкретный участок на Rust — когда уже точно понимаю, что делаю и какие вычисления нужны.
Разделение логики и рутины
Критически важно не усложнять себе работу и уметь отделять логику анализа от логистики. Я имею в виду следующее: я хочу иметь возможность на концептуальном уровне описать, как именно должны быть проанализированы данные и какой результат должен получиться, и при этом не думать о том, как технически будут выполняться вычисления. Как правило, если мне нужно размышлять о типах данных, числовых индексах, циклах или вручную разбирать и собирать наборы данных — почти наверняка я вязну в рутине.6
Для наглядности возьмём датасет с пингвинами из архипелага Палмер. В нём есть три вида пингвинов, и живут они на трёх разных островах. Допустим, я хочу вычислить среднее и стандартное отклонение массы тела для каждой комбинации вида и острова, исключив случаи, где масса пингвина неизвестна. Идеальный язык для data science позволил бы выразить это именно в таких терминах и потребовал бы примерно столько же кода, сколько мне понадобилось для этого предложения по-английски. И это действительно возможно — и в R, и в Python.
Вот соответствующий код на R в стиле tidyverse:
library(tidyverse)
library(palmerpenguins)
penguins |>
filter(!is.na(body_mass_g)) |>
group_by(species, island) |>
summarize(
body_weight_mean = mean(body_mass_g),
body_weight_sd = sd(body_mass_g)
)
А вот эквивалент на Python с использованием pandas:
import pandas as pd
from palmerpenguins import load_penguins
penguins = load_penguins()
(penguins
.dropna(subset=['body_mass_g'])
.groupby(['species', 'island'])
.agg(
body_weight_mean=('body_mass_g', 'mean'),
body_weight_sd=('body_mass_g', 'std')
)
.reset_index()
)
Эти два примера очень похожи. При такой сложности анализа Python вполне справляется. Я бы сказал, что код на R немного легче читать (обратите внимание, сколько кавычек и скобок нужно Python), но разница невелика. В обоих случаях мы берём датасет, убираем пингвинов с неизвестной массой, указываем, что хотим делать вычисления по всем сочетаниям вида и острова, и затем считаем средние и стандартные отклонения.
Для контраста — эквивалентный код, полностью состоящий из рутины, где используются только базовые возможности Python, без специализированных библиотек для работы с данными:
from palmerpenguins import load_penguins
import math
penguins = load_penguins()
# Convert DataFrame to list of dictionaries
penguins_list = penguins.to_dict('records')
# Filter out rows where body_mass_g is missing
filtered = [row for row in penguins_list if not math.isnan(row['body_mass_g'])]
# Group by species and island
groups = {}
for row in filtered:
key = (row['species'], row['island'])
if key not in groups:
groups[key] = []
groups[key].append(row['body_mass_g'])
# Calculate mean and standard deviation for each group
results = []
for (species, island), values in groups.items():
n = len(values)
# Calculate mean
mean = sum(values) / n
# Calculate standard deviation
variance = sum((x - mean) ** 2 for x in values) / (n - 1)
std_dev = math.sqrt(variance)
results.append({
'species': species,
'island': island,
'body_weight_mean': mean,
'body_weight_sd': std_dev
})
# Sort results to match order used by pandas
results.sort(key=lambda x: (x['species'], x['island']))
# Print results
for result in results:
print(f"{result['species']:10} {result['island']:10} "
f"Mean: {result['body_weight_mean']:7.2f} g, "
f"SD: {result['body_weight_sd']:6.2f} g")
Этот код намного длиннее, содержит множество циклов и явно «разбирает» датасет по частям, чтобы затем собрать его обратно. Какой бы язык вы ни использовали, думаю, вы видите: версия без рутины куда лучше, чем та, что утопает в технических подробностях.7
На этом пока закончу. В следующих частях я разберу конкретные проблемы, из-за которых анализ данных в Python часто оказывается сложнее, чем в R. Вкратце: мне кажется, Python-код слишком часто сваливается в рутину работы с данными. И сколько бы программист ни старался придерживаться высокоуровневых концептуальных подходов, язык или доступные библиотеки встают поперёк и мешают.
Русскоязычное сообщество про Python

Друзья! Эту статью подготовила команда Python for Devs — канала, где каждый день выходят самые свежие и полезные материалы о Python и его экосистеме. Подписывайтесь, чтобы ничего не пропустить!
Комментарии (17)

economist75
30.11.2025 11:10Для контраста можно на R что-нить тоже несвойственное выложить - телеграм-бота или тетрис. И вот тогда окажется что все "доводы - контрасты" - так себе. И R, и Pandas очень близки и делают одно и то же, одинаково бесплатно. Но один падает, другой растет.

dyanishev
30.11.2025 11:10Пока как-то ни разу не убедительно. Может, дальнейшие примеры реально что-то покажут, но пока ни одного такого примера, где в питоне было бы прям криво, а где-то в другом языке прям хорошо, я не увидел.

ivchatov309
30.11.2025 11:10С R не знаком, с Python работаю каждый день. Вскоре появится нужда научить жену азам предобработки и агрегации данных. И вот посмотрев на этот один пример, будто бы синтаксису R будет проще обучить человека, который даже SQL не знает.
Про плюсы python уже пару человек тут высказали главное.

RaptorTV
30.11.2025 11:10Так какой язык вы веберете?

ivchatov309
30.11.2025 11:10Лично я продолжу работать с языком, на котором весь мой департамент и профессия в целом работает. Я слишком ленивый, чтобы что-то еще учить в свободное время.
Жену учить - попробую оба варианта, что ей будет проще воспринимать.

kmatveev
30.11.2025 11:10Я понимаю, что это перевод, и автор не узнает моего и так нахрен никому не интересного мнения. Нельзя так писать, вбросил и "на этом пока закончу".
Примеры на R+tidyverse и Python+pandas не особо отличаются визуально, и надо понимать, что отсутствие кавычек и скобочек в R работает благодаря такой фишке как метапрограммирование (напоминает lisp-макросы). Вам повезло, если у вас что-то простое и оно работает, а вот если надо разобраться, почему оно не работает - удачи, я не осилил, проще переписать совсем другим способом.
Мне кажется, хорошими языками для data science были бы Scheme или OCaml.

JetRonin
30.11.2025 11:10R и python разные вещи, абсолютно и по назначению и по широте применения и по гибкости, R только под одну задачу в институте.

economist75
30.11.2025 11:10Если сравнивать R и Pandas - то почти одно и то же. Оба инструмента прекрасны, state-of-the-art.

Nuflyn
30.11.2025 11:10В нашем институте биологи тоже используют R.) Интересно, это просто так совпало или просто биологи его любят с давних пор?

Arkronus
30.11.2025 11:10Можно взять другую библиотеку (polars) и разница с R будет минимальна и читаема.
import polars as pl from palmerpenguins import load_penguins penguins = pl.from_pandas(load_penguins()) result = ( penguins .drop_nulls(subset=["body_mass_g"]) .groupby(["species", "island"]) .agg( body_weight_mean = pl.col("body_mass_g").mean(), body_weight_sd = pl.col("body_mass_g").std(), ) )
MegaPey
30.11.2025 11:10Спасибо, с вашим комментом пришло понимание, чем R удобнее: действительно, в R нет такого количества скобочек.
pipe - оператор "|>" упрощает сборку конвейера обработки данных, так как хорошо ложится в логику научного поиска, проб и ошибок.
Добавить новую операцию легко в любом месте цепочки конвеера, без необходимости контроля скобок глубины вложения функций, что было бы связано с возвратом в начало цепочки.
...но в R неудобные библиотеки создания интерактивных веб-приложений. Порты известных библиотек предоставляют ограниченное число переменных, что обедняет функциональность R в презентации результатов.

economist75
30.11.2025 11:10В Pandas конвейеры делают 3-мя способами:
внутри скобок ( )
с df.pipe()
сторонним инструментом (в sklearn, например)
Допускаю что R тут чуть-чуть читаемее. Но Python отыграется на списковых включениях, декораторах и др. мелком сахарке. Плюс DS-ник почти всегда свой ETL-конвейер в python оформляет как пакет/либу, с документацией, доктестами, CI/CD, контейнерами и вот этим вот всем. Экосистема Python выглядит тут гораздо более зрелой и массовой чем R, а размеры сообщества и число звезд на гитхабе и сравнивать нечего. Но, повторюсь, оба инструмента прекрасны.

kmatveev
30.11.2025 11:10но в R неудобные библиотеки создания интерактивных веб-приложений
Вы пробовали Shiny и она показалась вам неудобной?

kmatveev
30.11.2025 11:10Не знаю python, но очень интересно, как работает agg ? У меня есть такая гипотеза: внутри agg используется синтаксис с именованными параметрами, а p.col("...").mean() - это не значение, а функция, в которую внутри agg будет передан сам dataframe, из которого оно уже извлечёт столбец и посчитает значение. Получается, что у agg неспецифицированы параметры, они всегда должны быть именованными, и она сама разбирает, что за параметры ей были переданы. Не очень понятно только, зачем скобки.

economist75
30.11.2025 11:10Корни истории, вероятно, лежат в мультииндексах столбцов, которые pandas возвела в культ и потеряла лаконичность. И появился .agg() сахар со словарями и списками.

Alexander428
30.11.2025 11:10Вода. Много воды. Примеры неубедительные. Можно было подвергнуть критике
Ужасную документацию. Серьезно. У какой-то ноунейм библиотеки на java например для работы с exel документация в 100 раз лучше, чем у python-библиотек. Приходится лезть на гитхаб, открывать код, спускаться сквозь кучу слоев абстракции предоставляемого API, чтобы понять а что же делает этот код и какие данные на вход ожидает.
Проблем с документацией добавляет kwargs. Потому что что? Фичу добавили, а в доки параметр не прописали. Оно и понятно, если функция/метод вызывает функцию, передавая ей kwargs, а та тоже вызывает функцию, тоже передавая kwargs, то это ж везде надо дублировать доку на каждый ключ словаря. Почему в языках без kwargs такой проблемы нет? А какую проблему kwargs решает? - Проблему гиганстких сигнатур методов (пришлось бы все аргументы явно перечислять для всех функций в цепочке вызовов). А как решают в других языках эту проблему? Создают отдельных класс с полями. Всё. Задокументировал только этот класс и нет проблем. Добавил потом поле, фичу в функцию и доку для поля 1 раз. Всё.
Предоставление конвейерной обработки данных строго за счет библиотек и у каждой по своему (несовместимо с другими библиотеками, так что приходится добавлять адаптеры).
Из предыдущего пункта плавно вытекает плохая встроенная в язык реализация ФП (имхо удобнее для анализа данных)
Отсуствие нормальной поддержки аннотаций типов для библиотек. Там все еще изобилует нетипизированный код. Статическая типизация и борьба с компилятором - это конечно боль для людей которым нужно просто писать бизнеслогику и запускать интерактивно код, но типизация помогает искать и исключать ошибки. И когда добавили аннотации в Python для удобства разработчика, а не компьютера - это было круто. Но некруто когда спустя много лет, mypy бессилен с проверкаами на типы кода вызывающего библиотечные функции.
Нейминг порой убивает. Вроде snake_style, но startswith, tolist и т д.
Что еще (помимо R и Matlab) могло бы стать лучшим инструментом для анализа данных, если бы было более популярным (и потому с большим числом готовых решений и устоявшихся библиотек):
Ruby (лучшая поддержка ООП)
Scala Spark (типизация, ФП)
Julia (скорость, типизация)
Jupyter кстати поддерживает эти языки. А у Julia есть своя альтернатива в виде Pluto. Но как по мне, у Julia пока полный хаос с библиотеками (много маленьких, часто долго приходится выбирать нужную).
izibrizi2
Питон в целом лучше для ml, cv, nlp, big data задач ну и кучи всего остального, прикладного.
R больше для академической среды, где ты написал программулинку, построил график, выпустил статью и был таков (в плане, что код не нужно поддерживать).