gpt4 book ai didi

r - Purrr-Fection : In Search of An Elegant Solution to Conditional Data Frame Operations Leveraging Purrr

转载 作者:行者123 更新时间:2023-12-04 06:55:58 29 4
gpt4 key购买 nike

背景

我有一个问题,可能有多种解决方案,但我相信有一个尚未发现的优雅解决方案利用 purrr。

示例代码

我有一个如下的大数据框,为此我在下面提供了一个示例:

library(tibble)
library(ggmap)
library(purrr)
library(dplyr)

# Define Example Data
df <- frame_data(
~Street, ~City, ~State, ~Zip, ~lon, ~lat,
"226 W 46th St", "New York", "New York", 10036, -73.9867, 40.75902,
"5th Ave", "New York", "New York", 10022, NA, NA,
"75 Broadway", "New York", "New York", 10006, -74.01205, 40.70814,
"350 5th Ave", "New York", "New York", 10118, -73.98566, 40.74871,
"20 Sagamore Hill Rd", "Oyster Bay", "New York", 11771, NA, NA,
"45 Rockefeller Plaza", "New York", "New York", 10111, -73.97771, 40.75915
)

挑战

我想对 lon 的所有位置进行地理标记和 lat列当前为 NA .有很多方法可以解决这个问题,其中一种如下所示:
# Safe Code is Great Code
safe_geocode <- safely(geocode)

# Identify Data to be Geotagged by Absence of lon and lat
data_to_be_geotagged <- df %>% filter(is.na(lon) | is.na(lat))

# GeoTag Addresses of Missing Data Points
fullAddress <- paste(data_to_be_geotagged$Street,
data_to_be_geotagged$City,
data_to_be_geotagged$State,
data_to_be_geotagged$Zip,
sep = ", ")

fullAddress %>%
map(safe_geocode) %>%
map("result") %>%
plyr::ldply()

问题

虽然我可以让上述工作,甚至与新发现的 lon 争吵和 lat坐标回到原始数据框,整个方案感觉很脏。我相信有一种优雅的方法可以利用管道和 purrr 来遍历数据框,并根据 lon 的缺失有条件地对位置进行地理标记。和 lat .

我经历过很多兔子洞,包括 purrr::pmap试图在构建完整地址时并行遍历多个列(以及 rowwise()by_row() )。尽管如此,我在构建任何可以称为优雅解决方案的东西方面都做得不够好。

提供的任何见解将不胜感激。

最佳答案

真的,您想避免调用 geocode没有必要,因为它很慢,如果你使用谷歌,你每天只有 2500 个查询。因此,最好在同一个调用中创建两列,这可以通过列表列来完成,使用 do 创建新版本的 data.frame ,或自联接。

1.带有列表栏

使用列表列,您可以创建 lon 的新版本和 latifelse , 地理编码,如果有 NA s,否则只是复制现有值。然后,摆脱旧版本的列并取消嵌套新的列:

library(dplyr)
library(ggmap)
library(tidyr) # For `unnest`

# Evaluate each row separately
df %>% rowwise() %>%
# Add a list column. If lon or lat are NA,
mutate(data = ifelse(any(is.na(c(lon, lat))),
# return a data.frame of the geocoded results,
list(geocode(paste(Street, City, State, Zip))),
# else return a data.frame of existing columns.
list(data_frame(lon = lon, lat = lat)))) %>%
# Remove old columns
select(-lon, -lat) %>%
# Unnest newly created ones from list column
unnest(data)

## # A tibble: 6 × 6
## Street City State Zip lon lat
## <chr> <chr> <chr> <dbl> <dbl> <dbl>
## 1 226 W 46th St New York New York 10036 -73.98670 40.75902
## 2 5th Ave New York New York 10022 -73.97491 40.76167
## 3 75 Broadway New York New York 10006 -74.01205 40.70814
## 4 350 5th Ave New York New York 10118 -73.98566 40.74871
## 5 20 Sagamore Hill Rd Oyster Bay New York 11771 -73.50538 40.88259
## 6 45 Rockefeller Plaza New York New York 10111 -73.97771 40.75915

2.与 do do , 另一方面,从旧的部分创建一个全新的 data.frame。它需要稍微笨重的 $符号,带有 .表示通过管道输入的分组 data.frame。使用 ifelse而不是 ifelse让您避免在列表中嵌套结果(无论如何,它们必须在上面)。
       # Evaluate each row separately
df %>% rowwise() %>%
# Make a new data.frame from the first four columns and the geocode results or existing lon/lat
do(bind_cols(.[1:4], if(any(is.na(c(.$lon, .$lat)))){
geocode(paste(.[1:4], collapse = ' '))
} else {
.[5:6]
}))

它返回与第一个版本完全相同的东西。

3. 在一个子集上,用自连接重组

如果 ifelse过于困惑,您可以只对子集进行地理编码,然后通过将行绑定(bind)到 anti_join 来重新组合,即 df 中的所有行但不是子集 . :
df %>% filter(is.na(lon) | is.na(lat)) %>% 
select(1:4) %>%
bind_cols(geocode(paste(.$Street, .$City, .$State, .$Zip))) %>%
bind_rows(anti_join(df, ., by = c('Street', 'Zip')))

它返回相同的内容,但新的地理编码行位于顶部。相同的方法适用于列表列或 do ,但由于不需要合并两组列,只需 bind_cols会成功的。

4. 在具有 mutate_geocode 的子集上
ggmap实际上包括一个 mutate_geocode当传递一个 data.frame 和一列地址时将添加 lon 和 lat 列的函数。它有一个问题:它不能接受超过地址的列名,因此需要一个包含整个地址的列。因此,虽然这个版本可能非常好,但它需要创建和删除一个包含整个地址的额外列,使其不简洁:
df %>% filter(is.na(lon) | is.na(lat)) %>% 
select(1:4) %>%
mutate(address = paste(Street, City, State, Zip)) %>% # make an address column
mutate_geocode(address) %>%
select(-address) %>% # get rid of address column
bind_rows(anti_join(df, ., by = c('Street', 'Zip')))

## Street City State Zip lon lat
## 1 5th Ave New York New York 10022 -73.97491 40.76167
## 2 20 Sagamore Hill Rd Oyster Bay New York 11771 -73.50538 40.88259
## 3 45 Rockefeller Plaza New York New York 10111 -73.97771 40.75915
## 4 350 5th Ave New York New York 10118 -73.98566 40.74871
## 5 75 Broadway New York New York 10006 -74.01205 40.70814
## 6 226 W 46th St New York New York 10036 -73.98670 40.75902

5.基础R

Base R 可以直接赋值给一个子集,这使得这里的成语简单得多,即使它需要很多子集:
df[is.na(df$lon) | is.na(df$lat), c('lon', 'lat')] <- geocode(paste(df$Street, df$City, df$State, df$Zip)[is.na(df$lon) | is.na(df$lat)])

结果与第一个版本相同。

所有版本仅调用 geocode两次。

请注意,虽然您可以使用 purrr对于这项工作,它并不比普通的 dplyr 更适合。 . purrr擅长处理列表,虽然列表列是一种选择,但实际上并不需要对其进行操作。

关于r - Purrr-Fection : In Search of An Elegant Solution to Conditional Data Frame Operations Leveraging Purrr,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39172444/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com