dssg-pt / covid19pt-data

😷️🇵🇹 Dados relativos à pandemia COVID-19 em Portugal
GNU General Public License v3.0
446 stars 183 forks source link

Dados de casos confirmados por concelho #83

Closed ishouldbedany closed 4 years ago

ishouldbedany commented 4 years ago

Para desenhar a introdução do número de casos confirmados por concelho (e metadados associados) no repositório, mantendo a fiabilidade e o grau de automatização. Algumas questões a ter em conta:

paulomaia20 commented 4 years ago

Tenho feito algumas experiências com o Tabula que me parecem dar resultados aceitáveis.

Já vi alguma variabilidade do nome do concelho de dia para dia, por isso a minha sugestão seria criar um dataset que inicialmente teria, para cada dia, uma linha por concelho, e aí agrupar tudo num ID único.

Fazendo Left Join com uma lista de concelhos também percebemos quais estão a falhar, e podemos colocar a informação a NaN, não sabendo se tem algum infetado ou se o número é 0.

Estando isto feito, podemos usar o pivot_table do pandas para transformar a informação em colunas.

A inclusão seria feita num .csv separado, para evitar problemas com o processo atual.

ishouldbedany commented 4 years ago

Cortesia da @centraldedados, temos neste repositório, em data/concelhos.csv, os 308 concelhos de Portugal, acompanhados do identificador único código de distrito + código de concelho.

O scraping é feito a partir dos dados do site dos CTT e a licença permite o uso, portanto parece um bom ponto de partida.

ishouldbedany commented 4 years ago

Sobre os shapefiles, vou tomar a liberdade de convocar quem já demonstrou mestria em tais assuntos neste projecto: @joaopalmeiro , por aí? :grin:

perone commented 4 years ago

Tentei usar o tabula também mas não consegui resultados muito bons, no fim o que ficou mais fácil para mim foi:

1) Command-line: pdftotext -raw -f 3 -l 3 boletim.pdf

e o seguinte código Python (bem hacky, fiz rapidamente e dá para melhorar):

with open("boletim.txt", "r", encoding="iso-8859-1") as f:
    data = f.read().encode("iso-8859-1").decode("utf-8")

lines = data.split()[80:]
d = {}
name_state = ''
skip_words = ['CONCELHO', 'NÚMERO', 'DE', 'CASOS']
for l in lines:
    if l in skip_words:
        continue
    try:
        count = int(l)
        name_state = name_state.strip()
        d[name_state] = count
        name_state = ''
    except ValueError:
        name_state += l + ' '

dfpt = pd.DataFrame.from_dict(d.items())
dfpt.columns = ["city", "cases"]

Resultado (depois de fazer merge com geojson): image

Eu tirei algumas cidades fora de Portugal continental mas é fácil ajustar o que faltar também. Enfim, espero que ajude, foi o código que ficou mais simples para mim.

joaopalmeiro commented 4 years ago

Olá! :smile:

Antes de mais, desculpem a demora em responder!

Relativamente à extração dos dados dos Relatórios de Situação, gostava de começar por partilhar alguns pontos derivados do que andei a fazer (até porque coincidem com algumas das questões colocadas), dado que hoje terminei de extrair os dados (disponíveis aqui, divididos por dia, e ainda a necessitarem de uma certa uniformização em termos de nomenclatura dos concelhos, pelo menos), por concelho, de todos os Relatórios disponíveis (algo que comecei há uns bons dias atrás de modo a ter os dados para criar alguns gráficos mais focados no Alentejo).

Em primeiro lugar, penso que o "maior desafio" deve-se à "irregularidade" na formatação (à falta de melhor palavra) dos próprios Relatórios/PDFs, ou seja, nem todos os Relatórios apresentam tabelas que sejam facilmente extraídas de forma automática. Esta "irregularidade" prende-se, de uma forma mais concreta, à existência de "células" com quebras de linha, ao posicionamento vertical e horizontal do conteúdo dentro das "células" e ao desalinhamento das "linhas" entre tabelas, por exemplo. Para além disso, o pós-processamento dos dados (que poderá ser necessário), na minha perspetiva, está bastante dependente da opções escolhidas para extrair as tabelas dos Relatórios.

