purrr is package that extends R’s functional programming capabilities. It brings a lot of new stuff to the table and in this post I show you some of the most useful (at least to me) functions included in purrr.

Getting rid of loops with map()

library(purrr)

numbers <- list(11, 12, 13, 14)

map_dbl(numbers, sqrt)
## [1] 3.316625 3.464102 3.605551 3.741657

You might wonder why this might be preferred to a for loop? It’s a lot less verbose, and you do not need to initialise any kind of structure to hold the result. If you google “create empty list in R” you will see that this is very common. However, with themap() family of functions, there is no need for an initial structure. map_dbl() returns an atomic list of real numbers, but if you use map() you will get a list back. Try them all out!

Map conditionally

map_if()

# Create a helper function that returns TRUE if a number is even
is_even <- function(x){
!as.logical(x %% 2)
} map_if(numbers, is_even, sqrt)
## [[1]]
## [1] 11
##
## [[2]]
## [1] 3.464102
##
## [[3]]
## [1] 13
##
## [[4]]
## [1] 3.741657

map_at()

map_at(numbers, c(1,3), sqrt)
## [[1]]
## [1] 3.316625
##
## [[2]]
## [1] 12
##
## [[3]]
## [1] 3.605551
##
## [[4]]
## [1] 14

map_if() and map_at() have a further argument than map(); in the case of map_if(), a predicate function ( a function that returnsTRUE or FALSE) and a vector of positions for map_at(). This allows you to map your function only when certain conditions are met, which is also something that a lot of people google for.

Map a function with multiple arguments

numbers2 <- list(1, 2, 3, 4)

map2(numbers, numbers2, `+`)
## [[1]]
## [1] 12
##
## [[2]]
## [1] 14
##
## [[3]]
## [1] 16
##
## [[4]]
## [1] 18

You can map two lists to a function which takes two arguments using map_2(). You can even map an arbitrary number of lists to any function using pmap().

By the way, try this in: `+`(1,3) and see what happens.

Don’t stop execution of your function if something goes wrong

possible_sqrt <- possibly(sqrt, otherwise = NA_real_)

numbers_with_error <- list(1, 2, 3, "spam", 4)

map(numbers_with_error, possible_sqrt)
## [[1]]
## [1] 1
##
## [[2]]
## [1] 1.414214
##
## [[3]]
## [1] 1.732051
##
## [[4]]
## [1] NA
##
## [[5]]
## [1] 2

Another very common issue is to keep running your loop even when something goes wrong. In most cases the loop simply stops at the error, but you would like it to continue and see where it failed. Try to google “skip error in a loop” or some variation of it and you’ll see that a lot of people really just want that. This is possible by combining map() and possibly(). Most solutions involve the use of tryCatch() which I personally do not find very easy to use.

Don’t stop execution of your function if something goes wrong and capture the error

safe_sqrt <- safely(sqrt, otherwise = NA_real_)

map(numbers_with_error, safe_sqrt)
## [[1]]
## [[1]]$result
## [1] 1
##
## [[1]]$error
## NULL
##
##
## [[2]]
## [[2]]$result
## [1] 1.414214
##
## [[2]]$error
## NULL
##
##
## [[3]]
## [[3]]$result
## [1] 1.732051
##
## [[3]]$error
## NULL
##
##
## [[4]]
## [[4]]$result
## [1] NA
##
## [[4]]$error
## <simpleError in .f(...): non-numeric argument to mathematical function>
##
##
## [[5]]
## [[5]]$result
## [1] 2
##
## [[5]]$error
## NULL

safely() is very similar to possibly() but it returns a list of lists. An element is thus a list of the result and the accompagnying error message. If there is no error, the error component is NULL if there is an error, it returns the error message.

Transpose a list

safe_result_list <- map(numbers_with_error, safe_sqrt)

transpose(safe_result_list)
## $result
## $result[[1]]
## [1] 1
##
## $result[[2]]
## [1] 1.414214
##
## $result[[3]]
## [1] 1.732051
##
## $result[[4]]
## [1] NA
##
## $result[[5]]
## [1] 2
##
##
## $error
## $error[[1]]
## NULL
##
## $error[[2]]
## NULL
##
## $error[[3]]
## NULL
##
## $error[[4]]
## <simpleError in .f(...): non-numeric argument to mathematical function>
##
## $error[[5]]
## NULL

