nezahabjan / APPR-2017-18

Repozitorij z gradivi za predmet Analiza podatkov s programom R v študijskem letu 2017/18
MIT License
0 stars 1 forks source link

pridobitev tabele s spletne strani #1

Open nezahabjan opened 6 years ago

nezahabjan commented 6 years ago

Pozdravljeni,

pri pridobivanju podatkov s spletnih strani za projekt pri APPR, sem naletela na težavo pri eni od tabel. Ker je uvožena v CSV obliki zelo neuporabna, ste mi na vajah nekaj že pomagali z JSON obliko. Ker pa ni bilo dovolj časa, sva se dogovorila, da vam pošljem še link: http://apps.who.int/gho/data/node.main.A893?lang=en Prosila bi vas, če mi lahko pomagate.

Najlepša hvala, lep pozdrav, Neža Habjan

jaanos commented 6 years ago

Takole nekako bi šel uvoz:

library(rjson)
library(tidyr)

link <- "http://apps.who.int/gho/athena/data/GHO/NCD_PAC,NCD_PAA?profile=xtab&format=html&x-topaxis=GHO;SEX&x-sideaxis=COUNTRY;YEAR;AGEGROUP&x-title=table&filter=AGEGROUP:YEARS18-PLUS;COUNTRY:*;SEX:*;"
json <- html_session(link) %>% read_html() %>% html_nodes(xpath="//script[not(@src)]") %>%
  .[[1]] %>% html_text() %>% strapplyc("(\\{.*\\})") %>% unlist() %>% fromJSON() %>% .$Crosstable
matrika <- json$Matrix %>% sapply(. %>% sapply(. %>% .[[1]] %>% .$disp)) %>% t()
glava <- . %>% .$header %>% lapply(. %>% .[-1] %>% unlist() %>% { json$code[.+1] } %>%
                                     sapply(. %>% .$disp))
stolpci <- json$Vertical$layer %>% unlist() %>% { json$dimension[.+1] } %>% sapply(. %>% .$disp)
colnames(matrika) <- glava(json$Horizontal) %>% sapply(paste, collapse = ",")
data <- glava(json$Vertical) %>% lapply(. %>% as.list() %>% setNames(stolpci)) %>%
  bind_rows() %>% cbind(matrika) %>% melt(id.vars = 1:3) %>%
  rename(Age.Group = `Age Group`) %>%
  mutate(Country = factor(Country), Year = parse_number(Year),
         Age.Group = factor(Age.Group),
         value = parse_character(value, na = "No data"),
         variable = parse_character(variable)) %>% drop_na(value) %>%
  mutate(Indicator = variable %>% strapplyc("^([^,]+)") %>% unlist() %>% factor(),
         Sex = variable %>% strapplyc("([^,]+)$") %>% unlist() %>% factor(),
         Value = value %>% strapplyc("^([0-9.]+)") %>% unlist(),
         Lower = value %>% strapplyc("\\[([0-9.]+)") %>% unlist(),
         Upper = value %>% strapplyc("([0-9.]+)\\]") %>% unlist()) %>%
  select(-variable, -value) %>% melt(measure.vars = c("Value", "Lower", "Upper"),
                                     variable.name = "Statistic",
                                     value.name = "Value") %>%
  mutate(Value = parse_number(Value))

Za uvoz bo potrebna uporaba funkcij iz knjižnic rjson in tidyr. Svetujem, da njun uvoz opraviš kar v lib/libraries.r - pred začetkom dela potem vedno poženi ta program, da se ti naložijo vse potrebne knjižnice. Naslov, s katerega se poberejo podatki, dobiš iz značke <iframe> na tvoji povezavi - gre za spletno stran znotraj okvirja. Sami podatki v obliki JSON se pojavijo v bloku JavaScripta (značka script) in jih je treba od tam izluščiti (od prvega zavitega oklepaja do zadnjega zavitega zaklepaja).

Funkcija fromJSON iz knjižnice rjson pretvori podatke v obliki JSON v gnezdene R-jeve sezname. Sami podatki so podani v polju Matrix kot matrika (seznam seznamov) - celice vsebujejo še določene metapodatke, nas pa zanima polje disp. Polji Horizontal in Vertical določata, katerim dimenzijam ustrezajo stolpci oziroma vrstice - vsebujeta polji layer s kodami dimenzij in header s kodami njihovih vrednosti. Sama imena dimenzij in njihovih vrednosti so podana v poljih dimension in code.

Podatki iz matrike se preberejo z dvema uporabama funkcije sapply. Dobljeno matriko je potem potrebno transponirati (t()). Za branje vrednosti dimenzij se potem pripravi funkcija glava (notacija . %>% f(...) je ekvivalentna function(x) { f(x, ...) }); na podoben način se preberejo tudi imena stolpcev, ki ustrezajo dimenzijam za vrstice (torej država, leto, starostna skupina). Funkcija glava se potem uporabi za določitev imen stolpcev matrike (te sedaj vsebujejo indikator in spol ločena z vejico, kar bo potrebno kasneje ločiti) ter za pripravo stolpcev s prvimi tremi dimenzijami - tem pripnemo našo matriko, da združimo vse podatke v eno razpredelnico.

Sedaj bo potrebno podatke spraviti v obliko tidy data - to naredi funkcija melt iz knjižnice reshape2, ki ji povemo, naj prve tri stolpce uporabi za dimenzije, poleg teh pa bo dodala še stolpca variable in value z imeni ostalih stolpcev in ustreznimi vrednostmi. Nato se stolpec Age Group preimenuje tako, da nima presledka (odsvetujem tudi uporabo šumnikov in ostalih posebnih znakov v imenih stolpcev), ostalim stolpcem pa se nastavijo ustrezni tipi. Stolpec z vrednostmi vsebuje tri podatke (vrednost ter krajišči intervala zaupanja), tako da ga bomo zaenkrat pustili kot znakovni vektor, vrednosti No data pa nadomestili z NA, da lahko v naslednjem koraku ustrezne vrstice izpustimo s funkcijo drop_na iz knjižnice tidyr.

