早在 2009 年,SAS 的 Anne Milley 在一篇 纽约时报 文章中,驳斥了 R 语言(其竞争对手包括 SAS、Python,以及最近的 Julia)日益增长的重要性。她说
“我们有为飞机制造引擎的客户。 当我登上飞机时,我很高兴他们没有使用免费软件。”
在许多读者表达了他们的愤怒之后,Milley 在 SAS 网站上写了一篇后续的 博客文章,语气明显更加缓和。 她为 SAS 辩护,认为该软件因其“支持、可靠性和验证”而具有价值。 然而,最近的历史表明,将专有软件与可靠性或功能性混为一谈变得更加困难。
R 语言无疑为开源语言如何使长期占主导地位的专有软件(如 SAS)在很大程度上变得无关紧要提供了一个强有力的案例研究。 尽管很难量化 R 语言的用户群规模,但衡量其受欢迎程度的一个有趣指标是其在学术期刊文章中的使用情况。 在这方面,R 语言在 2015 年超越了 SAS。 此外,尽管这仅仅是轶事,但值得注意的是 2017 年在 Statistics subreddit 上的一个帖子,其中发帖者想知道 为什么 SAS 仍然在大量组织中使用。 用流行的回应来解释,公司仍然购买 SAS 是因为它一直是他们过去使用的东西,而改变是困难的! 正如伍德罗·威尔逊所说,“如果你想树敌,那就尝试改变一些东西。”
相比之下,有些开发人员和数据科学专业人士不想在功能方面做出任何让步。 他们想要用于分析的最佳工具,即使这意味着偶尔需要在 Stack Overflow 上搜索。 对于他们来说,有 R 语言。 它最初是一个统计计算环境,但它添加了如此多的功能,以至于现在可以归类为通用语言。
Python 呢?
这就引出了一个问题:“Python 呢?” 实际上,Python 也是一种流行的开源语言,用于数据分析。 如果我们有 Python,为什么我们还要关心 R 语言呢? 这不再能通过功能来回答; Python 和 R 语言多年来一直在互相复制功能。 例如,R 语言图形库 ggplot2
已移植到 Python; 有支持 R 语言的 Jupyter notebook 实现; 并且 Python 的 pandas 库中的 DataFrame
类与基本 R 语言中的 data.frame
类具有惊人的概念相似性。 因此,数据科学家现在因功能差异而在 R 和 Python 之间做出选择的情况已不那么常见。 此规则也有例外,例如(在 Python 方面)Python 的全栈功能和(在 R 方面)Shiny,这是一个 HTML 和 JavaScript 的 API,作为 R 语言库实现,允许 Web 应用程序开发和 R 语言功能之间实现无缝集成。
相反,“Python 呢?” 这个问题最好通过阐明 R 和 Python 之间对比鲜明的设计理念来回答,然后选择哪一个最符合您的个人风格。 这两种语言之间最大的概念差异是 Python 偏好只有一种显而易见的方式来做某事(Python 哲学中的一条规则),而 R 语言则相信为程序员提供无限的可能性,并允许他们选择他们想要的方法。 在 R 社区中,肯定没有像 Python 社区中使用的词语“Pythonic”这样的类比。 R 语言相信为程序员提供选择,而不是提倡规范化的方法。 虽然这当然是个人品味的问题,但我认为这使得 R 语言比 Python 更符合开源社区所坚持的价值观。
选择 R 语言的三个理由
归根结底,程序员应该选择他们觉得最舒适的语言,前提是它的实用性能够满足他们的需求。 我喜欢 R 语言的语法非常接近我的思维方式,这使得我使用起来非常舒服。 请考虑以下三个简单但具有启发意义的示例。
- R 语言从 1 开始索引,而不是通常的 0。 我对人们对此的强烈反应感到惊讶; 我的一位同事甚至仅仅因为这个原因而更喜欢 Python 而不是 R 语言。 但编程语言的目的是成为我们的思想与 1 和 0 之间的中间人。 如果一种语言是更有效的“中间人”(例如,像我们一样从 1 开始计数),那么这有什么问题呢? 我通常是遵循惯例的拥护者,除非有充分的理由不这样做。
R 语言索引方法的另一个好处是,您可以通过使用负索引进行子集化来从向量中删除元素(这需要语言从大于零的某个数字开始索引)。 例如:
> x = 1:5 > print(x) [1] 1 2 3 4 5 > x = x[-3] > print(x) [1] 1 2 4 5
- 基本 R 语言有四个不同的赋值运算符,每个运算符在运算顺序中都有不同的排名。 以下四个语句都产生相同的效果
assign('x', sqrt(pi)) x = sqrt(pi) x <- sqrt(pi) sqrt(pi) -> x
上面的第三个运算符(称为“向左赋值”)是最常见的,如果大多数 R 语言程序员(出于习惯)专门使用它,我不会感到惊讶。 我发现拥有所有这些运算符很有用,因为我认为某些选项更适合表达我如何形成某些想法。 此外,第一个运算符
assign()
函数的可选参数可以显式指定将新变量存储在哪个环境/命名空间中。 此外,R 语言还具有超级赋值运算符<<-
和->>
(分别与向左和向右赋值平行),即使在嵌套函数或结构深处,也允许将变量全局存储。 (这也可以通过assign()
函数完成。)
- 我认为在实现列表推导式的简易性方面,R 语言胜过所有其他语言,即使这通常被吹捧为 Python 的卖点。 R 语言中的几种列表推导式方法之一是“apply”函数系列,它提供了一种功能丰富的方式来跨向量或列表(即,R 语言等效于 C 结构)应用函数。 还有一种更简单的方法,基于 R 语言的“回收”约定,该约定规定,即使声明函数只接受一个输入元素,也可以将整个向量传递给函数,并且将在向量的每个元素处评估该函数。 例如,factorial() 函数被定义为仅接受一个输入元素,但您仍然可以将其用作:
> factorial(1:9) [1] 1 2 6 24 120 720 5040 40320 362880
尽管“apply”函数最初被认为是 R 语言中的一个细微差别,但它们无意中鼓励 R 语言程序员以易于并行化的方式设置他们的计算。 因此,R 语言社区自然而然地开发了用于并行和 GPU 计算的库。
在这些以及许多其他方面,R 语言对开源哲学的拥抱使其成为一种小众但不断增长的语言,其功能可以与任何其他高级解释型语言相媲美。
Samuel Lurie 将于今年 3 月 8 日至 11 日在加利福尼亚州帕萨迪纳举行的 SCaLE16x 大会上展示 R 语言亮点 。 要参加并获得 50% 的门票折扣,请使用促销代码 OSDC 注册。
3 条评论