Here we transposed the above list. This means that we still have a list of lists, but where the first list holds all the results (which you can then access with safe_result_list$result) and the second list holds all the errors (which you can access withsafe_result_list$error). This can be quite useful!

Apply a function to a lower depth of a list

transposed_list <- transpose(safe_result_list)

transposed_list %>%
at_depth(2, is_null)
## $result
## $result[[1]]
## [1] FALSE
##
## $result[[2]]
## [1] FALSE
##
## $result[[3]]
## [1] FALSE
##
## $result[[4]]
## [1] FALSE
##
## $result[[5]]
## [1] FALSE
##
##
## $error
## $error[[1]]
## [1] TRUE
##
## $error[[2]]
## [1] TRUE
##
## $error[[3]]
## [1] TRUE
##
## $error[[4]]
## [1] FALSE
##
## $error[[5]]
## [1] TRUE

Sometimes working with lists of lists can be tricky, especially when we want to apply a function to the sub-lists. This is easily done with at_depth()!

Set names of list elements

name_element <- c("sqrt()", "ok?")

set_names(transposed_list, name_element)
## $`sqrt()`
## $`sqrt()`[[1]]
## [1] 1
##
## $`sqrt()`[[2]]
## [1] 1.414214
##
## $`sqrt()`[[3]]
## [1] 1.732051
##
## $`sqrt()`[[4]]
## [1] NA
##
## $`sqrt()`[[5]]
## [1] 2
##
##
## $`ok?`
## $`ok?`[[1]]
## NULL
##
## $`ok?`[[2]]
## NULL
##
## $`ok?`[[3]]
## NULL
##
## $`ok?`[[4]]
## <simpleError in .f(...): non-numeric argument to mathematical function>
##
## $`ok?`[[5]]
## NULL

Reduce a list to a single value

reduce(numbers, `*`)
## [1] 24024

reduce() applies the function * iteratively to the list of numbers. There’s also accumulate():

accumulate(numbers, `*`)
## [1]    11   132  1716 24024

which keeps the intermediary results.

This function is very general, and you can reduce anything:

Matrices:

mat1 <- matrix(rnorm(10), nrow = 2)
mat2 <- matrix(rnorm(10), nrow = 2)
mat3 <- matrix(rnorm(10), nrow = 2) list_mat <- list(mat1, mat2, mat3) reduce(list_mat, `+`)
##            [,1]       [,2]       [,3]       [,4]      [,5]
## [1,] -0.5228188 0.4813357 0.3808749 -1.1678164 0.3080001
## [2,] -3.8330509 -0.1061853 -3.8315768 0.3052248 0.3486929

even data frames:

df1 <- as.data.frame(mat1)
df2 <- as.data.frame(mat2)
df3 <- as.data.frame(mat3) list_df <- list(df1, df2, df3) reduce(list_df, dplyr::full_join)
## Joining, by = c("V1", "V2", "V3", "V4", "V5")
## Joining, by = c("V1", "V2", "V3", "V4", "V5")
##            V1         V2          V3         V4         V5
## 1 0.01587062 0.8570925 1.04330594 -0.5354500 0.7557203
## 2 -0.46872345 0.3742191 -1.88322431 1.4983888 -1.2691007
## 3 -0.60675851 -0.7402364 -0.49269182 -0.4884616 -1.0127531
## 4 -1.49619518 1.0714251 0.06748534 0.6650679 1.1709317
## 5 0.06806907 0.3644795 -0.16973919 -0.1439047 0.5650329
## 6 -1.86813223 -1.5518295 -2.01583786 -1.8582319 0.4468619

Hope you enjoyed this list of useful functions! If you enjoy the content of my blog, you can follow me on twitter.

转自:https://www.r-bloggers.com/lesser-known-purrr-tricks/?utm_source=feedburner&utm_medium=email&utm_campaign=Feed%3A+RBloggers+%28R+bloggers%29

