Lesser known purrr tricks
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的更多相关文章
- Lesser known dplyr tricks
In this blog post I share some lesser-known (at least I believe they are) tricks that use mainly fun ...
- testng 教程之使用参数的一些tricks配合使用reportng
前两次的总结:testng annotation生命周期 http://www.cnblogs.com/tobecrazy/p/4579414.html testng.xml的使用和基本配置http: ...
- (转) 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 ...
- Matlab tips and tricks
matlab tips and tricks and ... page overview: I created this page as a vectorization helper but it g ...
- LoadRunner AJAX TruClient协议Tips and Tricks
LoadRunner AJAX TruClient协议Tips and Trickshttp://automationqa.com/forum.php?mod=viewthread&tid=2 ...
- 【翻译】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 ...
- 神经网络训练中的Tricks之高效BP(反向传播算法)
神经网络训练中的Tricks之高效BP(反向传播算法) 神经网络训练中的Tricks之高效BP(反向传播算法) zouxy09@qq.com http://blog.csdn.net/zouxy09 ...
- Hex-Rays Decompiler Tips and tricks Volatile memory
https://www.hex-rays.com/products/decompiler/manual/tricks.shtml First of all, read the troubleshoot ...
- hdu 5276 YJC tricks time 数学
YJC tricks time Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?p ...
随机推荐
- Struts 2 实现登录以及显示信息
---恢复内容开始--- 这个星期主要做了一个项目的开始,基于开始学习Struts2的框架首先要先做好Action的按钮 这是我一个Action的展示,chain中是把一个数据带着去跳转另一个网页中 ...
- AOP学习笔记一
软件开发的目的是为了解决各种需求,包括业务需求和系统需求.目前,业界通过使用面向对象的编程思想,已经可以对业务需求等普通关注点进行很好的抽象与封装,并且使之模块化.但是对于系统需求一类的关注点来说,情 ...
- 移动开发中使用的一些meta头部标签整理
<!DOCTYPE html> <!-- 使用 HTML5 doctype,不区分大小写 --> <html lang="zh-cmn-Hans"&g ...
- mac下CSV文件用FileReader、FileWriter读写乱码
先说下windows的excel文件搬到mac下打开为什么会显示乱码. 在win下,excel采用GBK编码,1个汉字是存为2个字节,而mac下各种软件广泛默认使用UTF-8编码方式,如在e ...
- Java 基础知识总结 2
11.Java常用类: StringBuffer StringBuffer 是使用缓冲区的,本身也是操作字符串的,但是与String类不同,String类的内容一旦声明之后则不可以改变,改变的只是其内 ...
- Java中的socket通信
socket又称套接字,应用程序通常通过"套接字"向网络发出请求或应答网络请求 建立过程:服务器监听-客户端发出请求-建立链接-通信 特点:1.基于tcp链接,数据传输有保障,2. ...
- OutOfMemoryError内存不足
java.lang.OutOfMemoryError内存不足错误.当可用内存不足以让Java虚拟机分配给一个对象时抛出该错误. 造成此错误的原因有一下几个: 1.内存中加载的数据量过于庞大,如一次从数 ...
- 短路运算|字符串操作函数|内存mem操作函数
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- cookie方法封装及cookie缺点分析
p.p1 { margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Consolas; color: #4f5d66 } p.p2 { margin: 0.0px ...
- 第三章 Docker的镜像
3.1.获取镜像 获取镜像 docker pull name[:TAG] #默认是从网络下载镜像,不指定tag会人下载latest标签下的镜像. 1 2 docker search ubuntu do ...