Title Image

Blog

Geocodificación de direcciones con Python

  |   Geolocalización, SIG

Para representar en un mapa las direcciones con la localización de personas, sucesos como accidentes, denuncias, incidencias de algún servicio, o cualquier otra elemento, se necesita realizar un proceso de geocodificación. Al geocodificar direcciones básicamente lo que hacemos es calcular las coordenadas geográficas latitud y longitud de un lugar donde solo conocemos el nombre de una localidad, un código postal o una dirección de calle.

¿Qué nos aporta la geocodificación? Principalmente con ella podemos mostrar localizaciones en un mapa y determinar las relaciones entre lugares, como son distancias, direcciones, o un patrón de dispersión. Pero además, determinando la ubicación de personas, cosas o sucesos podemos asociar sus localizaciones con otros datos que tengan una referencia geográfica como el censo demográfico, las transacciones de ventas, la concentración de accidentes de tráficos, contaminación, la distribución espacial de alguna enfermedad, etc.

Geocodificar una dirección a nivel de calle es el proceso más preciso para localizar un lugar, pero esto requiere una base de datos de referencia bastante completa que permita una localización a nivel de número de portal, información que no siempre es posible obtener.

Geocodificar múltiples direcciones

Un ejemplo de geocodificación muy fácil es introducir una dirección en la barra de búsqueda de Google Maps y la URL devuelta contendrá la longitud y latitud del lugar.

Geocodificacion en Google Maps

Geocodificacion en Google Maps del portal nº 1 en la Puerta del Sol de Madrid.

Si tenemos un listado de direcciones podríamos realizar esto a mano, pasando cada dirección una por una, aunque no es una opción muy atractiva. Una alternativa más interesante es programar algún script que las lea de un archivo csv y nos devuelva los pares de coordenadas latitud y longitud que necesitamos para posicionar esos puntos en nuestro mapa. Para ello necesitamos un geocodificador de direcciones que las analice en elementos identificables (nombre de la calle, número, localidad, región, código postal), que compare esas direcciones con la información almacenada en una base de datos de referencia, evalúe la similitud entre todos los candidatos y determine unas coordenadas geográficas para esa dirección en caso de que el porcentaje de similitud sea elevado.

Podemos realizar geocodificaciones masivas de diversas maneras. A través de un software de escritorio instalados en el ordenador, como ArcGIS, QGIS o Google Earth, o mediante un servicio de geocodificación on line como Google Map o Bing.
Ya hablamos en otra entrada de la geocodificación utilizando OpenRefine, pero en esta lo que nos interesan son los servicios on line con una interfaz de programación de aplicaciones (API) que nos permitan utilizar algún lenguaje de programación para geocodificar una vasta cantidad de direcciones. En Internet existen varios y la siguiente tabla muestra algunos de ellos:

Google Maps Geocoding API Bing Maps REST Services ESRI ArcGIS on line ESRI ArcGIS Desktop OpenStreetMap (vía Nominatim o MapQuest) GeoNames OpenCage Mapbox
Requiere programación No, si se usa Google Earth Pro o QGIS con el componente mmqgis No
Limitaciones en número de peticiones 2.500 en periodos de 24 horas y 5 por segundo. 10.000 al mes. 5.000 al día para aplicaciones Windows. 1.250 al día. Ilimitadas. 1 petición por segundo en Nominatim. En MapQuest 15.000 peticiones al mes Ilimitadas. 2.500 por día en periodo beta. Los resultados deben ser mostrados en un mapa de Mapbox. 1 geocodificación por petición.
Calidad de la información Alta Alta Alta Alta Media (depende de las zonas) Media Variable. Combina varios sistemas de geocodificación Alta
Covertura geográfica Mundial Mundial Mundial Depende de la base de datos utilizada Mundial, aunque la precisión depende mucho de las zonas. Parcial. Depende del país. Mundial Mundial
Servicio on line o local On line On line On line On line y local On line On line On line On line

Geocodificar direcciones con Python

Uno de los módulos más conocidos en Python para realizar geocodificación es geopy. Con él podremos utilizar varios servicios web de geocodificación como OpenStreetMap Nominatim, ESRI ArcGIS, Google Geocoding API (V3), Baidu Maps, Bing Maps API, Yahoo! PlaceFinder, Yandex, IGN France, GeoNames, NaviData, OpenMapQuest, What3Words, OpenCage, SmartyStreets, geocoder.us o GeocodeFarm.

