Kategoriaalsed andmed ja nende visualiseerimine

Eelmisel korral

Eelmine kord tegelesime arvuliste andmete kirjeldamise ja visualiseerimisega ning kasutasime andmestikku failis kysimustik_2024.RData.

load("data/kysimustik_2024.RData")

Arvuliste tunnuste (nt vanus, aasta, sõnasagedused jne) kirjeldamiseks kasutatakse põhiliselt

  • aritmeetilist keskmist mean(kysimustik$kaua_opid) koos standardhälbega sd(kysimustik$kaua_opid);
    • Mis on hulga vaatluste mingi keskmine näitaja ja kui erinevad üksikud vaatlused sellest keskmisest on?
  • mediaani median(kysimustik$kaua_opid).
    • Mis on hulga vaatluste tüüpiline näitaja?
  • Keskmist, standardhälvet ja mediaani erinevates gruppides saab arvutada näiteks käsuga tapply(): tapply(kysimustik$kaua_opid, kysimustik$lemmikjook, mean), tapply(kysimustik$kaua_opid, list(kysimustik$lemmikjook, lemmikloom), mean)

Arvuliste tunnuste visualiseerimiseks kasutatakse põhiliselt

  • karpdiagrammi, kui vaatleme ainult üht arvulist tunnust (või selle jaotumist mingites gruppides). Kujutab tunnuse kvartiiljaotust ja erindeid ehk erandlikult suuri/väikesi vaatlusi;
    • Mis on mediaanväärtus?
    • Kas tunnuse väärtused jaotuvad mediaanist ühtlaselt mõlemale poole?
    • Kas tunnuse väärtused on pigem homogeensed või heterogeensed?
    • Kas tunnuse väärtuste hulgas on mingeid vigu või lihtsalt erandlikke väärtusi, mis võivad statistilistes testides probleeme tekitama hakata?
  • histogrammi, kui vaatleme ainult üht arvulist tunnust; Kujutab tunnuse sageduste jaotumist intervallide ehk sagedusklasside kaupa;
    • Kas tunnuse väärtused jaotuvad ühtlaselt mingi keskväärtuse ümber?
    • Millis(t)es sagedusklassi(de)s on kõige enam vaatlusi?
    • Kas tunnuse jaotus on väiksemate või suuremate väärtuste suunas kaldu?
    • Kas tunnusel on mitu “harja” ehk mitu populaarset sagedusklassi?

Võrdle!

  • hajuvusdiagrammi plot(kysimustik$kaua_opid ~ kysimustik$synniaasta), (enamasti) kui vaatleme kahe arvulise tunnuse vahelist seost. Kujutab vaatluste paiknemist vastavalt nende kahe tunnuse väärtustele (üks tunnus y-teljel ja teine x-teljel).
    • Kuidas muutub ühe tunnuse väärtus teise tunnuse väärtuse muutudes?
    • Kas kahe arvulise tunnuse vahel on seos (nt mõlemad kasvavad samas suunas või kui üks kasvab, siis teine kahaneb)?

Tänased teemad

Kategoriaalsete andmete kirjeldamine ja visualiseerimine

  • sagedustabelid
  • paiknemise karakteristikud:
    • mood
    • mediaan (jälle!)
  • hajuvuse karakteristikud
    • variatsioonisuhe
    • hälve moodist
  • visualiseerimine
    • pirukas
    • tulpdiagramm

Kasutame edasi andmestikku kysimustik_2024.RData.

load("data/kysimustik_2024.RData")

Kuidas kirjeldada kategoriaalseid andmeid?

pilt
Levshina 2015: 18

Meeldetuletuseks: kvalitatiivsed/kategoriaalsed tunnused on (sisuliselt) mittearvulised tunnused, mis jagunevad nominaalskaala ja ordinaal- ehk järjestusskaala tunnusteks. Sisuliselt mittearvulised tähendab siinjuures seda, et ehkki ka järjestusskaalat võib esitada arvuliste väärtuste abil (nt hinnanguskaala 1st 5ni), ei ole need enamasti käsitletavad päris arvuliste tunnustena. Näiteks ei arvutata sageli hinnanguskaalade keskmist, sest kuidas peaks täpselt tõlgendama keskmist 3.6, kui 3 tähistab skaalal “Nii ja naa” ja 4 “Pigem nõustun”?
Samas on hinnangute arvuline käsitlemine võimalik näiteks juhul, kui vastajal lastakse vabalt määrata mingi sobiv väärtus skaalal, millel ainult algus- ja lõpp-punkti väärtused on määratletud. Küll aga peab ka sel juhul tulemuste tõlgendamisel alati arvestama sellega, kui laialt skaala on määratud (nt hakkab mängima rolli see, kas skaala on 1st 5ni või 1st 20ni).

