Сглаживание списка с переменными уровнями вложенности создает дополнительные наблюдения

У меня есть вложенный список адресов московских улиц с геокодированием, преобразованный из вложенного списка. Однако кадр данных, из которого я выполнял геокодирование, имел только адреса без почтовых индексов, и в нескольких сотнях (из 33 000) случаев адрес возвращал несколько результатов для одного и того же адреса улицы с разными почтовыми индексами. Это создало дополнительную вложенность в списке, что при преобразовании в фрейм данных приводит к количеству наблюдений, отличающемуся от исходного фрейма данных.

Результат только с одним адресом имеет следующую структуру: (не обращайте внимания на тарабарщину, консоль R не будет правильно отображать кириллицу)

structure(list(results = structure(list(address_components = list(
    structure(list(long_name = c("4", "óëèöà Áîëüøàÿ Àêàäåìè÷åñêàÿ", 
    "Ñåâåðíûé àäìèíèñòðàòèâíûé îêðóã", "Ìîñêâà", "Ìîñêâà", "Ðîññèÿ", 
    "127299"), short_name = c("4", "óë. Áîëüøàÿ Àêàäåìè÷åñêàÿ", 
    "Ñåâåðíûé àäìèíèñòðàòèâíûé îêðóã", "Ìîñêâà", "Ìîñêâà", "RU", 
    "127299"), types = list("street_number", "route", c("political", 
    "sublocality", "sublocality_level_1"), c("locality", "political"
    ), c("administrative_area_level_2", "political"), c("country", 
    "political"), "postal_code")), .Names = c("long_name", "short_name", 
    "types"), class = "data.frame", row.names = c(NA, 7L))), 
    formatted_address = "óë. Áîëüøàÿ Àêàäåìè÷åñêàÿ, 4, Ìîñêâà, Ðîññèÿ, 127299", 
    geometry = structure(list(location = structure(list(lat = 55.8176896, 
        lng = 37.522891), .Names = c("lat", "lng"), class = "data.frame", row.names = 1L), 
        location_type = "ROOFTOP", viewport = structure(list(
            northeast = structure(list(lat = 55.8190385802915, 
                lng = 37.5242399802915), .Names = c("lat", "lng"
            ), class = "data.frame", row.names = 1L), southwest = structure(list(
                lat = 55.8163406197085, lng = 37.5215420197085), .Names = c("lat", 
            "lng"), class = "data.frame", row.names = 1L)), .Names = c("northeast", 
        "southwest"), class = "data.frame", row.names = 1L)), .Names = c("location", 
    "location_type", "viewport"), class = "data.frame", row.names = 1L), 
    partial_match = TRUE, place_id = "ChIJ59yLsy1ItUYR5EEBFbFJoSA", 
    types = list("street_address")), .Names = c("address_components", 
"formatted_address", "geometry", "partial_match", "place_id", 
"types"), class = "data.frame", row.names = 1L), status = "OK"), .Names = c("results", 
"status"))

Тогда как результат с несколькими возможными адресами выглядит так:

