为何purrr::pmap_dfr会将Date类型转为数值型?如何避免?
为什么
purrr::pmap_dfr会把Date类型转为数值型?怎么解决? 我来帮你搞定这个问题——你碰到的Date列被转成数值的情况,根源在于pmap系列函数传递参数的逻辑:
问题原因
R里的Date类型本质是披着Date外衣的整数,它底层存储的是从1970-01-01开始计算的天数。当pmap_dfr遍历你的数据框时,它会把每一行拆成独立的原子向量传递给自定义函数,这个过程会剥离掉Date的类属性,只留下底层的数值。这就是为什么你的函数里class(d)返回numeric,最终输出的tibble里d列也变成了数值型。
解决方法
这里有几种实用的解决思路,你可以根据自己的场景选择:
1. 在函数中手动还原Date类型
既然参数被转成了数值,那我们就在函数里把它转回去就行,用as.Date()指定原点为1970-01-01:
library(tidyverse) library(lubridate) df <- data.frame( a = c('a', 'b', 'c'), b = c(10, 20, 30), c = c(100.5, 200.5, 300.5), d = c(ymd("2016-01-01"), ymd("2017-01-01"), ymd("2018-01-01")), stringsAsFactors = FALSE ) f <- function(a, b, c, d){ # 把数值转回Date类型 d <- as.Date(d, origin = "1970-01-01") r <- data_frame(a=a, b=b, c=c, d=d, class.of.d=class(d)) return(r) } pmap_dfr(df, f)
运行后你会看到d列恢复成Date类型,class.of.d显示为Date。
2. 传递完整行数据而非拆分参数
如果不想手动转类型,可以让函数接收整行数据,这样就能保留Date的类属性。我们可以先把数据框拆成每行的列表,再用pmap传递:
f_row <- function(row){ r <- data_frame( a = row$a, b = row$b, c = row$c, d = row$d, class.of.d = class(row$d) ) return(r) } df %>% split(1:nrow(.)) %>% pmap(f_row) %>% bind_rows()
这种方法因为直接传递的是带有类属性的行数据,所以Date类型不会丢失。
3. 换用dplyr::rowwise()处理
如果你的需求只是简单的逐行操作,rowwise()会更简洁,而且天然保留列的原始类型:
df %>% rowwise() %>% mutate(class.of.d = class(d)) %>% ungroup()
这个方法不需要额外写自定义函数,适合轻量的逐行计算场景。
内容的提问来源于stack exchange,提问作者dfv-MS
相关产品推荐
相关产品推荐

