从Python运行R脚本

68

我搜索了这个问题并找到了一些答案,但是它们都似乎不起作用。 这是我在Python中使用的脚本来运行我的R脚本。

import subprocess
retcode = subprocess.call("/usr/bin/Rscript --vanilla -e 'source(\"/pathto/MyrScript.r\")'", shell=True)

我遇到了这个错误:

Error in read.table(file = file, header = header, sep = sep, quote = quote,  : 
  no lines available in input
Calls: source ... withVisible -> eval -> eval -> read.csv -> read.table
Execution halted

以下是我的 R 脚本的内容(非常简单!)

data = read.csv('features.csv')
data1 = read.csv("BagofWords.csv")
merged = merge(data,data1)
write.table(merged, "merged.csv",quote=FALSE,sep=",",row.names=FALSE)
for (i in 1:length(merged$fileName))
{
        fileConn<-file(paste("output/",toString(merged$fileName[i]),".txt",sep=""))
        writeLines((toString(merged$BagofWord[i])),fileConn)
        close(fileConn)
}

当我在r命令行中使用source('MyrScript.r')时,r脚本正常工作。此外,当我尝试在命令行中使用传递给subprocess.call函数的确切命令(即/usr/bin/Rscript --vanilla -e 'source("/pathto/MyrScript.r")')时,它也能正常工作,我真的不知道问题出在哪里。


尝试指定完整的 CSV 文件路径,也许会更好? - kevinsa5
尝试使用 strace 命令查看 exec 调用之间的差异。 - Kevin Smyth
6个回答

80

Rscript调用中,我不会过分信任内部的source,因为您可能并不完全了解您运行的不同nested R会话所在的位置。由于简单的事情(如您的工作目录不是您想要的目录),该过程可能会失败。

Rscript使您能够直接运行脚本(如果您使用Linux,请参见man Rscript)。

然后,您可以直接执行以下操作:

subprocess.call ("/usr/bin/Rscript --vanilla /pathto/MyrScript.r", shell=True)

或者更好地将Rscript命令及其参数解析为列表

subprocess.call (["/usr/bin/Rscript", "--vanilla", "/pathto/MyrScript.r"])

另外,为了让事情更容易,您可以创建一个R可执行文件。为此,您只需在脚本的第一行添加以下内容:

#! /usr/bin/Rscript

并给它执行权限。详情请参见此处

然后,您可以像处理其他 shell 命令或脚本一样调用 Python:

subprocess.call ("/pathto/MyrScript.r")

1
subprocess.call() 在我的情况下无法工作,但 subprocess.Popen() 对我有用。这是一个例子:process = subprocess.Popen(["R --vanilla --args %s %d %.2f < /path/to/your/rscript/transformMatrixToSparseMatrix.R" % ("sparse", 11, 0.98) ], shell=True) process.wait() - Good Will
1
对我而言,所有的代码都可以这样工作:subprocess.call(['Rscript', '--vanilla', 'MyrScript.r']) subprocess.Popen(['Rscript', '--vanilla', 'MyrScript.r']) subprocess.call('Rscript --vanilla MyrScript.r', shell=True) subprocess.Popen('Rscript --vanilla MyrScript.r', shell=True)如果您不把参数拆分成列表,那么就需要使用 shell=True。关于如何使用 < 将参数解析到 Rscript 中,我不太确定。 - dmontaner

32

我认为RPy2值得一试,这里有一个很酷的演示在R-bloggers.com上可以帮助你入门:

http://www.r-bloggers.com/accessing-r-from-python-using-rpy2/

基本上,它允许你使用R对象访问R库,提供了高级和低级接口。

这是最新版本的文档:https://rpy2.github.io/doc/latest/html/

我喜欢向Python用户介绍Anaconda,如果你使用包管理器conda安装rpy2,它也会确保你安装了R。

$ conda install rpy2

以下是基于该文件介绍的一个简短描述:

>>> from rpy2 import robjects
>>> pi = robjects.r['pi']
>>> pi
R object with classes: ('numeric',) mapped to:
<FloatVector - Python:0x7fde1c00a088 / R:0x562b8fbbe118>
[3.141593]

>>> from rpy2.robjects.packages import importr
>>> base = importr('base')
>>> utils = importr('utils')

>>> import rpy2.robjects.packages as rpackages
>>> utils = rpackages.importr('utils')
>>> packnames = ('ggplot2', 'hexbin')
>>> from rpy2.robjects.vectors import StrVector
>>> names_to_install = [x for x in packnames if not rpackages.isinstalled(x)]
>>> if len(names_to_install) > 0:
...     utils.install_packages(StrVector(names_to_install))

运行 R 代码片段:

>>> robjects.r('''
...         # create a function `f`
...         f <- function(r, verbose=FALSE) {
...             if (verbose) {
...                 cat("I am calling f().\n")
...             }
...             2 * pi * r
...         }
...         # call the function `f` with argument value 3
...         f(3)
...         ''')
R object with classes: ('numeric',) mapped to:
<FloatVector - Python:0x7fde1be0d8c8 / R:0x562b91196b18>
[18.849556]

这里有一个小的自包含图形演示:

from rpy2.robjects.packages import importr
graphics = importr('graphics')
grdevices = importr('grDevices')
base = importr('base')
stats = importr('stats')

import array

x = array.array('i', range(10))
y = stats.rnorm(10)

grdevices.X11()

graphics.par(mfrow = array.array('i', [2,2]))
graphics.plot(x, y, ylab = "foo/bar", col = "red")

kwargs = {'ylab':"foo/bar", 'type':"b", 'col':"blue", 'log':"x"}
graphics.plot(x, y, **kwargs)


m = base.matrix(stats.rnorm(100), ncol=5)
pca = stats.princomp(m)
graphics.plot(pca, main="Eigen values")
stats.biplot(pca, main="biplot")

5
下面的代码应该能够正常工作:
import rpy2.robjects as robjects
robjects.r.source("/pathto/MyrScript.r", encoding="utf-8")

1
我不建议使用系统调用,因为Python和R之间存在许多差异,特别是在传递数据时。有许多标准库可供选择,可以从Python中调用R,请参见此答案

嗨,在这里,我只需要运行一个简单的脚本,所以我不想被设置rpy2或其他库所困扰。 - Ehsan
@Ehsan,这很容易设置,而且你可以避免重复造轮子。你用的是Windows、Mac还是Linux? - pyCthon
@Ehsan,如果你只是使用R加载CSV文件,为什么不将R代码重写为Python呢? - pyCthon
我正在使用Linux,不仅仅是加载CSV文件,但我会看一下rpy2并了解它的情况:) - Ehsan
如果你使用的是Ubuntu系统,那么只需要执行sudo apt-get install python-rpy2命令就可以安装python-rpy2了。 - pyCthon

