如何一次性从数据集中提取纬度和经度

How would you hoist latitude and longitude from a dataset in one stroke

提问人:f0nzie 提问时间:11/8/2023 最后编辑:M--f0nzie 更新时间:11/8/2023 访问量:85

问:

我最近一直在玩嵌套列表,并且能够从深层次中提取数据。我在功能上遇到了一个小问题。我能够提取 5 个和 7 个地址的纬度和经度,但使用两个单独的命令。我想知道是否可以以提取的方式访问列表结构,并且只需要一个命令。示例如下:tidyrhoist()hoist()latlng

library(tidyr)
library(dplyr)
library(repurrrsive)

gmaps_cities_o <- repurrrsive::gmaps_cities
gmaps_cities_o

带输出:

A tibble:5 × 2
  city         json
  <chr>       <list>
 Houston     <list [2]>         
 Washington  <list [2]>         
 New York    <list [2]>         
 Chicago     <list [2]>         
 Arlington   <list [2]>         
5 rows

要提取,我必须编写两段代码:latlng

# extract lat, long for the first address
gmaps_cities_o %>% 
    hoist(json, 
           lat = list("results", 1, "geometry", "location", "lat"),
           lng = list("results", 1, "geometry", "location", "lng")
           )

输出:

A tibble:5 × 4
 city        lat          lng         json
 <chr>       <dbl>        <dbl>      <list>
Houston     29.76043    -95.36980   <list [2]>  
Washington  47.75107    -120.74014  <list [2]>  
New York    40.71278    -74.00597   <list [2]>  
Chicago     41.87811    -87.62980   <list [2]>  
Arlington   32.73569    -97.10807   <list [2]>  
5 rows

对于第二个地址:

# extract lat, long for the second address
gmaps_cities_o %>% 
    hoist(json, 
           lat = list("results", 2, "geometry", "location", "lat"),
           lng = list("results", 2, "geometry", "location", "lng")
           )

带输出:

A tibble:5 × 4
 city          lat          lng        json
 <chr>        <dbl>        <dbl>      <list>
Houston           NA           NA   <list [2]>  
Washington  38.90719    -77.03687   <list [2]>  
New York          NA           NA   <list [2]>  
Chicago           NA           NA   <list [2]>  
Arlington   38.87997    -77.10677   <list [2]>  
5 rows

因此,两个单独的操作来获取和五个城市的 7 个地址。latlng

我可以提取并使用这段代码:latlng

gmaps_cities_o %>% 
    unnest_wider(json) %>% 
    unnest_longer(results) %>% 
    hoist(results,
          lat = list("geometry", "location", "lat"),
          lng = list("geometry", "location", "lng")
          ) %>% 
    select(city, lat, lng)

带输出:

A tibble:7 × 3
 city         lat          lng
 <chr>       <dbl>        <dbl>
Houston     29.76043    -95.36980       
Washington  47.75107   -120.74014       
Washington  38.90719    -77.03687       
New York    40.71278    -74.00597       
Chicago     41.87811    -87.62980       
Arlington   32.73569    -97.10807       
Arlington   38.87997    -77.10677       
7 rows

但是我不能在一次操作中做到这一点似乎是不对的。像这样的东西:hoist()

gmaps_cities_o %>% 
    hoist(json, 
           lat = list("results", (?), "geometry", "location", "lat"),
           lng = list("results", (?), "geometry", "location", "lng")
           )

任何有嵌套列表经验的人都会给我一个提示吗?

r tidyr 嵌套列表

评论


答:

1赞 I_O 11/8/2023 #1

如果您可以使用 base(递归地将函数应用于列表)而不是 ,您可以执行以下操作rapplyhoist

编辑:包括@SamR有用的评论,并添加了一些重塑:

library(dplyr)
library(repurrrsive)

gmaps_cities_o |>
    group_by(city) |>
    reframe(prop_value = json |> unlist(),
            prop_name = names(prop_value)
            ) |>
    filter(grepl('results\\.geometry\\.location\\.(lat|lng)', prop_name)) |>
    ## reshape and clean up:
    group_by(prop_name, city) |>
    mutate(coords_no = row_number(),
           prop_name = gsub('.*\\.', '', prop_name)
           ) |>
    pivot_wider(id_cols = c(coords_no, city),
                names_from = prop_name,
                values_from = prop_value
                )
    

这给了:

## # A tibble: 7 x 4
##   coords_no city       lat        lng         
##       <int> <chr>      <chr>      <chr>       
## 1         1 Arlington  32.735687  -97.1080656 
## 2         2 Arlington  38.8799697 -77.1067698 
## 3         1 Chicago    41.8781136 -87.6297982 
## 4         1 Houston    29.7604267 -95.3698028 
## 5         1 New York   40.7127753 -74.0059728 
## 6         1 Washington 47.7510741 -120.7401386
## 7         2 Washington 38.9071923 -77.0368707 

评论

1赞 SamR 11/8/2023
这很好!一些潜在的改进:1.应该比 .2. 然后你就不需要在 .3.可以替换为。4. 虽然在这种情况下无关紧要(因为没有prop_name称为例如),但您的正则表达式不应使用方括号,而应使用普通括号,即 .group_by(city)rowwise()city = cityreframe()rapply(json, \(x) x) unlist(json)"lta""(lat|lng)"
2赞 SamR 11/8/2023 #2

这是受到I_O的好答案的启发,但足以让人偏离,这可能是一个单独的答案。您可以创建一个函数:my_hoist

my_hoist <- function(x, path) {
    x_flat <- unlist(x)
    x_flat[grepl(paste(path, collapse = "\\."), names(x_flat))]
}

这可以以与 hoist 类似的方式使用,但无需指定索引:

gmaps_cities_o |>
    group_by(city) |>
    reframe(
        lat = my_hoist(json, c("results", "geometry", "location", "lat")),
        lng = my_hoist(json, c("results", "geometry", "location", "lng")),
    )

# # A tibble: 7 × 3
#   city       lat        lng         
#   <chr>      <chr>      <chr>       
# 1 Arlington  32.735687  -97.1080656 
# 2 Arlington  38.8799697 -77.1067698 
# 3 Chicago    41.8781136 -87.6297982 
# 4 Houston    29.7604267 -95.3698028 
# 5 New York   40.7127753 -74.0059728 
# 6 Washington 47.7510741 -120.7401386
# 7 Washington 38.9071923 -77.0368707