A título de exemplo, até dia 9 de abril, utilizei o R e o pdftools (apenas porque já conhecia este pacote e sabia utilizá-lo minimamente) para a extração dos dados das tabelas dos Relatórios, sendo que, para além da necessidade de executar alguma lógica de pós-processamento, tive de ir ajustando, por vezes, algumas coisas ao longo dos dias até conseguir ter um data frame pronto a ser guardado em formato CSV. Contudo, "no dia" 9 de abril, não consegui, em complemento ao que já tinha, adaptar a lógica de pós-processamento para, de forma minimamente "automatizada", estruturar as coisas num data frame (os padrões eram algo aleatórios e teria, dentro do que sei e consigo, introduzir praticamente alguns concelhos "manualmente"). Desta forma, explorei outras hipóteses e deparei-me com o tabulizer, um pacote criado "em cima" do pacote, em Java, que "alimenta" o Tabula. Através da função explore_text(), consegui extrair a tabela do Relatório de 9 de abril e, aplicando alguma lógica de pós-processamento, chegar ao dito data frame. Daí em diante, necessitei apenas de tornar esta função de pós-processamento mais robusta e desde o Relatório de dia 15 de abril que não necessito de alterar o código, apenas de o correr no RStudio. Quanto à linguagem e às bibliotecas, acabei por não explorar o que é que o Python tem para oferecer.

Posto isto, há, na minha opinião, mais 4 desafios:

Quanto à identificação dos concelhos, penso que uma boa abordagem seria seguir a hierarquia e a nomenclatura presentes na Carta Administrativa Oficial de Portugal (CAOP) da Direção-Geral do Território (podem encontrar a versão atual, a de 2019, aqui). Esta Carta segue a Nomenclatura das Unidades Territoriais para Fins Estatísticos (NUTS) e possui, também, um identificador numérico único para cada concelho chamado DICO (os dois primeiros digitos dizem respeito ao DIstrito, enquanto que os outros dois dizem respeito ao COncelho). Esta informação está disponível no ficheiro Áreas das freguesias, concelhos, distritos e país disponível aqui, nomeadamente na folha _Areas_ConcelhosCAOP2019. Assim, penso que é "apenas" necessário decidir que campos incluir, de modo a garantir a identificação de todos os concelhos e a desambiguação entre estes, e ter alguma lógica para comparar estes dados com aqueles extraídos. Em complemento, também gostaria de sugerir a introdução de um campo para a ARS de cada concelho.

Relativamente aos shapefiles disponibilizados junto da CAOP, pelo que consegui perceber, só se encontram disponíveis ficheiros divididos por freguesia (um ficheiro para cada Área Administrativa aproximadamente) e com o identificador número único por freguesia (o DICOFRE). Contudo, o shapefile/GeoJSON atualmente disponível aqui no repositório possui uma variável chamada _CC2 que coincide com o DICO, salvo erro.

Por fim, penso que estes dados deveriam ser guardados num novo ficheiro, para além de que opção sugerida pelo @ishouldbedany parece-me uma boa ideia quanto à introdução de todos os concelhos.

Desculpem a resposta bastante longa, mas acho que, desta forma, consegui partilhar o que sei sobre este tópico. Espero que esta partilha vos seja útil! Se precisarem de alguma ajuda, não hesitem em pedir! :smile:

piresn commented 4 years ago

Olá a todos!

Fiz um PR com uma primeira solução usando tabula e python.

O PR inclui um csv com os resultados (relatorios desde 24 Março), pelo q também pode ser usado para comparação de outras soluções.

Como já referido pelo @joaopalmeiro, os nomes dos concelhos não estão uniformizados nos relatorios e este script tambem ainda nao corrige isso.