Kategoriaalseid andmeid saab kirjeldada eelkõige sagedustabelite ja moodi abil, järjestusskaala tunnuste puhul saab teatavate mööndustega kasutada ka mediaani.

Vaatame korraks veel küsimustiku tunnuseid.

summary(kysimustik) # ülevaade/kokkuvõte andmestiku tunnustest

# Nimetame lemmiklooma tasemed 
# lühema esituse huvides ümber
levels(kysimustik$lemmikloom) <- c("Glcs", "Klkrjk", "Kr", "EiM")

Sagedustabelid

Sagedustabelites võime esitada kategoriaalsete/nominaaltunnuste väärtuste esinemise sagedusi. Sealjuures võivad tabelites olla nii absoluut- kui ka suhtelised sagedused.

Absoluutsagedused

Sagedustabeli saab teha funktsiooniga table(). Kui kasutada funktsiooni table() argumendina ainult üht tunnust, siis saame ühemõõtmelise sagedustabeli, milles esitatakse selle tunnuse tasemete esinemise sagedused.

table(kysimustik$lemmikjook) # tee sagedustabel ja trüki see konsooli
## 
## Kohv  Tee 
##   61   43
t.jook <- table(kysimustik$lemmikjook) # suuna tabel objekti t.jook
t.jook # trüki tabel konsooli
## 
## Kohv  Tee 
##   61   43
class(t.jook) # mis tüüpi andmestruktuur?
mode(t.jook) # mis tüüpi andmed?
str(t.jook) # sisuliselt nagu arvuvektor, millel on rea- ja/või tulbanimed

Kui kasutame funktsioonis kaht argumenti, saame kahemõõtmelise sagedustabeli ehk risttabeli ehk jaotustabeli. See esitab kahe tunnuse ühisjaotuse.

table(kysimustik$lemmikjook, kysimustik$lemmikloom) # tee risttabel ja trüki see konsooli
##       
##        Glcs Klkrjk Kr EiM
##   Kohv   11     20 29   1
##   Tee     8     13 22   0
# suuna tabel objekti t.jook.loom JA trüki tabel konsooli
(t.jook.loom <- table(kysimustik$lemmikjook, kysimustik$lemmikloom)) 
##       
##        Glcs Klkrjk Kr EiM
##   Kohv   11     20 29   1
##   Tee     8     13 22   0
str(t.jook.loom) # sisuliselt maatriks, millel on 2 rida ja 4 tulpa + rea- ja tulbanimed
dim(t.jook.loom)
is.matrix(t.jook.loom)

Võime muidugi vaadata ka enama kui kahe tunnuse ühisjaotust.

table(kysimustik$lemmikjook,
      kysimustik$lemmikloom,
      kysimustik$kogemused_kvant)
## , ,  = Ei
## 
##       
##        Glcs Klkrjk Kr EiM
##   Kohv    5      7 11   0
##   Tee     2      5  4   0
## 
## , ,  = Jah
## 
##       
##        Glcs Klkrjk Kr EiM
##   Kohv    6     13 18   1
##   Tee     6      8 18   0
# või
ftable(kysimustik$lemmikjook,
       kysimustik$lemmikloom,
       kysimustik$kogemused_kvant)
##              Ei Jah
##                    
## Kohv Glcs     5   6
##      Klkrjk   7  13
##      Kr      11  18
##      EiM      0   1
## Tee  Glcs     2   6
##      Klkrjk   5   8
##      Kr       4  18
##      EiM      0   0

table() on R-i baaspaketi (base) funktsioon, ftable() on paketi stats funktsioon. Vt ka teisi sama paketi funktsioone, nt aggregate(), mis töötab sarnaselt käsule tapply():

# Leia sünniaasta mediaan vastavalt lemmikjoogile
tapply(kysimustik$synniaasta, kysimustik$lemmikjook, median)
aggregate(kysimustik$synniaasta, list(kysimustik$lemmikjook), median)

