arrow 包提供了 reticulate 方法,用于在同一进程中的 R 和 Python 之间传递数据。 本文提供了一个简要概述。
本文中的代码假定 arrow 和 reticulate 都已加载
library(arrow, warn.conflicts = FALSE)
library(reticulate, warn.conflicts = FALSE)
动机
您可能希望在 R 中使用 PyArrow 的一个原因是,利用在当前的开发状态下,Python 比 R 更好地支持的功能。例如,曾经 R arrow 包不支持 concat_arrays()
,但 PyArrow 支持,因此当时这将是一个很好的用例。在当前写作时,PyArrow 比 R 包更全面地支持 Arrow Flight - 但请参阅 关于 arrow 中 Flight 支持的文章 - 因此这将是 PyArrow 对 R 用户有益的另一个例子。
R 用户可能希望使用 PyArrow 的第二个原因是,在 R 和 Python 之间有效地传递数据对象。 对于大型数据集,执行复制和转换操作以将 R 中的本机数据结构(例如,数据框)转换为 Python 中的类似结构(例如,Pandas DataFrame)反之亦然,在时间和 CPU 周期方面可能会非常昂贵。 因为像 Tables 这样的 Arrow 数据对象在 R 和 Python 中具有相同的内存格式,所以可以执行“零拷贝”数据传输,其中只需要在语言之间传递元数据。 正如稍后所示,这大大提高了性能。
安装 PyArrow
要在 Python 中使用 Arrow,需要安装 pyarrow
库。 例如,您可能希望创建一个包含 pyarrow
库的 Python 虚拟环境。 虚拟环境是为某个项目或目的而创建的特定 Python 安装。 在 Python 中,使用特定的环境是一个好习惯,这样更新一个包就不会影响其他项目中的包。
您可以从 R 内部执行设置。 假设您想将虚拟环境命名为 my-pyarrow-env
。 您的设置代码如下所示
virtualenv_create("my-pyarrow-env")
install_pyarrow("my-pyarrow-env")
如果您想将 pyarrow
的开发版本安装到虚拟环境中,请将 nightly = TRUE
添加到 install_pyarrow()
命令中
install_pyarrow("my-pyarrow-env", nightly = TRUE)
请注意,您不必使用虚拟环境。 如果您更喜欢 conda 环境,您可以使用以下设置代码
conda_create("my-pyarrow-env")
install_pyarrow("my-pyarrow-env")
要了解更多关于从 R 安装和配置 Python 的信息,请参阅 reticulate 文档,其中更详细地讨论了该主题。
导入 PyArrow
假设 arrow 和 reticulate 都已在 R 中加载,那么您的第一步是确保正在使用正确的 Python 环境。 要使用虚拟环境执行此操作,请使用如下命令
use_virtualenv("my-pyarrow-env")
对于 conda 环境,请使用以下命令
use_condaenv("my-pyarrow-env")
完成此操作后,下一步是将 pyarrow
导入到 Python 会话中,如下所示
pa <- import("pyarrow")
在 R 中执行此命令相当于在 Python 中执行以下导入
import pyarrow as pa
检查您的 pyarrow
版本也是一个好主意,如下所示
pa$`__version__`
## [1] "8.0.0"
pyarrow
0.17 及更高版本中包含对传递进出 R 的数据的支持。
使用 PyArrow
您可以使用 reticulate 函数 r_to_py()
将对象从 R 传递到 Python,类似地,您可以使用 py_to_r()
将对象从 Python 会话中拉到 R 中。 为了说明这一点,让我们在 R 中创建两个对象:df_random
是一个包含 1 亿行随机数据的 R 数据框,而 tb_random
是相同的数据,存储为 Arrow Table
set.seed(1234)
nrows <- 10^8
df_random <- data.frame(
x = rnorm(nrows),
y = rnorm(nrows),
subset = sample(10, nrows, replace = TRUE)
)
tb_random <- arrow_table(df_random)
在没有 Arrow 的情况下将数据从 R 传输到 Python 是一个耗时的过程,因为底层对象必须被复制并转换为 Python 数据结构
system.time({
df_py <- r_to_py(df_random)
})
## user system elapsed
## 0.307 5.172 5.529
相比之下,跨越传递 Arrow Table 几乎是瞬间发生的
system.time({
tb_py <- r_to_py(tb_random)
})
## user system elapsed
## 0.004 0.000 0.003
然而,“发送”并不是真正正确的词。 在内部,我们正在 R 和 Python 解释器之间传递数据的指针,它们在同一进程中一起运行,而无需复制任何内容。 没有发送任何东西:我们正在共享和访问相同的内部 Arrow 内存缓冲区。
也可以向另一个方向发送数据。 例如,让我们在 pyarrow 中创建一个 Array
。
a <- pa$array(c(1, 2, 3))
a
## Array
## <double>
## [
## 1,
## 2,
## 3
## ]
请注意,a
现在是 R 会话中的一个 Array
对象 - 即使您是在 Python 中创建的 - 并且您可以在其上应用 R 方法
a[a > 1]
## Array
## <double>
## [
## 2,
## 3
## ]
类似地,您可以将此对象与在 R 中创建的 Arrow 对象组合,并且可以使用 PyArrow 方法(如 pa$concat_arrays()
)来执行此操作
## Array
## <double>
## [
## 1,
## 2,
## 3,
## 5,
## 6,
## 7,
## 8,
## 9
## ]
现在您在 R 中有一个 Array。
进一步阅读
- 要了解更多关于从 R 安装和配置 Python 的信息,请参阅 reticulate 文档。
- 要了解 PyArrow,请参阅官方 PyArrow 文档 和 Apache Arrow Python Cookbook。
- 在 PyArrow 集成文档、这篇 关于 Arrow 中 reticulate 集成的博客文章 和这篇 关于 Arrow 中 rpy2 集成的博客文章 中也讨论了 Arrow 中的 R/Python 集成。
- R Arrow 和 PyArrow 之间的集成通过 Arrow C 数据接口 提供支持。
- 要了解更多关于 Arrow 数据对象的信息,请参阅 数据对象文章。