1
尝试在你的R脚本开头添加一行代码:
setwd("path-to-working-directory")

除此之外,将路径替换为包含文件features.csvBagofWords.csv的文件夹的路径。
我认为你遇到的问题是因为当你从R运行这个脚本时,你的工作目录已经是正确的路径了,但当你从python运行脚本时,默认的工作目录在其他地方(很可能是用户目录的顶部)。
通过在R脚本开头添加额外的一行,你可以明确地设置工作目录,读取这些文件的代码将会起作用。或者,你可以用这些文件的完整文件路径替换read.csv()中的文件名。
@dmontaner在他的答案中提出了这种可能性:

由于简单的事情,比如你的工作目录不是你想要的那个,所以这个过程可能会失败。


0
如果您只想运行一个脚本,那么可以使用sys库中可用的system("shell command")。如果您有一个有用的输出结果,您可以在您的shell命令末尾添加" > outputfilename"来打印结果。
例如:
import sys

system("ls -al > output.txt")

1
我不知道这个存在。它是旧的/过时的吗?它能将输出保存为字符串吗? - Tom
我不知道它是否已经过时,但是你可以得到输出。使用这个命令,你可以调用一个shell命令,所以如果你使用>更改输出目标,你就可以通过输出文件获取结果。 - Mips42

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接