Sedaj vsebuje stolpec variable dve vrednosti, stolpec value pa tri, tako da s sledečim mutate te vrednosti ločimo v nove stolpce, nato pa s select izpustimo stolpca variable in value. Taki podatki še vedno niso v obliki tidy data, tako da ponovno uporabimo melt - tokrat mu povemo, naj stolpce Value, Lower in Upper uporabi za meritve, stolpcu z njihovimi imeni da ime Statistic, stolpcu z vrednostmi pa Value. Nazadnje slednji stolpec pretvorimo še v števila.

Še to: poskrbi, da bo zaganjanje programa uvoz.r (po predhodnem uvozu knjižnic z libraries.r) v celoti izvedlo uvoz brez napak. Ukaza View ne uporabljaj v programu, saj bo povzročil, da se bodo razpredelnice odpirale med prevajanjem poročila. Svetujem tudi, da ne uporabljaš funkcij read.csv (in ostalih read.* s piko), pač pa za branje datotek CSV uporabljaš izključno funkcije iz knjižnice readr (s podčrtajem namesto pike). Del programa, ki je ostal iz uvoza, pobriši (oziroma vsaj ne kliči teh funkcij, če jih že želiš imeti kot vzorec).

jaanos commented 6 years ago

Očitno se je oblika podatkov JSON spet spremenila - tokrat bo treba popraviti le definicije spremenljivk matrika, glava in stolpci na prejšnje stanje:

matrika <- json$Matrix %>% sapply(. %>% sapply(. %>% .[[1]] %>% .$disp)) %>% t()
glava <- . %>% .$header %>% lapply(. %>% .[-1] %>% unlist() %>% { json$code[.+1] } %>%
                                     sapply(. %>% .$disp))
stolpci <- json$Vertical$layer %>% unlist() %>% { json$dimension[.+1] } %>% sapply(. %>% .$disp)

Nisem sicer prepričan, ali morda na različnih sistemih branje iz JSON deluje različno - če ti trenutna verzija že deluje, potem je najbrž že tako, in bi bilo potrebno zaznati, kateri način branja je pravi.

nezahabjan commented 6 years ago

Najlepša hvala za opozorilo. Ko poženem celoten program za uvoz te tabele mi sicer tabelo izpiše, a kot napako vrne napako v številu dimenzije. Pri zagonu Vaše, popravljene kode, vrne tabelo brez napak, a ne tako urejeno kot je bila pred tem. Zanima me, ali se to dogaja zaradi spreminjanja same spletne strani iz katere je tabela pobrana, ali jaz naredim kaj narobe, čeprav kode za uvoz tabele v zadnjem času nisem več spreminjala.

Še enkrat se Vam zahvaljujem in Vas lepo pozdravljam, Neža Habjan

Dne 16. januar 2018 11:14 je Janoš Vidali notifications@github.com napisal/-a:

Očitno se je oblika podatkov JSON spet spremenila - tokrat bo treba popraviti le definicije spremenljivk matrika, glava in stolpci na prejšnje stanje:

matrika <- json$Matrix %>% sapply(. %>% sapply(. %>% .[[1]] %>% .$disp)) %>% t()glava <- . %>% .$header %>% lapply(. %>% .[-1] %>% unlist() %>% { json$code[.+1] } %>% sapply(. %>% .$disp))stolpci <- json$Vertical$layer %>% unlist() %>% { json$dimension[.+1] } %>% sapply(. %>% .$disp)

Nisem sicer prepričan, ali morda na različnih sistemih branje iz JSON deluje različno - če ti trenutna verzija že deluje, potem je najbrž že tako, in bi bilo potrebno zaznati, kateri način branja je pravi.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/nezahabjan/APPR-2017-18/issues/1#issuecomment-357914179, or mute the thread https://github.com/notifications/unsubscribe-auth/AbCN56BDq59i81zXCI4d_RLW6do_9P8eks5tLHZpgaJpZM4RIAuK .

jaanos commented 6 years ago

Očitno so v zadnjem času (vsaj) dvakrat spremenili organizacijo podatkov v obliki JSON. Vmes so namreč odstranili spremenljivko Indicator, pri čemer se je spremenila struktura; zdaj je struktura taka kot prvotna, a spremenljivke Indicator ni več (kolikor se spomnim, je bila vrednost povsod enaka, tako da ni prišlo do izgube podatkov).

Skratka, nič ne delaš narobe - upajmo pa, da do novih sprememb ne bo prihajalo.

nezahabjan commented 6 years ago

V redu, najlepša hvala za vse napotke.

lp, Neža

Dne 16. januar 2018 21:39 je Janoš Vidali notifications@github.com napisal/-a:

Očitno so v zadnjem času (vsaj) dvakrat spremenili organizacijo podatkov v obliki JSON. Vmes so namreč odstranili spremenljivko Indicator, pri čemer se je spremenila struktura; zdaj je struktura taka kot prvotna, a spremenljivke Indicator ni več (kolikor se spomnim, je bila vrednost povsod enaka, tako da ni prišlo do izgube podatkov).

Skratka, nič ne delaš narobe - upajmo pa, da do novih sprememb ne bo prihajalo.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/nezahabjan/APPR-2017-18/issues/1#issuecomment-358097596, or mute the thread https://github.com/notifications/unsubscribe-auth/AbCN5zVzYq4PymfB2p_BAIZy3SfjbpjYks5tLQkFgaJpZM4RIAuK .