早在 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 条评论