“Python 不是数据科学的最佳语言!”

近来,Python 在各大编程语言榜单上持续霸榜,成为增速最快的语言之一。从数据分析到深度学习,从科研到工程项目,几乎无处不在。但它真的适合所有的数据科学任务吗?对此,本文作者结合自己二十多年带实验室的经历,深入探讨了 Python 在数据科学中的优势与局限,并对比了 R 的使用体验,得出这样一个结论——Python 并不是做数据科学的最佳语言。那么,他为什么这么说?我们一起看看他的最新观察。

原文链接:https://blog.genesmindsmachines.com/p/python-is-not-a-great-language-for

作者 | Claus Wilke       责编 | 苏宓

出品 | 优快云(ID:优快云news)

我已经准备好踩进语言之争这趟浑水了。但我先说一句最重要的:用你最熟的工具。比如你熟悉 Python?那就用 Python。再补充一句:做哪件事最合适用哪个工具就用哪个工具。如果刚好还是 Python,那也没问题。

还有就是,如果你本来就天天用某个工具,顺手拿它来干点别的活,也完全正常。你一天到晚拿锤子敲钉子,用它开瓶啤酒、挠挠背,也都说得过去。同样地,你整天写 Python,用它顺带做做混合线性模型,也没毛病。

如果你用得顺手,那继续用就行。但如果你越用越觉得别扭、感觉一些事情明明不该这么难,那这篇文章可能就是给你看的。

首先,我提出一个观点——大家对“Python 是数据科学语言”这件事过度依赖了。它的局限性其实相当明显。有许多数据科学任务,我宁可用 R 完成,也不愿用 Python。

之所以 Python 在数据科学领域如此普及,我认为更多是历史偶然,加上一种“各方面都还行”的通用性,而不是它在数据科学上有某种天生优势。

与此同时,我认为 Python 在深度学习上确实表现不错。PyTorch 之所以成为行业标准是有理由的。这里我谈的数据科学,并不包括深度学习,而是指其他那些工作:数据清洗、探索性分析、可视化、统计建模等等。

正如开头提到的,如果你本来就有充分理由每天都在用 Python(比如训练 AI 模型),那么顺便用它把剩下的事情一起做完也可以。我自己在教授深度学习课程时就是这么做的。但这并不能抵消我在 Python 世界里做数据分析时常常感到的笨拙与不便。

来自一线的观察

我先谈谈自己的亲身经历,不做任何原因分析。我带领计算生物实验室已经二十多年了,期间合作过大约三十位能力很强的研究生和博士后。实验室的规则是:每个人可以自由选择任何想用的编程语言和工具,我从不干预。

结果往往是,大多数人会选择 Python。

下面是我经常遇到的情况:一位学生来办公室向我展示一些结果。我说:“这很好,你能不能把图换一种方式快速画一下?”或者“能不能快速算一个我刚想到的量,并画出来看看?”诸如此类的需求。通常这些都是我知道在 R 里几分钟就能搞定的任务,比如把箱线图改成小提琴图、把折线图改成热力图、把直方图换成密度估计、把原始值换成排序值再计算等等。

几乎毫无例外,使用 Python 的学生总会回答:“这要花点时间,我得回去研究一下,弄好再告诉你。”

我要强调的是:这些学生都非常强。问题并不是他们不懂工具,而是工具本身似乎就比较笨拙,让我以为是“非常简单的请求”,却经常变得一点也不简单。

无论原因是什么,我都不得不得出一个结论:Python 在数据分析上的某些基础环节出现了结构性问题。可能是语言本身的问题,也可能是库生态的问题,或两者共同作用,但结果是真实存在的,而且我长期都能看到类似情况。

事实上,我再举一个例子,以避免你认为“这是学生水平问题”。

去年秋天,我和一位资深的数据科学家一起教授生物学的 AI 课程。他所有工作都用 Python,对 NumPy、pandas、matplotlib 都熟得不能再熟。在课上,他负责带学生做 Python 练习,我负责讲理论。这让我可以观察到一位 Python 专家如何现场解决各种数据分析问题。

我的反应往往是:“为什么要写得这么复杂?”许多我认为用 R 几行就能写出的东西,在 Python 里却变得又长又绕。我自己要是不花大量时间重新训练大脑、适应完全不同的编程思维,就根本写不出那些代码。这种陌生感并不是“陌生但优雅”,而是“陌生、怪异、且繁琐”。

而我很确定原因不在于同事,他非常厉害。真正的问题,似乎就在这些工具的底层设计上。

什么才是适合数据科学的语言?

退一步讲,选择数据科学语言时有一些基本考量。这里说的数据科学,是指剖析和总结数据、寻找模式、拟合模型、绘制可视化——也就是科研人员在日常数据分析中会做的所有工作。这与数据工程或应用开发并不相同。

