我从 R 转向 Julia 的旅程
本文最初发布于 Tomás Aragón 的个人博客。
15 年来,我在加州大学伯克利分校公共卫生学院教授“应用流行病学 R 语言版”课程。我从 21 世纪初就开始教这门课,当时大多数人对 R 不感兴趣。后来,R 越来越受欢迎,我的课程入学率也越来越高。我教授流行病学概念的 R 编程基础。学生们有自己选择的项目。因为他们来自多个学科,所以项目通常非常具有创新性,我也从他们身上学到了很多东西。
在过去的 15 年里,我见证了“数据科学”的兴起,以及学生们在项目中的独创性和创造性。当然,课程也在不断发展。我引入贝叶斯网络作为统一的框架,以引入概率依赖、因果图和决策网络(用于决策分析)。
我开始涉猎 Python。遗憾的是,COVID-19 大流行打断了我的教学,因为我是旧金山的卫生官员兼人口卫生司司长。在大流行应对工作中,我几乎没有时间分析或学习 Python。
不记得是什么时候,我发现了 Julia——一种为科学计算而设计的编程语言,有 Python 或 R 的直观,同时又有 C++ 的速度。我爱上了 Julia,放弃了学习 Python。我过去没有,现在也没有时间在 1.5 种以上的编程语言中保持核心竞争力。随着我对 Julia 的了解越来越多,我开始确信,对我来说,学习 Julia 是比坚持学习 R 更好的长期投资。
我使用编程来探索或测试我的流行病学直觉,学习新的方法,并可视化和分析数据。我个人对贝叶斯网络、决策网络、因果推理、马尔可夫决策过程和基于代理的建模很感兴趣。
以下是我认为流行病学家应该会看重的 Julia 的一些关键特性:
多重指派
复合类型
即时编译
速度(非常快)
社区
Julia 编程更直观。例如,在 R 中,我们会设法避免循环,因为它们的效率非常低。而在 Julia 中,循环很高效,因为它在执行之前编译,使得编程更加自然。
下面我将用一个简单的示例演示多重指派。R 是单指派的。
我是 R ' epitools '包的创始开发者。我开发了基本流行病学分析函数(如 2x2 表),其中几个来自 Rothman 的“现代流行病学”教科书。例如,如果我想创建一个函数来计算一个 2x2 列联表的优势比(odds ratio),数据可以通过以下几种方式提供:
四个整数
两个比例
一个 2x2 表(矩阵)
两个带有分类数据的向量
如果我想编写一个函数,将这些可能的数据类型作为参数来处理,那么为了调用下一个函数(嵌套的或外部的),就必须对数据类型进行大量的处理和检查。这需要做大量不必要的工作。我们看看使用 Julia 的多重指派如何实现。
2003 年,我们发表了一项研究,证据了饮用未经过滤的城市自来水与晚期 HIV 疾病患者患隐孢子虫病有关。以下是这篇论文中的列联表:
我们计算下最高暴露类别和最低暴露类别之间未经调整的优势比。以下是这个计算的 2x2 表:
对于一个适当的结构化表格,优势比是交叉积:
对于病例对照设计,优势比是暴露优势比:
我们将创建三个函数,它们可以接收以下三种不同类型的参数来计算优势比:
四个整数
两个比例
一个 2x2 表(矩阵)
有个问题是,这三个函数的名称相同:oddsratio。在 Julia 中,这是可能的,因为它有多重指派。相比之下,R 是单指派的。
## 函数 1
function oddsratio(a::Int, b::Int, c::Int, d::Int)
or = (a * d) / (b * c)
return or
end
oddsratio (generic function with 1 method)
我们将 2x2 表的 4 个整数作为参数传递给 oddsratio 以测试这个函数:
oddsratio(12, 6, 2, 29)
29.0
下面是第二个函数,处理比例参数;例如,比较病例和对照组的暴露优势比。
## 函数 2
function oddsratio(p1::Float64, p0::Float64)
or = ((p1)/(1 - p1)) / ((p0)/(1 - p0))
return or
end
oddsratio (generic function with 2 methods)
我们将 2x2 表的 2 个比例作为参数传递给 oddsratio 以测试这个函数:
prop1 = 12 / (12 + 2) # probability of exposure among cases
prop0 = 6 / (6 + 29) # probability of exposure among controls
oddsratio(prop1, prop0)
28.999999999999982
最后,第 3 个函数处理一个 2x2 表(矩阵)参数:
## 函数 3
function oddsratio(x::Matrix{Int})
or = (x[1, 1] * x[2, 2]) / (x[1, 2] * x[2, 1])
return or
end
oddsratio (generic function with 3 methods)
我们将 2x2 表作为参数传递给 oddsratio 以测试这个函数:
tab = [12 6; 2 29]
2×2 Matrix{Int64}:
12 6
2 29
oddsratio(tab)
29.0
这称为多重指派。oddsratio 函数有 3 个方法,可以处理多种数据类型。请注意,这有多简单。
以下是泛型函数 oddsratio 的 3 个方法:
oddsratio(a::Int64, b::Int64, c::Int64, d::Int64) in Main at In[2]:2
oddsratio(p1::Float64, p0::Float64) in Main at In[4]:2
oddsratio(x::Matrix{Int64}) in Main at In[6]:2
在这篇博文中,我总结了自己为什么从 R 转到 Julia。我通过函数演示了多重指派。请注意,创建一个 oddsratio 函数,提供三个方法来处理不同的参数数据类型(整数、比例和矩阵),是多么简单。
我喜欢 Julia,你也会喜欢的。你还可以从 Julia 运行 R 或 Python,而且不会有任何中断。
我将发布一些简单的例子,着重突出 Julia 应用于基础流行病学或流行病学编程的特性。
Julia 在创建函数方面非常灵活。以下是三个同名函数的缩写形式。
## 函数 1
oddsratio(a::Int, b::Int, c::Int, d::Int) = (a * d) / (b * c)
oddsratio (generic function with 3 methods)
## 函数 2
oddsratio(p1::Float64, p0::Float64) = ((p1)/(1 - p1)) / ((p0)/(1 - p0))
oddsratio (generic function with 3 methods)
## 函数 3
oddsratio(x::Matrix{Int}) = (x[1, 1] * x[2, 2]) / (x[1, 2] * x[2, 1])
oddsratio (generic function with 3 methods)
以我带有偏见的眼光来看,Julia 有一种 R 所缺乏的简单和优雅。
声明:本文为 InfoQ 翻译,未经许可禁止转载。
原文链接:
https://drtomasaragon.github.io/posts/2023-01-14-my-journey-from-r-to-julia/
你也「在看」吗? 👇
微信扫码关注该文公众号作者