# ... ja lemmikloomale
tapply(kysimustik$synniaasta, list(kysimustik$lemmikjook, kysimustik$lemmikloom), median)
aggregate(kysimustik$synniaasta, list(kysimustik$lemmikjook, kysimustik$lemmikloom), median)

Ka sagedustabeleid saab indekseerida, nagu vektoreid ja andmetabeleid (data.frame): kantsulgudes enne koma tulevad ridade indeksid (või nimed) ja pärast koma tulpade indeksid (või nimed). Mida näitavad meile järgmised kolm käsku?

t.jook.loom[1,]
t.jook.loom[,c("Kr", "Glcs")]
t.jook.loom["Kohv",c("Kr", "Glcs")]

Tabeli tulbanimede muutmiseks saame asendada käsus colnames() saadud vektori sama pika vektoriga, milles on uued tulbanimed.

colnames(t.jook.loom)
## [1] "Glcs"   "Klkrjk" "Kr"     "EiM"
colnames(t.jook.loom) <- c("Glaucus", "Kirjak", "Koer", "Ei meeldi")
t.jook.loom
##       
##        Glaucus Kirjak Koer Ei meeldi
##   Kohv      11     20   29         1
##   Tee        8     13   22         0

Tabeli reanimede muutmiseks saame asendada käsus rownames() saadud vektori.

rownames(t.jook.loom)
## [1] "Kohv" "Tee"
rownames(t.jook.loom) <- c("kohv", "tee")
t.jook.loom
##       
##        Glaucus Kirjak Koer Ei meeldi
##   kohv      11     20   29         1
##   tee        8     13   22         0

Suhtelised sagedused

Sagedustabeli põhjal võime leida ka suhtelised sagedused ehk osakaalud ehk proportsioonid, mida saab 100-ga läbi korrutades teisendada protsentideks. Suhtelisi sagedusi on vaja näiteks selleks, et võrrelda eri suuruses valimeid.

# Leia tee või kohvi valinute osakaalud kõikidest vastustest
t.jook/sum(t.jook)
## 
##      Kohv       Tee 
## 0.5865385 0.4134615

Sama tulemuse saame, kasutades tabeli objektil funktsiooni prop.table() või proportions(). Mõlemal juhul tuleb sisendiks anda table() objekt (mitte lihtsalt tunnuste nimed).

prop.table(t.jook)
# ehk
prop.table(table(kysimustik$lemmikjook))
# või proportions()
proportions(t.jook)
# ehk
proportions(table(kysimustik$lemmikjook))

# Salvestame proportsioonidega tabeli
# eraldi objekti t.jook.prop
t.jook.prop <- prop.table(t.jook)

# Teisendame proportsioonid protsentideks
t.jook.prop*100
round(t.jook.prop*100, 2) # ümardame tulemused 2 komakohani

Vaatame ka 2 kategoriaalse tunnuse risttabeli suhtelisi sagedusi ja kasutame argumenti margin, et kuvada neid ridade (margin = 1) või tulpade (margin = 2) lõikes.

prop.table(t.jook.loom) # kõikide lahtrite summa = 1

# Milline on loomade valik kohvijoojate seas?
# Milline teejoojate seas?
prop.table(t.jook.loom, 
           margin = 1) # ridade summa = 1

# Milline on joogi valik molluskiarmastajate seas?
# Milline kaelkirjakuarmastajate seas?
# Milline koeraarmastajate seas?
# Milline nende seas, kellele ei meeldi loomad?
prop.table(t.jook.loom, 
           margin = 2) # tulpade summa = 1

Marginaalsagedused

Nii absoluutsete kui ka suhteliste sagedustega tabelitele saab lisada marginaalsagedused (margins) ehk ridade ja tulpade summeeritud sagedused funktsiooniga addmargins().

addmargins(t.jook.loom)
addmargins(prop.table(t.jook.loom))

# argumenti "margin =" ei pea tingimata välja kirjutama
addmargins(prop.table(t.jook.loom, 1), 2)  
addmargins(prop.table(t.jook.loom, 2), 1)

Tabelite salvestamine

Sagedustabeleid saab kirjutada faili, nagu ka andmetabeleid ehk data frame’e. Selleks võib kasutada käsku write.table(). Vaikimisi salvestatakse tabel nii, et tekstile lisatakse ümber jutumärgid ning tulpasid eraldavad tühikud (vaata vaikeväärtusi käsuga ?write.table). Neid vaikeväärtusi saab aga muuta.

