使用管道操作符提高代码简洁性

在编写R语言代码时,有时候需要对一个变量进行一系列的运算,例如对于一个同时包含数值列和字符串列的数据框,如果要计算所有数值列之间的相关系数,一般要分两步,第一步首先筛选数据框中的数值列,第二步计算数值列之间的相关系数。

x=data.frame(x1=c(1,34,22),x2=c(4,6,29),x3=c('a','b','c'))
  • 1

假设我们需要计算上数据框x中数值列的相关系数,通常有两种做法:

  • 分步进行
x_num=x[,unlist(lapply(x,function(i){is.numeric(i)==TRUE}))]
cor(x_num)
  • 1
  • 2
##           x1        x2
## x1 1.0000000 0.2262448
## x2 0.2262448 1.0000000
  • 1
  • 2
  • 3

在分步进行的方法中,我们需要保存每一步产生的中间结果,用于下一步的计算,对于包含多步骤连续运算的计算问题,分步进行将会变得非常繁琐。

  • 嵌套函数
cor(x[,unlist(lapply(x,function(i){is.numeric(i)==TRUE}))])
  • 1
##           x1        x2
## x1 1.0000000 0.2262448
## x2 0.2262448 1.0000000
  • 1
  • 2
  • 3

以上展示了嵌套函数的写法,嵌套函数通过逐层向外扩充表示对数据进行从内到外的不断依次计算,通常对于一两步连续运算,嵌套函数的写法还可以接受,但是超过三步的运算,如果不断向外嵌套,对于他人阅读理解代码以及代码的整洁性是非常不理想的,此外,嵌套写法不利于代码的修改。

以上两种写法是初学者在学习R语言执行多步计算时经常采用的写法,一种更为简洁明了、便于维护的写作方式便是今天讲的管道操作符。如果有人之前用过dplyrdplyr这个程序包,想必已经对于管道操作符的高效有了一定的了解和掌握。事实上,dplyrdplyr中管道符的实现是依赖于另一个函数包magrittrmagrittr,此处主要讲解该软件包中对于管道操作符的一些常用用法。

magrittrmagrittr包含四种管道操作符”%>%”,”%T>%”,”%<>%”,”%$%”,其中最重要最常用的是第一个”%>%”操作符。管道操作符是通过一种流程式的书写方式来表达一系列依次进行的运算操作,逻辑清晰且书写简便,下面通过一系列实际例子讲解管道操作符”%>%”的使用。

管道操作符”%>%”的基本用法

library(magrittr)
x[,unlist(lapply(x,function(i){is.numeric(i)==TRUE}))]%>%cor()
  • 1
  • 2
##           x1        x2
## x1 1.0000000 0.2262448
## x2 0.2262448 1.0000000
  • 1
  • 2
  • 3

注意到上式中管道操作符的写法”%>%cor()”,事实上,管道操作符的实质就是将左边表达式(前一步运算)返回的结果默认地传给后续要执行的函数,因此管道操作符的实质可以用如下表达式清晰地表示为:

管道操作符:x%>%f1()%>%f2()
嵌套表达式:f2(f1(x))
分步书写: res_1=x
res_2=f1(res_1)
res_3=f2(res_2)
  • 1
  • 2
  • 3
  • 4
  • 5

可以看出,使用管道操作符具有逻辑清晰,书写方便的优点,此外管道操作符的表达方式允许我们方便地增加或删除其中一步的运算。

管道操作符中‘.’号的用法

在使用管道操作符时,默认地实际上是将左边表达式的结果作为右边函数的第一个参数传入的,如果右边函数只有一个参数,那自然无需考虑,但对于右边函数有多个参数,我们并不希望表达式的结果作为第一个参数时,就需要考虑更换默认的参数位置了。如何更换呢?这就需要了解‘.’在管道操作符中的用法。‘.’表达的即是左边表达式返回的结果,请观察下例:

