jonagricar / APPR-2017-18

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

tabela 1&2 #2

Closed jonagricar closed 6 years ago

jonagricar commented 6 years ago

rada bi naredila ločeni tabeli za moške in ženske, zaenkrat imam za vsako od njiju dve tabeli. Npr.: za moške bi rada naredila tako, da je prvi stolpec sezona, drugi polno ime(2.tabela), narodnost(2.tabela), točke, starost ob zmagi. Zaenkrat sem samo iz obeh glavnih tabel ločila na manjše (smucarji1, smucarke1, ...). Zanima pa me tudi, kako bi pri obeh tabelah začela sezono z 1966/1967, oziroma kako pri 1.tabeli začeti z vrstico z imenom 1, ki je sedaj spodaj. Hvala za odgovor!

jaanos commented 6 years ago

Najbolje bo, da imaš te podatke v eni sami tabeli, saj imaš za oba spola iste podatke - dodati bo treba torej še stolpec za spol.

Trenutno uvoziš obe tabeli s funkcijama uvozi.smucarje1 in uvozi.smucarje2 - ti funkciji bo treba tudi nekje klicati, da se dejansko izvedeta. V funkcijah imaš še zanko for, kjer se opravi pretvorba znakovnih stolpcev v UTF-8 - v tej zanki se sklicuješ na spremenljivko tabela, ki pa je nimaš definirane, tako da bo treba popraviti na ustrezno spremenljivko (če pretvorbo sploh potrebuješ - tj., če ti takoj po uvozu vseh znakov ne pokaže pravilno).

Ko imaš uvoženi obe tabeli, ju torej ločiš po spolih, nato pa združiš po sezoni s funkcijo inner_join iz knjižnice dplyr - v ta namen preimenuješ stolpce razpredelnic tako, da bo samo sezona imela v obeh isto ime (sicer lahko uporabiš tudi parameter by, s katerim poveš, po katerih stolpcih želiš združevati). Dobljenima razpredelnicama lahko potem dodaš stolpec s spolom (funkcija mutate iz knjižnice dplyr) in nato združiš po vrsticah (rbind). Nazadnje se še izberejo stolpci v želenem vrstnem redu (select) in uredijo vrstice po danem kriteriju (arrange).

tabela1 <- uvozi.smucarje1()
tabela2 <- uvozi.smucarje2()
smucarji1 <- tabela1[ , c(1:4)]
smucarke1 <- tabela1[ , c(1, 5:7)]
smucarji2 <- tabela2[ , c(1:3)]
smucarke2 <- tabela2[ , c(1, 4:5)]
colnames(smucarke1) <- colnames(smucarji1) <- c("sezona", "priimek", "tocke", "starost")
colnames(smucarke2) <- colnames(smucarji2) <- c("sezona", "zmagovalec", "narodnost")
spoli <- c("M", "Z")
smucarji <- inner_join(smucarji1, smucarji2) %>% mutate(spol = factor("M", levels = spoli))
smucarke <- inner_join(smucarke1, smucarke2) %>% mutate(spol = factor("Z", levels = spoli))
zmagovalci <- rbind(smucarji, smucarke) %>%
  select(sezona, spol, zmagovalec, narodnost, starost) %>% arrange(sezona, spol)

Pri imenih stolpcev se izogibaj rabi šumnikov in presledkov (pa tudi drugih posebnih znakov), saj se je potem nanje lažje sklicevati.

Še to: če želiš izpustiti prvo vrstico razpredelnice, lahko narediš npr.

tabela1 <- tabela1[-1, ]

Tako ni potrebno vnaprej vedeti, koliko vrstic imaš. Svetujem še, da na tej točki še ne prevajaš imen držav, saj bodo na zemljevidu najverjetneje podana v angleščini in bo tako mogoče združevanje (morda bo sicer treba katero ime spremeniti, da se bo vse ujemalo). Za potrebe prikaza si lahko pripraviš vektor s prevodi držav, npr.

drzave.slo <- c(
  "Austria" = "Avstrija",
  "Switzerland" = "Švica",
  "France" = "Francija",
  ...
)

Potem lahko narediš razpredelnico s prevodi držav:

zmagovalci.slo <- zmagovalci %>% mutate(narodnost = drzave.slo[narodnost])

Ker je stolpec narodnost že obstajal v razpredelnici zmagovalci, ga bo funkcija mutate prepisala.

