Геокод адреса в R: grep() набор данных world.cities
Я пытаюсь геокодировать некоторые адреса, хранящиеся в символьных векторах. Я использовал geocode()
функция в ggmaps
; однако, это только классифицировало приблизительно 50% моих адресов. Я надеялся использовать более рудиментарный подход при поиске названия города (из world.cities
данные в maps
Пакет находится в моем списке адресов, и если да, то берет информацию о долготе и широте из этой таблицы поиска. Я попытаюсь очистить возвращенный файл и дополнить его другими подходами геокодирования (вызовами различных внешних API), которые предоставляет R. То, что я кодировал до сих пор, ниже:
places <- c("Atlanta,Georgia", "My house, Paris, France", "Some Other House, Paris, Ontario, Canada", "Paris", "Oxford", "Oxford, USA")
library(maps)
data(world.cities)
ddd <- world.cities[world.cities$name %in% c("Paris","Oxford","New York"),]
is.integer0 <- function(x) {
is.integer(x) && length(x) == 0L
}
for (i in 1:length(places)) {
for (j in 1:dim(ddd)[1]) {
k <- ddd$name[j]
if (is.integer0(grep(k,places[i],perl=TRUE))==TRUE) next
if (exists("zzz")==FALSE) {
zzz <- cbind(places[i],ddd[j,1:5])
} else {
zzz <- rbind(zzz,cbind(places[i],ddd[j,1:5]))
}
}
}
Выход - то, что я хочу (я субъективно уберу это позже). Моя проблема в том, что мои реальные данные о 8000 адресов и world.cities
данные о 40000+ городах, так что двойной подход к циклу немного медленный. Как и в случае с другими задачами в R I, предполагается, что это может быть векторизовано некоторым членом семейства apply. У меня проблемы с тем, как я могу это сделать. Какие-нибудь мысли?
### Output
places[i] name country.etc pop lat long
28245 My house, Paris, France Paris Canada 10570 43.20 0.38
28246 My house, Paris, France Paris France 2141839 48.86 2.34
282451 Some Other House, Paris, Ontario, Canada Paris Canada 10570 43.20 -80.38
282461 Some Other House, Paris, Ontario, Canada Paris France 2141839 48.86 2.34
282452 Paris Paris Canada 10570 43.20 -80.38
282462 Paris Paris France 2141839 48.86 2.34
27671 Oxford Oxford Canada 1271 45.73 -63.87
27672 Oxford Oxford New Zealand 1816 -43.30 172.18
27673 Oxford Oxford UK 157568 51.76 -1.26
276711 Oxford, USA Oxford Canada 1271 45.73 -63.87
276721 Oxford, USA Oxford New Zealand 1816 -43.30 172.18
276731 Oxford, USA Oxford UK 157568 51.76 -1.26
После некоторой дальнейшей очистки данных мне бы очень хотелось:
### Output
places[i] name country.etc pop lat long
28246 My house, Paris, France Paris France 2141839 48.86 2.34
282451 Some Other House, Paris, Ontario, Canada Paris Canada 10570 43.20 -80.38
282462 Paris Paris France 2141839 48.86 2.34
27673 Oxford Oxford UK 157568 51.76 -1.26
276731 Oxford, USA Oxford NA NA NA NA
Atlanta, Georgia NA NA NA NA NA
По сути, логика такова:
- Если страна также совпадает со строкой мест, сохраните эту строку. Париж, Франция и Париж, Канада, примеры.
- Если строка мест содержит одно слово, то предположите, что он относится к городу с наибольшим населением. Так что по умолчанию Париж - Париж, Франция и Оксфорд - Оксфорд, Великобритания. Поскольку трудно геокодировать неуникальный адрес.
- Если строка мест содержит более одного слова, но Страна не соответствует ни одному из этих других слов, например Оксфорд, США. Тогда сделайте все, кроме города Н.А. Здесь я попробую свою удачу с
geocode()
и другие услуги, чтобы получить лучшую информацию. - Если адрес мест никогда не был в поисковом словаре, добавьте его, а затем попробуйте заполнить все (на самом деле я хочу только long/lat), используя
geocode()
и т.д. Вот пример Атланты Джорджия.
Мысли о подходе в целом, и как сделать лучше в R? Как упомянуто выше, стимулом для этого подхода было узнать, смогу ли я дополнить то, что уже получил (50% геокодированных адресов с geocode()
функция)
1 ответ
Это делает извлечение города более общим (использует сопоставление с регулярным выражением строки), а затем выполняет слияние с world.cities
данные:
places_dat <- cbind(places, Reduce(rbind,
lapply(str_match_all(places, ",*\ *([[:alpha:]]+)\ *,\ *([[:alpha:]]+)\ *$"),
function(x) {
if (length(x) == 0) {
return(data.frame(city=NA, state=NA))
} else {
return(data.frame(city=x[,2], state=x[,3]))
}
})))
places_dat
## places city state
## 1 Atlanta,Georgia Atlanta Georgia
## 2 My house, Paris, France Paris France
## 3 Some Other House, Paris, Ontario, Canada Ontario Canada
## 4 Paris <NA> <NA>
## 5 Oxford <NA> <NA>
## 6 Oxford, USA Oxford USA
##
merge(places_dat, world.cities, by.x="city", by.y="name", all.x=TRUE)
## city places state country.etc pop lat long capital
## 1 Atlanta Atlanta,Georgia Georgia USA 424096 33.76 -84.42 0
## 2 Paris My house, Paris, France France France 2141839 48.86 2.34 1
## 3 Paris My house, Paris, France France Canada 10570 43.20 -80.38 0
## 4 Ontario Some Other House, Paris, Ontario, Canada Canada USA 175805 34.05 -117.61 0
## 5 Oxford Oxford, USA USA Canada 1271 45.73 -63.87 0
## 6 Oxford Oxford, USA USA New Zealand 1816 -43.30 172.18 0
## 7 Oxford Oxford, USA USA UK 157568 51.76 -1.26 0
## 8 <NA> Paris <NA> <NA> NA NA NA NA
## 9 <NA> Oxford <NA> <NA> NA NA NA NA
Это все еще требует некоторого просеивания (возможно complete.cases
в качестве одного шага), но это продвигает вас дальше и должно быть немного быстрее.