purrr 0.2.0
purrr 0.2.0
Hadley Wickham
2016-01-06
Categories: Packages tidyverse
原文地址
我很高兴的发布了purrr
0.2.0。Purrr
填补了R的函数式编程工具中的缺失部分,让你的函数更加纯粹、类型稳定。
我仍然在研究purrr应该做什么,以及它如何与基础R、dplyr
, tidyr
的现有功能进行比较。一个主要的观点影响了当前的版本那就是:为编程设计的函数应该是类型稳定的。类型稳定性是一个来自Julia的概念,并引起了我的注意。尽管R和Julia中的函数可以返回不同类型的输出,但总的来说,您应该努力让函数总是返回相同类型数据结构。这使得函数对变化的输入更加稳健,并且使得它们合理。(但是并不是每个函数都能是类型稳定的)
Purrr 0.2.0
为map,flattens和try()添加了类型稳定的替代方法,如下所述。还有很多其他的小改进,错误修复和一些弃用。请参阅发布说明以获取完整的更改列表。
类型稳定的映射
map是一个让函数作用在每个向量上的函数。在基础R中的map函数有*apply族:lapply()
,sapply()
,vapply
等。lapply()
是一个类型稳定的函数:无论输入什么,都将返回一个列表。sapply
不是一个类型稳定函数,它会根据输入返回不同的类型的输出。下面的代码会向你展示一个简单的sapply
的例子,它会根据他的输入返回一个向量,矩阵或者列表。
df <- data.frame(a = 1L,b = 1.5,y = Sys.time(),z = ordered(1)
)df[1:4] %>% sapply(class) %>% str()
#> List of 4
#> $ a: chr "integer"
#> $ b: chr "numeric"
#> $ y: chr [1:2] "POSIXct" "POSIXt"
#> $ z: chr [1:2] "ordered" "factor"
df[1:2] %>% sapply(class) %>% str()
#> Named chr [1:2] "integer" "numeric"
#> - attr(*, "names")= chr [1:2] "a" "b"
df[3:4] %>% sapply(class) %>% str()
#> chr [1:2, 1:2] "POSIXct" "POSIXt" "ordered" "factor"
#> - attr(*, "dimnames")=List of 2
#> ..$ : NULL
#> ..$ : chr [1:2] "y" "z"
这种行为使得sapply()
适合于交互式使用,因为它通常会正确地猜测并给出一个有用的数据结构。
但在包或生产代码中使用它是不合适的,因为如果输入不是你所期望的,它将不会失败,而是会返回一个意外的数据结构。这通常会在整个过程中导致进一步的错误,所以你会收到令人困惑的错误消息,并且很难找出根本原因。
基础R有一个sapply()
的类型稳定版本叫做vapply()
。它需要一个额外的参数来决定输出结果。purrr
则是采用不同的方法,purrr
有多个函数而不是一个函数做所有的事情,每个函数对应一种常见的输出类型: map_lgl()
, map_int()
, map_dbl()
, map_chr()
, and map_df()
。
- int,代表integer
- dbl,代表double
- chr,代表character向量或字符串。
- dttm,代表日期+时间(a date + a time)
- lgl,代表逻辑判断TRUE或者FALSE
- fctr,代表因子类型factor
- date,代表日期dates.
这些要么产生指定类型的输出要么抛出一个错误。 这迫使你立即处理这个问题:
df[1:4] %>% map_chr(class)
#> Error: Result 3 is not a length 1 atomic vector
df[1:4] %>% map_chr(~ paste(class(.), collapse = "/"))
#> a b y z
#> "integer" "numeric" "POSIXct/POSIXt" "ordered/factor"
map()
的其他变体具有相似的后缀。 例如,map2()
允许你并行地迭代两个向量:
x <- list(1, 3, 5)
y <- list(2, 4, 6)
map2(x, y, c)
#> [[1]]
#> [1] 1 2
#>
#> [[2]]
#> [1] 3 4
#>
#> [[3]]
#> [1] 5 6
map2()
总是返回一个列表。如果要将相应的值相加,并将结果存储为double类型的向量,你可以使用 map2_dbl()
:
map2_dbl(x, y, `+`)
#> [1] 3 7 11
另一个map变体是invoke_map()
,它接受函数列表和参数列表。 它也有类型稳定的后缀:
#IQR为四分位距,mad为中位数绝对偏差
spread <- list(sd = sd, iqr = IQR, mad = mad)
x <- rnorm(100)invoke_map_dbl(spread, x = x)
#> sd iqr mad
#> 0.9121309 1.2515807 0.9774154
Type-stable flatten
当类型稳定性很重要时,另一种情况是将嵌套列表展平为更简单的数据结构。基础R有unlist
函数,但它是危险的,因为它总是成功的。作为替代,purrr
提供了flatten_lgl()
, flatten_int()
, flatten_dbl()
, 和 flatten_chr()
:
x <- list(1L, 2:3, 4L)
x %>% str()
#> List of 3
#> $ : int 1
#> $ : int [1:2] 2 3
#> $ : int 4
x %>% flatten() %>% str()
#> List of 4
#> $ : int 1
#> $ : int 2
#> $ : int 3
#> $ : int 4
x %>% flatten_int() %>% str()
#> int [1:4] 1 2 3 4
Type-stable try()
另一个在基础R中的非类型稳定函数是 try
。try()
确保表达式总是成功,返回原始值或错误消息:
str(try(log(10)))
#> num 2.3
str(try(log("a"), silent = TRUE))
#> Class 'try-error' atomic [1:1] Error in log("a") : non-numeric argument to mathematical function
#>
#> ..- attr(*, "condition")=List of 2
#> .. ..$ message: chr "non-numeric argument to mathematical function"
#> .. ..$ call : language log("a")
#> .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
safely()
是一个类型稳定版本的try()
。它总是返回2个元素:结果与错误,有一个总为NULL
(有结果则不报错,报错则没结果)
safely(log)(10)
#> $result
#> [1] 2.302585
#>
#> $error
#> NULL
safely(log)("a")
#> $result
#> NULL
#>
#> $error
#> <simpleError in .f(...): non-numeric argument to mathematical function>
注意到safely()
将一个函数作为输入,并返回一个“安全”函数,这个函数永远不会抛出错误。一个强大的技术是地使用safely()
和map()
一起尝试对列表中的每个元素进行操作:
#注意safely()是将函数作为输入,故若对多个值进行操作,可用map
safe_sqrt <- safely(sqrt, otherwise = NA_real_)
numbers_with_error <- list(1, 2, 3, "spam", 4)
map(numbers_with_error, safe_sqrt)%>%transpose()
safe_log <- safely(log)
x <- list(10, "a", 5)
log_x <- x %>% map(safe_log)str(log_x)
#> List of 3
#> $ :List of 2
#> ..$ result: num 2.3
#> ..$ error : NULL
#> $ :List of 2
#> ..$ result: NULL
#> ..$ error :List of 2
#> .. ..$ message: chr "non-numeric argument to mathematical function"
#> .. ..$ call : language .f(...)
#> .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
#> $ :List of 2
#> ..$ result: num 1.61
#> ..$ error : NULL
这是输出稍微不方便,因为你更想有一个三个结果的列表,另一个三个错误的列表。 您可以使用新的transpose()
函数来切换层次结构中第一个和第二个层次的顺序:
log_x %>% transpose() %>% str()
#> List of 2
#> $ result:List of 3
#> ..$ : num 2.3
#> ..$ : NULL
#> ..$ : num 1.61
#> $ error :List of 3
#> ..$ : NULL
#> ..$ :List of 2
#> .. ..$ message: chr "non-numeric argument to mathematical function"
#> .. ..$ call : language .f(...)
#> .. ..- attr(*, "class")= chr [1:3] "simpleError" "error" "condition"
#> ..$ : NULL
这样可以很容易地提取原始函数失败的输入,或者保存成功结果:
keep()
保留TRUE
的
discard()
保留FALSE
的
results <- x %>% map(safe_log) %>% transpose()(ok <- results$error %>% map_lgl(is_null))
#> [1] TRUE FALSE TRUE
(bad_inputs <- x %>% discard(ok))
#> [[1]]
#> [1] "a"
(successes <- results$result %>% keep(ok) %>% flatten_dbl())
#> [1] 2.302585 1.609438
一般分3步:
- 保留转化好的含有result 与 error 的列表
- 使用
map_lgl(is_null)
获取逻辑向量 - 根据逻辑向量与列表得到想要的数
purrr 0.2.0相关推荐
- libgstreamer-1.0.so.0: cannot open shared object file: No such file or directory
1. 问题现象 error while loading shared libraries: libgstreamer-1.0.so.0: cannot open shared object file: ...
- c+语言+null,C/C++语言中NULL、'\0’和0的区别
NULL.'\0'和0的值是一样的,都是0,不过它们的表现形式不一样: 1. NULL: 即空指针,不过在C和C++中并不一样.在VS 2013的库文件string.h中可以看到如果定义. 1 /* ...
- Ubuntu14.04 64位机上安装cuda8.0+cudnn5.0操作步骤
查看Ubuntu14.04 64位上显卡信息,执行: lspci | grep -i vga lspci -v -s 01:00.0 nvidia-smi 第一条此命令可以显示一些显卡的相关信息:如果 ...
- Spring Cloud Alibaba 基础教程:Nacos 生产级版本 0.8.0
Spring Cloud Alibaba 基础教程:Nacos 生产级版本 0.8.0 昨晚Nacos社区发布了第一个生产级版本:0.8.0.由于该版本除了Bug修复之外,还提供了几个生产管理非常重要 ...
- Silverlight 3发布新版3.0.50106.0
微软1月19日发布Silverlight 3新版本3.0.50106.0. 该版本主要修复以下几个问题: 问题一: 当使用图形硬件加速功能(GPU)的时候,如果GPU驱动报错,Silverlight ...
- AS1.0(2.0)中的XML示例
虽然Flash早就升级为AS3.0,但是FMS的服务端编程依然仅支持AS1.0(2.0),服务端与.net通讯的最简单方式莫过于请求一个RESTful的webService或wcf,通过它们返回的xm ...
- 多数编程语言里的0.1+0.2≠0.3?
作者 | Parul Malhotra 译者 | Raku 出品 | AI科技大本营(ID:rgznai100) 我们从小就被教导说0.1+0.2=0.3,但是在奇妙的计算机编程世界里面,事情变得不一 ...
- flannel原理初探针对0.1.0版本
flannel flannel是针对k8s设计的三层的网络解决方案.在k8s中为了使pod之间能够使用一种偏平的网络架构,从而完成跨Pod的网络通信. 官网给的原理图如下: flannel 使用TUN ...
- GTX 1080Ti + cuda8.0 + cuDNN6.0 安装及测试
GPU 显卡厂商已经安装好了,直接安装 cuda8.0 + cuDNN6.0 我这里的显卡是 GTX 1080 Ti cuda安装 我下载的是cuda8.0的是deb格式的1.9个G地址:https: ...
最新文章
- 自定义Kubernetes调度程序来编排高可用性应用程序
- 基于python的人工智能Jiagu深度学习自然语言处理开源工具
- centos7 docker 安装 otter 注意事项
- ASP.NET MVC5+EF6+EasyUI 后台管理系统(47)-工作流设计-补充
- python装饰器函数-python 装饰器 函数被装饰+函数执行
- Android Configuration change引发的问题及解决方法
- 微信平台开发1--开发者模式基本配置
- Maven 使用 Tomcat7
- TensorFlow学习笔记(十二)TensorFLow tensorBoard 总结
- 打钱!我的数据库被黑客勒索了!
- 记一次微信数据库解密过程
- VMware 修复 Workstation、Fusion 和 ESXi中的多个漏洞
- Jquery的jqzoom插件的使用(图片放大镜)
- 一些实用但不为人知的Unix命令
- Elaine的python初学习
- 艺多不压身—摩尔斯电码
- 因为改 UOM conversion 导致库存数量和財务上的数据错误
- GD32F330+DS18B20
- 突破生命法则极限!它会是外星生命的遗传密码?
- DeFi热潮下的安全隐患:流动性危机恐将造成连锁反应 | 非正式会谈
热门文章
- 树莓派B+使用入门RPI库安装wringPi库安装
- Java学习笔记-1.简介
- SQL基础实例(学生课程系统)
- 【Java】Springboot项目中jar包加密
- linux运维高频命令汇总
- 03-19 分布式测试-Selenium Grid
- html中的数字选框,带有复选框和数字类型的HTML表单提交与PHP?
- c#用canny算子做边缘提取_干货 | 边缘检测
- knn的python代码_详细的的KNN代码——python实现
- compose部署redis和mysql_浅析docker-compose部署mysql无法访问的问题