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

在编写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. cookie 和 session 的一些事 中间件

    cookie 和 session cookie 1. 保存在浏览器上一组组键值对,服务器让浏览器进行设置. 2. 为什么要用cookie? HTTP协议是无状态.使用cookie保存状态. 3. dj ...

  2. ajax 检测用户名是否可用

    下面是一个 ajax 检测用户名是否可用的例子. django  项目中. —— views.py 里—— from django.shortcuts import render,HttpRespon ...

  3. Linux文件管理和编辑常用命令

    Linux文件管理和编辑常用命令 mkdir 命令 功能说明 mkdir 命令用于创建一个目录,mkdir是make directory的缩写 格式: mkdir [选项] 目录名 mkdir 命令的 ...

  4. 一起学习在 Ubuntu 上授予和移除 sudo 权限

    如你所知,用户可以在 Ubuntu 系统上使用 sudo 权限执行任何管理任务.在 Linux 机器上创建新用户时,他们无法执行任何管理任务,直到你将其加入 sudo 组的成员.在这个简短的教程中,我 ...

  5. Django后端项目---- rest framework(3)

    一.版本 程序也来越大时,可能通过版本不同做不同的处理 没用rest_framework之前,我们可以通过以下这样的方式去获取. class UserView(APIView): def get(se ...

  6. javaweb笔记06—(页面跳转及编码格式)

    1.指令:<%@     %>:一个页面可以有多个import, 但是标识本页面为jsp页面的指令只能是一条(建议是一条 ) 2.出错页面:<%@ isError(true)%> ...

  7. How many zero's and how many digits ? UVA - 10061

    Given a decimal integer number you will have to find out how many trailing zeros will be there in it ...

  8. django自定义错误响应

    在做一个web时,总是会出现各种错误,如400.403.404.500等.一般开发都要做对应的处理,给一些友好提示,或返回一些公益广告等. 在Django中,默认提供了常见的错误处理方式,比如: ha ...

  9. 源码部署pxc集群

    想了想还是研究一下怎么源码安装pxc吧,毕竟很多组件都是源码安装的. 环境: yum install -y boost-devel libodb-boost-devel check-devel ope ...

  10. shell脚本一键安装redis集群

    简介: 明天再写,上脚本 #!/bin/bash #-------------------------------------------------------------------------- ...