跳转至

通过 Python 从 IDL 调用 R 统计包

原文链接: https://www.nv5geospatialsoftware.com/Learn/Blogs/Blog-Details/calling-the-r-statistical-package-from-idl-via-python

18612 给这篇文章评分:

2.7

通过 Python 从 IDL 调用 R 统计包

Jim Pendleton 2016年2月4日,星期四

R 脚本语言 是一个功能强大的数据分析和统计工具,为特定的输入问题集和输出解决方案提供了多种内置的图形输出类型。

客户经常要求我们在 IDL 中加入一个访问 R 的机制,因为这两种语言在许多方面是互补的。

随着 IDL 8.5 中 Python 桥接 的引入,我们能够通过 rpy2 调用 R,并在 IDL 和 R 之间交换数据。

安装

本文中的信息是静态的,发布后可能保持不变。但安装要求可能会随时间变化。我能提供的最佳建议是,返回 R 和 rpy2 的软件源,以获取关于将 R 与 Python 结合的最佳实践的最新信息。一旦 Python 和 R 能够互相通信,距离 IDL 就只有一步之遥。

Linux

本文作者遗憾地承认,由于时间和资源有限,未能在 Linux 上进行安装尝试,不过下面针对 Windows 的描述以及访问 FAQ 和 stackoverflow 网站一两次,很可能可以解答任何问题。

Windows

第一个假设是您已经按照 IDL Python 桥接文档 中的描述安装并配置了某个版本的 Python。

接下来,安装适合您平台(32位 vs 64位等)的 R 版本。本文发布时的安装说明可以在这里找到。如果链接已失效,请在你喜欢的搜索引擎中搜索“R scripting language download”。

安装 R 后,需要定义一些系统环境变量,以便 rpy2 桥接在 Windows 上正确安装。这在 R 版本 3.2.3 和 rpy2 版本 2.7.6 时是如此。

  1. 将平台特定的安装目录添加到你的 PATH 环境变量中,例如 C:\Program Files\R\R-X.Y.Z\bin\x64
  2. 创建一个新的 R_HOME 环境变量,指向 R 的“版本”目录,例如 C:\Program Files\R\R-X.Y.Z
  3. 创建一个新的 R_USER 环境变量,设置为您的 Windows 用户名

在 Windows 上,如果您有合适的工具,可以选择从源代码构建 rpy2 桥接。

或者,您可以搜索包含预编译二进制文件的软件源。其中一个这样的源,包含 rpy2 以及许多 Python 工具,可以在这里找到。如果链接已失效,请搜索“rpy2 windows binaries download”。

下载适合您的 R 和 Python 版本的 rpy2 桥接版本非常重要。在 Python 提示符或 IDL Python 桥接中输入:

import pip print(pip.pep425tags.get_supported())

搜索最高的“cp”版本。在我的例子中,这是“cp34”。

[('cp34', 'none', 'win_amd64'), ('py3', 'none', 'win_amd64'), ('cp34', 'none', ' any'), ('cp3', 'none', 'any'), ('cp33', 'none', 'any'), ('cp32', 'none', 'any'), ('cp31', 'none', 'any'), ('cp30', 'none', 'any'), ('py34', 'none', 'any'), ('py 3', 'none', 'any'), ('py33', 'none', 'any'), ('py32', 'none', 'any'), ('py31', ' none', 'any'), ('py30', 'none', 'any')]

将此版本与 rpy2 源中可用的版本进行比较。任何版本号高于 Python 的 pip 工具支持的版本都无法安装。

下载合适的 rpy2 Python wheel 文件(扩展名为“.whl”)。使用 Python 的 pip 工具安装它,指定文件路径,例如:

pip install rpy2 rpy2-2.7.6-cp34-none-win32.whl

现在 R 应该可以通过 Python 桥接在 IDL 中使用了。

Hello World

请参阅 rpy2 文档中关于从 Python 调用 R 的简单示例

从 IDL 中,我们只需通过 Python 桥接,这种方式通常是无缝的。

首先,将 rpy2 的 “rpy2.robjects” 包加载到 Python 中。这会启动嵌入的 R 进程。

IDL> !null = Python.run('import rpy2.robjects as robjects')

R 解释器是 robjects 的成员“r”。你可以直接获取其在 IDL 中的引用。

IDL> !null = Python.run('import rpy2.robjects as robjects') IDL> robjects = Python.robjects IDL> R = robjects.r

在最简单的情况下,可以构造 R 字符串,然后直接传递给 R 进行解释。

IDL> !null = R('ctl <- c(4.17,5.58,5.18,6.11,4.50,4.61,5.17,4.53,5.33,5.14)')

这相当于 IDL 中的 EXECUTE 函数调用。然而,通常你会希望将数值数据作为数字传递。

IDL 和 NumPy

IDL 在将数字字面量传递给 Python 之前,会将其转换为 NumPy 类型。当这些变量随后通过 rpy2 桥接传递时,会存在轻微的冲突。默认情况下,它不会自动执行从 NumPy 类型到数值原子类型的反向转换。

这可以通过一个简单的解决方法轻松克服。

在将任何数值数据从 IDL 传递到 Python 之前,执行以下两行:

IDL> !null = Python.run("import rpy2.robjects.numpy2ri") IDL> !null = Python.run("rpy2.robjects.numpy2ri.activate()")

创建可从 IDL 调用的 R 函数

有时 IDL 的语法不能直接映射到 Python 或 R 的数据对象。在这种情况下,类似于 Python.run() 命令,可以通过 rpy2 桥接将完整的字符串传递给 R 执行。

首先,获取对 R 解释器本身的引用(如果尚未这样做)。

IDL> !null = Python.run('import rpy2.robjects as robjects') IDL> R = Python.robjects.r

