Pozdrav svima.

U zadnjem blog postu Kristijan se pozabavio vizualizacijom i projekcijom podataka vezanih za Covid-19. Kao što je i obećano, cijeli projekt dostupan je ovdje. Danas ste zapeli sa mnom, gdje ćemo proći korak po korak kako dobiti ovakve rezultate, ali s fokusom na Hrvatsku.

Moram napomenuti da je Hrvatska u usporedbi sa svijetom mala zemlja s malo zaraženih, te da su općenito sve projekcije točnije što više podataka imamo, a u HR ih je prilično malo. Ipak, dobro je uzeti za primjer nešto s čime smo povezani i gdje pratimo situaciju iz dana u dan.

Oni koji već znaju kako sve ovo koristiti, nemojte biti hejteri, sve možete pokrenuti iz repozitorija. Također, imamo i puno kompleksnijih vizualizacija i projekcija, u istom repozitoriju.

Za bilo kakvu analizu podataka trebaju nam dvije stvari. Podaci i softver kojim ćemo te podatke obraditi.

U ovom slučaju podatke povlačimo direktno s GitHuba, sa Sveučilišta Johns Hopkins koji se od početka Corona krize istaknuo u prikupljanju podataka

Software koji ćemo iskoristi zove se Anaconda.

Korak 1 - Anaconda

Platformu Anaconda možete preuzeti ovdje. Za ovaj projekt koristi ćemo verziju “Python 3.7 version”.

Detaljnije upute za instalaciju na različitim operativnim sustavima možete pronaći ovdje:

Windows

macOS

Linux

Korak 2 - Okolina

Kada instalirate Anacondu na Windowsima dočekat će vas početna stranica.

To ćete napraviti u “Environments” tabu.

Pri svježoj instalaciji, imat ćete samo “base (root)” okolinu, te ju možemo pokrenuti i putem nje postaviti svoju okolinu i instalirati sve što nam je potrebno. Pokrenite ju klikom na i “Open terminal”.

Okolinu postavljamo sljedećim komandama.

(Unesite ih jednu po jednu, i sve potvrdite, kako bi instalirali sve potrebno). 

Kreacija okoline:

conda create -n covid-analysis python=3.7

Aktivacija okoline:

conda activate covid-analysis

Instaliranje Jupyterlaba – za rad i prezentaciju u web pregledniku:

conda install -c conda-forge jupyterlab

Za rad s podacima:

conda install numpy pandas

Za fancy grafove:

conda install plotly seaborn

Za modele:

conda install pymc3

Kada je to sve postavljeno, imamo svoju okolinu za rad.

Što nam još treba? A da, podaci.

Njih ćete preuzeti tako da u terminal upišete:

git clone https://github.com/CSSEGISandData/COVID-19.git

To je sada to, imamo i podatke, bacimo se na posao.

Napomena: Ako git ne radi kako treba, rješenje možete potražiti ovdje.

conda install -c anaconda git

Nakon toga probajte ponovo pokrenuti preuzimanje podataka.

Korak 3 -Jupyter Notebook

Slobodno zatvorite terminal i natrag ste na Environments tabu. Sada imate novu okolinu koja se zove “covid-analysis”. Kliknite na i “Open with Jupyter Notebook”. Otvorit će se jedan terminal (kojeg nema potrebe da dirate) i prozor u vašem pregledniku gdje ćete vidjeti datoteke u svom sustavu.

Ako ste pravilno slijedili upute, vidjet ćete mapu “COVID-19” u koju možete ući i u kojoj ćemo raditi. Tu se nalaze svi podaci koje smo preuzeli. Unutar te mape možemo si pod new -> Notebook: Python 3, otvoriti novi notebook u kojem ćemo sve analizirati i vizualizirati. Ja sam nazvao taj notebook “COVID-19 Tutorial Notebook”, i tako ćete ga vidjeti u screenshotovima.

Dočekat će vas prazan notebook, i sada kreće pravi posao.

Sjećate se onih stvari što smo instalirali? Sad ćemo i najaviti da ćemo to koristiti.

#import and alias

import pandas as pd
import numpy as np
import plotly.express as px
import plotly.graph_objects as go
import matplotlib.pyplot as plt
import seaborn as sns

Usput im dodjeljujemo kratice tako da kada koristimo ‘pandas’ ne moramo pisati cijelu riječ, nego su od sada nadalje ‘pandas’ i ‘pd’ sinonimi, i jupiyter notebook ih jednako vidi. Tako i za ostale. To su standardni akronimi koji svi koriste!

