跳至內容

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 週期。由於 Arrow 資料物件(例如 Table)在 R 和 Python 中具有相同的記憶體格式,因此可以執行「零複製」資料傳輸,其中只需要在語言之間傳遞 metadata。正如稍後所示,這大幅提高了效能。

安裝 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 和從 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())來執行此操作

b <- Array$create(c(5, 6, 7, 8, 9))
a_and_b <- pa$concat_arrays(list(a, b))
a_and_b
## Array
## <double>
## [
##   1,
##   2,
##   3,
##   5,
##   6,
##   7,
##   8,
##   9
## ]

現在您在 R 中有一個單一的 Array。

延伸閱讀