前言

使用R语言进行数据处理是非常方便的,几行代码就可以完成很复杂的操作。但是,对于数据的连续处理,还是有人觉得代码不好看,要么是长长的函数嵌套调用,有点像Lisp感觉,括号包一切;要么就是每次操作赋值一个临时变量,啰嗦。为什么就不能像Linux的管道一样优雅呢?

magrittr包在这样场景中被开发出来,通过管道的方式让连续复杂数据的处理操作,代码更短,更容易读,甚至一行代码可以搞定原来10行代码的事情。

目录

  1. magrittr介绍
  2. magrittr安装
  3. magrittr包的基本使用
  4. magrittr包的扩展功能

1. magrittr介绍

magrittr包被定义为一个高效的管道操作工具包,通过管道的连接方式,让数据或表达式的传递更高效,使用操作符%>%,可以直接把数据传递给下一个函数调用或表达式。magrittr包的主要目标有2个,第一是减少代码开发时间,提高代码的可读性和维护性;第二是让你的代码更短,再短,短短短…

magrittr包,主要定义了4个管道操作符,分另是%>%, %T>%, %$% 和 %<>%。其中,操作符%>%是最常用的,其他3个操作符,与%>%类似,在特殊的使用场景会起到更好的作用。当正确掌握这几个操作符后,你一定会爱不释手的,快去把所有的代码都重构吧,砍掉原来大段冗长的代码是一件多么令人激动的事情啊。

magrittr的项目主页:https://github.com/smbache/magrittr

2. magrittr安装

本文所使用的系统环境

  • Win10 64bit
  • R: 3.2.3 x86_64-w64-mingw32/x64 b4bit

magrittr是在CRAN发布的标准库,安装起来非常简单,2条命令就可以了。


~ R
> install.packages('magrittr')
> library(magrittr)

3. magrittr包的使用

对于magrittr包的使用,其实就是掌握这4个操作符的用法,向右操作符%>%, 向左操作符%T>%, 解释操作符%$% 和 复合赋值操作符%<>%。

3.1 %>% 向右操作符(forward-pipe operator)

%>%是最常用的一个操作符,就是把左侧准备的数据或表达式,传递给右侧的函数调用或表达式进行运行,可以连续操作就像一个链条一样。

现实原理如下图所示,使用%>%把左侧的程序的数据集A传递右侧程序的B函数,B函数的结果数据集再向右侧传递给C函数,最后完成数据计算。

比如,我们要做下面的事情。(这是一个YY的需求。)

  1. 取10000个随机数符合,符合正态分布。
  2. 求这个10000个数的绝对值,同时乘以50。
  3. 把结果组成一个100*100列的方阵。
  4. 计算方阵中每行的均值,并四舍五入保留到整数。
  5. 把结果除以7求余数,并话出余数的直方图。

我们发现上面的5个过程是连续的,正常的代码我要怎么实现呢。


# 设置随机种子
> set.seed(1)# 开始
> n1<-rnorm(10000)            # 第1步
> n2<-abs(n1)*50              # 第2步
> n3<-matrix(n2,ncol = 100)   # 第3步
> n4<-round(rowMeans(n3))     # 第4步
> hist(n4%%7)                 # 第5步

输出的直方图:

上面的代码写法是,每一行实现一个条件,但中间多了不少的临时变量。再看另外一种的写法,括号包一切。


# 设置随机种子
> set.seed(1)
> hist(round(rowMeans(matrix(abs(rnorm(10000))*50,ncol=100)))%%7)

输出的直方图:

我分别用两种常见的代码风格,实现了我们的需求。再看看%>%的方式,有多么的不一样。


# 设置随机种子
> set.seed(1)# 开始
> rnorm(10000) %>%
+   abs %>% `*` (50)  %>%
+   matrix(ncol=100)  %>%
+   rowMeans %>% round %>%
+   `%%`(7) %>% hist

输出的直方图:

一行代码,不仅搞定所有的事情,而且结构清楚,可读性非常强。这就是管道代码风格,带来的优雅和简约。

3.2 %T>% 向左操作符(tee operator)

%T>%向左操作符,其实功能和 %>% 基本是一样的,只不过它是把左边的值做为传递的值,而不是右边的值。这种情况的使用场景也是很多的,比如,你在数据处理的中间过程,需要打印输出或图片输出,这时整个过程就会被中断,用向左操作符,就可以解决这样的问题。

现实原理如下图所示,使用%T>%把左侧的程序的数据集A传递右侧程序的B函数,,B函数的结果数据集不再向右侧传递,而是把B左侧的A数据集再次向右传递给C函数,最后完成数据计算。

