从事数据分析以来,一直有个强迫症,那就是喜欢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引用。类型转换如下:
从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://rstudio.github.io/reticulate/index.html