Animações na época do coronavírus

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br


[Esteartigofoipublicadopelaprimeiravezem[Thisarticlewasfirstpublishedon R na rotação da cabeça – the Heads or Tails blog, e gentilmente contribuiu para os R-blogueiros]. (Você pode relatar um problema sobre o conteúdo desta página aqui)


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.

Os primeiros quatro meses de 2020 foram dominados pela pandemia de Coronavírus (aka COVID-19), que transformou a vida global de uma maneira sem precedentes. Sociedades e economias lutam para se adaptar às novas condições e restrições necessárias. Uma fração tranquilamente grande de governos ao redor do mundo continua adotando abordagens baseadas em evidências para esta crise, baseadas em esforços de coleta de dados em larga escala. A maioria desses dados está sendo disponibilizada ao público e pode ser estudada em tempo real. Este post descreverá como extrair e preparar os dados necessários para animar a propagação do vírus ao longo do tempo em meu país natal, a Alemanha.

Publiquei uma versão pré-processada dos dados relevantes para este projeto como um conjunto de dados Kaggle, juntamente com os arquivos de forma geoespacial necessários para plotar o mapa resultante. Esta publicação descreve como criar esse conjunto de dados a partir dos dados de origem originais usando um conjunto de ferramentas arrumadas. Em seguida, usaremos os pacotes gganimate e sf para criar visuais animados do mapa.

Esses são os pacotes que precisamos:

libs <- c('dplyr', 'tibble',      # wrangling
          'stringr', 'readr',     # strings, input
          'lubridate', 'tidyr',   # time, wrangling
          'knitr', 'kableExtra',  # table styling
          'ggplot2', 'viridis',   # visuals
          'gganimate', 'sf',      # animations, maps
          'ggthemes')             # visuals
invisible(lapply(libs, library, character.only = TRUE))

Os dados COVID-19 para a Alemanha estão sendo coletados pelo Instituto Robert Koch e podem ser baixados através da Plataforma Nacional de Dados Geográficos (que também hospeda um painel interativo). Os primeiros casos registrados são de 2020-01-24. Aqui, definimos o link correspondente e lemos o conjunto de dados:

infile <- "https://opendata.arcgis.com/datasets/dd4580c810204019a7b8eb3e0b329dd6_0.csv"
covid_de <- read_csv(infile, col_types = cols())

Esses dados contêm um número de colunas que são, sem surpresa, nomeadas em alemão:

covid_de %>%
  head(5) %>%
  glimpse()
## Observations: 5
## Variables: 18
## $ FID                   4281356, 4281357, 4281358, 4281359, 4281360
## $ IdBundesland          1, 1, 1, 1, 1
## $ Bundesland            "Schleswig-Holstein", "Schleswig-Holstein",…
## $ Landkreis             "SK Flensburg", "SK Flensburg", "SK Flensbu…
## $ Altersgruppe          "A15-A34", "A15-A34", "A15-A34", "A15-A34",…
## $ Geschlecht            "M", "M", "M", "M", "M"
## $ AnzahlFall            1, 1, 1, 1, 1
## $ AnzahlTodesfall       0, 0, 0, 0, 0
## $ Meldedatum            "2020/03/14 00:00:00", "2020/03/19 00:00:00…
## $ IdLandkreis           "01001", "01001", "01001", "01001", "01001"
## $ Datenstand            "30.04.2020, 00:00 Uhr", "30.04.2020, 00:00…
## $ NeuerFall             0, 0, 0, 0, 0
## $ NeuerTodesfall        -9, -9, -9, -9, -9
## $ Refdatum              "2020/03/16 00:00:00", "2020/03/13 00:00:00…
## $ NeuGenesen            0, 0, 0, 0, 0
## $ AnzahlGenesen         1, 1, 1, 1, 1
## $ IstErkrankungsbeginn  1, 1, 1, 1, 1
## $ Altersgruppe2         "nicht übermittelt", "nicht übermittelt", "…

O seguinte bloco de código reformula e converte os dados para torná-los mais acessíveis. Isso inclui substituir nossos amados tremados alemães por ditongos simplificados, criar faixas etárias e agregar números COVID-19 por município, faixa etária, gênero e data:

covid_de %
  select(state = Bundesland,
         county = Landkreis,
         age_group = Altersgruppe,
         gender = Geschlecht,
         cases = AnzahlFall,
         deaths = AnzahlTodesfall,
         recovered = AnzahlGenesen,
         date = Meldedatum) %>%
  mutate(date = date(date)) %>%
  mutate(age_group = str_remove_all(age_group, "A")) %>%
  mutate(age_group = case_when(
    age_group == "unbekannt" ~ NA_character_,
    age_group == "80+" ~ "80-99",
    TRUE ~ age_group
  )) %>%
  mutate(gender = case_when(
    gender == "W" ~ "F",
    gender == "unbekannt" ~ NA_character_,
    TRUE ~ gender
  )) %>%
  group_by(state, county, age_group, gender, date) %>%
  summarise(cases = sum(cases),
            deaths = sum(deaths),
            recovered = sum(recovered)) %>%
  ungroup() %>%
  filter(cases >= 0 & deaths >= 0) %>%
  filter(date %
  mutate(state = str_replace_all(state, "ü", "ue")) %>%
  mutate(state = str_replace_all(state, "ä", "ae")) %>%
  mutate(state = str_replace_all(state, "ö", "oe")) %>%
  mutate(state = str_replace_all(state, "ß", "ss")) %>%
  mutate(county = str_replace_all(county, "ü", "ue")) %>%
  mutate(county = str_replace_all(county, "ä", "ae")) %>%
  mutate(county = str_replace_all(county, "ö", "oe")) %>%
  mutate(county = str_replace_all(county, "ß", "ss")) %>%
  mutate(county = str_remove(county, "\(.+\)")) %>%
  mutate(county = str_trim(county)) 

O resultado é um conjunto de dados que lista diariamente (não cumulativo!) casos, mortes e casos recuperados para 6 faixas etárias, sexo e municípios alemães e seus estados federais correspondentes. Semelhante aos EUA, a Alemanha possui um sistema federal no qual os 16 estados federais possuem uma grande quantidade de poder legislativo. O equivalente alemão do condado dos EUA é o "Kreis", que pode ser associado a uma cidade ("Stadtkreis" = "SK") ou ao lado do país ("Landkreis" = "LK"). Aqui, apenas um subconjunto de colunas é mostrado por razões de clareza:

covid_de %>%
  filter(state == "Sachsen") %>%
  select(-deaths, -recovered) %>%
  head(5) %>%
  kable() %>%
  column_spec(1:6, width = c("15%", "25%", "15%", "10%", "25%", "10%")) %>%
  kable_styling()

Estado

município

grupo de idade

gênero

encontro

casos

Sachsen

LK Bautzen

00-04

F

2020-03-20

1 1

Sachsen

LK Bautzen

00-04

F

2020-04-07

2

Sachsen

LK Bautzen

00-04

M

2020-03-21

1 1

Sachsen

LK Bautzen

05-14

F

2020-03-20

1 1

Sachsen

LK Bautzen

05-14

F

2020-03-21

1 1

Este é o conjunto de dados limpo disponível no Kaggle como covid_de.csv. Com esses dados, você já pode dividir e analisar as características COVID-19 da Alemanha por vários recursos demográficos e geográficos.

cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br

No entanto, para os mapas que estamos interessados ​​em mais uma entrada, faltam: shapefiles. Um shapefile usa um formato vetorial padrão para especificar geometrias espaciais. Ele empacota os dados de limite do mapa das entidades necessárias (como países, estados federais) em um pequeno conjunto de arquivos relacionados. Para este projeto, encontrei shapefiles disponíveis publicamente no nível estadual e municipal, fornecidos pela Agência Federal de Cartografia e Geodésia da Alemanha. Ambos os níveis estão disponíveis no conjunto de dados Kaggle. Aqui eu coloquei os arquivos no nível do condado (de_county.*) em um diretório estático local.

Os arquivos de forma podem ser lidos no R usando o sf ferramenta de embalagem st_read. Para juntá-los em breve aos nossos dados COVID-19, precisamos fazer algumas traduções e discussões de string novamente. o tidyr ferramenta unite está sendo usado para combinar o tipo de município (BEZ in c("LK", "SK")) e nome do município no formato que temos em nossos dados COVID-19:

shape_county %
  rename(county = GEN) %>%
  select(county, BEZ, geometry) %>%
  mutate(county = as.character(county)) %>%
  mutate(county = str_replace_all(county, "ü", "ue")) %>%
  mutate(county = str_replace_all(county, "ä", "ae")) %>%
  mutate(county = str_replace_all(county, "ö", "oe")) %>%
  mutate(county = str_replace_all(county, "ß", "ss")) %>%
  mutate(county = str_remove(county, "\(.+\)")) %>%
  mutate(county = str_trim(county)) %>%
  mutate(BEZ = case_when(
    BEZ == "Kreis" ~ "LK",
    BEZ == "Landkreis" ~ "LK",
    BEZ == "Stadtkreis" ~ "SK",
    BEZ == "Kreisfreie Stadt" ~ "SK"
  )) %>%
  unite(county, BEZ, county, sep = " ", remove = TRUE)

Nesta fase, ainda existem alguns nomes de condados que não correspondem exatamente. Caso contrário, teria sido fácil demais. Esses casos se resumem principalmente a diferentes estilos de abreviações, sendo usados ​​para municípios com nomes mais longos. Uma maneira escalável de lidar com essas maravilhas do idioma alemão seria a correspondência nebulosa pelas semelhanças entre as distâncias das cordas. Aqui, o número de incompatibilidades é pequeno e eu decidi ajustá-las manualmente.

Então, eu agrupo tudo por county e date e soma os demais recursos. Uma questão importante aqui é que nem todos os municípios relatam números para todos os dias. Afinal, essas são pequenas áreas. Nesse conjunto de dados, esses casos estão implicitamente ausentes; ou seja, as linhas correspondentes simplesmente não estão presentes. É importante converter esses casos em entradas explicitamente ausentes: linhas com contagem zero. Caso contrário, nosso mapa eventual terá "buracos" nele por dias e municípios específicos. A solução elegante no código é possibilitada pelo tidyr função complete: simplesmente nomeie todas as colunas para as quais queremos ter todas as combinações e especifique como elas devem ser preenchidas. Essa abordagem se aplica a qualquer situação em que temos um conjunto de recursos e precisamos de uma grade completa de todas as combinações possíveis.

Finalmente, resumimos os casos acumulados e as mortes. Aqui, eu também apliquei um filter extrair dados apenas de 1 a 31 de março, para impedir que o arquivo de animação fique muito grande. Sinta-se à vontade para expandir isso para um período mais longo:

foo %
  mutate(county = case_when(
    county == "Region Hannover" ~ "LK Region Hannover",
    county == "SK Muelheim a.d.Ruhr" ~ "SK Muelheim an der Ruhr",
    county == "StadtRegion Aachen" ~ "LK Staedteregion Aachen",
    county == "SK Offenbach" ~ "SK Offenbach am Main",
    county == "LK Bitburg-Pruem" ~ "LK Eifelkreis Bitburg-Pruem",
    county == "SK Landau i.d.Pfalz" ~ "SK Landau in der Pfalz",
    county == "SK Ludwigshafen" ~ "SK Ludwigshafen am Rhein",
    county == "SK Neustadt a.d.Weinstrasse" ~ "SK Neustadt an der Weinstrasse",
    county == "SK Freiburg i.Breisgau" ~ "SK Freiburg im Breisgau",
    county == "LK Landsberg a.Lech" ~ "LK Landsberg am Lech",
    county == "LK Muehldorf a.Inn" ~ "LK Muehldorf a. Inn",
    county == "LK Pfaffenhofen a.d.Ilm" ~ "LK Pfaffenhofen a.d. Ilm",
    county == "SK Weiden i.d.OPf." ~ "SK Weiden i.d. OPf.",
    county == "LK Neumarkt i.d.OPf." ~ "LK Neumarkt i.d. OPf.",
    county == "LK Neustadt a.d.Waldnaab" ~ "LK Neustadt a.d. Waldnaab",
    county == "LK Wunsiedel i.Fichtelgebirge" ~ "LK Wunsiedel i. Fichtelgebirge",
    county == "LK Neustadt a.d.Aisch-Bad Windsheim" ~ "LK Neustadt a.d. Aisch-Bad Windsheim",
    county == "LK Dillingen a.d.Donau" ~ "LK Dillingen a.d. Donau",
    county == "LK Stadtverband Saarbruecken" ~ "LK Regionalverband Saarbruecken",
    county == "LK Saar-Pfalz-Kreis" ~ "LK Saarpfalz-Kreis",
    county == "LK Sankt Wendel" ~ "LK St. Wendel",
    county == "SK Brandenburg a.d.Havel" ~ "SK Brandenburg an der Havel",
    str_detect(county, "Berlin") ~ "SK Berlin",
    TRUE ~ county
  )) %>%
  group_by(county, date) %>%
  summarise(cases = sum(cases),
            deaths = sum(deaths)) %>%
  ungroup() %>%
  complete(county, date, fill = list(cases = 0, deaths = 0)) %>%
  group_by(county) %>%
  mutate(cumul_cases = cumsum(cases),
         cumul_deaths = cumsum(deaths)) %>%
  ungroup() %>%
  filter(between(date, date("2020-03-01"), date("2020-03-31")))

Agora, temos todos os ingredientes para animar um mapa de casos cumulativos no nível do condado. Aqui, primeiro definimos o objeto de animação especificando geom_sf() e theme_map() para o estilo do mapa, fornecendo a coluna etapas da animação date ao transition_time() método. A vantagem do tempo de transição é que a duração das transições entre as etapas é proporcional às diferenças de tempo intrínsecas. Aqui, temos um conjunto de dados muito bem comportado e todas as nossas etapas são de 1 dia. Assim, também poderíamos usar transition_states() diretamente. No entanto, considero uma boa prática usar transition_time sempre que etapas de tempo reais estiverem envolvidas; estar preparado para intervalos de tempo desiguais.

Os parâmetros de animação são fornecidos no animate função, como o estilo de transição de um dia para o outro (cubic-in-out), a velocidade da animação (10 quadros por s) ou o tamanho do gráfico. Para animações cumulativas como essa, é sempre uma boa ideia incluir um end_pause quadro congelado, para que o leitor possa observar mais de perto o estado final antes que o loop comece novamente:

gg %
  right_join(foo, by = "county") %>%
  ggplot(aes(fill = cumul_cases)) +
  geom_sf() +
  scale_fill_viridis(trans = "log1p", breaks = c(0, 10, 100, 1000)) +
  theme_map() +
  theme(title = element_text(size = 15), legend.text = element_text(size = 12),
        legend.title = element_text(size = 15)) +
  labs(title = "Total COVID-19 cases in Germany: {frame_time}", fill = "Cases") +
  transition_time(date)

animate(gg + ease_aes('cubic-in-out'), fps = 10, end_pause = 25, height = 800, width = round(800/1.61803398875))

Nosso mapa final mostra como o número de casos de COVID-19 na Alemanha começou a aumentar no sul e oeste e como eles se espalharam para outras partes do país. O meio geográfico da Alemanha parece estar atrasado em casos de contagem ainda mais tarde. Observe a escala de cores logarítmica.

Mais informações:

  • Uma ressalva: essa visão não leva em consideração a densidade populacional, o que faz com que grandes cidades como Berlim (nordeste) se destacem mais no final. Atualmente, meu conjunto de dados Kaggle inclui contagens de população apenas para o estado, mas planejo adicionar dados de condados em um futuro próximo.

  • Se você está procurando mais inspiração sobre como analisar esse conjunto de dados, consulte os vários blocos de anotações (também conhecidos como "Kernels") associados a ele no Kaggle. O Kaggle tem a grande vantagem de poder executar scripts e notebooks R ou Python em um ambiente de nuvem bastante poderoso; e apresente seu trabalho ao lado de conjuntos de dados e competições.

  • Outro conjunto de dados meus da Kaggle com casos diários de COVID-19, mortes e recuperações nos EUA pode ser encontrado aqui. Esses dados também têm uma resolução no nível do condado. Ele se baseia nos dados da Universidade Johns Hopkins e eu os atualizo diariamente.

var vglnk = {key: '949efb41171ac6ec1bf7f206d57e90b8'};

(função (d, t) {
var s = d.createElement
s.src = '//cdn.viglink.com/api/vglnk.js';
var r = d.getElementsByTagName
} (documento, 'script'));

Para Deixe um comentário para o autor, siga o link e comente no blog: R na rotação da cabeça - the Heads or Tails blog.

R-bloggers.com oferece atualizações diárias por email sobre notícias e tutoriais do R sobre o aprendizado do R e muitos outros tópicos. Clique aqui se você deseja publicar ou encontrar um emprego em ciência da dados / R.


Deseja compartilhar seu conteúdo com R-blogueiros? clique aqui se você tiver um blog ou aqui se não tiver.



cupom com desconto - o melhor site de cupom de desconto cupomcomdesconto.com.br
Leia Também  O membro do consórcio R, Esri, capacita a tomada de decisão informada em torno do COVID-19