purrr::map可以将任何类型转换为其他类型。

13

有没有办法使用 purrr::map 映射到任何类型?

library(tidyverse)
library(lubridate)

df <- data_frame(id = c(1, 1, 1, 2, 2, 2), 
                 val = c(1, 2, 3, 1, 2, 3), 
                 date = ymd("2017-01-01") + days(1:6))

df1 <- df %>% nest(-id) %>% 
  mutate(first_val = map_dbl(data, ~ .$val[1]), 
         first_day = map(data, ~ .$date[1]))

我希望first_day是一个类型为<date>的列,就像df中的一样。我尝试了flatten,但这不起作用,因为它将该列强制转换为数字。

4个回答

11

purrr很注重类型的稳定性,这需要一些时间来适应。

在此情况下,它返回一个列表,而您希望得到一个<date>对象。

对于您的情况,一个简单且“稳定”的解决方案是将第二个map替换为map_dbl,然后使用lubridateas_date将输出转换回<date>对象,就像这样:

df3 <- df %>% nest(-id) %>% 
   mutate(first_val = map_dbl(data, ~ .$val[1]), 
          first_day = as_date(map_dbl(data, ~ .$date[1])))

您将获得:

# A tibble: 2 × 4
  id             data                 first_val  first_day
 <dbl>          <list>                  <dbl>     <date>
 1              <tibble [3 × 2]>         1      2017-01-02
 2              <tibble [3 × 2]>         1      2017-01-05

这正是你想要的(针对此示例)。

编辑:对于除<date>之外的任何其他类型,您都需要找到不同的解决方案,但是,专用于标准类型的map_lglmap_dblmap_chr等已经覆盖了。


6

除了使用map_dbl() %>% as_date()的方法外,另一种方法是在所需输出列上使用unnest()

library(tidyverse)
library(lubridate)
#> 
#> Attaching package: 'lubridate'
#> The following object is masked from 'package:base':
#> 
#>     date

df <- data_frame(id = c(1, 1, 1, 2, 2, 2), 
                 val = c(1, 2, 3, 1, 2, 3), 
                 date = ymd("2017-01-01") + days(1:6))

df %>% nest(-id) %>% 
  mutate(first_val = map_dbl(data, ~ .$val[1]), 
         first_day = map(data, ~ .$date[1])) %>% 
  unnest(first_day)
#> # A tibble: 2 x 4
#>      id data             first_val first_day 
#>   <dbl> <list>               <dbl> <date>    
#> 1     1 <tibble [3 × 2]>         1 2017-01-02
#> 2     2 <tibble [3 × 2]>         1 2017-01-05

此文档由reprex软件包(v0.2.1)于2018年11月17日创建。


4

purrr 1.0.0 中,您可以使用 map_vec

map_vec()(以及map2_vec()pmap_vec())处理更多类型的向量。 map_vec()map_lgl()map_int()map_dbl()map_chr() 扩展到任意类型的向量,例如日期、因子和日期时间:

df %>% nest(data = -id) %>% 
  mutate(first_val = map_dbl(data, ~ .$val[1]), 
         first_day = map_vec(data, ~ .$date[1]))

输出

# A tibble: 2 × 4
     id data             first_val first_day 
  <dbl> <list>               <dbl> <date>    
1     1 <tibble [3 × 2]>         1 2017-01-02
2     2 <tibble [3 × 2]>         1 2017-01-05

map_vec 将总是返回一个正确的向量类别更简单的向量(如果没有公共类型则报错),但你也可以通过 .ptype 指定它:

df %>% nest(data = -id) %>% 
  mutate(first_val = map_vec(data, ~ .$val[1], .ptype = integer()), 
         first_day = map_vec(data, ~ .$date[1], .ptype = Date()))

1
你可以使用 purrr 的 reduce()c() 来实现。
library(tidyverse)
library(lubridate)

df <- tibble(id = c(1, 1, 1, 2, 2, 2), 
             val = c(1, 2, 3, 1, 2, 3), 
             date = ymd("2017-01-01") + days(1:6))

df1 <- df %>% nest(data = -id) %>% 
    mutate(first_val = map_dbl(data, ~ .$val[1]), 
           first_day = reduce(map(data, ~ .$date[1]), c))

结果:

> df1
# A tibble: 2 × 4
     id data             first_val first_day 
  <dbl> <list>               <dbl> <date>    
1     1 <tibble [3 × 2]>         1 2017-01-02
2     2 <tibble [3 × 2]>         1 2017-01-05

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接