pandas, numpy, plotly.express, plotly.graph_objects, matplotlib.pyplot

Također ćemo postaviti neke početne točke za njih, poput nekih vrijednosti i formata. (tko ovo čita a bavi se ovime mi se sada smije, ali cilj je približiti sve onima koji nisu programeri, nego imaju volje i želje proučiti ovako nešto).

#set the seed – numpy
np.random.seed(1)

#style sheet – matplotlib.pyplot
plt.rcParams[‘figure.figsize’] = [12.0, 6.0]
plt.rcParams[‘figure.dpi’] = 80
plt.style.use(‘seaborn-darkgrid’)

#context (style) – seaborn
sns.set_context(“notebook”)

(kada se u liniji # – onda je to komentar, koji program zanemaruje, napisan je za programere)

Sljedeće, moramo reći programu gdje su podaci na kojima radimo. Te podatke možete sami pregledati da znate što je u njima, ali ovako izgleda učitavanje podataka.

(naziv seta podataka) = (panda).(pročitaj csv datoteku)(mjesto datoteke)

#COVID-19/archived_data/archived_time_series

confirmed_df = pd.read_csv(‘./csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_confirmed_global.csv’)

deaths_df = pd.read_csv(‘./csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_deaths_global.csv’)

recovered_df = pd.read_csv(‘./csse_covid_19_data/csse_covid_19_time_series/time_series_covid19_recovered_global.csv’)

Ovo nam daje 3 seta podataka, koji su isti kao tablice koje smo skinuli sa GitHuba.

Možete pokrenuti sve te dijelove koda klikom na ►∣ pored svakog segmenta, ili putem izbornika (Cell, run all).

Sada možemo pregledati što smo učitali. Možemo u novu ćeliju upisati “confirmed_df” i to će nam dati sve što se nalazi unutra.
Isto tako možemo i sa deaths_df, recovered_df.

Ok, imamo brdo podataka u tablicama koje ne vidimo u potpunosti. ALI IMAMO PODATKE!

Ovo je dobro mjesto za pauzu za kavu.

Sljedeće što bi nam bilo korisno je da podatke koji su sada u formi:

Province/State,Country/Region,Lat,Long,1/22/20,1/23/20,1/24/20,

Croatia,45.1,15.2,0,0,0 

Odnosno “Pokrajina” ako postoji, Zemlja, Geografska Širina, Geografska Dužina, broj slučajeva na 22.1.2020., broj slučajeva na 23.1.2020., broj slučajeva na 24.1.2020. itd.

Takve podatke mogli bi ipak preoblikovati, u nešto što ćemo lakše vizualizirati. Na primjer u:

Croatia, 45.1,15.2, 1/22/20, 0

Croatia, 45.1,15.2,13/29/20,713
Croatia, 45.1,15.2,3/30/20,790
Croatia, 45.1,15.2,3/31/20,867

 

Odnosno svaki datum staviti u poseban red u podacima.

To radimo funkcijama koje već postoje u pandas:

(novo ime podataka) = (koje podatke koristimo).(panda melt)((što ostavljamo, po čemu dijelimo, kako nazivamo produciranu varijablu)

Kako to napisati?

confirmed_data_df = confirmed_df.melt(id_vars=[‘Province/State’, ‘Country/Region’, ‘Lat’, ‘Long’], var_name=”Date”, value_name=”Confirmed”)

death_data_df = deaths_df.melt(id_vars=[‘Province/State’, ‘Country/Region’, ‘Lat’, ‘Long’], var_name=”Date”, value_name=”Deaths”)

recovered_data_df = recovered_df.melt(id_vars=[‘Province/State’, ‘Country/Region’, ‘Lat’, ‘Long’], var_name=”Date”, value_name=”Recovered”)

I sad imamo 3 nova seta podataka koja su lakša za pročitati.

Ok, sada imamo liste po datumu, još duže tablice koje ne vidimo! ALI IMAMO NEŠTO!

Sada, moramo provjeriti da li negdje imamo rupu u vrijednostima, da fale podaci, to bi nam zbilja pokvarilo dan.

confirmed_data_df[confirmed_data_df[“Confirmed”].isna()]

Ovo je praktički, da li što fali u podacima confirmed_data_df u stupcu “Confirmed”.

Isto tako i za druga dva seta podataka.

death_data_df[death_data_df[‘Deaths’].isna()]

recovered_data_df[recovered_data_df[‘Recovered’].isna()]

Kaže da ništa ne fali! ZAKON!

Radimo s 3 seta podataka sada, potvrđeni slučajevi (confirmed_data_df), smrtni slučajevi (death_data_df), ozdravljeni slučajevi (recovered_data_df). To bi mogli sve skupa spojiti, da radimo samo na jednom setu podataka.

all_data_df = pd.concat([confirmed_data_df, death_data_df[‘Deaths’] , recovered_data_df[‘Recovered’]], axis=1).reset_index().drop([‘index’], axis=1)

(ime novog skupa) = (panda natakni)(tablica na koju spajamo, što spajamo 1 (smrtni slučajevi), što spajamo 2 (oporavljeni slučajevi))

Ok da vidimo što smo dobili.

Ok, sada imamo ozbiljno veliku tablicu.

Hajdemo samo provjeriti da li negdje fali podataka? I to svaki stupac posebno.

all_data_df[all_data_df[“Province/State”].isna()]

all_data_df[all_data_df[“Country/Region”].isna()]

all_data_df[all_data_df[“Confirmed”].isna()]

all_data_df[all_data_df[“Deaths”].isna()]

all_data_df[all_data_df[“Recovered”].isna()]

FALI SVAŠTA!

Tu moramo ipak malo razmisliti, i pogledati što fali…

iskoristi ćemo prikaz prvih X unosa u tablici:

all_data_df[all_data_df[“Province/State”].isna()].head(50)

Fale nam provincije u zemljama koje se prate kao ukupne, ne po provincijama, to nam je OK.

I isto tako za opravljene slučajeve.

all_data_df[all_data_df[“Recovered”].isna()].head(50)

To su znači dani kada je ta vrijednost bila 0 i zato nije bilježena.

Ok, da nam se ne ponovi takvo pitanje, zamijenit ćemo nepostojeće vrijednosti u Deaths, Recovered i Confirmed s nulama. Za pokrajine nam to nije bitno jer znamo da se neke države prate po provincijama a neke kompletne. Listu takvih zemalja možemo tražiti sa:

all_data_df[all_data_df[“Province/State”].isna()][“Country/Region”].unique()

U tablici, gdje je Province/State prazan, izlistaj jedinstvene vrijednosti Country/Region.

Sada na zamjenu nepostojećih vrijednosti s nulama.

all_data_df[[“Deaths”, “Recovered”, “Confirmed”]] = all_data_df[[“Deaths”, “Recovered”, “Confirmed”]].apply(lambda row: row.fillna(0))

(na čemu radimo) = (u kojoj tablici)(u kojim stupcima)(primijeni)(ako je ćelija prazna, upiši nulu)

Još jedna stvar koju treba primijeniti je format datuma koji je američki malo težak za koristi, pa bi to mogli malo urediti.

all_data_df.loc[:, “Date”] = all_data_df[“Date”].apply(lambda s: pd.to_datetime(s).date())

I još bi mogli reći da će grafovi i sve ostalo ići do dana do kad imamo podatke.

latest_date = all_data_df[“Date”].max()

To već i sami možete primijeniti i izlistati rezultate. Ok to je to, podaci su sada čišći i možemo raditi s njima. 

Pogledajmo sada Hrvatsku

Novi set podataka zove se cro_data_df i sadrži sve podatke gdje je zemlja Hrvatska, sortirane po datumu.

cro_data_df = all_data_df[(all_data_df[“Country/Region”] == “Croatia”)].sort_values(‘Date’)

Ok to je korisno ALI možda bi bilo korisnije da gledamo samo datume kada imamo slučajeva.

cro_data_df_conf = all_data_df[(all_data_df[“Country/Region”] == “Croatia”)&(all_data_df[“Confirmed”] > 0)].sort_values(‘Date’)

Ok to sada ima smisla. Imamo podatke. Ajmo sada to nacrtati.

grid = sns.lineplot(data=cro_data_df_conf[(cro_data_df_conf[“Confirmed”] > 0)], x=”Date”, y=”Confirmed”)

grid = sns.lineplot(data=cro_data_df_conf[(cro_data_df_conf[“Confirmed”] > 0)], x=”Date”, y=”Deaths”)

grid = sns.lineplot(data=cro_data_df_conf[(cro_data_df_conf[“Confirmed”] > 0)], x=”Date”, y=”Recovered”)

Ok ne izgleda baš dobro, sabio je neke datume s istim vrijednostima…

I imamo grešku u podacima što se tiče opravljenih, jer 17.3.2020. nismo imali 4444 oporavljenih. Rezultat takve greške je tome što je sveučilište odlučilo promijeniti tip podataka pa su nastale neke greške. Ali opet, nemamo dovoljno oporavljenih da išta napravimo s tim podacima, pa ćemo ih trenutno zanemariti.

Ok, kako je to traženo, sve što smo u prošlom članku primijenili na Kinu i Europu, sada ćemo primijeniti na Hrvatsku. Kako sada idemo na kompliciranije stvari, ako vam treba još jedna kava sada je pravo vrijeme.

Regresija

Prije nego krenemo na same grafove, moramo si još neke stvari omogućiti. Za početak, trebali bi datume pretvoriti u dane u godini. Tako 15.1. postaje 15. dan u godini, dok 4.2. postaje 35. dan u godini.

import datetime

cro_data_df_conf[‘DateWeek’] = cro_data_df_conf[‘Date’].apply(lambda date_row: date_row.isocalendar()[1])

cro_data_df_conf[‘DayOfYear’] = cro_data_df_conf[‘Date’].apply(lambda date_row: date_row.timetuple().tm_yday)

Kako smo ušli u kompleksije prikaze, nećemo baš svaku liniju objašnjavati, ali ćete i moći sami pokrenuti prikaze.

Sljedeće što si moramo omogućiti su funkcije za logističke regresije za što kod možete preuzeti u repozitoriju ili na HTML datotekama pri kraju članka.

Sada možemo prikazati broj potvrđenih slučajeva u Hrvatskoj ovako:

ax = sns.barplot(data=cro_data_df_conf, x=”DayOfYear”, y=”Confirmed”, ci=”sd”, palette=”Oranges_d”)
ax.set_title(‘Croatia confirmed cases’)

I napraviti projekciju:

fit_data_df = cro_data_df_conf

x_data = fit_data_df[‘DayOfYear’].values
y_data = fit_data_df[‘Confirmed’].values

show_logistic_regression(x_data, y_data, title=’Croatia projection’)

Projekcija nam govori, da po tome kako je do sada raslo, približnom krivuljom, broj zaraženih bi se u idealnim uvjetima trebao zaustaviti malo iznad 1300. Ova funkcija je aproksimacija, ne predviđanje!

Broj novozaraženih

Zadnja stvar koja je ustvari i pobudila najviše interesa, bila je Gaussova projekcija broja novozaraženih, pa ćemo je i ucrtati za Hrvatsku. Ali kako su podaci ograničeni, rezultat možete smatrati samo prezentacijom tehnologije, ne realnom projekcijom.

Za tako nešto je malo problematično ovdje davati kodove, možete ih pogledati na orginalnom repozitoriju, kao i pri kraju članka gdje su poveznice na potpune notebooke.

Prvo što možemo pogledati je usporedba novozaraženih po danima.

Opet nam fale neke vrijednosti, gdje nije bilo razlike pa bi to mogli popuniti.

Sada sve to možemo ucrtati na graf.

show_gaussian_regression(x, y, params=np.array([100.0, 35.0, 1.0]))

Ili drugačije pokazano

Interval sigurnosti i procjena bez modela

Ok, zadnja stvar za danas, interval sigurnosti i procjena bez modela. U statistiku iza svega ovoga nećemo ulaziti, to zaslužuje poseban post, ali kako je bio dio originalnog članka dotaknuti ćemo se i toga.

UPOZORENJE! Podataka je stvarno malo i takva procjena je netočna!

Kao i sa gornjim grafovima, neću ovdje dodavati kodove jer su dugački i nezgrapni, ali znate gdje ih možete preuzeti.

Ili:

Svakodnevno osvježavanje podataka

Sve ovo skupa ne bi bilo uopće korisno da ne možete osvježiti podatke.

Za to napraviti, vratite se na Enviroment tab, te pokrenite terminal na okolini “covid-analysis” ( i “Open terminal”).

Morate ući u folder COVID-19:

cd COVID-19

I osvježiti podatke:

git pull

Nakon toga možete ponovo otvoriti Jupyter notebook i sve osvježiti kroz izbornik: Kernel -> Restart and Run All

Ostavljam vam još dvije stvari za kraj, HTML verzije notebooka, za neku budućnost ili detaljnije isprobavanje da lakše možete kopirati funkcije.

HTML – Sve otvoreno, i kontrolne funkcije.

HTML – Samo relevantne stvari.

Zaključak

Ovo je bio dugačak tutorial, i vama za napraviti ga, i nama za producirati.

Nadam se da vam je bilo zabavno i da ste nešto naučili. Ovaj primjer je sada aktualan jer smo svi doma u karanteni. I napravljen je na jako malo podataka za Hrvatsku. Kao i uvijek, više podataka znači veću točnost.