Geocodificação — sem Google maps API— Parte II
Olá novamente! Essa é a segunda parte de uma série de geocodificação de dados com R sem Google maps API. Para você que não leu o artigo anterior clica aqui.
Pra quem leu, eu preciso destacar uns pontos:
1 — Graças as atualizações das políticas de uso do Docker Hub (que não permitem mais imagens inativas) não estão mais disponíveis as imagens do postmon e do cepnode no meu repositório.
2 — Alguns leitores me retornaram que os CEP estão registrados no OpenStreetMaps para consultas nos servidores deles. Todavia, a política de uso não permite consultas em larga escala.
Considerando que faz muito tempo desde a publicação do primeiro artigo, eu preciso atualizar algumas coisas antes de continuarmos.
É possível que quem seguiu o que foi passado anteriormente realmente tenha uma lista de endereços válidos para pesquisa, porém, a maneira com que os dados foram obtidos está longe de ser a melhor forma. A seguir eu apresento uma opção.
Funções para ajudar.
Baixar a base de dados do SIHSUS de forma manual é um trabalho muito grande (além de ser chato). Uma opção prática é criar uma função que possa fazer o download dos arquivos disponibilizados direto no servidor de FTP (File Transfer Protocol) do Datasus. Volte na tela inicial dos dados, escolha as opções de download e clique “copiar endereço de link”.
O endereço que obtive foi esse:
ftp://ftp.datasus.gov.br/dissemin/publicos/SIHSUS/200801_/dados/RDRJ2001.dbc
Elimine a parte do “…/RDEJ2001.dbc”, cole em seu navegador o endereço e pronto! Acesso ao servidor FTP.
Repare que as siglas de nomeação dos arquivos segue o disposto na página anterior:
- RD para guias de internação reduzidas;
- RJ para guias de internação rejeitadas para pagamento;
- SP para os registros dos procedimentos profissionais realizados;
- ER para guias de internação rejeitadas que possuem o código do erro.
Agora você deve ter pensado: “bastaria fazer um loop for pela lista de arquivos que eu quiser baixar…”, certo?! E é isso mesmo, mas indo além, vou copiar a função final que eu fiz para isso. A chamada é simples assim:
Ok, agora vamos para a função em si.
Eu não publiquei em pacotes porque existem outras opções disponíveis por ai que fazem a mesma coisa (ainda que não tenha visto com Sparklyr).
A seguir tem uma função wrapper do sapply para fazer as solicitações http na API do OpenStreetMaps.
A chamada da função é a seguinte:
Um serviço de mapas pra chamar de seu!
Bem, chegamos nos finalmente. Se você tentou utilizar a última função direto com URL do OpenStreetMaps deve ter reparado que começou a ficar lento, retornar informações vazias ou dar erro, certo?! A política de uso dos servidores de Tiles deles deixa claro que eles mantém os servidores na base da doação por isso não é para abusar, sequer pode-se anexar apps sem a autorização prévia deles.
Mas calma, tem solução. Crie o seu servidor! O software permite isso, lembre-se de ler atentamente a licença.
Inicialmente precisaremos de um arquivo .osm da localização que se pretende montar o serviço. Vá até a o site do Geofabrik ao clicar na America do Sul e depois em Brasil, será possível escolher o mapa de uma das macroregiões brasileiras. Para esse exemplo o nosso servidor será da região Sudeste.
Salve o arquivo e em seguida vá até o repositório do mediagis e faça um clone:
git clone https://github.com/mediagis/nominatim-docker.git
Escolha a versão que pretende usar e construa a imagem Docker (o Dockerfile da 3.4 quebra em pacotes de segurança).
cd nominatim-docker/3.5
docker build -t nominatim .
TESTE A SUA PACIÊNCIA: o comando a seguir vai descompactar o arquivo .osm em um banco de dados PostgreSQL, porém o tempo que leva para isso acontecer é muito grande.
docker run -t -v <local onde está o arquivo .osm>:/data nominatim sh /app/init.sh /data/<nome do seu arquivo .osm>.osm.pbf postgresdata 4
O número 4 é a quantidade de cores na operação, no meu isso demorou aproximadamente 8 horas para a região sudeste.
Feito esse processo ira surgir no local onde estava o arquivo .osm uma pasta chamada postgresdata. Caso voce não tenha alterado de local essa pasta bastaria apenas executar a linha de comando a seguir para ter o seu servidor funcionando.
docker run --restart=always -p 6432:5432 -p 7070:8080 -d --name nominatim -v <local do aquivo .osm>/postgresdata:/var/lib/postgresql/11/main nominatim bash /app/start.sh
Acesse o http://localhost:7070/ e verás a seguinte page:
Pronto! servidor ativo. Agora basta utilizar como URL para a função make_tiles_query o endereço http://localhost:7070/search?q=.
Dica 1: Dê uma olhada na parte de update da base de dados, para não ter que ficar descompactando novamente a cada atualização.
Dica 2: Salve a pasta postgresdata com o nome da sua região, “sudeste” por exemplo, pois, caso descompacte mais de um .osm, todos eles poderão existir dentro da mesma pasta e só alteraria o final de linha de comando do container:
docker run --restart=always -p 6432:5432 -p 7070:8080 -d --name nominatim -v <local do aquivo .osm>/sudeste:/var/lib/postgresql/11/main nominatim bash /app/start.shoudocker run --restart=always -p 6432:5432 -p 7070:8080 -d --name nominatim -v <local do aquivo .osm>/sul:/var/lib/postgresql/11/main nominatim bash /app/start.sh
Dica 3: No Brasil existem muitos municípios com nomes dobrados ou triplicados, além de infinitos nomes de bairros e ruas iguais. Utilizar a base do Brasil inteira, além de ser muito lento e pesado, irá fazer com que você tenha que lidar com esse cenário. Ao optar por manter em macroregiões a chance disso acontecer reduz.
Selecionando e Juntando as peças.
Se você chegou até essa parte deve ter percebido que muitos endereços podem vir com com mais de uma opção de escolha e que o objeto virou uma monstruosa lista aninhada.
É agora que o Cientista de Dados precisa colocar em prática aquele mantra do ETL (Extract, Transform and Load).
O que eu irei apresentar a seguir é uma alternativa para extrair a localização do primeiro endereço que vier nas listas, não significa que é a melhor opção.
E a chamada da função é essa:
Geocoficação Reversa funciona?! O.o
Com a latitude e a longitude em mãos é possível obter informações do endereço assim:
http://localhost:7070/reverse?format=geojson&lat=<valor>&lon=<valor>
Caso não seja encontrado, um erro será retornado.
Por enquanto é só! Já é perfeitamente possível trabalhar sem API externas para converter ceps em endereços, como visto no primeiro artigo, e sem a API do Google Maps para converter endereços em dados de localização.
A motivação de todo esse trabalho é o tamanho do Dataset, que, quando grande, gera um custo de processamento elevado apenas no estágio de desenvolvimento (imaginem em produção).
Caso ele não seja grande, compensaria usar serviços profissionais como o do Google. Inclusive, vale a pena mencionar, que quando se trata de geolocalização a precisão se torna um fator importante, nesse quesito, o Google maps ainda é imbatível.
Em momento nenhum eu inseri informações sobre o número das casas, pois a fonte escolhida só fornece o CEP para localização da rua, entretanto, a lógica aplicada seria a mesma, bastaria inserir mais uma referência geográfica na função make_tiles_query.
Espero que tenha ajudado. Abaixo estão meus contatos, sintam-se a vontade de me procurar em casos de dúvidas, responderei com prazer.
Github: https://github.com/dr2pedro
Linkedin: https://www.linkedin.com/in/pedro-paulo-teixeira-dos-santos-75b81b199/