Opozoril bi še, da v funkciji uvozi.smucarje2 izbereš napačen stolpec za narodnost pri moških, zaradi česar so te vrednosti vse NA. Poleg tega so pri večkratnih zmagovalcih navedene še zaporedne številke zmag - teh ne potrebuješ, saj lahko ta podatek izpelješ iz razpredelnice. Sezone bo treba še pretvoriti v številke, da bo mogoče ustrezno risati grafe skozi čas. Oboje lahko popraviš na združeni razpredelnici:

zmagovalci <- zmagovalci %>% mutate(sezona = sezona %>% parse_number() + 1,
                                    zmagovalec = zmagovalec %>% strapplyc("^([^(]+)") %>%
                                      unlist() %>% trimws())

Sezona se torej pretvori v število - pri tem se ignorira vse od prvega neštevilskega znaka naprej, zato je rezultat pretvorbe prva letnica, ki ji prištejemo 1, da dobimo letnico konca sezone. Pri zmagovalcih poberemo vse od začetka do morebitnega oklepaja - ker bo to pustilo presledek, ko je bila navedena številka zmage, se ta poreže s funkcijo trimws.

Naj opozorim, da se v vsaj enem primeru zgodi, da nastopa smučarka pod dvema različnima imenoma - to bi bilo potrebno poenotiti, da bo mogoče ustrezno grupiranje. Take spremembe se potem lahko omenijo v besedilu poročila.

Še to: opažam, da pri razpredelnicah za discipline popravljaš podatke tako, da imajo nekatere vrstice po dva podatka. Namesto tega raje podvoji vrstico - torej da imaš za neko disciplino po dve vrstici, če imaš več rekorderjev. Na koncu programa uvoz.r kličeš še funkciji iz vzorca, ki ju nimaš več - to pobriši, tako da se ti ob poganjanju celotnega programa (ob predhodnem uvozu knjižnic iz libraries.r) brez napak uvozijo in uredijo želeni podatki.

jonagricar commented 6 years ago

Sem uredila ta veliko tabelo in vse deluje, hvala. Zanima pa me še glede tabele discipline, če se da vrstico podvojiti s kakšnim ukazom?

jaanos commented 6 years ago

Načeloma bi lahko vrstice z več podatki izpustila in na roko dodala nove vrstice (npr. z data.frame narediš novo razpredelnico z ustreznimi podatki in jo pridružiš z rbind). Lahko pa podvojene vrstice generiraš iz ustreznih vrstic - v tvojem primeru jih prepoznaš tako, da je v stolpcu smucar zaporedje male in velike črke, države so pa ločene z nedeljivim presledkom. Potem bi lahko naredila nekaj takega:

dvojni <- grep("[[:lower:]][[:upper:]]", discipline$smucar)
discipline <- apply(discipline[dvojni, ], 1, . %>% as.list() %>%
                      { data.frame(disciplina = .$disciplina, spol = .$spol,
                                   smucar = .$smucar %>%
                                     strapplyc("(.*[[:lower:]])([[:upper:]].*)") %>% unlist(),
                                   narodnost = .$narodnost %>%
                                     strapplyc("([[:alnum:] ]+)[^[:alnum:] ]+([[:alnum:] ]+)") %>%
                                     unlist(), naslovi = .$naslovi,
                                   stringsAsFactors = FALSE) }) %>%
  bind_rows() %>% rbind(discipline[-dvojni, ]) %>% arrange(spol, disciplina)

Za vsako vrstico z dvema smučarjema torej narediš novo razpredelnico z ustrezno disciplino, spolom in številom naslovov ter ločenima podatkoma o imenu in narodnosti. Dobiš seznam razpredelnic, ki ga z bind_rows združiš v eno, nato pa še z rbind pridružiš preostale vrstice. Nazadnje arrange še uredi vrstice (discipline so sedaj urejene po abecedi - če bi hotela drugačno ureditev, bi jih morala pretvoriti v urejen faktor).

Glede prevajanja imen držav velja enako kot prej - zaenkrat naj bodo v angleščini, prevedeno razpredelnico pa dobiš na podoben način kot prej.

jaanos commented 6 years ago

Poskusi s tem:

library(devtools)
install_github("jaanos/rvest", ref = "table-span-filling")
jonagricar commented 6 years ago

Imam še zadnje vprašanje glede tabel in sicer za prizorišča. Kako bi zraven vključila še stolpec, ki ima slikice zastav, tako da bi mi namesto tega izpisalo imena držav, kot sta to naredili že dve sošolki? Zaenkrat imam tabelo urejeno brez držav, a bi želela, da je tudi to zraven, ker paše primerno h kraju.

jaanos commented 6 years ago