write.table(x = t.jook.loom, # tabelobjekt
            file = "joogid_loomad.tsv", # salvestatava faili nimi koos laiendiga
            quote = FALSE, # tekstitunnused ilma ümbritsevate jutumärkideta
            sep = "\t") # tulpi eraldab tabulaator

Missuguse faili saad? Kas kõik on tabelis nii, nagu peaks?

Kindlam on salvestamisel teisendada sagedus- v risttabelid enne siiski niisiis data.frame’i klassi.

# data.frame() muudab sagedustabeli andmetabeliks
data.frame(t.jook.loom) # nn pikk andmetabel

write.table(x = data.frame(t.jook.loom), # andmetabeli objekt
            file = "joogid_loomad.tsv", # faili nimi koos laiendiga
            quote = FALSE, # tekstitunnused ilma ümbritsevate jutumärkideta
            sep = "\t", # tulpi eraldab tabulaator
            row.names = FALSE) # reanimesid (1, 2, 3 jne) ei lisata
# unclass() säilitab tabeli struktuuri, aga muudab selle maatriksiks
# data.frame() muudab maatriksi andmetabeliks
(t.jook.loom.df <- data.frame(unclass(t.jook.loom)))

class(t.jook.loom)
class(t.jook.loom.df)

# lisame andmetabelisse tulba "jook" jooginimedega, mis praegu on lihtsalt tabelobjekti reanimed
t.jook.loom.df$jook <- rownames(t.jook.loom)

# järjestame tulbad ümber (5. tulp esimeseks ja siis tulbad 1-4)
t.jook.loom.df <- t.jook.loom.df[c(5,1:4)]

write.table(x = t.jook.loom.df, # andmetabeli objekt
            file = "joogid_loomad.tsv", # faili nimi koos laiendiga
            quote = F, # tekstitunnused ilma ümbritsevate jutumärkideta
            sep = "\t", # tulpi eraldab tabulaator
            row.names = F) # reanimesid ("Kohv", "Tee") ei lisata

Vahel võib olla tarvilik salvestada tabel pildifailina (näiteks selleks, et lisada see otse mingisse tekstidokumenti).

# install.packages("gridExtra")
library(gridExtra) # laadi pakett
grid.table(t.jook.loom) # joonista tabel

Tabeli salvestamiseks võib kasutada RStudio graafilist liidest (Plots -> Export -> Save as Image) või koodi.

# loo png-fail, mille laius on 7 sentimeetrit, kõrgus 3 sentimeetrit ja resolutsioon 300 ppi (vt ?png)
png(filename = "jookloom.png", width = 7, height = 3, units = "cm", res = 300) 
grid.table(t.jook.loom) # joonista tabel faili
dev.off() # sulge fail

NB! grid.table() tahab sisendiks maatriksit või andmetabelit, st kahemõõtmelist objekti. Kui tahta salvestada pildina n-ö ühemõõtmelist sagedustabelit, mis on tehtud ainult ühe tunnuse põhjal, tuleb see teisendada esmalt päris maatriksiks või data frame’iks, nagu eelnevalt näitasime.

Kui tahta tulpasid ümber nimetada, on lihtsam salvestada esmalt maatriksiks või andmetabeliks muudetud tabel eraldi objekti.

mat <- as.matrix(table(kysimustik$lemmikloom)) # ühemõõtmeline sagedustabel maatriksina
colnames(mat) <- "Vastajaid" # määrame maatriksi tulbanimeks "Vastajaid", loomad on maatriksi reanimed (rownames)
grid.table(mat)

df <- as.data.frame(table(kysimustik$lemmikloom)) # ühemõõtmeline sagedustabel andmetabelina
colnames(df) <- c("Loom", "Vastajaid") # määrame andmetabeli tulbanimedeks "Loom" ja "Vastajaid", loomad on niisiis eraldi tabeli tulbas
grid.table(df)

Mood

Nii arvuliste kui ka kategoriaalsete tunnuste puhul võib leida moodi ehk kõige populaarsema väärtuse/klassi.

Kõige populaarsema väärtuse sageduse saab leida funktsiooniga max(), kõige ebapopulaarsema väärtuse sageduse funktsiooniga min().

(t.loom <- table(kysimustik$lemmikloom))
## 
##   Glcs Klkrjk     Kr    EiM 
##     19     33     51      1
max(t.loom)
## [1] 51
min(t.loom)
## [1] 1