structure(list(results = structure(list(address_components = list(
    structure(list(long_name = c("23", "óëèöà Áîëüøàÿ Àêàäåìè÷åñêàÿ", 
    "Ñåâåðíûé àäìèíèñòðàòèâíûé îêðóã", "Ìîñêâà", "Ìîñêâà", "Ðîññèÿ", 
    "127299"), short_name = c("23", "óë. Áîëüøàÿ Àêàäåìè÷åñêàÿ", 
    "Ñåâåðíûé àäìèíèñòðàòèâíûé îêðóã", "Ìîñêâà", "Ìîñêâà", "RU", 
    "127299"), types = list("street_number", "route", c("political", 
    "sublocality", "sublocality_level_1"), c("locality", "political"
    ), c("administrative_area_level_2", "political"), c("country", 
    "political"), "postal_code")), .Names = c("long_name", "short_name", 
    "types"), class = "data.frame", row.names = c(NA, 7L)), structure(list(
        long_name = c("23", "óëèöà Áîëüøàÿ Àêàäåìè÷åñêàÿ", "Ñåâåðíûé àäìèíèñòðàòèâíûé îêðóã", 
        "Ìîñêâà", "Ìîñêâà", "Ðîññèÿ", "125008"), short_name = c("23", 
        "óë. Áîëüøàÿ Àêàäåìè÷åñêàÿ", "Ñåâåðíûé àäìèíèñòðàòèâíûé îêðóã", 
        "Ìîñêâà", "Ìîñêâà", "RU", "125008"), types = list("street_number", 
            "route", c("political", "sublocality", "sublocality_level_1"
            ), c("locality", "political"), c("administrative_area_level_2", 
            "political"), c("country", "political"), "postal_code")), .Names = c("long_name", 
    "short_name", "types"), class = "data.frame", row.names = c(NA, 
    7L))), formatted_address = c("óë. Áîëüøàÿ Àêàäåìè÷åñêàÿ, 23, Ìîñêâà, Ðîññèÿ, 127299", 
"óë. Áîëüøàÿ Àêàäåìè÷åñêàÿ, 23, Ìîñêâà, Ðîññèÿ, 125008"), geometry = structure(list(
    location = structure(list(lat = c(55.8169112, 55.826859), 
        lng = c(37.5202899, 37.529427)), .Names = c("lat", "lng"
    ), class = "data.frame", row.names = 1:2), location_type = c("ROOFTOP", 
    "ROOFTOP"), viewport = structure(list(northeast = structure(list(
        lat = c(55.8182601802915, 55.8282079802915), lng = c(37.5216388802915, 
        37.5307759802915)), .Names = c("lat", "lng"), class = "data.frame", row.names = 1:2), 
        southwest = structure(list(lat = c(55.8155622197085, 
        55.8255100197085), lng = c(37.5189409197085, 37.5280780197085
        )), .Names = c("lat", "lng"), class = "data.frame", row.names = 1:2)), .Names = c("northeast", 
    "southwest"), class = "data.frame", row.names = 1:2)), .Names = c("location", 
"location_type", "viewport"), class = "data.frame", row.names = 1:2), 
    partial_match = c(TRUE, TRUE), place_id = c("ChIJnVMw7C1ItUYRdfeWEQrXuAk", 
    "ChIJnbnwOdY3tUYR1_D9pHTqCsI"), types = list("street_address", 
        "street_address")), .Names = c("address_components", 
"formatted_address", "geometry", "partial_match", "place_id", 
"types"), class = "data.frame", row.names = 1:2), status = "OK"), .Names = c("results", 
"status"))

В элементе результатов во втором списке есть дополнительный уровень вложенности для каждого возможного адреса, который при выравнивании создает «дополнительное» наблюдение для этого адреса, что делает невозможным cbind() возвращение результатов геокодирования в список адресов. Я использую следующие функции, чтобы свести мои вложенные списки к фреймам данных. Как я могу изменить их, чтобы они принимали только первый адрес, когда происходит это дополнительное вложение? Если адрес неверный, здания будут просто исключены из выборки, когда я позже объединимся с другим фреймом данных, поэтому я заинтересован только в том, чтобы каждое геокодированное наблюдение соответствовало соответствующей строке в исходном фрейме данных (источник адресов).

flatten_googleway <- function(df) {
  require(jsonlite)
  res <- jsonlite::flatten(df)
  res[, names(res) %in% c("geometry.location_type", "geometry.location.lat", 
                          "geometry.location.lng", "formatted_address")]
}
moscowhousegeo.df <- do.call(rbind, lapply(moscowhouse.list, function(x) {
  if (length(x$results) == 0) template_res[1, ] else flatten_googleway(x$results)
}))

##template for NA results
structure(list(formatted_address = character(0), geometry.location_type = character(0), 
    geometry.location.lat = numeric(0), geometry.location.lng = numeric(0)), .Names = c("formatted_address", 
"geometry.location_type", "geometry.location.lat", "geometry.location.lng"
), row.names = integer(0), class = "data.frame")

person Sean Norton    schedule 05.09.2017    source источник


Ответы (1)


Ой, я, как обычно, сильно усложнил ситуацию. Я смог исправить это, просто изменив вызов lapply(), чтобы заменить все элементы списка без результатов и элементы, где x$results$address_components больше длины 1 (как в случае, когда возвращается несколько возможных результатов).

moscowhousegeo.df <- do.call(rbind, lapply(moscowhouse.list, function(x) {
  if (length(x$results) == 0 | length(x$results$formatted_address) > 1) template_res[1, ] else flatten_googleway(x$results)
}))

К сожалению, я все еще теряю некоторые данные таким образом, но определение правильного адреса из предоставленных вариантов, вероятно, займет слишком много времени и немного глупо в наборе данных с таким количеством наблюдений.

person Sean Norton    schedule 05.09.2017