我们把上面的需求稍微进行调整,在最后增加一个要求,就会用到向左操作符。

  1. 取10000个随机数符合,符合正态分布。
  2. 求这个10000个数的绝对值,同时乘以50。
  3. 把结果组成一个100*100列的方阵。
  4. 计算方阵中每行的均值,并四舍五入保留到整数。
  5. 把结果除以7求余数,并话出余数的直方图。
  6. 对余数求和

由于输出直方图后,返回值为空,那么再继续管道,就会把空值向右进行传递,这样计算最后一步时就会出错。这时我们需求的是,把除以7的余数向右传递给最后一步求和,那么就可以用到 %T>% 了

直接使用%>%向右传值,出现异常。


> set.seed(1)
> rnorm(10000) %>%
+   abs %>% `*` (50)  %>%
+   matrix(ncol=100)  %>%
+   rowMeans %>% round %>%
+   `%%`(7) %>% hist %>% sum
Error in sum(.) : invalid 'type' (list) of argument

使用 %T>% 把左边的值,再向右传值,则结果正确。


> rnorm(10000) %>%
+   abs %>% `*` (50)  %>%
+   matrix(ncol=100)  %>%
+   rowMeans %>% round %>%
+   `%%`(7) %T>% hist %>% sum
[1] 328

3.3 %$% 解释操作符(exposition pipe-operator)

%$% 的作用是把左侧数据的属性名传给右侧,让右侧的调用函数直接通过名字,就可以获取左侧的数据。比如,我们获得一个data.frame类型的数据集,通过使用 %$%,在右侧的函数中可以直接使用列名操作数据。

现实原理如下图所示,使用%$%把左侧的程序的数据集A传递右侧程序的B函数,同时传递数据集A的属性名,作为B函数的内部变量方便对A数据集进行处理,最后完成数据计算。

下面定义一个3列10行的data.frame,列名分别为x,y,z,或缺x列大于5的数据集。使用 %$% 把列名x直接传到右侧进行判断。这里.代表左侧的完整数据对象。一行代码就实现了需求,而且这里不需要显示的定义中间变量。


> set.seed(1)
> data.frame(x=1:10,y=rnorm(10),z=letters[1:10]) %$% .[which(x>5),]x          y z
6   6 -0.8204684 f
7   7  0.4874291 g
8   8  0.7383247 h
9   9  0.5757814 i
10 10 -0.3053884 j

如果不使用%$%,我们通常的代码写法为:


> set.seed(1)
> df<-data.frame(x=1:10,y=rnorm(10),z=letters[1:10])
> df[which(df$x>5),]x          y z
6   6 -0.8204684 f
7   7  0.4874291 g
8   8  0.7383247 h
9   9  0.5757814 i
10 10 -0.3053884 j

从代码中可以发现,通常的写法是需要定义变量df的,df一共要被显示的使用3次,就是这一点点的改进,会让代码看起来更干净。

3.4 %<>% 复合赋值操作符(compound assignment pipe-operator)

%<>%复合赋值操作符, 功能与 %>% 基本是一样的,对了一项额外的操作,就是把结果写到左侧对象。比如,我们需要对一个数据集进行排序,那么需要获得排序的结果,用%<>%就是非常方便的。

现实原理如下图所示,使用%<>%把左侧的程序的数据集A传递右侧程序的B函数,B函数的结果数据集再向右侧传递给C函数,C函数结果的数据集再重新赋值给A,完成整个过程。

定义一个符合正态分布的100个随机数,计算绝对值,并按从小到大的顺序排序,获得并取前10个数字赋值给x。


> set.seed(1)
> x<-rnorm(100) %<>% abs %>% sort %>% head(10)
> x[1] 0.001105352 0.016190263 0.028002159 0.039240003 0.044933609 0.053805041 0.056128740[8] 0.059313397 0.074341324 0.074564983

是不是太方便了,一行就实现了一连串的操作。但是这里同时有一个陷阱,需要注意一下 %<>% 必须要用在第一个管道的对象处,才能完成赋值的操作,如果不是左侧第一个位置,那么赋值将不起作用。


> set.seed(1)
> x<-rnorm(100)# 左侧第一个位置,赋值成功
> x %<>% abs %>% sort %>% head(10)
> x[1] 0.001105352 0.016190263 0.028002159 0.039240003 0.044933609 0.053805041 0.056128740[8] 0.059313397 0.074341324 0.074564983# 左侧第二个位置,结果被直接打印出来,但是x的值没有变
> x %>% abs %<>% sort %>% head(10)[1] 0.001105352 0.016190263 0.028002159 0.039240003 0.044933609 0.053805041 0.056128740[8] 0.059313397 0.074341324 0.074564983
> length(x)
[1] 10# 左侧第三个位置,结果被直接打印出来,但是x的值没有变
> x %>% abs %>% sort %<>% head(10)[1] 0.001105352 0.016190263 0.028002159 0.039240003 0.044933609 0.053805041 0.056128740[8] 0.059313397 0.074341324 0.074564983
> length(x)
[1] 10

