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

在编写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. HDU 1527 取石子游戏 (威佐夫博弈)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1527 有两堆石子,数量任意,可以不同.游戏开始由两个人轮流取石子.游戏规定,每次有两种不同的取法,一是 ...

  2. memcache,redis对比

    一.问题:     数据库表数据量极大(千万条),要求让服务器更加快速地响应用户的需求.   二.解决方案:      1.通过高速服务器Cache缓存数据库数据      2.内存数据库     ( ...

  3. javascript 的01

    javaScript可以实现验证表单.制作特效等功能,JavaScript的目的主要是一下三点: 1 客户端表单验证2 页面动态效果3 jQuery的基础JavaScript是一种描述性语言,也是一种 ...

  4. pyenv安装

    petalinux-config出错 以为是pyenv的问题,后发现不是,把pyenv的安装卸载总结如下: 折腾了半天发觉是安装了pyenv导致的python版本混乱,卸载后问题解决了.(卸载过程见h ...

  5. Linux sed 命令字符串替换使用方法详解

    1. sed替换的基本语法 sed 's/原字符串/替换字符串/' 单引号里面,s表示替换,三根斜线中间是替换的样式,特殊字符需要使用反斜线”\”进行转义.2. 单引号” ‘ ’”是没有办法用反斜线” ...

  6. Docker学习笔记之docker volume 容器卷的那些事(一)

    预览目录 volume 方式 相关用例 使用方式 使用 volume driver bind mount 方式 相关用例 使用方式 配置selinux标签 配置macOS的安装一致性 tmpfs 方式 ...

  7. linux 文件 md5校验

    为解决官方发布的软件包被别人更改或者软件在传输过程中出现传输错误等问题,软件官方在提供软件包的同时,还提供一个保存MD5校验码的文件. Linux/unix中可以使用命令 # md5sum 文件名 方 ...

  8. rabbitmq集群安装与配置(故障恢复)

    0.首先按照http://www.cnblogs.com/zhjh256/p/5922562.html在至少两个节点安装好(不建议单机,没什么意义) 1.先了解rabbitmq集群架构,http:// ...

  9. 【题解】Luogu P4450 双亲数

    原题传送门 这题需要运用莫比乌斯反演(懵逼钨丝繁衍) 设F(t)表示满足gcd(x,y)%t=0的数对个数,f(t)表示满足gcd(x,y)=t的数对个数,实际上答案就是f(d) 这就满足莫比乌斯反演 ...

  10. 【4Opencv】如何识别出轮廓准确的长和宽

    问题来源: 实际项目中,需要给出识别轮廓的长度和宽度. 初步分析: 轮廓分析的例程为: int main( int argc, char** argv ){    //read the image  ...