数据科学高度依赖交互式探索,需要大量快速试验性的分析。因此,适合数据科学的语言必须支持解释执行,并能在交互式 Shell 或 Notebook 中使用。性能反而是次要的。当你做一个线性回归时,你根本不会在意是 50ms 还是 500ms;你关心的是:能不能立刻打开 Shell,写几行代码,几分钟内得到结果,而不是新建工程、写一堆模板代码、取悦编译器,还要花比运行更久的时间等待编译。

既然交互性和低启动成本是必须,那候选自然落在 Python、R、Matlab、Mathematica 这类脚本或数据科学语言上。也包括 Julia,但说实话我对 Julia 了解不足,不好评价。它可能非常优秀,但我也看到不少深度用户对它有所保留。本文就不展开。Matlab、Mathematica 之类的商业语言,以及缺乏生态的 Octave 也先放一边。现实选择就是 R 和 Python。

继续之前我想补充一下关于性能的看法。性能通常要以牺牲语言其他特性为代价:程序员额外负担(如 Rust)、更高的隐蔽 bug 风险(如 C),或两者皆有。在数据科学里,高 bug 风险不可接受,而程序员便利性远比极致性能重要。电脑足够快,而思考会痛。我宁愿少费心力告诉电脑该做什么,多等一会儿。有真正性能瓶颈时,我完全可以在明确需求后把关键路径重写成 Rust。

把“逻辑”与“搬运工作”分开

不让分析变得更困难的关键,就是把“分析逻辑”与“实现细节”分离。我希望能用概念层面的描述来写分析代码:数据要怎么处理、目标是什么;而不想被迫去操心底层细节,比如数据类型、数字索引、循环、手动拆装数据表等等。

只要我开始管这些事,那多半是在被“繁琐的机械劳动”拖累。

举个例子,来看 Palmer 群岛的企鹅数据集。里面有三种企鹅分布在三座岛上。假设我要计算“岛 × 物种”两个维度下的体重均值和标准差,并排除体重缺失的记录。

理想的数据科学语言应该能让我以接近自然语言的方式完成这个任务,用的代码量与我刚用英语描述的句子词汇量差不多才算优秀。R 和 Python 都做得到——只是难易度差别很大。

下面是使用 tidyverse 风格的 R 代码:

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 pdfrom palmerpenguins import load_penguinspenguins = 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 里有多少引号和括号),但差别不算大。

两者的流程也一致:取 penguins 数据集、去掉体重缺失的记录、按“物种 × 岛屿”分组,然后分别计算均值和标准差。

对比一下只用 Python 基础语法、完全不依赖数据处理库时的等价版本:

from palmerpenguins import load_penguinsimport mathpenguins = load_penguins()# Convert DataFrame to list of dictionariespenguins_list = penguins.to_dict('records')# Filter out rows where body_mass_g is missingfiltered = [row for row in penguins_list if not math.isnan(row['body_mass_g'])]# Group by species and islandgroups = {}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 groupresults = []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 pandasresults.sort(key=lambda x: (x['species'], x['island']))# Print resultsfor 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")

这段代码明显长得多,里面到处是循环,还得把数据集拆开再重新拼回去。不管你喜欢哪种语言,应该都能看出来:不用管这些琐碎步骤、直接表达你要做什么的版本,比被一堆杂事拖住的版本好太多了。

简单来说,我觉得 Python 代码之所以动不动就变成“苦力活”,是因为无论你多想保持高层抽象、写得清爽一点,语言本身或者它的库,总会出来添乱,让你不得不去处理那些底层细节。

推荐阅读:

C++之父亲临北京,AI 原生时代最值得参加的系统软件技术大会日程发布

“Linux真正的活不是我在干”,Linus爆料近况:近20年不做程序员、没碰过AI编程、压力全来自于“人”

你的盗版Windows,可能一夜之间“失效”了!微软正式封杀KMS38,“白嫖时代”或将走向终点

【活动分享】2025 年是 C++ 正式发布以来的 40 周年,也是全球 C++ 及系统软件技术大会举办 20 周年。这一次,C++ 之父 Bjarne Stroustrup 将再次亲临「2025 全球 C++及系统软件技术大会」现场,与全球顶尖的系统软件工程师、编译器专家、AI 基础设施研究者同台对话。

本次大会共设立现代 C++ 最佳实践、架构与设计演化、软件质量建设、安全与可靠、研发效能、大模型驱动的软件开发、AI 算力与优化、异构计算、高性能与低时延、并发与并行、系统级软件、嵌入式系统十二大主题,共同构建了一个全面而立体的知识体系,确保每一位参会者——无论是语言爱好者、系统架构师、性能优化工程师,还是技术管理者——都能在这里找到自己的坐标,收获深刻的洞见与启发。详情参考官网:https://cpp-summit.org/

图片

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

优快云资讯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值