在 R 中定义一个函数,该函数将简单地计算一个数的平方。我们需要将函数定义作为字符串字面量传递给 R,R 会对其进行解释。

IDL> sqr = R('function(x) x^2')

现在 R 函数“sqr”在 IDL 中可以直接作为函数访问:

IDL> b=sqr(2) IDL> help, b B PYTHON

要复制存储在 Vector 类型(例如上面显示的 FloatVector)中的输出 R 数据,请使用 Python.tuple 方法。

IDL> value=(Python.tuple(b))[0] IDL> print, value 4.0000000 IDL> help, value VALUE DOUBLE = 4.0000000

Python-R 示例

请参阅 rpy2 介绍网页底部的示例代码此处。它生成一个类似于下图的图形:

生成示例数据集时涉及随机数,因此您的输出可能不完全相同。

IDL-Python-R 等效示例

以下代码块从 IDL 执行等效命令,但在本例中,输入数据是在 IDL 中生成,然后传递给 Python,再传递给 R。

其中包含许多注释,将帮助指导您。请将代码复制并粘贴到您的 IDL 命令行中。



; This code is a conversion from the pure Python "One more example" at the bottom

; of the page http://rpy.sourceforge.net/rpy2/doc-dev/html/introduction.html

!null = Python.run("from rpy2.robjects.packages import importr")

; The following two lines allow us to pass numeric types through

; to R methods, for example, "stats.norm(10)".  IDL, by default, converts all

; numeric variables to numpy types rather than treating them as the

; underlying number.  R requires the underlying number instead, by default.

; Unlike IDL, it does not assume that numpy has been imported.  The

; "activate()" method allows us to continue to pass numpy types

; to R where R then converts them back to the required type.

!null = Python.run("import rpy2.robjects.numpy2ri")

!null = Python.run("rpy2.robjects.numpy2ri.activate()")

importr = Python.importr

graphics = importr('graphics')

grdevices = importr('grDevices')



base = importr('base')

stats = importr('stats')

;

; Generate some data on the IDL side to be evaluated on the R side,

; via the Python bridge.

;

array = Python.Import('array')

XX = Indgen(10)

x = array.array('i', XX)

y = randomn(seed, 10)

; Create a 2x2 grid of Python plots and show the first plot

!null = grdevices.windows()

!null = graphics.par(mfrow = array.array('i', [2,2]))

!null = graphics.plot(x, y, ylab = "foo/bar", col = "red")

; Create an equivalent IDL plot of the data

p = plot(xx, y, $

  color='red', ytitle = 'foo/bar', xtickdir= 1, ytickdir = 1, xminor = 0, yminor = 0, $

  symbol = 'D', linestyle = 'none', layout = [2, 2, 1], $

  dimensions = [768, 768], xstyle = 2, ystyle = 2)



Python.kwargs = hash('ylab', 'foo/bar', 'type', 'b', 'col', 'blue', 'log', 'x')

;

; Due to the syntax required by Python and a mistmatch with IDL syntax,

; we can't execute the next plot using dot notation.  But we can construct

; the Python syntax as a string and use the Python.run() method instead.

;

; Transfer references to the x and y IDL variables and the graphics package

; from IDL to Python before calling the plot method.

;

Python.x = x

Python.y = y

Python.graphics = graphics

!null = Python.run("graphics.plot(x, y, **kwargs)")

;

p = plot(xx, y, $

  color='blue', ytitle = 'foo/bar', xtickdir= 1, ytickdir = 1, yminor = 0, $

  symbol = 'D', position = 2,  xlog = !true, $

  layout = [2, 2, 2], /current, xminor = 0, xtickvalues = [1, 2, 5], $

  xstyle = 2, ystyle = 2)

;

; Execute principal components analysis on IDL-defined data and plot results.

;

;m = base.matrix(stats.rnorm(100), ncol=5) ; this is the R equivalent

m = randomn(seed, 5, 20)

pca = stats.princomp(m)

!null = graphics.plot(pca, main="Eigen values")

!null = stats.biplot(pca, main="biplot")

;

; From the result, extract the tuples associated with the principal components

; calculation.

;

pcatup = Python.tuple(pca)

r = Python.tuple(pcatup)

;

; Show the data in the R principle components results, as represented by

; Python objects.

;

Help, r

Print, r

fv = Python.tuple(r[0])

print, fv

;

; Run IDL's principal components to extract eigenvalues

;

i = pcomp(m, eigenvalues = e)

p = barplot(layout = [2, 2, 3], /current, $

  lindgen(e.length) + 1, reform(e), $

  ytitle = 'Variances', $

  title = 'Eigen values', xminor=0, $

  xtickname = 'Comp. ' + ([1, 3, 5]).tostring(), $

  xstyle = 1, $

  xtickval = [1, 3, 5], $

  fill_color = 'light gray', $

  thick = 1, $

  ytickdir = 1, $

  xticklen = 0, $

  yminor= 0)

p.axes[2].hide = 1

p.axes[3].hide = 1

我的目标是,在调用 R 时尽可能使用“原生”IDL 语法,而不是通过传递字符串字面量命令给 Python 或 R。换句话说,R 调用“看起来像”IDL 调用。

我还想展示在 IDL 中生成类似图形输出的等效命令,相对于 R 的输出,因此您将看到显示一对绘图窗口:上面显示的 R 图形和下面显示的 IDL 等效图形。

在右下角重新创建 R 双标图的 IDL 代码留给读者作为练习!

即将发布

即将在 IDL Data Point 上发布的博客文章将包含一个更深入的示例,将基于 R 的数据分类方案集成到 IDL 中。

扩展您针对无人机影像的 ENVI 分析能力 地理空间智能的大构想:小卫星