从地址中提取唯一的美国邮政编码(5 位数字可选后跟连字符和 4 位数字)
Extract unique US zipcodes (5 digits optionally followed by hyphen and 4 digits) from addresses
我在找 U.S。地址和邮政编码 df 中的邮政编码。这些记录未规范化并且包含数据输入错误。普通邮政编码是 5 位数字。我还在邮政编码字段中寻找 4 位数字,因为前导 0 可能因无意中转换为数值而被删除。 5 位邮政编码后可以跟一个连字符和 4 位数字,我也想捕获这些数字。我希望邮政编码字段中只有一个邮政编码,但地址字段中可能有多个邮政编码,因为有些人以一种只用于一个地址的形式键入两个地址。只有在邮政编码中找到 none 时,我才想在地址中查找邮政编码,因为地址中的 5 位数街道号码会产生太多误报。我实现了U.S之外的地址。如果本地邮政编码与 U.S 匹配,将产生误报。格式。
我想要的结果是一个新的 zip_code 列,由找到的唯一邮政编码字符串组成,用“/”分隔(如果有多个),前导 0 添加到 4 位邮政编码,如果没有则为空字符串找到了。
这是我的尝试,完全行不通:
pc <- offices$postal_code[offices$postal_code != ""]
offices$zip_code[offices$postal_code != ""] <- unlist(lapply(pc, function(x) {
pczc <- sub("(?<!\d)(\d{5}\-\d{4}|\d{4,5})(?!\d)", "\2", x, perl = T)
pczc <- ifelse(nchar(pczc) == 4, paste0("0", pczc), pczc)
return(pczc)
}))
ad <- offices$address[offices$zip_code == ""]
adzc <- regmatches(ad, gregexpr("(?<!\d)(\d{5}\-\d{4}|\d{5})(?!\d)", ad, perl = T))
offices$zip_code[offices$zip_code != ""] <- paste(unique(adzc), collapse = "/")
我的正则表达式不起作用。此外,可能有更快的方法来执行此操作(我有很多地址)。我考虑过先合并这两个字段,但这种方法的问题是地址字段中的 4 位街道号码会与缺少前导 0 的邮政编码混淆,这只能出现在邮政编码字段中。 (也有5位数字的门牌号码,但我想这没办法。)
这是 df offices 的示例(不包括所有可能的用例,例如,任何一个字段都可能为空):
structure(list(address = c("Headquarters 2355 E. Camelback Road Suite 300 Phoenix",
"Headquarters 1401 Constitution Ave NW Washington", "Headquarters 80 State Street 7th Floor Albany",
"Headquarters Spray Gaarde 46 Nieuwegein", "HQ 1055 Washington Blvd., 7th Floor Stamford",
"Headquarters Village Khubavali, PO Paud Taluka Mulshi Pune",
"Headquarters 231 Lagrange Street Boston", "Headquarters 401 Chestnut St Suite 410 Chattanooga",
"Israel Office st. ha Rav Bar Shaul 6 Rehovot", "Headquarters 7721 New Market Street Olympia",
"HQ Bernrieder Str. 15 Niederwinkling", "Headquarters 2810 Sydney Road Plant City",
"Headquarters 1350 Avenue of the Americas 9th Floor New York",
"Headquarters Askanischer Platz 3 Berlin", "Australian Head Office Level 2, 145 Flinders Lane Melbourne",
"HQ 13303 Washington Avenue Racine", "HQ 9150 E. Del Camino Dr., Ste 112 Scottsdale",
"Arcadia Corporate Merchandise Ltd - Promotional Giveaways Grove Place, Wellington Road High Wycombe",
"Israel Office Shorashim, D.N.Misgav ", "HQ 6009 Penn Avenue S. Minneapolis"
), postal_code = c("85016", "20230", "12207", "3436", "6901",
"412 108", "2132", "37402", "7625149", "98501", "94559", "33566-1173",
"10019", "10963", "3000", "53406", "85258", "HP12 3PR", "20164",
"55419")), .Names = c("address", "postal_code"), row.names = c(1L,
2L, 4L, 5L, 6L, 8L, 10L, 11L, 12L, 14L, 15L, 18L, 19L, 21L, 22L,
23L, 24L, 25L, 27L, 28L), class = "data.frame")
您可以使用 googlemapsapi
而不是执行一些复杂的 regex
。我确定有 R 包,但以下代码应该有所帮助。
library(tidyr)
library(magrittr)
library(dplyr)
library(rvest)
library(jsonlite)
library(data.table)
getInfo <- function(data, address){
mURL <- "http://maps.googleapis.com/maps/api/geocode/json?address=" %>%
paste0(unlist(data[address])) %>% gsub("Headquarters|HQ", "", .) %>% sapply(URLencode)
temp <- lapply(mURL, function(y) {
info <- read_html(y) %>% html_text %>% fromJSON(simplifyDataFrame = TRUE)
if(length(info$results)){
info <- info[[1]]$address_components[[1]] %>% as.data.frame %>% select(-short_name)
info$types <- sapply(info$types, function(x) x[1])
info %<>% group_by(types) %>% summarize(long_name=toString(long_name)) %>%
select(long_name, types) %>% ungroup
info %<>% spread(types, long_name)
} else {
info <- data.frame(administrative_area_level_1=NA, administrative_area_level_2=NA,
country=NA, locality=NA, neighborhood=NA, postal_code=NA,
route=NA, street_number=NA, subpremise=NA)
}
info
}) %>% rbindlist(fill=TRUE)
cbind(data, temp)
}
df2 <- getInfo(df, "address")
在你的 data.frame
的一小部分上测试它,我假设它被命名为 df
。
您可以在 googlemapsapi
上阅读更多内容
df2 %>% View
以下清理了 postal_code
列,但您没有在地址字段中提供带 zips 的数据帧切片,因此不知道该列中的 "real world" 数据是什么样的会是一个潜在的消磨时间 w/o 的功效。一旦您为您的问题提供更具代表性的数据,我可以从地址字段中添加 zip 提取。
library(stringi)
library(purrr)
df$zip_1 <- stri_trim_both(df$postal_code) %>%
stri_match_last_regex("((?:[[:digit:]]{5}-[[:digit:]]{4})|(?:[[:digit:]]{4,5}))") %>%
ifelse(nchar(.)==4, 0 %s+% ., .) %>%
.[,2]
df[,2:3]
## postal_code zip_1
## 1 85016 85016
## 2 20230 20230
## 4 12207 12207
## 5 3436 03436
## 6 6901 06901
## 8 412 108 <NA>
## 10 2132 02132
## 11 37402 37402
## 12 7625149 76251
## 14 98501 98501
## 15 94559 94559
## 18 33566-1173 33566-1173
## 19 10019 10019
## 21 10963 10963
## 22 3000 03000
## 23 53406 53406
## 24 85258 85258
## 25 HP12 3PR <NA>
## 27 20164 20164
## 28 55419 55419
我在找 U.S。地址和邮政编码 df 中的邮政编码。这些记录未规范化并且包含数据输入错误。普通邮政编码是 5 位数字。我还在邮政编码字段中寻找 4 位数字,因为前导 0 可能因无意中转换为数值而被删除。 5 位邮政编码后可以跟一个连字符和 4 位数字,我也想捕获这些数字。我希望邮政编码字段中只有一个邮政编码,但地址字段中可能有多个邮政编码,因为有些人以一种只用于一个地址的形式键入两个地址。只有在邮政编码中找到 none 时,我才想在地址中查找邮政编码,因为地址中的 5 位数街道号码会产生太多误报。我实现了U.S之外的地址。如果本地邮政编码与 U.S 匹配,将产生误报。格式。
我想要的结果是一个新的 zip_code 列,由找到的唯一邮政编码字符串组成,用“/”分隔(如果有多个),前导 0 添加到 4 位邮政编码,如果没有则为空字符串找到了。
这是我的尝试,完全行不通:
pc <- offices$postal_code[offices$postal_code != ""]
offices$zip_code[offices$postal_code != ""] <- unlist(lapply(pc, function(x) {
pczc <- sub("(?<!\d)(\d{5}\-\d{4}|\d{4,5})(?!\d)", "\2", x, perl = T)
pczc <- ifelse(nchar(pczc) == 4, paste0("0", pczc), pczc)
return(pczc)
}))
ad <- offices$address[offices$zip_code == ""]
adzc <- regmatches(ad, gregexpr("(?<!\d)(\d{5}\-\d{4}|\d{5})(?!\d)", ad, perl = T))
offices$zip_code[offices$zip_code != ""] <- paste(unique(adzc), collapse = "/")
我的正则表达式不起作用。此外,可能有更快的方法来执行此操作(我有很多地址)。我考虑过先合并这两个字段,但这种方法的问题是地址字段中的 4 位街道号码会与缺少前导 0 的邮政编码混淆,这只能出现在邮政编码字段中。 (也有5位数字的门牌号码,但我想这没办法。)
这是 df offices 的示例(不包括所有可能的用例,例如,任何一个字段都可能为空):
structure(list(address = c("Headquarters 2355 E. Camelback Road Suite 300 Phoenix",
"Headquarters 1401 Constitution Ave NW Washington", "Headquarters 80 State Street 7th Floor Albany",
"Headquarters Spray Gaarde 46 Nieuwegein", "HQ 1055 Washington Blvd., 7th Floor Stamford",
"Headquarters Village Khubavali, PO Paud Taluka Mulshi Pune",
"Headquarters 231 Lagrange Street Boston", "Headquarters 401 Chestnut St Suite 410 Chattanooga",
"Israel Office st. ha Rav Bar Shaul 6 Rehovot", "Headquarters 7721 New Market Street Olympia",
"HQ Bernrieder Str. 15 Niederwinkling", "Headquarters 2810 Sydney Road Plant City",
"Headquarters 1350 Avenue of the Americas 9th Floor New York",
"Headquarters Askanischer Platz 3 Berlin", "Australian Head Office Level 2, 145 Flinders Lane Melbourne",
"HQ 13303 Washington Avenue Racine", "HQ 9150 E. Del Camino Dr., Ste 112 Scottsdale",
"Arcadia Corporate Merchandise Ltd - Promotional Giveaways Grove Place, Wellington Road High Wycombe",
"Israel Office Shorashim, D.N.Misgav ", "HQ 6009 Penn Avenue S. Minneapolis"
), postal_code = c("85016", "20230", "12207", "3436", "6901",
"412 108", "2132", "37402", "7625149", "98501", "94559", "33566-1173",
"10019", "10963", "3000", "53406", "85258", "HP12 3PR", "20164",
"55419")), .Names = c("address", "postal_code"), row.names = c(1L,
2L, 4L, 5L, 6L, 8L, 10L, 11L, 12L, 14L, 15L, 18L, 19L, 21L, 22L,
23L, 24L, 25L, 27L, 28L), class = "data.frame")
您可以使用 googlemapsapi
而不是执行一些复杂的 regex
。我确定有 R 包,但以下代码应该有所帮助。
library(tidyr)
library(magrittr)
library(dplyr)
library(rvest)
library(jsonlite)
library(data.table)
getInfo <- function(data, address){
mURL <- "http://maps.googleapis.com/maps/api/geocode/json?address=" %>%
paste0(unlist(data[address])) %>% gsub("Headquarters|HQ", "", .) %>% sapply(URLencode)
temp <- lapply(mURL, function(y) {
info <- read_html(y) %>% html_text %>% fromJSON(simplifyDataFrame = TRUE)
if(length(info$results)){
info <- info[[1]]$address_components[[1]] %>% as.data.frame %>% select(-short_name)
info$types <- sapply(info$types, function(x) x[1])
info %<>% group_by(types) %>% summarize(long_name=toString(long_name)) %>%
select(long_name, types) %>% ungroup
info %<>% spread(types, long_name)
} else {
info <- data.frame(administrative_area_level_1=NA, administrative_area_level_2=NA,
country=NA, locality=NA, neighborhood=NA, postal_code=NA,
route=NA, street_number=NA, subpremise=NA)
}
info
}) %>% rbindlist(fill=TRUE)
cbind(data, temp)
}
df2 <- getInfo(df, "address")
在你的 data.frame
的一小部分上测试它,我假设它被命名为 df
。
您可以在 googlemapsapi
df2 %>% View
以下清理了 postal_code
列,但您没有在地址字段中提供带 zips 的数据帧切片,因此不知道该列中的 "real world" 数据是什么样的会是一个潜在的消磨时间 w/o 的功效。一旦您为您的问题提供更具代表性的数据,我可以从地址字段中添加 zip 提取。
library(stringi)
library(purrr)
df$zip_1 <- stri_trim_both(df$postal_code) %>%
stri_match_last_regex("((?:[[:digit:]]{5}-[[:digit:]]{4})|(?:[[:digit:]]{4,5}))") %>%
ifelse(nchar(.)==4, 0 %s+% ., .) %>%
.[,2]
df[,2:3]
## postal_code zip_1
## 1 85016 85016
## 2 20230 20230
## 4 12207 12207
## 5 3436 03436
## 6 6901 06901
## 8 412 108 <NA>
## 10 2132 02132
## 11 37402 37402
## 12 7625149 76251
## 14 98501 98501
## 15 94559 94559
## 18 33566-1173 33566-1173
## 19 10019 10019
## 21 10963 10963
## 22 3000 03000
## 23 53406 53406
## 24 85258 85258
## 25 HP12 3PR <NA>
## 27 20164 20164
## 28 55419 55419