Verificarea încrucișării ID -urilor OSM între OSM și Wikidata

URMĂREȘTE-NE
16,065FaniÎmi place
1,142CititoriConectați-vă

Utilități

Apoi facem două funcții care ne vor permite să interogărilem API -ul Wikidata pentru a -i asocia identificatorii OSM la o entitate Wikidata. Există trei proprietăți necesare (pentru noduri, moduri și relații). O entitate poate avea zero, una, două sau trei dintre aceste proprietăți, iar pentru fiecare proprietate poate avea unul sau mai multe ID -uri.

#' Get the OpenStreetMap IDs of a wikidata item
#'
#' @param item (char) wikidata ID (e.g. "Q19368619")
#'
#' @returns (vec) 
#'   OSM ID (possibly several), prefixed with 
#'    "n" for "node",
#'    "w" for "way" and
#'    "r" for relation
#'  NULL if no OSM ID or
#'  NA if not available,
#' @example get_wd_osm_id("Q19368619")
get_wd_osm_id <- purrr::possibly(function(item) {
  
  # avoid spending time querying if no wikidata item
  if (is.na(item) | item == "" | !stringr::str_detect(item, "Q(0-9)+")) { 
    return(NA_character_)
  } else {
    i <- WikidataR::get_item(item)
    
    # P402 relation
    relation <- purrr::pluck(i, 
                             1, "claims", "P402", "mainsnak", "datavalue", "value")
    relation <- if (!is.null(relation)) { paste0("r", relation) } else { NULL }
    
    # P10689 way
    way <- purrr::pluck(i, 
                        1, "claims", "P10689", "mainsnak", "datavalue", "value")
    way <- if (!is.null(way)) { paste0("w", way) } else { NULL }
    
    # P11693 node
    node <- purrr::pluck(i, 
                         1, "claims", "P11693", "mainsnak", "datavalue", "value")
    node <- if (!is.null(node)) { paste0("n", node) } else { NULL }
    
    return(purrr::compact(c(relation, way, node)))
  }
}, otherwise = NA_character_)

#' Add a column with the OpenStreetMap IDs from wikidata
#' 
#' For all features of an osmdata sf object having a wikidata ID, get the 
#' associated OSM IDs recorded in wikidata
#'
#' @param osmdata_features (sf) osmdata sub-object (osm_points, osm_lines,...)
#'   with a `wikidata` column
#'
#' @returns (sf) input object with a new column `wd_osm_id` as a list-column of
#'   character IDs (or NULL)
#' @examples add_osmid_from_wikidata(my_osmdata_sf$osm_points)
add_osm_id_from_wikidata <- function(osmdata_features) {
  geom_type <- sf::st_geometry_type(osmdata_features, by_geometry = FALSE)
  osmdata_features |>
    tibble::as_tibble(.name_repair = janitor::make_clean_names) |> 
    dplyr::mutate(
      wd_osm_id = purrr::map(
        wikidata,
        slowly(get_wd_osm_id), 
        .progress = glue::glue("Getting OSM ID for {geom_type}...")))
}

#' Add a prefix to the OSM ID according to the element geometry type
#' 
#' It will allow us to compare `osm_id` and `wd_osm_id`
#'
#' @param x (sf) OSM data sub-object
#'
#' @returns x with the `osm_id` field prefixed with "n" for "node",
#'    "w" for "way" and "r" for relation
#' @examples prefix_osm_id(osm_wd$osm_points)
prefix_osm_id <- function(x, p = c("n", "w", "r")) {
  geom_type <- sf::st_geometry_type(osmdata_features, by_geometry = FALSE)
  p <- case_when(geom_type == "POINT" ~ "n",
                 geom_type %in% c("LINESTRING", "POLYGON") ~ "w",
                 geom_type %in% c("MULTILINESTRING", "MULTIPOLYGON") ~ "r",
                 .default = "")
  
  x |> 
    mutate(osm_id = glue("{p}{osm_id}"))
}

