使用 rpy2 从 python 动态调用 R 库
dynamically calling R library from python using rpy2
基于:
我有一个 R 例程,我需要以动态方式从我的 python 代码中调用它。
为此,我打算使用 rpy2。
首先我想使用的 R 代码来自 python(第一次 R 用户):
设置虚拟数据以展示 R 例程用法
set.seed(101)
data_sample <- c(5+ 3*rt(1000,df=5),
10+1*rt(10000,df=20))
num_components <- 2
例程本身
library(teigen)
tt <- teigen(data_sample,
Gs=num_components,
scale=FALSE,dfupdate="numeric",
models=c("univUU")
)
df = c(tt$parameters$df)
mean = c(tt$parameters$mean)
scale = c(tt$parameters$sigma)
参数 data_sample
和 num_components
由我的 python 代码动态计算,其中 num_components
它只是一个整数, data_sample
一个 numpy 数组。
作为最终目标,我希望 df
、mean
和 scale
作为列表或 numpy 数组返回 "python world" 以进一步处理和使用它们在我的程序逻辑中。
到目前为止我用 rpy2 解决这个问题的第一个实验:
import rpy2
from rpy2.robjects.packages import importr
from rpy2 import robjects as ro
numpy_t_mix_samples = get_student_t_data(n_samples=10000)
r_t_mix_samples = ro.FloatVector(numpy_t_mix_samples)
teigen = importr('teigen')
rres = teigen.teigen(r_t_mix_samples, Gs=2, scale=False, dfupdate="numeric", models=c("univUU"))
此处 Gs
的参数仍然是硬编码的,但应该如上文所述是动态的。
rres 然后打印大部分难以理解的输出(我猜是因为它还没有用 rpy2 正确地转换):
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
iter: <class 'rpy2.robjects.vectors.FloatVector'>
R object with classes: ('numeric',) mapped to:
<FloatVector - Python:0x11e3fdd08 / R:0x7ff7cced0a28>
[156.000000]
fuzzy: <class 'rpy2.robjects.vectors.Matrix'>
R object with classes: ('matrix',) mapped to:
<Matrix - Python:0x11e3fd8c8 / R:0x118e78000>
[0.000000, 0.917546, 0.004050, ..., 0.077300, 0.076273, 0.091252]
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
...
iter: <class 'rpy2.robjects.vectors.FloatVector'>
R object with classes: ('numeric',) mapped to:
<FloatVector - Python:0x11d632508 / R:0x7ff7cfa81658>
[-25365.912426]
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
总而言之,我希望获得与第一个代码框中原始 R 示例相同的结果,只是 df、均值和比例变量是 python lists/numpy 数组。
我根本不知道 R 的事实使得使用 rpy2 变得非常困难,也许有更优雅的方法来动态调用这个例程并将结果返回 python world.
考虑使用 x.names.index('myname')
来引用 R 对象中的嵌套命名元素。参见 rpy2 docs。作为提醒和下面的演示,您仍然可以使用数字索引引用 R 和 Python 嵌套对象。
要使用精确的随机数据重现您的 R 对象,我们需要 运行 R 端的 set.seed
,因为没有简单的方法可以跨语言找到等效的随机数生成器。参见相关 post。最后,基数 R 的 as.vector()
用于将数组对象转换为向量。 Python 中的所有 returns 都是 R FloatVectors: <class 'rpy2.robjects.vectors.FloatVector'>
.
Python
from rpy2.robjects.packages import importr
base = importr('base')
stats = importr('stats')
teigen = importr('teigen')
base.set_seed(101)
data_sample = base.as_numeric([(5+3*i) for i in stats.rt(1000,df=5)] + \
[(10+1*i) for i in stats.rt(10000,df=20)])
num_components = 2
rres = teigen.teigen(data_sample, Gs=num_components, scale=False,
dfupdate="numeric", models="univUU")
# BY NUMBER INDEX
df = rres[2][0]
mean = base.as_vector(rres[2][1])
scale = base.as_vector(rres[2][3])
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
# BY NAME INDEX
# (i.e., find corresponding number to name in R object)
params = rres[rres.names.index('parameters')]
df = params[params.names.index('df')]
mean = base.as_vector(params[params.names.index('mean')])
scale = base.as_vector(params[params.names.index('sigma')])
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
R (等效脚本)
library(teigen)
set.seed(101)
data_sample <- c(5+ 3*rt(1000,df=5),
10+1*rt(10000,df=20))
num_components <- 2
tt <- teigen(data_sample, Gs=num_components, scale=FALSE,
dfupdate="numeric", models="univUU")
# BY NUMBER INDEX
df = tt[[3]][[1]]
mean = as.vector(tt[[3]][[2]])
scale = as.vector(tt[[3]][[4]])
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
# BY NAME INDEX
df = c(tt$parameters$df)
mean = c(tt$parameters$mean)
scale = c(tt$parameters$sigma)
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
基于
我有一个 R 例程,我需要以动态方式从我的 python 代码中调用它。 为此,我打算使用 rpy2。
首先我想使用的 R 代码来自 python(第一次 R 用户):
设置虚拟数据以展示 R 例程用法
set.seed(101)
data_sample <- c(5+ 3*rt(1000,df=5),
10+1*rt(10000,df=20))
num_components <- 2
例程本身
library(teigen)
tt <- teigen(data_sample,
Gs=num_components,
scale=FALSE,dfupdate="numeric",
models=c("univUU")
)
df = c(tt$parameters$df)
mean = c(tt$parameters$mean)
scale = c(tt$parameters$sigma)
参数 data_sample
和 num_components
由我的 python 代码动态计算,其中 num_components
它只是一个整数, data_sample
一个 numpy 数组。
作为最终目标,我希望 df
、mean
和 scale
作为列表或 numpy 数组返回 "python world" 以进一步处理和使用它们在我的程序逻辑中。
到目前为止我用 rpy2 解决这个问题的第一个实验:
import rpy2
from rpy2.robjects.packages import importr
from rpy2 import robjects as ro
numpy_t_mix_samples = get_student_t_data(n_samples=10000)
r_t_mix_samples = ro.FloatVector(numpy_t_mix_samples)
teigen = importr('teigen')
rres = teigen.teigen(r_t_mix_samples, Gs=2, scale=False, dfupdate="numeric", models=c("univUU"))
此处 Gs
的参数仍然是硬编码的,但应该如上文所述是动态的。
rres 然后打印大部分难以理解的输出(我猜是因为它还没有用 rpy2 正确地转换):
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
iter: <class 'rpy2.robjects.vectors.FloatVector'>
R object with classes: ('numeric',) mapped to:
<FloatVector - Python:0x11e3fdd08 / R:0x7ff7cced0a28>
[156.000000]
fuzzy: <class 'rpy2.robjects.vectors.Matrix'>
R object with classes: ('matrix',) mapped to:
<Matrix - Python:0x11e3fd8c8 / R:0x118e78000>
[0.000000, 0.917546, 0.004050, ..., 0.077300, 0.076273, 0.091252]
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
...
iter: <class 'rpy2.robjects.vectors.FloatVector'>
R object with classes: ('numeric',) mapped to:
<FloatVector - Python:0x11d632508 / R:0x7ff7cfa81658>
[-25365.912426]
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
R object with classes: ('teigen',) mapped to:
<ListVector - Python:0x11e3fdc48 / R:0x7ff7d229dcb0>
[Float..., Matrix, ListV..., ..., Float..., ListV..., ListV...]
总而言之,我希望获得与第一个代码框中原始 R 示例相同的结果,只是 df、均值和比例变量是 python lists/numpy 数组。 我根本不知道 R 的事实使得使用 rpy2 变得非常困难,也许有更优雅的方法来动态调用这个例程并将结果返回 python world.
考虑使用 x.names.index('myname')
来引用 R 对象中的嵌套命名元素。参见 rpy2 docs。作为提醒和下面的演示,您仍然可以使用数字索引引用 R 和 Python 嵌套对象。
要使用精确的随机数据重现您的 R 对象,我们需要 运行 R 端的 set.seed
,因为没有简单的方法可以跨语言找到等效的随机数生成器。参见相关 post。最后,基数 R 的 as.vector()
用于将数组对象转换为向量。 Python 中的所有 returns 都是 R FloatVectors: <class 'rpy2.robjects.vectors.FloatVector'>
.
Python
from rpy2.robjects.packages import importr
base = importr('base')
stats = importr('stats')
teigen = importr('teigen')
base.set_seed(101)
data_sample = base.as_numeric([(5+3*i) for i in stats.rt(1000,df=5)] + \
[(10+1*i) for i in stats.rt(10000,df=20)])
num_components = 2
rres = teigen.teigen(data_sample, Gs=num_components, scale=False,
dfupdate="numeric", models="univUU")
# BY NUMBER INDEX
df = rres[2][0]
mean = base.as_vector(rres[2][1])
scale = base.as_vector(rres[2][3])
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
# BY NAME INDEX
# (i.e., find corresponding number to name in R object)
params = rres[rres.names.index('parameters')]
df = params[params.names.index('df')]
mean = base.as_vector(params[params.names.index('mean')])
scale = base.as_vector(params[params.names.index('sigma')])
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
R (等效脚本)
library(teigen)
set.seed(101)
data_sample <- c(5+ 3*rt(1000,df=5),
10+1*rt(10000,df=20))
num_components <- 2
tt <- teigen(data_sample, Gs=num_components, scale=FALSE,
dfupdate="numeric", models="univUU")
# BY NUMBER INDEX
df = tt[[3]][[1]]
mean = as.vector(tt[[3]][[2]])
scale = as.vector(tt[[3]][[4]])
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588
# BY NAME INDEX
df = c(tt$parameters$df)
mean = c(tt$parameters$mean)
scale = c(tt$parameters$sigma)
print(df)
# [1] 3.578491 47.059841
print(mean)
# [1] 4.939179 10.002038
print(scale)
# [1] 8.763076 1.041588