Геокодирование в Open Refine
получаем координаты из адресов
Одна из функций Refine (далее OR) — создание дополнительных значений в таблице на основе http-запросов. Фактически функция может быть использована в двух целях:
- Скрейпинг данных со страниц. Для этого можно, к примеру, создать табличку с сылками на схожие страницы, и последовательно собрать с них данные. В GREL (внутренний язык для OR, очень схожий с Python) для этого случая существует специальные функции, — parseHtml, select, htmlAttr, htmlText и др.
- Обращение к API через http-запрос. Запрос может быть любой, например к этим сервисам.
Одна из наиболее частых задач, решаемых с помощью API — геокодирование.
Геокодирование — определение координат локации по адресу и наоборот ( обратное геокодирование).
Услуги геокодирования предоставляют все основные картографические сервисы (Google Maps, Yandex maps, OSM) и другие фирмы (существует ряд тонкостей, связанных с точностью и технологией геокодирования, например геокодирование по словаря топонимов, такие услуги обеспечивают специализированные сервисы).
Примечание: Для быстрого геокодирования существует уникальный сервис Google Fusion Tables, позволяющий автоматически расставить точки адресов на карте без указания координат. Однако у сервиса есть сильные ограничения: его невозможно настроить, а главное, через него невозможно заполучить сами координаты. Оба ограничения не позволяют считать Fusion полноценным геокодером.
Каждый сервис налагает свои лицензионные и технические требования.
В этом примере я пользуюсь сервисом Yandex, обладающим, по всей видимостью, одной из лучших баз адресов по России,и большим лимитом на количество запросов (25000 в день, для сравнения лимит Google — 2500 в день). Вместе с тем, Яндекс налагает ряд ограничений, поэтому для коммерческого использования может быть удобнее использовать сервис OSM (впрочем, этот сервис тоже требует указание источника).
I. Подготовка
Итак, для обращения к сервису мы будем использовать адреса велопарковок города Москвы.Набор данных лежит здесь. Для начала, загрузим данные в OR.
Первое, что стоит сделать — удалить очевидно ненужные столбцы. Следующий шаг — просмотреть качество данных. Сразу можно сделать два вывода:
- В первой колонке должен стоять только номер, cлова “Велосипедная парковка” и адрес здесь излишни.
- Адрес во второй колонке описательный (“Вблизи входа в парк Музеон”), что хорошо для человека,но будет мешать геокодированию. Намного более нам подходит формальный адрес в первом столбце.
Следовательно, мы удаляем ненужное в первой колонке, адрес выделяем в отдельную колонку. Для этого мы используем команды Transform cell и Split column into several columns соответственно:
После таких трансформаций мы получаем следующую структуру данных: номер парковки, формальный адрес парковки, неформальный адрес, вместимость.
В принципе, все готово для геокодинга, однако мы можем несколько упростить для компьютера задачу…
Важно понимать, что геокодинг — процесс, сама технология которого допускает определенный уровень погрешности
Чтобы упростить задачу, в начало каждого адреса мы впишем указание города. В этом нам поможет та же функция Transform cell.
Теперь мы точно готовы к геокодингу. Что нам для этого нужно?
II. Параметры геокодирования
Геокодинг требует сформированного запроса, причем помимо адреса мы должны указать ряд дополнительных параметров. Вся документация лежит здесь.
Итак, первое что мы видим — базовый запрос:
http://geocode-maps.yandex.ru/1.x/?geocode=Москва,+Тверская+улица,+дом+7
Какие дополнительные параметры стоит указать в геокодировании? Во-первых, давайте определим тип ответа. OR умеет разбирать json-файлы, так что давайте использовать этот формат:
format=json
Для уточнения зоны геокодирования мы можем включить ограничение области ответов:
rspn=1
В таком случае мы должны указать эти границы — центр зоны и диапазон допустимых значений относительно центра.
ll=37.618920,55.756994 (координаты Москвы)
spn=0.552069,0.400552 (диапазон)
Количество вариантов ответа, начиная с самого правдоподобного. Наши адреса достаточно простые, так что надеемся, что нам поведет:
results=1
Еще один параметр запроса — персональный ключ API. Такой ключ необязателен, но помогает в некоторых ситуациях. Подробнее о получении ключа. В нашем примере мы не будем его использовать.
key=API-ключ
III. Начинаем геокодирование
Определившись с параметрами, мы должны сформировать запрос целиком. Все параметры объединяются в одну строку знаком “&” . Первым идет адрес запроса, после этого очередность не важна. Для простоты, адрес мы будем указывать в самом конце. Должно получиться что-то типа того:
http://geocode-maps.yandex.ru/1.x/?format=json&rspn=1&ll=37.618920,55.756994&spn=0.552069,0.400552&results=1&geocode=
Обратите внимание, что в примере (начало предыдущего раздела) в адресе вместо пробела используется знак “+”. Мы и сами можем заменить его, но проще воспользоваться стандартной функцией подготовки текста для url:
escape(value, ‘url’)
Наш рецепт готов! Теперь включаем режим “Add column by fetching URLs”
Две команды соединяются простым символом сложения. Я не нашел у яндекса лимита на количество запросов в секунду, но предполагаю что нам будет достаточно и одного запроса/с, чтобы быть уверенным, что нам не закроют доступ к сервису. Для указания скорости в верхнем правом углу окна есть поле “Throttle delay”, где я указал 1000 ms на один запрос. Теперь нам остается нажать “Start” и ждать результатов.
IV. Парсим Json
Как только процесс завершается, мы получаем дополнительную колонку с длинным и непонятным текстом — ответ в формате Json. Наша следующая задача — разобрать Json на отдельные параметры. Чтобы это сделать, необходимо разобраться в структуре ответа — нажмите “edit” в любой ячейке столбца, выделите текст и скопируйте его в любой редактор/визуализатор Json. Я использую для таких случаев этот и этот инструменты (второй — в комбинации с текстовым редактором Sublime text).
На основании структуры файла формируем запрос. Для Яндекс-карт он такой:
value.parseJson()[“response”][“GeoObjectCollection”][“featureMember”][0][“GeoObject”][“Point”][“pos”]
Запрос отправляем через команду New column based on this column:
В результате мы получаем новый столбец с координатами, при этом широта и долгота разделены пробелом. Чтобы для каждой координаты создать отдельный столбик, используем уже знакому команду Split column into several columns:
Собственно, на этом геокодинг и заканчивается — мы получили координаты для каждого адреса. Однако, к сожалению, случается, что координаты бывают неправильными. В следующей части мы рассмотрим, как можно простейшим образом проверить результат.
V. Проверка
Самый очевидный вариант проверки — расставить точки по координатам на карте. здесь есть несколько вариантов решений:
A. отсечение по Scatterplot
Если адресов очень много, а в результатах вы неуверены, иногда бывает полезно посмотреть на Scatterplot. Чтобы его создать, зайдите в Facet>Scatterplot Facet, и выберите график с комбинацией широты и долготы. При серьезных ошибках, например если в некоторых случаях координаты перепутаны (это, правда, невозможно конкретно при геокодировании) ошибка видна невооруженным глазом. Так-же, на scatterplot можно выделить и удалить, или наоборот, выделить в отдельную базу конкретную область на карте.
Б. Визуализация сторонним сервисом
Для визуализации может быть использован сторонний сервис. В своей практике я использую два: Fusion tables от google (простой, данные можно загрузить прямо из OR) и CartoDB (позволяет редактировать записи, перемещая точки прямо на карте). Однако перепроверять все координаты — большой труд, который хочется минимизировать.
Очевидно, что ошибка случается в первую очередь при сложных и абстрактных запросах, следовательно, в первую очередь стоит проверить именно их. В зоне риска — адреса без указания конкретного дома, например “парк Музеон”.
Но, если конкретный дом указан, он указывается номером, значит мы можем выделить адреса без цифр в названии, и целенаправленно проверить их. Для выделения нам понадобится функция текстового поиска и использование RegEx (регулярного выражения), для их включения нужно поставить галку в соответствующем чекбоксе.
^[^\d()]+$
В зависимости от данных, мы можем придумать и другие фильтры опасных адресов, например по количеству запятых.
После этого у нас есть выбор — мы можем проверять адреса в фасете вручную (копировать широту и долготу в поле поиска maps.yandex.ru), или выделить их для проверки в внешнем сервисе. В этом случае создадим отдельную колонку с идентификатором сложных адресов.
Fusion tables может красить точки по названию в файле, так что давайте для попавших в фасет строчек впишем в ячейки слово “small_red”, для остальных — “small_blue” (все названия можно посмотреть здесь, cтиль точек назначается так.) В свою очередь СartoDB может раскрашивать точки по любому несовпадающему значению (обычный Css-selector):
#my_Set[icons=’small_red’] { marker-fill: #D30027;}
Теперь мы видим подозрительные адреса на карте и можем проверить и поправить координаты, — иногда их стоить изменить из соображений банальной композиции на экране.
VI. Послесловие
Данный урок — плод накопленного мной субъективного опыта. Если вы знаете альтернативные решения задачи,или же готовы поделиться личными рецептами обращения к другим геолокационным сервисам, я буду бесконечно благодарен!