Cu aceste funcții, putem să ne uităm la datele noastre OSM, să îi păstrăm pe cei care au un atribut Wikidata, iar pentru aceste entități obține ID -urile OSM, permițându -ne să verificăm dacă sunt similare sau, pentru cei care lipsesc, adăugând ID -ul manual în Wikidata. Deoarece datele OSM sunt expediate în diferite obiecte, în funcție de tipul de geometrie, trebuie să le facem pentru fiecare dintre ele.

osm_wd_augmented <- list(
  prefix_osm_id(osm_wd$osm_points, "n"),
  prefix_osm_id(osm_wd$osm_lines, "w"),
  prefix_osm_id(osm_wd$osm_polygons, "w"),
  prefix_osm_id(osm_wd$osm_multilines, "r"),
  prefix_osm_id(osm_wd$osm_multipolygons, "r")) |>
  map((x) {
    x |> 
      filter(!is.na(wikidata) & wikidata != "") |> 
      add_osm_id_from_wikidata() |> 
      select(osm_id, name, wikidata, wd_osm_id) |> 
      unnest(wd_osm_id, keep_empty = TRUE)}) |> 
  list_rbind() |> 
  distinct()

Obținem o nouă variabilă wd_osm_id a cărui semnificație este „Este unul dintre identificatorii OSM din entitatea Wikidata, care este indicată în elementul OSM

Cazuri de utilizare

De exemplu, dacă dorim să vedem elementele OSM având o entitate Wikidata care nu se leagă înapoi:

osm_wd_augmented |> 
  filter(is.na(wd_osm_id)) |> 
  arrange(name)
# A tibble: 29 × 4
   osm_id      name                                 wikidata   wd_osm_id
                                                   
 1 w194448267  Cenischia                            Q3539637        
 2 n41645050   Champagny-en-Vanoise                 Q34791526       
 3 w108980863  Chapelle Notre-Dame de la Visitation Q13518652       
 4 w131213010  Chapelle Saint-Antoine               Q22975798       
 5 w131213054  Chapelle Saint-Sébastien             Q22968509       
 6 n4573291011 Cinéma Chantelouve                   Q61858809       
 7 r2149907    Communauté de Communes Terra Modana  Q17355571       
 8 w37792978   Dora di Bardonecchia                 Q3714186        
 9 w131215535  Espace Baroque                       Q22968504       
10 r377905     GR 55 La Vanoise                     Q124149580      
# ℹ 19 more rows

Unele sunt poate legitime (?), Dar unii altele ar putea avea nevoie de editare …

Un alt exemplu, verificați incoerența dintre osm_id şi wd_osm_id:

osm_wd_augmented |> 
  filter(osm_id != wd_osm_id) |> 
  arrange(name)
# A tibble: 25 × 4
   osm_id       name                                          wikidata wd_osm_id
                                                           
 1 n26691864    Albertville                                   Q159469  r111528  
 2 n26691864    Albertville                                   Q159469  r17160712
 3 n41644953    Aussois                                       Q567783  r89823   
 4 r2149905     Communauté de Communes de Haute Maurienne-Va… Q2987514 r6876759 
 5 n11646993705 Dent Parrachée                                Q1189850 n6705389…
 6 w1257820968  Ferrovia del Moncenisio                       Q950823  r15987785
 7 w1257820969  Ferrovia del Moncenisio                       Q950823  r15987785
 8 w1257820970  Ferrovia del Moncenisio                       Q950823  r15987785
 9 w1257820971  Ferrovia del Moncenisio                       Q950823  r15987785
10 w993297614   Glacier de Méan-Martin                        Q348352… w42239115
# ℹ 15 more rows

Acesta ar putea indica faptul că elementele OSM au fost puternic editate sau șterse/recreate fără a actualiza entitatea Wikidata corespunzătoare.

Corecțiile necesită manual înainte și înapoi între site -urile R, OSM și Wikidata, dar aceste utilități fac destul de ușor îmbunătățirea calității datelor.

Dominic Botezariu
Dominic Botezariuhttps://www.noobz.ro/
Creator de site și redactor-șef.

Cele mai noi știri

Pe același subiect

LĂSAȚI UN MESAJ

Vă rugăm să introduceți comentariul dvs.!
Introduceți aici numele dvs.