Kõige populaarsema väärtuse enda ehk moodi indeksi saame leida funktsiooniga which.max() ning kõige ebapopulaarsema väärtuse indeksi funktsiooniga which.min().

which.max(t.loom) # moodi indeks: tabeli 3. element on kõige sagedasem
## Kr 
##  3
which.min(t.loom) # tabeli 4. element on kõige harvem
## EiM 
##   4
names(t.loom[which.max(t.loom)]) # mood
## [1] "Kr"
names(t.loom[which.min(t.loom)]) # lihtsalt kõige harvem esinev väärtus
## [1] "EiM"

which.max() annab meile niisiis tabeli kõige sagedasema elemendi indeksi ehk järjekorranumbri. Selle abil saame kõige sagedasema elemendi enda tabelist nurksulgude abil välja võtta ning lõpuks küsida names() funktsiooni abil ainult moodi ehk elementi ennast (st tabeli tulbanime) ilma sageduseta.

Mediaan järjestustunnuste kirjeldamiseks

Järjestustunnuste kirjeldamiseks saab kasutada kõiki neid samu meetodeid, mida ka nominaaltunnuste puhul.

summary(kysimustik)

(t.labi <- table(kysimustik$kursuse_labimine)) # ühemõõtmeline sagedustabel
(t.labi.kokk <- table(kysimustik$kursuse_labimine, # kahemõõtmeline sagedustabel (risttabel)
                     kysimustik$soogitegemisoskus, 
                     deparse.level = 2)) # lisa tunnuste nimed

prop.table(t.labi)
addmargins(prop.table(t.labi.kokk, margin = 2)*100, 1)

max(t.labi.kokk) # suurim sagedus tabelis
min(t.labi) # vähim sagedus tabelis

which.max(t.labi.kokk) # suurima sagedusega elemendi (moodi) indeks
# kuna kahemõõtmeline sagedustabel on olemuselt maatriks,
# hakatakse elemente lugema tulpade kaupa, st 1. tulba elemendid, siis 2. tulba elemendid jne.

which.min(t.labi)

Lisaks võime järjestustunnuste puhul leida ka mediaani ehk kõige keskmise väärtuse, kui järjestada kõik vaatlused tunnuse alusel väiksemast suuremani.

sort(kysimustik$kursuse_labimine)
##   [1] 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 4 4 4
##  [38] 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5
##  [75] 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
## Levels: 1 < 2 < 3 < 4 < 5
median(kysimustik$kursuse_labimine)

Mis juhtus?

class(kysimustik$kursuse_labimine)

Kuna tegemist on (järjestatud) faktoriga, ei suuda R ise selle mediaani kohe leida ja ütleb, et mediaani leidmiseks on vaja arvulisi andmeid.

median(as.numeric(kysimustik$kursuse_labimine))
## [1] 4

Mäletatavasti oli mediaan paaritu arvu vaatluste korral variatsioonirea keskmine. Kui meil on aga paarisarv vaatlusi, on mediaan kahe keskmise vaatluse aritmeetiline keskmine (siin (4+4)/2 = 4). Kui meil oleks nüüd paarisarv vaatlusi, mille mediaan jääks täpselt 3 ja 4 vahele, siis kuidas tõlgendada mediaani 3.5, kui 3 tähistab vastust “Võin läbi saada, aga võin ka põruda” ja 4 tähistab vastust “Tõenäoliselt saan läbi”?

Aga aritmeetiline keskmine ise?

mean(as.numeric(kysimustik$kursuse_labimine))
## [1] 4.076923

Kuidas seda tulemust tõlgendada?

Statistikud ei pea järjestustunnuste aritmeetilise keskmise arvutamist reeglina mõistlikuks, ent on ka teistsuguseid arvamusi, vt nt https://measuringu.com/mean-ordinal/.

Kategoriaalsete tunnuste hajuvus

Arvuliste tunnuste hajuvust ehk seda, kui palju väärtused üldiselt mingist keskmisest väärtusest erinevad, kirjeldavad suurused nagu dispersioon ja standardhälve.

Ka kategoriaalsete tunnuste hajuvust on võimalik erinevate suuruste abil kirjeldada. Vt nt


Käsitleme siin kaht hajuvusnäitajat:

  • variatsioonisuhe (variation ratio)
  • hälve moodist (deviation from the mode)