paulomaia20 commented 4 years ago

Obrigado pelo vosso contributo :) Acho que pode ser importante extrair também a % de população que esses números representam, pois varia de dia para dia (aquele asterisco com os 78-83% que tem aparecido, por baixo da tabela dos concelhos). Talvez dê para fazer isso com o script que temos de momento para fazer parse do texto do boletim - vou investigar.

ishouldbedany commented 4 years ago

Depois da (magnífica) exposição do @joaopalmeiro sobre este assunto, parece-me que a melhor opção é mesmo identificar os concelhos pelo respectivo DICO, que creio até estar no repositório já falado aqui da @centraldedados.

Não fica tão fácil para quem quiser abrir a folha de cálculo e explorar directamente, porque as colunas passam a ser mapeadas por DICO, mas de qualquer das formas seria um ficheiro com 300 colunas, já não seria muito user-friendly e não.

Paralelamente, poderíamos ter um ficheiro anexo (um .yaml, um .json, um outro .csv, qualquer coisa no formato de dicionário) que mapeasse os DICOs ao nome do respectivo concelho - e poderíamos aí incluir as respectivas variações no nome do concelho.

{
1234: ["Reguengos de Monsaraz", "Reg. de Monsaraz", "Reguengos Monsaraz"]
},

O primeiro elemento de cada lista seria sempre o nome comum e oficial, sendo os seguintes as possíveis variações. Se fosse minimanente sustentável curar esta lista (não sei qual a % de concelhos que pode recair nestes casos), até poderíamos usá-la para fazer a uniformização, ao invés de tentarmos criar heurísticas genéricas (que geralmente se revelam frágeis).

paulomaia20 commented 4 years ago

Entretanto foi nos enviada a seguinte informação, com os dados que estão a alimentar o dashboard da ERSI:

http://esriportugal.maps.arcgis.com/home/item.html?id=b895ffa41e8e4f2e8bd957abd9a933cf#data

paulomaia20 commented 4 years ago

Estamos a aguardar para ver se a ESRI vai fazer a atualização dos dados por concelho nas novas versões do relatório, antes de fundir esta informação. O script que temos vindo a desenvolver é alimentado pelos dados históricos desse link acima.

jgrocha commented 4 years ago

Gente, podem usar e abusar de uma script que uso para fazer isso, disponível em: https://github.com/jgrocha/covid-pt/blob/master/Relat%C3%B3rios/relatorio.py

A script usa-se da seguinte forma:

wget https://covid19.min-saude.pt/wp-content/uploads/2020/05/69_DGS_boletim_20200510.pdf
./relatorio.py 2020-05-10 https://covid19.min-saude.pt/wp-content/uploads/2020/05/69_DGS_boletim_20200510.pdf 69_DGS_boletim_20200510.sql

Eu estou a gerar um sql para atualizar a minha BD Postgresql todos os dias. Depois exporto para um geopackage, onde têm os dados todos (geográficos e não geográficos).

Têm um csv com os dados por concelho atualizados, num csv, logo na raiz do repositório, em: https://github.com/jgrocha/covid-pt/blob/master/confirmados_concelho.csv

Com o pandas, por exemplo, uso diretamente o ficheiro do repositório:

pandemia = pandas.read_csv('https://raw.githubusercontent.com/jgrocha/covid-pt/master/confirmados_concelho.csv')

Se precisarem de alguma coisa, é só dizerem. Posso adaptar o meu o workflow para atualizar este respositório.

Nota

Os dados da ESRI são copiados à mão (pelo menos assim era feito no início).

paulomaia20 commented 4 years ago

Para já vou fechar, dado que estamos a usar os dados da ESRI (que têm vindo a tratar da atualização diariamente), e que nos traz menos variabilidade em relação a um scraper do PDF, que nos ia roubar algum tempo a fazer eventuais correções. Se virmos que queremos usar o PDF como fonte volto a abrir este tema :)

Obrigado a todos pelas contribuições!