4. magrittr包的扩展功能

我们已经了解了magrittr包的4个操作符的使用,除了操作符,我们再看一下magrittr还有哪些功能。

  • 符号操作符定义
  • %>%对代码块的传递
  • %>%对函数的传递

    4.1 符号操作符定义

    为了让链条传递看起来更友好,magrittr对于常见的计算符号操作符进行的重新定义,让每个操作都对应用一个函数,这样所有的传递调用代码都是风格统一的。比如,add()函数和`+`是等价的。

    下面列出对应的列表:

    
    extract                   `[`
    extract2              `[[`
    inset                     `[<-`
    inset2                    `[[<-`
    use_series            `$`
    add                   `+`
    subtract              `-`
    multiply_by           `*`
    raise_to_power            `^`
    multiply_by_matrix    `%*%`
    divide_by             `/`
    divide_by_int             `%/%`
    mod                   `%%`
    is_in                     `%in%`
    and                   `&`
    or                    `|`
    equals                    `==`
    is_greater_than           `>`
    is_weakly_greater_than    `>=`
    is_less_than              `<`
    is_weakly_less_than   `<=`
    not (`n'est pas`)      `!`
    set_colnames              `colnames<-`
    set_rownames              `rownames<-`
    set_names             `names<-`
    

    我们来看一下使用的效果。对一个包括10个随机数的向量的先*5再+5。

    
    # 使用符号的写法
    > set.seed(1)
    > rnorm(10) %>% `*`(5) %>% `+`(5)[1]  1.8677309  5.9182166  0.8218569 12.9764040  6.6475389  0.8976581  7.4371453  8.6916235[9]  7.8789068  3.4730581# 使用函数的写法
    > set.seed(1)
    > rnorm(10) %>% multiply_by(5) %>% add(5)[1]  1.8677309  5.9182166  0.8218569 12.9764040  6.6475389  0.8976581  7.4371453  8.6916235[9]  7.8789068  3.4730581
    

    上面计算结果是完全一样的,用函数替换了符号。其实,这种转换的操作在面向对象的封装时是非常有用的,像hibernate封装了所有的SQL,XFire封装了WebServices协议等。

    4.2 %>%传递到代码块

    有些时候,我们对同一个数据块的要进行次行的处理,一条语句是很难完成的,这些就需要一个代码块也进行处理。把数据集传递到{}代码块中,传入的数据集以.来表示,通过一段代码来完成操作,而不是一句话完成操作。

    比如,对一个包括10个随机数的向量的先*5再+5,求出向量的均值和标准差,并从小到大排序后返回前5条。

    
    > set.seed(1)
    > rnorm(10)    %>%
    +   multiply_by(5) %>%
    +   add(5)         %>%
    +   {
    +     cat("Mean:", mean(.),
    +         "Var:", var(.), "\n")
    +     sort(.) %>% head
    +   }
    Mean: 5.661014 Var: 15.23286
    [1] 0.8218569 0.8976581 1.8677309 3.4730581 5.9182166 6.6475389
    

    通过{}包装的代码块,就可以很方便的完成多少处理的复杂操作。

    4.3 %>%传递到函数

    传递到函数和传递到代码块设计是类似的,是把一个数据集传给一个匿名函数,进行复杂的数据数据的操作。在这里,我们会显示的定义数据集的名字作为匿名函数的参数。

    比如,对鸢尾花数据集进行处理,只保留第一行和最后一行作为结果。

    
    > iris %>%
    +     (function(x) {
    +         if (nrow(x) > 2)
    +             rbind(head(x, 1), tail(x, 1))
    +         else x
    +     })Sepal.Length Sepal.Width Petal.Length Petal.Width   Species
    1            5.1         3.5          1.4         0.2    setosa
    150          5.9         3.0          5.1         1.8 virginica
    

    这里x就是iris数据集,作为了函数的显示参数,被应用于后续的数据处理过程。

    通过对magrittr的学习,我们掌握了一些特殊的R语言代码的编程技巧,用magrittr包写出的R语言程序,与传统的R语言代码是有区别,可以你的程序很简单、很高效。

