手记

剪不断理还乱的R与Python

从事数据分析以来,一直有个强迫症,那就是喜欢R不怎么喜欢Python的语法,但是在机器学习方面R包乱的不行,在调参方面不如Python的sklearn好使,尤其是决策树的可视化,因为工作原因,需要决策树的可视化比较直观,但是R中的决策树算法虽然多,但是结果可视化方面简直惨不忍睹,然后一直想着两者能够结合

最近用了rpy2库在Python中调用R,但是感觉怪怪的,不怎么好使,然后无意间发现了R中的又一肾宝:reticulate,好使的不要不要的,所以趁着周末赶紧出个扫盲贴,把使用过程中遇到的问题总结一下。废话不多说,上吧

1、Mac系统中Python版本选择问题

这个问题在Windows系统中只要将Python添加在环境变量中,应该是不会出现的。
而在Mac中,因为Mac有自带的Python2.7,而我用的是Python3.7,所以在默认调用的Python版本方面有点坑,这应该是我安装anocanda的路径选择问题
具体原因可到官网去查看,这里只说明解决办法

  • 方法一

#这个路径是我电脑中的路径,大家要自己去查看自己的路径Sys.setenv(RETICULATE_PYTHON = '/anaconda3/bin/python')
  • 方法二

#使用reticulate包中的use_python函数library(reticulate)
use_python("/anaconda3/bin/python")

另外还有

use_virtualenv()    指定包含Python virtualenv的目录。
use_condaenv()  指定Conda环境的名称。

顺便提一下怎么解决Mac系统下R的中文乱码问题

#使用如下代码,万事大吉Sys.setlocale(category = "LC_ALL", locale = "zh_cn.utf-8”)
#或者
Sys.setlocale(locale =“en_us.UTF-8”)

解决了最基本也是最重要的问题之后,我们就可以在R上任意撒欢啦

2、利用reticulate包安装Python库

这个的话涉及到Python的不同环境了,关于这方面大家自行搜索,因为用的anocanda,所以平常要用的库都有了,不需要再进行管理,这里直接贴出官网的连接
https://rstudio.github.io/reticulate/articles/python_packages.html

3、类型转换

当调用Python时,R数据类型会自动转换为它们等效的Python类型。 当值从Python返回到R时,它们会被转换回R类型。 如果返回自定义类的Python对象,则返回该对象的R引用。类型转换如下:


image.png


从R类型到Python类型的自动转换在大多数情况下都能很好地工作,但是偶尔需要在R方面更加明确地提供Python所期望的类型。

比如,Python API可能需要元组而不是列表。在这种情况下,可以使用tuple()函数,又或者R命名列表被转换为Python字典,但是您也可以使用dict()函数显式地创建一个Python字典:

>(dic <- dict(foo='bar',index=42L))
{'foo': 'bar', 'index': 42}

>py_to_r(dic)$foo[1] "bar"$index[1] 42

>tuple('a','b','c')
('a', 'b', 'c')

4、实际使用

使用repl_python实现与Python的交互

> repl_python() #在R环境中执行Python 3.7.0 (/anaconda3/bin/python)
Reticulate 1.10 REPL -- A Python interpreter in R.>>> import pandas as pd #然后就会发现变成Python环境了,所有语法都用Python的>>> repl_data = pd.read_csv("/Users/pengfeiwang/Desktop/iris.csv",encoding = 'UTF-8')>>> repl_data=repl_data.fillna(0)>>> exit #退出python> str(py$repl_data) #得到Python对象'data.frame':   150 obs. of  6 variables:
 $ Unnamed: 0  : num  1 2 3 4 5 6 7 8 9 10 ...
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : chr  "setosa" "setosa" "setosa" "setosa" ...
 - attr(*, "pandas.index")=RangeIndex(start=0, stop=150, step=1)

4.1、使用import函数调用Python库

通常与来自R的Python对象交互需要使用$操作符来访问所需对象函数的任何属性。在使用$时,Python对象会在可能的情况下自动转换为它们的R等价物。

pd <- import("pandas")
iris_python <- pd$read_csv("/Desktop/iris.csv",encoding = 'UTF-8')
str(iris_python)'data.frame':   150 obs. of  6 variables:
 $ Unnamed: 0  : num  1 2 3 4 5 6 7 8 9 10 ...
 $ Sepal.Length: num  5.1 4.9 4.7 4.6 5 5.4 4.6 5 4.4 4.9 ...
 $ Sepal.Width : num  3.5 3 3.2 3.1 3.6 3.9 3.4 3.4 2.9 3.1 ...
 $ Petal.Length: num  1.4 1.4 1.3 1.5 1.4 1.7 1.4 1.5 1.4 1.5 ...
 $ Petal.Width : num  0.2 0.2 0.2 0.2 0.2 0.4 0.3 0.2 0.2 0.1 ...
 $ Species     : chr  "setosa" "setosa" "setosa" "setosa" ...
 - attr(*, "pandas.index")=RangeIndex(start=0, stop=150, step=1)

可以看到,利用pandas读取进来的数据可以直接被R语言调用

4.2、执行Python文件并调用Python文件中的变量