Lesser known purrr tricks的更多相关文章

  1. Lesser known dplyr tricks

    In this blog post I share some lesser-known (at least I believe they are) tricks that use mainly fun ...

  2. testng 教程之使用参数的一些tricks配合使用reportng

    前两次的总结:testng annotation生命周期 http://www.cnblogs.com/tobecrazy/p/4579414.html testng.xml的使用和基本配置http: ...

  3. (转) How to Train a GAN? Tips and tricks to make GANs work

    How to Train a GAN? Tips and tricks to make GANs work 转自:https://github.com/soumith/ganhacks While r ...

  4. Matlab tips and tricks

    matlab tips and tricks and ... page overview: I created this page as a vectorization helper but it g ...

  5. LoadRunner AJAX TruClient协议Tips and Tricks

    LoadRunner AJAX TruClient协议Tips and Trickshttp://automationqa.com/forum.php?mod=viewthread&tid=2 ...

  6. 【翻译】C# Tips & Tricks: Weak References - When and How to Use Them

    原文:C# Tips & Tricks: Weak References - When and How to Use Them Sometimes you have an object whi ...

  7. 神经网络训练中的Tricks之高效BP(反向传播算法)

    神经网络训练中的Tricks之高效BP(反向传播算法) 神经网络训练中的Tricks之高效BP(反向传播算法) zouxy09@qq.com http://blog.csdn.net/zouxy09 ...

  8. Hex-Rays Decompiler Tips and tricks Volatile memory

    https://www.hex-rays.com/products/decompiler/manual/tricks.shtml First of all, read the troubleshoot ...

  9. hdu 5276 YJC tricks time 数学

    YJC tricks time Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...

随机推荐

  1. 最新windows 0day漏洞利用

    利用视屏:https://v.qq.com/iframe/player.html?vid=g0393qtgvj0&tiny=0&auto=0 使用方法 环境搭建 注意,必须安装32位p ...

  2. Node.js 原理简介

    Node.js 的官方文档中有一段对 Node.js 的简介,如下. Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript ...

  3. PHP7中我们应该学习会用的新特性

    PHP7于2015年11月正式发布,本次更新可谓是PHP的重要里程碑,它将带来显著的性能改进和新特性,并对之前版本的一些特性进行改进.本文小编将和大家一起来了解探讨PHP7中的新特性. 1. 标量类型 ...

  4. 用react开发一个新闻列表网站(PC和移动端)

    最近在学习react,试着做了一个新闻类的网站,结合ant design框架, 并且可以同时在PC和移动端运行: 主要包含登录和注册组件.头部和脚部组件.新闻块类组件.详情页组件.评论和收藏组件等: ...

  5. CSS border实现各个方向等腰直角三角

    CSS代码: .border_cort, .border_corr, .border_corb, .border_corl { display: inline-block; ; ; border-wi ...

  6. redis 压缩链表

    redis 压缩链表 概述 压缩链表是相对于普通链表而言的 当普通链表的数据越来越多, 链表查询性能会低效 当存储的数据较少时, 使用链表存储会浪费空间 压缩链表本质上是一个字符串 压缩链表内存储的数 ...

  7. Spring多种加载Bean方式简析

    1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: <bean id="dictionaryRelMap" class="java.ut ...

  8. (知识点)JavaScript闭包

    下面是我对闭包的理解:(把他们整理出来,整理的过程也是在梳理) 1.首先,在理解闭包之前: 我们首先应该清楚下作用域和作用域链 作用域:每个函数定义时创建时自己的环境即作用域 作用域链:函数内可访问自 ...

  9. MYSQL不能从远程连接的解决方法

    为了在其它电脑上能用root用户登录,需进行以下动作: 首先在mysql服务器端打开mysql 1. mark>mysql -u root -p //输入密码,进入MySQL服务器 2.mysq ...

  10. AspNetCore-MVC实战系列(三)之个人中心

    AspNetCore - MVC实战系列目录 . 爱留图网站诞生 . git源码:https://github.com/shenniubuxing3/LovePicture.Web . AspNetC ...