Variatsioonisuhe

Variatsioonisuhte leidmiseks lahutatakse 1st moodi sageduse ja kõikide vaatluste hulga jagatis. Variatsioonisuhe näitab, kui suure osa andmetest jätab kõige sagedasem väärtus kirjeldamata. Põhimõtteliselt lahutatakse 1st moodi suhteline sagedus.

fm <- max(t.loom) # kõige populaarsema vastuse sagedus
N <- sum(t.loom) # kõikide vaatluste arv
fm/N # populaarseima vastuse osakaal kõikidest vastustest

# variatsioonisuhe ehk
(v <- 1-fm/N) # ülejäänud vastuste osakaal kõikidest vastustest

Mida lähemal v on nullile, seda homogeensem on andmestik (kõige sagedasem väärtus kirjeldab üksi suurema osa andmetest ära). Mida lähemal v on ühele, seda heterogeensem ja hajuvam on andmestik (palju erinevaid kategooriaid).

Siin näitab variatsioonisuhte väärtus, et kõige populaarsem kategooria (koer) kirjeldab ära umbes poole kõikidest andmetest, aga ka muid loomi on piisavalt palju vastatud selleks, et need oleksid andmete kirjeldamisel olulised.

Variatsioonisuhe ei peegelda aga seda, kui palju neid teisi vastusevariante on, nt kas need 51% vastustest lähevad jagamisele kahe, kolme, nelja, kümne või kasvõi saja vastusevariandi vahel.

Praegusel juhul saabki maksimaalne variatsioonisuhe olla 0.75, sest kui jagada 104 vaatlust võrdselt 4 kategooriasse (= maksimaalne andmete hajuvus), on meil 4 moodi (igaühe sagedus 26) ja 1-(26/104) = 0.75. Kohe, kui mõnda kategooriasse mõne teise arvelt vaatlusi juurde lisada (nt 26, 26, 27, 25), muutub see moodiks ja variatsioonisuhe väheneb: 1-(27/104) = 0.74.

Kui meil oleks ainult 2 kategooriat (nt koera vastuseid 52 ja kaelkirjaku vastuseid 52), siis saaks maksimaalne variatsioonisuhe olla 1-(52/104) = 0.5. Kui meil oleks 13 kategooriat ja igas kategoorias võrdselt vastuseid (8), saaks maksimaalne variatsioonisuhe olla aga tervelt 1-(8/104) = 0.92.

Variatsioonisuhte tõlgendamisel ja võrdlemisel tuleks seega arvesse võtta ka seda, mitmesse klassi vaatlused üldse on jagatud.

Hälve moodist

Selle näitaja puhul on tegu nominaaltunnuste analoogiga dispersioonile ehk hajuvusele. Siinjuures kasutatakse ära ka variatsioonisuhet. Sisuliselt näitab hälve moodist kõikide klasside/kategooriate moodist hälbimiste summat, mis on korrigeeritud vaatluste ja klasside koguarvu suhtes nii, et statistiku väärtus jääb 0 ja 1 vahele.

# klasside arv
K <- nlevels(kysimustik$lemmikloom)
# tavalise vektori (st mitte tasemetega faktori) puhul saaks K kätte nii:
K <- length(unique(kysimustik$lemmikloom)) # erinevate väärtuste arv
# või ka lihtsalt
K <- length(names(t.loom)) # sagedustabeli tulbanimede arv

v <- 1-max(t.loom)/sum(t.loom) # variatsioonisuhe, mille enne juba tegelikult arvutasime

# hälve moodist
(DM <- K/(K-1)*v)

Mida suurem on DM, seda rohkem on andmetes varieerumist ja seda ühtlasema sagedusega kategooriad esinevad. Mida väiksem on DM, seda vähem on varieerumist ja seda suurema osa andmetest kirjeldab ära mood. Kui kõikides kategooriates on ühepalju vaatlusi, on DM 1. Kui kõik vaatlused on ühes kategoorias, on DM 0.


Sealjuures “karistab” mõõdik vähese valikuvõimaluse eest (vähemate klassidega on väiksem väärtus).

R-i paketis qualvar on sama asja leidmiseks funktsioon DM(), mille sisendiks peab olema sagedustabel.

# install.packages("qualvar")
library(qualvar)
DM(t.loom)
## [1] 0.6794872