Además de poder realizar geocodificaciones y geocodificaciones inversas (encontrar una dirección a partir de unas coordenadas), geopy también es capaz de medir distancias entre dos puntos. El siguiente código muestra la forma de geocodificar un listado de direcciones almacenadas en un archivo CSV. En este caso utilizamos el servicio de Nominatim y creamos otro CSV donde guardamos las coordenadas que corresponden a cada dirección.

# -*- coding: utf-8 -*-

#Importación del módulo Nominatim de geopy que utilizaremos para geocodificar
from geopy.geocoders import Nominatim
#Importación del módulo csv que necesitaremos para leer y escribir en nuestros csv
import csv
#Importación del módulo shutil que usaremos para crear una copia de nuestro csv original
import shutil

#Realizamos una copia del archivo csv original que llamaremos procesado.csv
shutil.copyfile("original.csv","procesado.csv")

#Abrimos el archivo y le asignamos una variable.
archivo = open('original.csv', 'rb')

#Creamos una lista vacía donde almacenaremos las direcciones.
direcciones = []

#Utilizamos la función reader para leer el contenido del csv cuyas columnas están delimitadas por el caracter ;
csv_archivo = csv.reader(archivo, delimiter=';')
#Vamos leyendo la primera columna de cada fila del csv y añadiendo la dirección a la lista.
for fila in csv_archivo:
   direcciones.append(fila[0])

#Cerramos el archivo abierto
archivo.close()

#Creamos un nueva lista donde se guardarán las localizaciones.
localizaciones = []

#Cada servicio de geolocalización como Google Maps, Bing Maps, Yahoo, MapQuest o Nominatim tiene su propia clase en geopy.geocoders para utilizar el servicio API.
#Creamos un objeto llamado geolocalizador a partir de la clase Nominatim().
geolocalizador = Nominatim()

#Para cada dirección almacenada en la lista 'direcciones' pedimos al servicios de geocodificación de Nominatim que nos devuelva su coordenada y la guardamos en la variable 'coordenadas'. Añadimos la latitud y lo9ngitud a la lista 'localizaciones'.
for val in direcciones:
   direccion = geolocalizador.geocode([val], timeout=15)
   localizaciones.append((direccion.latitude, direccion.longitude))

#Creamos una cabecera para nuestro nuevo csv.
cabecera = ['DIRECCION','COORDENADAS']

#Abrimos de nuevo el archivo original y guardamos todos los datos en la variable 'datos'. Finalmente cerramos el archivo.
archivo = open('original.csv')
datos = [item for item in csv.reader(archivo, delimiter=';')]
archivo.close()

#Creamos una nueva lista llamada 'nuevos_datos'
nuevos_datos = []

#Para cada item en la lista 'datos' añadimos sus cordenadas almacenadas en la lista 'localizacion'. Finalmente incorporamos todo el conjunto a la lista 'nuevos_datos'.
for i, item in enumerate(datos):
    item.append(localizaciones[i])
    print localizaciones[i]
    nuevos_datos.append(item)

#Abrimos el archivo procesado.csv que habíamos creado y le asignamos una variable. El parámetro wb indica que queremos escribir. Añadimos una cabecera seguido de las filas con cada uno de los datos almacenados en la lista. Cerramos el archivo.
archivo = open('procesado.csv', 'wb')
csv.writer(archivo, delimiter=';', lineterminator='\n').writerow(cabecera)
csv.writer(archivo, delimiter=';', lineterminator='\n').writerows(nuevos_datos)
archivo.close()

Algo a tener en cuenta, es que el servicio de geocodificación de OpenStreetMap basado en Nominatim no requiere de ninguna key ni de registro, puede ser instalado en local (gracias @Xeviby) y no tiene límite de consultas. Por contra presenta dos principales inconvenientes:

  • Al utilizar datos de OpenStreetMap la calidad de los resultados varía mucho según la zona geográfica.
  • En sus búsquedas no filtra muchas de las palabras vacías de algunos idiomas, lo que condiciona su uso para la georreferenciación de direcciones en español, por ejemplo. No obstante, sí es efectivo para la geocodificación de poblaciones o para realizar geocodificaciones inversas.

Imagen de portada CC: Thomas Abbs, tomada de Flickr.

Guardar

Guardar

Guardar