x[,unlist(lapply(x,function(i){is.numeric(i)==TRUE}))]%>%cor(.)
  • 1
##           x1        x2
## x1 1.0000000 0.2262448
## x2 0.2262448 1.0000000
  • 1
  • 2
  • 3

注意到,在右边函数中有一个‘.’,这表示的即是左边筛选的数据框结果,对于右边函数只有一个参数或者只需要将表达式作为第一个参数传入的情形,我们可以不用显示地将这个‘.’号写出来,但对于需要更改表达式结果作为函数其他位置的参数或者需要将表达式结果的其他形式作为函数参数的情形,则需要使用‘.’号来显示地表达上一表达式返回的结果。下面通过实例分别讲解这两种情况: 
– 将表达式结果作为其他位置的参数传入

假设需要通过sum函数计算一系列向量的和,通常我们会制定na.rm参数来设定是否忽略缺失值。如果我们需要根据前面表达式的结果(TRUE or FALSE)来决定是否忽略缺失值NA,便会遇到一个问题,na.rm参数并不是sum函数的第一个参数,为了正确地执行,我们需要修改表达式参数的默认位置,这一需求便可通过‘.’来实现

TRUE%>%sum(c(1,2,3,NA),na.rm = .)
  • 1
## [1] 6
  • 1

可以看到,通过显示地制定‘.’的位置,我们可以更改参数的默认位置,‘.’号可以在函数中出现在任意多次任意位置,表示其他参数设定需要依赖该结果。

– 将表达式结果的其他形式作为函数参数

第二种用法实际上和第一种用法是一致的,在此单一列出只是为了更清楚的展示。借助tidyr中的fill函数来说明这一用法。tidyr中的fill函数可以用来根据前一行的值填充后一行的缺失值。

x=data.frame(x1=c(1,NA,3),x2=c(12.3,34,NA))
x
  • 1
  • 2
##   x1   x2
## 1 1 12.3
## 2 NA 34.0
## 3 3 NA
  • 1
  • 2
  • 3
  • 4

这种填充缺失值的方法对于一系列时间上连续的采样样本应用较为合适。使用tidyr时,需要指定哪一列需要填充,如果我们需要填充函数的所有列,则需要在传入所有的列名称。由于列名称是数据框的某一属性,因此此时我们的函数既需要表达式的结果(即数据框)作为函数的第一个参数,又需要表达式结果的其他属性或者变形作为函数的另外参数,这一问题的解决可以依靠‘.’号来实现。

library(tidyr)
x%>%fill(names(.))
  • 1
  • 2
##   x1   x2
## 1 1 12.3
## 2 1 34.0
## 3 3 34.0
  • 1
  • 2
  • 3
  • 4

更为具体的,可以写成

x%>%fill(.,names(.))
  • 1
##   x1   x2
## 1 1 12.3
## 2 1 34.0
## 3 3 34.0
  • 1
  • 2
  • 3
  • 4

以上便是‘.’号的用法。