Kategoriaalsete tunnuste visualiseerimine


Kategoriaalsete andmete visualiseerimiseks kasutatakse enamasti sektordiagramme (nn pirukaid) ja tulpdiagramme. Tegeleme selles aines põhiliselt tulpdiagrammidega, sest

  • sektordiagramme on keeruline tõlgendada, väiksemad erinevused ei tule selgelt esile;
  • sektordiagramme on kerge väärkasutada;
  • kui lisada protsentide sildid loetavuse parandamiseks, kaotab sektordiagramm ise kogu oma mõtte;
  • sektordiagrammid on kasulikud ainult siis, kui võrrelda maksimaalselt 3 gruppi, mille sageduserinevused on suured.

https://www.businessinsider.com/pie-charts-are-the-worst-2013-6

Võrdle:


Kas A ajahetkel on 3. kandidaadi toetus suurem kui 5. oma?
Kas võrreldes A-ga kasvas B ajahetkel rohkem 2. või 4. kandidaadi toetus?
Kes viimase küsitluse järgi võidab?


Sektordiagrammi funktsioon R-is on pie().

pie(table(kysimustik$kursuse_labimine))

Tulpdiagramm

Tulpdiagramm (bar chart) kuvab tulpades kategoriaalse tunnuse tasemete sagedused. R-is on tulpdiagrammi funktsiooniks baasgraafika paketis barplot().

barplot(kysimustik$oppekava)

Mis juhtus?

Funktsioon barplot() eeldab, et tal on võtta kohe kuskilt ka kategooriate sagedusandmed, mille põhjal joonistamisel tulpade kõrgusi määrata. Seepärast peame enne kategooriate esinemissagedused kokku lugema.

barplot(table(kysimustik$kogemused_kvant))

Kui tahame tulpdiagrammi joonistada nn “pikast” data.frame tüüpi tabelist, kus kategooriate nimed on ühes tulbas (tekstiline tunnus) ja nende sagedused teises tulbas (arvuline tunnus), tuleb barplot funktsioonile anda sisendiks sagedustega tulp ning kategooriate nimetusi täpsustada argumendiga names.arg.

(df_kogemused_kvant <- data.frame(table(kysimustik$kogemused_kvant)))
##   Var1 Freq
## 1   Ei   34
## 2  Jah   70
barplot(df_kogemused_kvant$Freq, names.arg = df_kogemused_kvant$Var1)

Tulpdiagramme võib teha ka kahe (kategoriaalse) tunnuse alusel. Vaatame näiteks, kas osaleja hinnang oma kursuse läbimise tõenäosusele võiks olla kuidagi seotud sellega, kas tal on eelnevalt kvantitatiivsete meetoditega kogemusi või mitte.

Visualiseerime kategooriaid üksteise kõrval,
näitame tulpasid horisontaalselt,
lisame kategooriaid eristavad värvid,
telgede pealkirjad
ja legendi.
Pöörame ka y-telje sildid õigetpidi.

barplot(table(kysimustik$kogemused_kvant, # risttabel
              kysimustik$kursuse_labimine), 
        beside = TRUE, # kategooriad kõrvuti
        horiz = TRUE, # tulbad horisontaalselt
        col = c("grey35", "orange"), # eristavad värvid
        ylab = "Kursuse läbimise tõenäosus", # y-telje pealkiri
        xlab = "Vastanute arv", # x-telje pealkiri
        legend = TRUE, # legend
        args.legend = list(x = "bottomright", # legendi asetus
                           ncol = 2, # legendi tulpade arv
                           title = "Kogemused kvantmeetoditega"), # legendi pealkiri
        las = 1) # pööra y-telje silte

Vaatleme nüüd absoluutsageduste asemel proportsioone: kui suurel osal mingi hinnangu valinutest on eelnevaid kogemusi kvantitatiivsete meetoditega ja kui suurel osal mitte?

t <- prop.table(
  table(
    kysimustik$kogemused_kvant,
    kysimustik$kursuse_labimine), 
  margin = 2)
# sama, mis t <- prop.table(table(kysimustik$kogemused_kvant, kysimustik$kursuse_labimine), margin = 2)