R语言中管道操作 %%, %T%, %$% 和 %%相关推荐

  1. R语言数据分析笔记——t检验(含正态性检验和方差齐性检验在SPSS和R语言中的操作t检验(单样本、双独立样本、配对样本)在Excel、SPSS、R语言中的操作)

    前言:本文为个人学习笔记,为各大网站上的教学内容之综合整理,综合整理了①假设分析的基础知识.②正态性检验和方差齐性检验在SPSS和R语言中的操作.③t检验(单样本.双独立样本.配对样本)在Excel. ...

  2. R语言中的管道函数操作 %>%

    R语言中的管道操作 %>% :相当于将左边的作为右边函数的第一个参数. 快捷键:ctrl+shift+M 例如:f(x,y)等价于x %>% f(y) g(f(x,y),z)等价于x %& ...

  3. R语言中的管道操作——magrittr包

    R语言中的管道操作--magrittr包 一.项目环境 开发工具:RStudio R:3.5.2 相关包:magritter 二.数据准备以及问题阐述 这次要解决的问题是如何使用提取数据框中所有包含缺 ...

  4. 【R语言中如何去除替换NA相关操作】

    R语言中如何去除替换NA相关操作 1.去除矩阵所有含NA的行 2.去除矩阵特定列中含NA的行 3.替换矩阵中的NA值为0 4.将矩阵中某一列的特殊值替换为NA 1.去除矩阵所有含NA的行 data=n ...

  5. R 语言中的高级图像处理包

    最新的 magick 包是为能够在 R 中更现代化.简单化高质量图像处理而进行的一次努力.该包封装了目前最强大的开源图片处理库 ImageMagick STL . ImageMagick 库具有大量功 ...

  6. r语言 rgl 强制过程中_一个R语言中操纵矢量空间数据的标准化工具—sf

    ​注: 本文是R语言sf包的核心开发者和维护者--来自德国明斯特大学的地理信息学教授:Edzer Pebesma 的一篇关于sf包的简介,发表于2018年7月的R语言期刊,主要讲述了sf的定位.功能. ...

  7. R语言中使用pkgbuild::find_rtools查看是否有Rtools、使用Sys.which函数查看make是否存在、如果没有则安装、使用writeLines函数绑定R和Rtools

    R语言中使用pkgbuild::find_rtools(debug = TRUE)查看是否有Rtools.使用Sys.which函数查看make是否存在.如果没有则安装Rtools.使用writeLi ...

  8. r语言 将表格导出为csv_如何将R语言中表格数据输出为Excel文件.pdf

    如何将R 语言中的表格数据输出为Excel 文件 熊荣川 六盘水师范学院生物信息学实验室 xiongrongchuan@126.com /u/Bearjazz 平台的开放性使得R 语言具有了丰富的运算 ...

  9. r语言中的或怎么表示什么不同_R经典入门 之 R语言的基本原理与概念 -- 200430

    一.基本原理 R是一种解释型语言,输入的命令可以直接被执行,不同于C等编译语言需要构成完整的程序才能运行. R的语法非常简单和直观.合法的R函数总是带有圆括号的形式,即使括号内没有内容(如,ls()) ...

最新文章

  1. Android memory
  2. Hibernate【XXXX.hbm.xml】总结
  3. HUD - 4463 Outlets
  4. Angular jasmine.expect单步调试
  5. 天哪!原来PWM这么简单
  6. Oracle 11g 新特性 -- Invisible Indexes(不可见的索引) 说明
  7. 4013-基于深度优先搜索的两顶点路径存在与否的判断(C++,附详细思路)
  8. 转豆瓣--梁海棠尽管死了,但却占领了陈少杰的身心。乔燕尽管还…
  9. MongoDB副本集配置系列二:配置MongoDB副本集
  10. 大屏可视化项目之智慧楼宇 智慧园区项目 智慧城市项目 智慧水库项目 RayData 效果 U3D项目 UE4项目 ventuz 系列 三维可视化 大屏可视化
  11. Mesh平滑处理的几种算法比较
  12. 产品经理必懂的28个心理学效应
  13. 数值分析Guass分解——错误讨论
  14. Java成员变量初始化顺序
  15. php vip卡,vip.php
  16. csgo 一键配置cfg、道具图、练枪图、连跳图
  17. 全缓存、行缓存和无缓存
  18. 微型计算机赛睿寒冰5评测,为什么说寒冰5才是赛睿性价比最高的游戏耳机?
  19. 伤感 html代码,让对方瞬间心酸的文案,伤感入体,痛彻心扉!
  20. 常见的有规律的单复数转换(随笔)

热门文章

  1. 剑指offer(C++)-JZ36:二叉搜索树与双向链表(数据结构-树)
  2. linux格式化nfs,NFS协议详解与配置实现
  3. mysql 存储ts数据_理解性记忆MySQL数据库
  4. python高手养成_不要总抱怨它慢了 突破性能瓶颈 找到Python序列筛选数据的最优解...
  5. ftp linux 推送文件_Linux下SSH用FTP命令上传文件至另一个FTP空间
  6. Python协程原理介绍及基本使用
  7. 亲密关系沟通-【认识需求2】-建立良好沟通环境
  8. 21天JenkinsDay11 对某个job单独设置权限
  9. 上一秒投简历下一秒被裁 ?小心,你的一举一动可能都在监控中
  10. java socket 浏览器_java实现websocket(图文)