magrittr管道操作符使用解释(一)的更多相关文章

  1. R语言中的管道操作符 %>% %T>% %$% %<>%

    magrittr 包的官网 https://magrittr.tidyverse.org/ magrittr 包的 github 主页 https://github.com/tidyverse/mag ...

  2. Linux - 命令行 管道(Pipelines) 详细解释

    命令行 管道(Pipelines) 详细解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24249529 管道操作符" ...

  3. Linux - 命令行 管道(Pipelines) 具体解释

    命令行 管道(Pipelines) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/24249529 管道操作符" ...

  4. MongoDB入门---聚合操作&管道操作符&索引的使用

    经过前段时间的学习呢,我们对MongoDB有了一个大概的了解,接下来就要开始使用稍稍深入一点的东西了,首先呢,就是MongoDB中的聚合函数,跟mysql中的count等函数差不多.话不多说哈,我们先 ...

  5. SQL Server 运行计划操作符具体解释(2)——串联(Concatenation )

    本文接上文:SQL Server 运行计划操作符具体解释(1)--断言(Assert) 前言: 依据计划.本文開始讲述另外一个操作符串联(Concatenation).读者能够依据这个词(中英文均可) ...

  6. SQL Server 运行计划操作符具体解释(3)——计算标量(Compute Scalar)

    接上文:SQL Server 运行计划操作符详细解释(2)--串联(Concatenation ) 前言: 前面两篇文章介绍了关于串联(Concatenation)和断言(Assert)操作符,本文介 ...

  7. (数据科学学习手札144)使用管道操作符高效书写Python代码

    本文示例代码已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes 1 简介 大家好我是费老师,一些比较熟悉pandas的读者 ...

  8. SQL Server 运行计划操作符具体解释(1)——断言(Assert)

    前言: 非常多非常多地方对于语句的优化,一般比較靠谱的回复即使--把运行计划发出来看看.当然那些仅仅看语句就说怎样怎样改代码,我一直都是拒绝的,由于这样的算是纯蒙.依据本人经验,大量的性能问题单纯从语 ...

  9. RxJava系列之二 变换类操作符具体解释1

    1.回想 上一篇文章我们主要介绍了RxJava , RxJava 的Observables和 RxJava的just操作符.以及RxJava一些经常使用的操作. 没看过的抓紧点我去看吧. 事实上RxJ ...

随机推荐

  1. Java中this和super关键字

    今天练习到Java中的this和super关键字,我有如下总结: 1.子类继承父类,子类初始化对象,必须先调用父类构造方法,因为随时有可能要使用父类的成员变量. 2.get和set方法只是对成员变量进 ...

  2. Eloquent JavaScript #08# Bugs and Errors

    索引 Notes strict mode js类型 js测试 Debugging Exceptions finally 异常分支 Exercise Retry The locked box Notes ...

  3. Linux的简单介绍.

    Linux操作系统概述: Linux是基于Unix的开源免费的操作系统,由于系统的稳定性和安全性几乎成为程序代码运行的最佳系统环境.Linux是由Linux Torvalds(林纳斯·托瓦兹)起初开发 ...

  4. pyqt5界面切换

    #主要的思路就是创建两个frame(如果有两个以上同理)使用setVisible()函数显示或者隐藏frame 参数是bool值import sys from PyQt5.QtWidgets impo ...

  5. Tensorflow学习笔记01

    Tensorflow官方网站:http://tensorflow.org/ 极客学院Tensorflow中文版:http://wiki.jikexueyuan.com/project/tensorfl ...

  6. Spring Boot(九):定时任务

    Spring Boot(九):定时任务 一.pom包配置 pom包里面只需要引入springboot starter包即可 <dependencies> <dependency> ...

  7. 零基础Python爬虫实现(爬取最新电影排行)

    提示:本学习来自Ehco前辈的文章, 经过实现得出的笔记. 目标网站 http://dianying.2345.com/top/ 网站结构 要爬的部分,在ul标签下(包括li标签), 大致来说迭代li ...

  8. Java快捷键与搜狗输入法快键的冲突

    搜狗五笔,简繁体转换快捷键 ctrl+shift+F Java编辑器 格式化 Ctrl+Shift+F 搜狗输入法 搜狗词典 Ctrl+/ Java编辑器 取消注释 Ctrl+/ Java编辑器 注释 ...

  9. opencv学习之路(17)、边缘检测

    一.概述 二.canny边缘检测 #include "opencv2/opencv.hpp" using namespace cv; void main() { //Canny边缘 ...

  10. ODAC(V9.5.15) 学习笔记(四)TOraDataSet

    名称 类型 说明 SequenceMode TSequenceMode ODAC可以直接利用Oracle中的序列对象为表的主键赋值,从而实现主键自动增长的功能.该属性决定了在什么场合下使用序列: sm ...