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 ...
随机推荐
- codevs2019 Uva10029 递变阶梯
提交地址:[codevs][Uva] 题目描述 递变是指通过增加.减少或改变单词x中的一个字母,使它变成字典中的另一个单词y.比如将dig变成dog,将dog变成do都是递变.递变阶梯是一个按字典序 ...
- scss的初级学习随笔小计
$white: #fff;$three: #333;$six: #666;$nine: #999;$red: #fff;$orange: #f63;$yellow: #fc0;$opcity: rgb ...
- Map和Set
JavaScript的默认对象表示方式{}可以视为其他语言中的Map或Dictionary的数据结构,即一组键值对. 但是JavaScript的对象有个小问题,就是键必须是字符串.但实际上Number ...
- Coordinator节点
Coordinator节点 Coordinator 节点主要负责segment 的管理和分配.更具体的说,它同通过配置往historical 节点 load 或者 drop segment .Coo ...
- 核心J2EE模式 - 截取过滤器
核心J2EE模式 - 截取过滤器 背景 呈现层请求处理机制接收许多不同类型的请求,这些请求需要不同类型的处理.一些请求被简单转发到适当的处理程序组件,而其他请求必须在进一步处理之前进行修改,审核或未压 ...
- (转)什么是P问题、NP问题和NPC问题
这或许是众多OIer最大的误区之一. 你会经常看到网上出现"这怎么做,这不是NP问题吗"."这个只有搜了,这已经被证明是NP问题了"之类的话.你要知道,大 ...
- struts2 之 Action的优化配置
总结:struts2种action的配置文件会随着业务的增加而增加,导致配置文件膨胀.struts2中提供了三种方案来解决这个问题: 1. 动态方法调用来实现. 2. 通配符配置来解决. 3. 使用注 ...
- 《HelloGitHub》第 13 期
公告 本期推荐的项目到达了 30 个,里面少不了对本项目支持的小伙伴们,再次感谢大家. 本次排版尝试:根据分类项目名排序,为了让大家方便查阅.如果有任何建议和意见欢迎留言讨论 临近 5.1 假期,所以 ...
- grunt轻松入门
项目目录,js源文件 gruntest Gruntfile.js package.json -- js ext community_plugin.js glogin_frm_cover.js iLog ...
- logback配置文件详解
一:根节点<configuration>包含的属性: scan: 当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true. scanPeriod: 设置监测配置文 ...