Financial Times zamieścił wykres wględnego tempa wzrostu (rate of growth) czyli procentu liczonego jako liczba-nowych / liczba-ogółem-z-okresu-poprzedniego x 100%. Na wykresie wględnego tempa wzrostu zachorowań na COVID19 wszystkim spada: Every day the Covid-19 virus is infecting an increasing number of people, but the rate of growth in cases in some of the worst-hit countries is starting to slow. Powyższe Czerscy przetłumaczyli jako m.in. trend dotyczy niemal wszystkich krajów rozwiniętych. [he, he... Rozwiniętych pod względem liczby chorych, pewnie chcieli uściślić, ale się nie zmieściło]
Spróbowałem narysować taki wykres samodzielnie:
library("dplyr") library("ggplot2") library("ggpubr") ## surl <- "https://www.ecdc.europa.eu/en/publications-data/download-todays-data-geographic-distribution-covid-19-cases-worldwide" today <- Sys.Date() tt<- format(today, "%d/%m/%Y") #d <- read.csv("covid19_C.csv", sep = ';', header=T, na.string="NA", stringsAsFactors=FALSE); d <- read.csv("covid19_C.csv", sep = ';', header=T, na.string="NA", colClasses = c('factor', 'factor', 'factor', 'character', 'character', 'numeric', 'numeric')); d$newc <- as.numeric(d$newc) d$newd <- as.numeric(d$newd)
Zwykłe read_csv
skutkowało tym, że newc/newd
nie były liczbami całkowitymi, tylko
czynnikami. Z kolei dodanie colClasses kończyło się błędem. W końcu stanęło na tym, że czytam
dane w kolumnach newc/newd zadeklarowanych jako napisy a potem konwertuję na liczby. Czy to jest
prawidłowa strategia to ja nie wiem...
Kolejny problem: kolumny newc/newd zawierają NA, wykorzystywana
później funkcja cumsum
z pakietu dplyr
,
obliczająca szereg kumulowany nie działa poprawnie jeżeli szereg
zawiera NA
. Zamieniam od razu NA
na zero.
Alternatywnie można korzystać
z funkcji replace_na
(pakiet dplyr):
# change NA to 0 d[is.na(d)] = 0 # Alternatywnie replace_na #d %>% replace_na(list(newc = 0, newd=0)) %>% # mutate( cc = cumsum(newc), dd=cumsum(newd))
Ograniczam się tylko do danych dla wybranych krajów, nie starszych niż 16 luty 2020:
d <- d %>% filter(as.Date(date, format="%Y-%m-%d") > "2020-02-15") %>% as.data.frame str(d) last.obs <- last(d$date) c1 <- c('IT', 'DE', 'ES', 'UK', 'FR') d1 <- d %>% filter (id %in% c1) %>% as.data.frame str(d1)
Obliczam wartości skumulowane (d
zawiera już skumulowane wartości,
ale obliczone Perlem tak nawiasem mówiąc):
t1 <- d1 %>% group_by(id) %>% summarise(cc = sum(newc, na.rm=T), dd=sum(newd, na.rm=T)) t1c <- d %>% group_by(id) %>% mutate(cum_cc = cumsum(newc), cum_dd = cumsum(newd)) %>% filter (id %in% c1) %>% filter(as.Date(date, format="%Y-%m-%d") > "2020-02-15") %>% as.data.frame str(t1c)
Wykres wartości skumulowanych:
pc1c <- ggplot(t1c, aes(x= as.Date(date, format="%Y-%m-%d"), y=cum_cc)) + geom_line(aes(group = id, color = id), size=.8) + xlab(label="") + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + ggtitle(sprintf("COVID19: total confirmed cases (%s)", last.obs), subtitle=sprintf("%s", surl)) ggsave(plot=pc1c, "Covid19_1c.png", width=15)
Kolumny cum_lcc/cum_ldd
zawierają wartości z kolumny cum_cc/cum_dd
ale opóźnione o jeden okres (funkcja lag
):
## t1c <- t1c %>% group_by(id) %>% mutate(cum_lcc = lag(cum_cc)) %>% as.data.frame t1c <- t1c %>% group_by(id) %>% mutate(cum_ldd = lag(cum_dd)) %>% as.data.frame t1c$gr_cc <- t1c$newc / (t1c$cum_lcc + 0.01) * 100 t1c$gr_dd <- t1c$newd / (t1c$cum_ldd + 0.01) * 100 ## Początkowo wartości mogą być ogromne zatem ## zamień na NA jeżeli gr_cc/dd > 90 t1c$gr_cc[ (t1c$gr_cc > 90) ] <- NA t1c$gr_dd[ (t1c$gr_dd > 90) ] <- NA
Wykres tempa wzrostu:
pc1c_gr <- ggplot(t1c, aes(x= as.Date(date, format="%Y-%m-%d"), y=gr_cc, colour = id, group=id )) + ##geom_line(aes(group = id, color = id), size=.8) + geom_smooth(method = "loess", se=FALSE) + xlab(label="") + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + ggtitle(sprintf("COVID19: confirmed cases growth rate (smoothed)"), subtitle=sprintf("%s", surl)) ggsave(plot=pc1c_gr, "Covid19_1g.png", width=15)
To samo co wyżej tylko dla PL/CZ/SK/HU:
c2 <- c('PL', 'CZ', 'SK', 'HU') t2c <- d %>% group_by(id) %>% mutate(cum_cc = cumsum(newc), cum_dd = cumsum(newd)) %>% filter (id %in% c2) %>% filter(as.Date(date, format="%Y-%m-%d") > "2020-02-15") %>% as.data.frame ##str(t2c) t2c.PL <- t2c %>% filter (id == "PL") %>% as.data.frame t2c.PL head(t2c.PL, n=200) pc2c <- ggplot(t2c, aes(x= as.Date(date, format="%Y-%m-%d"), y=cum_cc)) + geom_line(aes(group = id, color = id), size=.8) + xlab(label="") + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + ggtitle(sprintf("COVID19: total confirmed cases (%s)", last.obs), subtitle=sprintf("Total: %s\n%s", lab1c, surl)) ggsave(plot=pc2c, "Covid19_2c.png", width=15) t2c <- t2c %>% group_by(id) %>% mutate(cum_lcc = lag(cum_cc)) %>% as.data.frame t2c <- t2c %>% group_by(id) %>% mutate(cum_ldd = lag(cum_dd)) %>% as.data.frame t2c$gr_cc <- t2c$newc / (t2c$cum_lcc + 0.01) * 100 t2c$gr_dd <- t2c$newd / (t2c$cum_ldd + 0.01) * 100 ## zamień na NA jeżeli gr_cc/dd > 90 t2c$gr_cc[ (t2c$gr_cc > 90) ] <- NA t2c$gr_dd[ (t2c$gr_dd > 90) ] <- NA t2c.PL <- t2c %>% filter (id == "PL") %>% as.data.frame t2c.PL pc2c_gr <- ggplot(t2c, aes(x= as.Date(date, format="%Y-%m-%d"), y=gr_cc, colour = id, group=id )) + ##geom_line(aes(group = id, color = id), size=.8) + geom_smooth(method = "loess", se=FALSE) + xlab(label="") + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + ggtitle(sprintf("COVID19: confirmed cases growth rate (smoothed)"), subtitle=sprintf("%s", surl)) ggsave(plot=pc2c_gr, "Covid19_2g.png", width=15)
Koniec
Dane pierwotne: Center for Systems Science and
Engineering (CSSE/Johns Hopkins University)
https://github.com/CSSEGISandData/COVID-19
(także słynna
wizualizacja:
https://gisanddata.maps.arcgis.com/apps/opsdashboard/index.html#/bda7594740fd40299423467b48e9ecf6
.)
European Centre for Disease Prevention and Control
https://ecdc.europa.eu/en/geographical-distribution-2019-ncov-cases
.
Dane agregowane od innych: Our World in
Data/Coronavirus Source Data/WHO Situation Reports
https://ourworldindata.org/coronavirus-source-data
.
Są też tzw. dane w czasie rzeczywistym:
https://worldometers.info/coronavirus/
, ale ich
wiarygodność jest podejrzana, bo w przeciwieństwie do tych wyżej
opisanych nie wiadomo jak są zbierane i/lub
skąd agregowane (więc nie ma klikalnego linku).
Na stronie
https://ourworldindata.org/coronavirus-source-data
są dane nt liczby przypadków/zgonów z powodu zarażenia wirusem covid19, których źródłem
są 'Raporty Sytuacyjne WHO'
(https://www.who.int/emergencies/diseases/novel-coronavirus-2019/situation-reports/
).
Raporty są w formacie PDF więc bezpośrednio nie można korzystać
z publikowanych tam danych.
No ale uprzejmi ludzie z ourworldindata.org
już te raporty zamienili na csv i są one gotowe do pobrania:
wget -N https://covid.ourworldindata.org/data/full_data.csv
Za pomocą prostych skryptów Perla modyfikuję plik full_data.csv
tak, żeby
poszczególne kolumny zawierały:
date;id;country;newc;newd;totalc;totald
(data, ISO-kod
kraju, nazwa-kraju, nowe-przypadki, nowe-zgony, wszystkie-przypadki,
wszystkie-zgony)
Dla wybranych krajów rysują wykresy liniowe (wykorzystując R):
library("dplyr") library("ggplot2") library("ggpubr") ## today <- Sys.Date() tt<- format(today, "%d/%m/%Y") d <- read.csv("covid19.csv", sep = ';', header=T, na.string="NA"); d <- d %>% filter(as.Date(date, format="%Y-%m-%d") > "2020-02-15") %>% as.data.frame ## c1 <- c('ITw', 'DEw', 'ESw', 'UKw', 'FRw', 'DKw', 'SEw') # date;id;country;newc;newd;totalc;totald d1 <- d %>% filter (id %in% c1) %>% as.data.frame t1 <- d1 %>% group_by(id) %>% summarise(cc = sum(newc, na.rm=T), dd=sum(newd, na.rm=T)) lab1c <- toString(paste (sep=" = ", t1$id, t1$cc)) lab1d <- toString(paste (sep=" = ", t1$id, t1$dd)) str(d1) pc1 <- ggplot(d1, aes(x= as.Date(date, format="%Y-%m-%d"), y=newc)) + geom_line(aes(group = id, color = id), size=.8) + xlab(label="") + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + ggtitle(sprintf("COVID19: new confirmed cases (%s)", tt), subtitle=sprintf("Total: %s\n%s", lab1c, surl)) pd1 <- ggplot(d1, aes(x= as.Date(date, format="%Y-%m-%d"), y=newd)) + geom_line(aes(group = id, color = id), size=.8) + xlab(label="") + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + ggtitle(sprintf ("COVID19: deaths (%s)", tt), subtitle=sprintf("Total: %s\n%s", lab1d, surl)) c2 <- c('PLw', 'CZw', 'SKw', 'HUw', 'ROw', 'BGw', 'ELw') d2 <- d %>% filter (id %in% c2) %>% as.data.frame t2 <- d2 %>% group_by(id) %>% summarise(cc = sum(newc, na.rm=T), dd=sum(newd, na.rm=T)) str(d2) lab2c <- toString(paste (sep=" = ", t2$id, t2$cc)) lab2d <- toString(paste (sep=" = ", t2$id, t2$dd)) pc2 <- ggplot(d2, aes(x= as.Date(date, format="%Y-%m-%d"), y=newc)) + geom_line(aes(group = id, color = id), size=.8) + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + xlab(label="") + ggtitle(sprintf("COVID19: new confirmed cases (%s)", tt), subtitle=sprintf("Total: %s\n%s", lab2c, surl)) pd2 <- ggplot(d2, aes(x= as.Date(date, format="%Y-%m-%d"), y=newd)) + geom_line(aes(group = id, color = id), size=.8) + theme(plot.subtitle=element_text(size=8, hjust=0, color="black")) + xlab(label="") + scale_y_continuous(breaks=c(1,2,3,4,5,6,7,8,9)) + ggtitle(sprintf ("COVID19: deaths (%s)", tt), subtitle=sprintf("Total: %s\n%s", lab2d, surl)) p1 <- ggarrange(pc1,pd1, ncol=2, nrow=1) p2 <- ggarrange(pc2,pd2, ncol=2, nrow=1) ggsave(plot=p1, "Covid19_1w.png", width=15) ggsave(plot=p2, "Covid19_2w.png", width=15)
Zatem: Liczba przypadków/zgonów z powodu zarażenia wirusem covid19 na podstawie danych ourworldindata.org/WHO:
UE, która jest powszechnie krytykowana, że nic nie robi w sprawie, okazuje się że coś tobi -- też udostępnia jakieś dane w temacie (https://www.ecdc.europa.eu/en/publications-data/download-todays-data-geographic-distribution-covid-19-cases-worldwide). Wprawdzie nie jest określone skąd te dane pochodzą, ale sądząc po ich zawartości źródło jest to samo (WHO).
wget -N https://www.ecdc.europa.eu/sites/default/files/documents/COVID-19-geographic-disbtribution-worldwide-2020-03-15.xls\ -O covid19.csv
Ponieważ dane, że tak powiem, unijne są w formacie xls
zamieniam
je na csv
, wykorzystując
do tego LibreOffice:
## zamień wszystkie pliki z bieżącego katalogu na csv ze ; (59) jako znakiem separacji: soffice --convert-to csv:"Text - txt - csv (StarCalc)":59,,0,1,1 --outdir . *.xls
Rysuję wykresy liniowe zmodyfikowanym z dokładnością do pliku z danymi R-skryptem. Wyniki są prawie takie same. Może bym nawet nie zwrócił uwagi, że się różnią gdyby nie podejrzane załamanie liczby przypadków dla Włoch dla 15.03.2020 (z 2,5 tys na 90).
Drążąc temat wyrysowałem wykresy dla wybranych czterech krajów w dwóch wariantach danych
(dane z ourworldindata.org oznaczone literką w
). W szczególności i niestety
Włochy 15/3/2020 odnotowały ponad 3497 nowych przypadków
a nie 90 jak podano w bazie Unijnej. Są też mniejsze różnice w innych miejscach:
Wszystko to robione jest automatem co pobiera/zamienia/rysuje/wstawia na githuba
(https://github.com/hrpunio/Nafisa/tree/master/Covid19
)
oraz wysyła na twittera (https://twitter.com/tprzechlewski
). Automat działa
na RaspberryPi zresztą...