比如有这么一个文件test.py
里面封印了一个自定义函数

def add(x, y):
  return x + y

然后可以这样在R中调用

#获取Python脚本并使其在R环境中创建的对象可用source_python("/Users/pengfeiwang/Desktop/test.py")
add(5,10)

又或者这样
我们稍微修改下上面的Python代码

def add(x, y):
  return(x + y)

result = add(5,10)

然后在R中执行如下命令:就可以将上面Python代码的结果给导入到R环境中

py_run_file("/Users/pengfeiwang/Desktop/test.py")
py$result

又或者这样

> py_run_string("x=10;y=20")
> py$x[1] 10
> py$y[1] 20

4.3、对象转换

默认情况下,当Python对象返回到R时,它们被转换为等效的R类型。但是,如果您希望将Python显式转换为R,并在缺省情况下处理本机Python对象,则可以将convert = FALSE传递给导入函数。在这种情况下,从import返回的模块将禁用Python到R的转换。
比如,你觉得有些变量在Python中直接运行出来更方便,那么就可以酱紫

np <- import("numpy", convert = FALSE) 
a <- np$array(c(1:4)) #a还是个Python的array对象sum <- a$cumsum() #sum还是个array对象sum_r <- py_to_r(sum) #将Python对象转换为r对象

上面的代码等价于下面的代码

np2 <- import('numpy')
a <- np2$array(c(1:4)) #R对象cumsum(a) #R函数

4.4、获取帮助

如果要是忘了Python函数怎么写了,可以使用

pd <- import('pandas')
py_help(pd$read_csv)

4.5、数值型和索引

数值类型和索引
R和Python有不同的默认数值类型。如果在R中写42,它被认为是浮点数,而在Python中42被认为是整数。

这意味着,当Python API需要一个整数时,需要确保使用r中的L后缀,
Python集合使用的是基于0的索引,而不是您可能熟悉的R中的基于1的索引。
所以利用reticulate包在Python环境获取索引是必须带上L,例如

items$get(0L)

4.6、数组

矩阵和数组可以自动转换成数字数组和数字数组。

当从R转换为NumPy时,NumPy数组直接映射到R数组的底层内存(不进行复制)。在这种情况下,NumPy数组在内存布局中使用基于列的布局,它与R(即Fortran样式,而不是C样式)兼容。当从NumPy转换为R时,R接收到NumPy数组的列有序副本。

还可以使用np_array()函数手动将R数组转换为NumPy。例如,如果需要用C而不是Fortran样式的内存布局创建NumPy数组(以提高面向行计算的性能),或者希望更显式地控制NumPy数组的数据类型,那么可以这样做。下面是np_array()的一些用法示例:

> (a<-np_array(c(1:8),dtype = 'float16'))
[1. 2. 3. 4. 5. 6. 7. 8.]
> (a <- np_array(c(1:8),order = 'C'))
[1 2 3 4 5 6 7 8]

始终要记住,当调用NumPy方法时,数组索引是基于0而不是基于1的,并且需要L后缀来表示它们是整数。

4.7 数据框

这个是重点中的重点,毕竟数据分析常用的就是数据框,下面是两者之间的转换


如果R数框具有行名称,则生成的pandas :DataFrame将使用这些行名称重新建立索引(反之亦然)。还可以对与pandas:DataFrame相关联的DatetimeIndex进行特殊处理;但是,因为R只支持行名称的字符向量,所以它们首先被转换为字符。


4.8 迭代器

如果Python API返回迭代器或生成器,您可以使用iterate()函数与之交互。可以使用iterate()函数对迭代器产生的每个项应用R函数:

> (a <- np_array(c(1:8),order = 'C'))
[1 2 3 4 5 6 7 8]
> (iterate(a,pd$isna))
[1] FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE

4.9 函数

默认情况下,R函数通过泛型签名(函数(…))转换为Python,其中没有关键字参数,也没有参数的默认值。

例如,下面我们对一个R函数应用r_to_py(),然后使用inspect模块获得转换后的函数的参数规范。

> inspect <- import("inspect")
> python_function <- r_to_py(function(a,b=1.5){return(a*b)})
> inspect$getargspec(python_function)
ArgSpec(args=[], varargs='args', keywords='kwargs', defaults=None)

这种默认转换通常工作得很好,但是一些Python库对用户提供回调的函数签名有严格的检查。在这些情况下,泛型函数(…)签名将不能通过此检查。

对于这些情况,您可以使用py_func()来包装R函数,使包装的函数具有与原始R函数完全相同的签名,例如一个参数a没有默认值,另一个参数b有默认值1.5。

> python_function2 <- py_func(function(a,b=1.5){return(a*b)})
> inspect$getargspec(python_function2)
ArgSpec(args=['a', 'b'], varargs=None, keywords=None, defaults=(1.5,))

注意,R函数的签名不能包含深奥的python不兼容的构造。例如,我们不能有带有签名的R函数(a = 1, b),因为Python函数要求没有默认值的参数出现在有默认值的参数之前。



作者:鸣人吃土豆
链接:https://www.jianshu.com/p/6dec8d1d6ed3


0人推荐
随时随地看视频
慕课网APP