R语言编程篇 您所在的位置:网站首页 r语言执行命令 R语言编程篇

R语言编程篇

2024-06-29 08:19| 来源: 网络整理| 查看: 265

在R语言中调用C/C++、java、python等计算机语言、运行操作系统命令行命令,可以极大的扩展R语言的功能。这篇文章我们将介绍R语言中如何调用外部函数。

目录 1、R语言系统内部函数

R语言的底层函数绝大部分都是由C语言实现的,用户调用这些底层函数时,这些函数会使用.Primitive、.Internal函数,调用系统内部函数来实现特定的功能。

使用.Primitive调用的内部函数,可以直接与C语言对接,使用形式类似.Primitive(name)(args)。这种形式可以直接通过name调用C语言中的某个函数,所以运行速度更快。R语言中的操作符、基础数学运算函数、流程控制类函数等,为了提高运行效率,都是以.Primitive直接调用内部函数的方式存在的,比如函数abs相当于.Primitive("abs")。但是这类函数没有函数体、参数列表、定义环境,所以不遵守R语言中的参数查找、函数分发等机制(参考 这里),只适合简单明确的传参形式。这类函数的数据类型大多为builtin,但其中一些函数会将未执行的命令作为参数传递给内部函数,所以数据类型为special,比如操作符&&在内部函数中才会决定是否计算第二个参数。

使用.Internal调用的内部函数,参数可以被R语言处理后,再与C语言对接,使用形式类似.Internal(call)。以这种方式作为函数体(或函数体中的一条语句)的函数,本质上与普通函数无异。但需要注意的是,.Internal也是用.Primitive函数实现的,相当于.Primitive(".Internal")。

> .Primitive("+")(1:10, -1) [1] 0 1 2 3 4 5 6 7 8 9 > .Internal(strtoi("13141F", base = 16L)) [1] 1250335

实际上无论以何种方式调用的内部函数,都以do_作为函数名的前缀,且都只能接受4个SEXP类型的参数,其中op的作用在于,当该内部函数对应R语言中的多个函数时(比如R语言中的操作符 cppFunction( + code = " + SEXP ParseEval(const char * expr){ + return R_ParseEvalString(expr, R_GlobalEnv); + } + " + )

3、调用操作系统命令行命令

我们可以在R语言中使用system、system2函数,调用操作系统命令行中的命令。这两个函数都可以重定向操作系统命令行的标准输入、标准输出、错误输出流,并决定是否在R语言后台调用这些命令,但它们的参数设置略有不同。以下是system2函数的部分参数释义:

command参数即需要被调用的操作系统命令行命令 args参数即需要传递给命令的参数 stdout、stderr参数即操作系统命令行标准输出与错误输出的输出位置,默认输出到R语言命令行,NULL或FALSE表示舍弃这些输出内容,TRUE表示将这些输出内容存放到R语言中的字符串数组对象中,当然也可以是一个路径,表示输出到到特定文件中 stdin参数即操作系统命令行标准输入的接收位置,仅当input参数为空时有效,默认从R语言命令行接收输入,当然也可以是一个路径,表示从特定文件中接收输入 input参数即需要作为操作系统命令行标准输入的字符串数组,其中每个字符串代表一行命令 env参数即需要提前设置的操作系统环境变量,需要以name=value形式的字符串数组提供 wait参数即R语言是否应该等待命令完成,当需要接收命令的输出内容时,必须等待命令完成 timeout参数即命令完成的时限(秒),如果命令超出这个时限仍未完成,则会终止命令并抛出超时错误

使用system、system2函数,我们不仅可以运行操作系统命令(如ls、cd等),还可以调用其它脚本语言(如python、R等),但这种调用方式并不能直接将命令返回值转化为相应的R语言对象,而且直接将输出结果转化为字符串,往往会破坏输出结果的数据结构。所以这种方式更适合调用操作系统命令行,完成一些不需要用到返回值的操作,比如编译C/C++脚本、后台运行某项任务等。当然我们也可以借助字符串类型的数据交换格式,在操作系统命令行与R语言命令行之间传递数据。比如我们可以将输出结果转化为json字符串,然后在R语言中解析json字符串,即可将输出结果转化为相应的R语言对象。

# 调用操作系统命令行下的R语言 > system("R --slave -e '1:10 - 1'", intern = TRUE) [1] " [1] 0 1 2 3 4 5 6 7 8 9" > system2("R", "--slave -e '1:10 - 1'", stdout = TRUE) [1] " [1] 0 1 2 3 4 5 6 7 8 9" # 使用json字符串传递高级数据类型的数据 > result rjson::fromJSON(result) [1] 0 1 2 3 4 5 6 7 8 9

4、调用其它计算机语言

上文我们已经介绍了如何在R语言中通过操作系统命令行调用其它计算机语言,但这种方法必须使用操作系统标注输出,才能将其它计算机语言的计算结果(返回值)传递给R语言。当然我们也可以使用第三方程序包,直接在R语言中调用特定的计算机语言,比如我们可以使用rJava程序包,在R与java之间进行数据传递、方法调用。更多关于rava的使用帮助,请参考 这里。

> library(rJava) # 启动JVM > .jinit() [1] 0 # 在JVM中创建一个字符串对象s > s print(s) [1] "Java-Object{Hello World!}" # 获取JVM中字符串对象s对应的值 > .jstrVal(s) [1] "Hello World!" # 调用字符串对象s的length方法, # 注意returnSig参数为返回值对应R语言中的数据类型 # 此外返回值还可以是以下类型: # I integer D double (numeric) J long (*) F float (*) # V void Z boolean C char (integer) B byte (raw) # L 类型的Java对象 (比如,Ljava/lang/Object) # [ 类型的数组对象 (比如,[D double类型的数组) > .jcall(s, returnSig = "I", method = "length") [1] 12 # 调用字符串对象s的indexOf方法 > s$indexOf("World") [1] 6

并非所有桥接计算机语言的程序包都能实现两种计算机语言之间数据无缝对接,比如rPython程序包就是通过json字符串的形式,在R与pthon之间传递数据的。以下代码展示了rPython在R语言中调用python的基本原理(linux操作系统下调用python2.7),当然rPython中加入了错误处理、跨版本兼容等机制,所以真正实现起来会更加复杂。更多关于python的C/C++接口规范,请参考 这里。

> WD rPython.c rPython.o rPython.so writeLines(con = rPython.c, text = ' + #include + + void python_init(){ + Py_Initialize(); + PyRun_SimpleString("import json"); + } + void python_stop(){ + Py_Finalize(); + } + void python_exec(char** code) + { + PyRun_SimpleString(*code); + } + void python_get( const char** name, char** value ) + { + PyObject * module = PyImport_AddModule("__main__"); + PyObject * dictionary = PyModule_GetDict(module); + PyObject * result = PyDict_GetItemString(dictionary, *name ); + *value = PyString_AS_STRING(result); + } + ') # 生成rPython动态链接库 > system2("gcc", paste(" -c", rPython.c, " -o", rPython.o, + system2("python-config", "--includes", stdout = TRUE))) > system2("gcc", paste("-shared", rPython.o, " -o", rPython.so, + system2("python-config", "--ldflags", stdout = TRUE))) # 载入rPython动态链接库 > dyn.load(rPython.so) # 在R语言中编写包裹函数 > python_init python_stop python_exec python_get python_get("abc") [1] "Hello World!" > python_stop()

思考思考 sum函数没有参数列表,那么na.rm = FALSE参数是其默认参数吗? 如何使用R语言系统函数实现inline程序包中的cfunction函数? 如何在其它计算机语言中调用R语言?



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有