barplot(t, 
        horiz = TRUE, 
        col = c("grey35", "orange"), 
        ylab = "Kursuse läbimise tõenäosus",
        xlab = "Vastanute proportsioonid",
        main = "Hinnang kursuse läbimise tõenäosusele\nvastavalt kogemusele kvantitatiivsete meetoditega",
        legend = TRUE, 
        args.legend = list(x = "bottomright", 
                           ncol = 2, 
                           title = "Kogemused kvantmeetoditega"),
        las = 1)

Jooniste salvestamine käib samamoodi nagu eelnevalt tabelobjektide joonisena salvestamisega: kas Plots -> Export -> Save as Image või

png(filename = "joonis1.png", width = 15, height = 12, units = "cm", res = 300)
barplot(t, 
        horiz = TRUE, 
        col = c("grey35", "orange"), 
        ylab = "Kursuse läbimise tõenäosus",
        xlab = "Vastanute proportsioonid",
        main = "Hinnang kursuse läbimise tõenäosusele\nvastavalt kogemusele kvantitatiivsete meetoditega",
        legend = TRUE, 
        args.legend = list(x = "bottomright", 
                           ncol = 2, 
                           title = "Kogemused kvantmeetoditega"),
        las = 1)
dev.off()

Harjutused

  1. Võrdle lemmiklooma hälvet moodist lemmikjoogi hälbega moodist. Mida järeldad?
  2. Tee sagedustabel küsimustikule vastanute programmeerimisoskuse kohta ja salvesta see eraldi objekti (nt nimega t.prog). Tulemuste mugavamaks kuvamiseks nimeta tunnuse tasemed lühemalt ümber (nt “Oskan hästi”, “Oskan vähe”, “Ei oska” ja “Oskan natuke”).
  3. Salvesta loodud tabel txt-failina nii, et tulpasid eraldavad tühikud. Kas vajad jutumärke (quote = TRUE)? Kas vajad ridade numbreid (row.names = TRUE)?
  4. Tee küsimustiku lemmiklooma tunnusest allolev joonis. Kui hätta jääd, uuri käsuga ?barplot abifailist, mida mingid funktsiooni argumendid teevad. R-i n-ö sisse-ehitatud värvipaleti värvinimesid näed käsuga colors() ja värve koos värvinimedega käsuga scales::show_col(colors(), cex_label = 0.5) (cex_label argumendi väärtust muutes saad värvinimede silte suuremaks ja väiksemaks teha).

  1. Salvesta joonis.

Järgmisel korral

Graafikapakett ggplot2.

Funktsioonide sõnastik

  • addmargins() - lisab sagedus- või risttabelile marginaal- ehk äärsagedused (= ridade ja tulpade summeeritud sagedused)
  • as.numeric() - teeb tekstilistest või loogilistest väärtustest arvulised väärtused
  • barplot() - joonistab tulpdiagrammi
  • colnames() - küsib sagedustabeli, risttabeli või andmetabeli tulbanimesid
  • ftable() - teeb sagedustabeli (ühest tunnusest) või risttabeli (kahest või enamast tunnusest)
  • gridExtra::grid.table() - võimaldab salvestada sagedustabeli pildifailina (paketist gridExtra)
  • names() - küsib mis tahes R-i objekti elementide nimesid
  • nlevels() - küsib faktori erinevate unikaalsete väärtuste arvu
  • pie() - joonistab sektordiagrammi ehk piruka
  • proportions() - teeb suhteliste sagedustega sagedustabeli (ühest tunnusest) või risttabeli (kahest või enamast tunnusest)
  • prop.table() - teeb suhteliste sagedustega sagedustabeli (ühest tunnusest) või risttabeli (kahest või enamast tunnusest)
  • round() - ümardab vektori või sagedustabeli arvud
  • rownames() - küsib sagedustabeli, risttabeli või andmetabeli reanimesid
  • sort() - sorteerib vektori, sagedustabeli või risttabeli väärtused kasvavas järjekorras
  • sum() - liidab kokku funktsiooni sisendiks olevad arvulised väärtused
  • table() - teeb sagedustabeli (ühest tunnusest) või risttabeli (kahest või enamast tunnusest)
  • unclass() - muudab R-i objekti andmestruktuuri (nt data.frame’i maatriksiks)
  • which.max() - küsib arvuvektori, sagedustabeli või risttabeli suurima väärtuse indeksit ehk järjekorranumbrit
  • which.min() - küsib arvuvektori, sagedustabeli või risttabeli vähima väärtuse indeksit ehk järjekorranumbrit
  • write.table() - salvestab andmetabeli faili