Če pogledaš v HTML, vidiš, da imajo zastave imena oblike drz_2.gif, kjer je drz tričrkovna koda države (z malimi črkami). Ker imaš v vsaki vrstici natanko eno zastavo, to nekoliko poenostavi zadevo, tako da lahko uvoz narediš nekako tako:

uvozi.prizorisce <- function() {
  link <- "http://www.ski-db.com/db/loc/main.php"
  stran <- html_session(link) %>% read_html()
  html_tabela <- stran %>% html_nodes(xpath="//table[@class='primary']") %>% .[[1]]
  prizorisca <- html_tabela %>% html_table(dec = ",", fill = TRUE) %>% .[-1, ]
  prizorisca[[3]] <- html_tabela %>% html_nodes(xpath=".//img") %>% html_attr("src") %>%
    strapplyc("([a-z]+)_2\\.gif$") %>% unlist()
  for (i in 1:ncol(prizorisca)) {
    if (is.character(prizorisca[[i]])) {
      Encoding(prizorisca[[i]]) <- "UTF-8"
    }
  }
  prizorisca <- prizorisca[, 1:5]
  colnames(prizorisca) <- c("prizorisce", "kratica", "drzava", "moski", "zenske")
  prizorisca <- prizorisca %>% mutate(moski = parse_number(moski),
                                      zenske = parse_number(zenske)) %>%
    filter(!is.na(moski) | !is.na(zenske))
  return(prizorisca)
}

Takoj pri branju tabele se izpusti prva vrstica, da bomo lahko dodali kode držav (kar v tretji stolpec, kjer so bile zastave). Nato se izpustijo odvečni stolpci ter opravi pretvorba stolpcev moski in zenske v števila - prazne vrednosti sedaj postanejo NA, kar nam omogoči, da odstranimo vrstice, kjer sta obe vrednosti NA (tj., ohranimo samo tiste vrstice z vsaj eno znano vrednostjo). Nastavljanje imen vrstic tako ni potrebno.

Da bi bili podatki res v obliki tidy data, bi moral podatek o spolu biti v svojem stolpcu. Ker bi se s tem podatki ponavljali, bi bilo treba razpredelnico razbiti - ena naj vsebuje samo ime prizorišča, kratico in državo (torej iz trenutne razpredelnice odstranišš stolpca moski in zenske), druga pa npr. kratico, spol in število tekem (torej brez imena in države, potem pa pretvoriš z melt). Če bi želela kratice držav nadomestiti z imeni, lahko uporabiš podoben pristop kot pri prevajanju.

Mimogrede, za pretvorbo v števila bo potrebno poskrbeti tudi pri stolpcih tocke in starost v razpredelnici zmagovalci (lahko kar v istem mutate kot to narediš za stolpec sezona) ter za stolpec naslovi v razpredelnici discipline (zadostovala bo pretvorba pri ustvarjanju data.frame za podovjene vrstice). V funkciji uvozi.narode na koncu namesto tabela vrni razpredelnico narodi (kar poženi celoten uvoz.r, da vidiš, če ti deluje).

jonagricar commented 6 years ago

Sem popravila v tipe številk in dodala slovar kratic. Razbila sem prizorisca na dve tabeli in dodala spol, vendar ne vem kako to sedaj združiti, ker ne razumem kako deluje funkcija melt oz kako jo uporabiti?

jaanos commented 6 years ago

Tako kot je, je v redu - razpredelnico prizorisca2 bi se sicer dalo hitreje dobiti s funkcijo melt:

prizorisca2 <- prizorisca %>% select(kratica, moski, zenske) %>%
  melt(variable.name = "spol", value.name = "tekme", na.rm = TRUE)

Funkcija melt deluje tako, da nekatere stolpce ohrani, ostale pa nadomesti z dvema stolpcema: stolpec z imenom, podanim s parametrom variable.name, vsebuje imena nadomeščenih stolpcev, stolpec z imenom, podanim s parametrom value.name, pa vsebuje vrednosti v teh stolpcih. Število vrstic se pri tem seveda pomnoži s številom nadomeščenih stolpcev. Privzeto se nadomestijo stolpci s številskimi vrednostmi (kar se je tukaj zgodilo) - sicer pa lahko s parametrom measure.vars podaš vektor imen stolpcev, ki se nadomestijo, oziroma z id.vars podaš vektor imen stolpcev, ki se ohranijo. Parameter na.rm = TRUE pomeni, naj odstranijo se vrstice z vrednostjo NA v stolpcu z vrednostjo.

jonagricar commented 6 years ago

Super, hvala za pomoč.