【问题标题】:How can I use purrr to extract an attribute in a deeply nested list column in R?如何使用 purrr 在 R 中深度嵌套的列表列中提取属性?
【发布时间】:2020-04-18 22:53:06
【问题描述】:

我使用 Google Geocoding API 来请求数千个地址的位置数据。每个请求的内容都被解析为一个列表。结果列表已添加到“get_response”列下。

我在使用 purrr 包从这些列表中提取单个属性时遇到很大困难,希望各位优秀的人能提供帮助。

library(tidyverse)
#> Warning: package 'tidyverse' was built under R version 3.5.3

l1 <- list(results = list(list(geometry = list(location = list(lat = 41.9, lng = -87.6)))), status = "OK")
l2 <- list(results = list(list(geometry = list(location = list(lat = 35.1, lng = -70.6)))), status = "OK")

starting_df <- tribble(~name, ~get_response,
                     "first_location", l1,
                     "second_location", l2)
print(starting_df)
#> # A tibble: 2 x 2
#>   name            get_response    
#>   <chr>           <list>          
#> 1 first_location  <named list [2]>
#> 2 second_location <named list [2]>

下面我将演示如何一次提取一个属性:

pluck(starting_df[1,]$get_response, 1, "results", 1, "geometry", "location", "lat")
#> [1] 41.9
pluck(starting_df[2,]$get_response, 1, "results", 1, "geometry", "location", "lat")
#> [1] 35.1

这是我想要的输出:

desired_output <- tribble(~name, ~get_response, ~lat,
                                  "first_location", l1, 41.9,
                                  "second_location", l2, 35.1)
print(desired_output)
#> # A tibble: 2 x 3
#>   name            get_response       lat
#>   <chr>           <list>           <dbl>
#> 1 first_location  <named list [2]>  41.9
#> 2 second_location <named list [2]>  35.1

这是我尝试使用 purrr::map

new_df <- mutate(starting_df, lat = map(get_response, pluck(1, "results", 1, "geometry", "location", "lat")))
#> Error: Can't convert NULL to function

reprex package (v0.3.0) 于 2020-04-18 创建

有谁知道这样做的好方法吗?

【问题讨论】:

    标签: r tidyverse purrr


    【解决方案1】:

    您可以使用purrr 中的map_dbl,并使用公式格式应用您的pluck:

    starting_df %>%
    mutate(lat=map_dbl(get_response,~pluck(.x,"results",1,"geometry","location","lat")))
    
    # A tibble: 2 x 3
      name            get_response       lat
      <chr>           <list>           <dbl>
    1 first_location  <named list [2]>  41.9
    2 second_location <named list [2]>  35.1
    

    【讨论】:

      【解决方案2】:

      我们可以从purrr使用map

      library(dplyr)
      library(purrr)
      starting_df %>%
          mutate(lat = map_dbl(get_response, ~ pluck(.x, 1, 1, 
                   'geometry', 'location', 'lat', .default = NA_real_), 
                    .default = NA_real_))
      # A tibble: 2 x 3
      #  name            get_response       lat
      #  <chr>           <list>           <dbl>
      #1 first_location  <named list [2]>  41.9
      #2 second_location <named list [2]>  35.1
      

      当某些元素没有'lat'时它也应该工作

      l3 <-  list(results = list(list(geometry = 
               list(location = list( lng = -70.6)))), status = "OK")
      
      starting_df <- tribble(~name, ~get_response,
                            "first_location", l1,
                            "second_location", l2,  
                             "third_location", l3)
      starting_df %>%
           mutate(lat = map_dbl(get_response, ~ pluck(.x, 1, 1, 
                    'geometry', 'location', 'lat', .default = NA_real_), 
                      .default = NA_real_))
      # A tibble: 3 x 3
      #  name            get_response       lat
      #  <chr>           <list>           <dbl>
      #1 first_location  <named list [2]>  41.9
      #2 second_location <named list [2]>  35.1
      #3 third_location  <named list [2]>  NA  
      

      或者另一个选项是rowwise from dplyr

      starting_df %>% 
           rowwise %>%
           mutate(lat = pluck(get_response, 1, 1, 'geometry', 'location', 'lat'))
      # A tibble: 2 x 3
      # Rowwise: 
      #  name            get_response       lat
      #  <chr>           <list>           <dbl>
      #1 first_location  <named list [2]>  41.9
      #2 second_location <named list [2]>  35.1
      

      【讨论】:

      • 谢谢!两种选择都有效。我确实想指出我的数据有一些没有“纬度”值的响应,因此使用 map_dbl 不起作用。相反,我使用了 map,然后将值分别转换为 double。
      • @ThomasSteiner 如果您没有任何值,请使用.default = NA_real_
      猜你喜欢
      • 1970-01-01
      • 2021-10-20
      • 2019-02-03
      • 1970-01-01
      • 2023-04-01
      • 1970-01-01
      • 2016-04-17
      • 2019-06-25
      相关资源
      最近更新 更多