Statistik och dataanalys I, 15 hp

Datorlaboration 2

Authors

Mona Sfaxi

Matias Quiroz

Mattias Villani (redigering)

Publicerad

July 3, 2024

Varning

Den här labben förutsätter att följande paket finns installerade:

  • openxlsx

  • mosaic

Paket kan installeras via kommandot install.packages('packagename'), där 'packagename' är namnet på paketet, t.ex 'mosaic'.

Introduktion

I den här datorlabben kommer vi att titta på hur fördelningar för olika typer av variabler kan beskrivas numeriskt och grafiskt.

💪 Uppgift 0.1

Skapa en mapp Lab2 i din kursmapp SDA1 (från Lab 1). Ladda ner Quarto-filen för denna lab genom att högerklicka här och välj ‘Spara länk’ eller något likande från menyn som dyker upp. Spara filen i din nya Lab2 mapp. Öppna Quarto-filen i RStudio. Du kan nu fortsätta med denna laboration direkt i Quarto-dokumentet, där du också fyller i svaren på dina laborationsövningar. Du kan alltså lämna den här webbsidan nu och fortsätta arbetet i RStudio.

Väl inne i RStudio med öppnat Quarto-dokument i ‘Editor’ kan ni gå över till ‘Source mode’ genom att klicka på ‘Source’ i det vänstra hörnet av din ‘Editor’. Source mode är detaljerat och bra att skriva kod i eftersom man har full kontroll på dokumentet, men det är svårt att få en översikt av dokumentet. Prova nu att gå över till ‘Visual mode’ genom att klicka på ‘Visual’ i det vänstra hörnet av din ‘Editor’. Vi rekommenderar att ni mestadels arbetar i Visual mode, men att gå över till Source mode när man verkligen få till någon detalj som är svår att ändra i Visual mode. ´

💪 Uppgift 0.2

Klicka på knappen Render i Editor-fönstret för att kompilera filen till en webbsida (html). Webbsidan kommer antingen att visas i Viewer-fönstret i RStudio eller i webbläsaren på din dator. Om din webbsida visas i webbläsaren rekommenderar vi att du ändrar inställningarna i RStudio så webbsidan visas i Viewer-fönstret. Du ställer in detta på menyn Tools/Global Options… och sen väljer du Viewer Pane vid Show output preview in:

💪 Uppgift 0.3

Quarto säkerställer att man befinner sig i korrekt arbetsmapp när koden i dokumentet exekveras. Med korrekt arbetsmapp menas den mappen ni sparade .qmd filen i. Vill du komma åt dataseten via load() kommandot måste dataseten vara sparade i samma mapp.

Ett vanligt arbetssätt är att man jobbar i RStudio i en separat .R fil, där man kan testa att köra kod innan den kopieras över till Quarto dokumentet. Den .R filen kommer inte att ha samma ‘working directory’ som Quarto filen. Du måste då använda setwd() funktionen i .R filen för att ställa in ‘working directory’. Notera att man också välja att skriva kod i Console som finns längst ner i RStudio. Där måste du också ställa in rätt ‘working directory’. Det är inte rekommenderat att använda Console eftersom koden inte sparas där. Du kanske kommer på något jättesmart som du glömmer att kopiera över till Quarto dokumentet och kan senare inte hitta det du skrev.

RStudios Editor ändras beroende på vilken sorts fil du har öppen

Notera att ikonerna i Editor är annorlunda när du har ett Quarto-dokument öppet jämfört med tidigare när vi hade en fil med ren R-kod (dvs en .R fil) öppen.

Skapa en ny .R som du döper till Lab2_test_code.R och sparar i din Lab 2 mapp. Ställ in ‘working directory’ till den nya mappen genom att följa anvisningarna från Lab 1.

💪 Uppgift 0.4

Många intressanta dataset finns tillgängliga på webben. Kursboken har gjort ca 500 av dataseten tillgängliga här. Ni kommer att jobba med titanic datasetet som finns i Chapter 3. Ladda ner den zip-filen samt packa upp/extrahera filen genom att klicka på den och välj ‘Extrahera’ eller något liknande. Du kan extrahera filerna på datorns Skrivbord eller annan mapp. Om du går in i den extraherade mappen Ch3 så finns där filen Chapter_3.xlsx. Kopiera den filen till din Lab2 mapp. Vi kommer snart att läsa in datasetet.

1. Skapa tabeller för kategoriska variabler

En kategorisk variabel är en variabel vars utfall är kategorier. En kategorisk variabel kan antingen vara på nominalskala eller ordinalskala. Den vanligaste typen är nominalskala, vilket innebär att utfallen saknar en naturlig rangordning. Ett exempel är kön, där man inte kan rangordna utfallen på ett meningsfullt sätt. För en kategorisk variabel på ordinalskala så gäller det att utfallen har en naturlig rangordning. Ett exempel är betyg, där till exempel betyg A är bättre än betyg C. Än så länge behöver vi inte oroa oss för om en kategorisk variabel är på ordinalskala eller nominalskala. Vi använder en tabell för att representera dess fördelning i bägge fallen.

Först ska vi installera och ladda paketen openxlsx för att läsa in data från Excelfil och mosaic för dataanalys.

#install.packages("openxlsx") # Kommentera bort denna rad om du redan har openxlsx installerat från Lab 1
#install.packages("mosaic") # Kommentera bort denna rad efter att du kört Quarto-filen första gången
library(openxlsx)
library(mosaic)
Snyggare utskrifter genom att undvika paket-meddelanden

Många paket är ‘pratiga’ och skriver ut en massa meddelanden och ibland varningar när man laddar in dem med library men oftast orsakar det inga problem. Om paketen inte fungerar som det ska kan det dock vara värt att titta igenom meddelanden som skrivits ut vid aktivering av paketen.

Vi kan nu läsa in datamaterialet som finns i fliken Titanic i den Excelfil Chapter_3.xls ni laddade ner ovan:

titanic = read.xlsx("https://github.com/StatisticsSU/SDA1/raw/main/datorlab/lab2/Chapter_3.xlsx", sheet = "Titanic")
Funktionen read.xlsx() är smart

Om du tittar på koden ovan ser du att det ser lite annorlunda ut än i Lab 1:

  • Funktionen read.xlsx() kan läsa in filer inte bara från din dator utan direkt från internet. Istället för att ange en sökväg till Excel-filen på din dator (om den inte ligger i working directory) kan du bara ange en webbadress där data finns. Vi har laddat upp data till adressen ovan.

  • Funktionen read.xlsx() har ett argument sheet som talar om vilken av alla flikar som ska läsas in. I Lab 1 satte vi sheet = 1 för att läsas in den första fliken. Men man kan också skriva namnet på fliken, dvs sheet = "Titanic". Notera att eftersom Titanic är ett namn så måste vi skriva citationtecken “” kring för att tala om för R att det är bokstäver (en sträng som vi lärde oss om i Lab 1).

💪 Uppgift 1.1

Ändra koden ovan så read.xlsx() istället läser in filen ‘Chapter_3.xlsx’ från din dator.

Vi kan ta titt på de första observationerna genom att använda funktionen head(). Vi kan också lista de första observationerna för varje variabel i datasetet genom att använda funktionen str():

head(titanic)
                           Name Survived     Boarded Class   MWC Age
1            ABBING, Mr Anthony     Dead Southampton     3   Man  42
2        ABBOTT, Mr Ernest Owen     Dead Southampton  Crew   Man  21
3      ABBOTT, Mr Eugene Joseph     Dead Southampton     3 Child  14
4    ABBOTT, Mr Rossmore Edward     Dead Southampton     3   Man  16
5 ABBOTT, Mrs Rhoda Mary 'Rosa'    Alive Southampton     3 Woman  39
6    ABELSETH, Miss Karen Marie    Alive Southampton     3 Woman  16
  Adut_or_Chld    Sex  Paid Ticket_No Boat_or_Body                   Job
1        Adult   Male  7.55      5547         <NA>            Blacksmith
2        Adult   Male    NA      <NA>         <NA> Lounge Pantry Steward
3        Child   Male 20.25    CA2673         <NA>               Scholar
4        Adult   Male 20.25    CA2673        [190]              Jeweller
5        Adult Female 20.25    CA2673            A                  <NA>
6        Adult Female  7.65    348125           16                  <NA>
           Class_Dept Class_Full
1 3rd Class Passenger          3
2    Victualling Crew          V
3 3rd Class Passenger          3
4 3rd Class Passenger          3
5 3rd Class Passenger          3
6 3rd Class Passenger          3
str(titanic)
'data.frame':   2208 obs. of  14 variables:
 $ Name        : chr  "ABBING, Mr Anthony" "ABBOTT, Mr Ernest Owen" "ABBOTT, Mr Eugene Joseph" "ABBOTT, Mr Rossmore Edward" ...
 $ Survived    : chr  "Dead" "Dead" "Dead" "Dead" ...
 $ Boarded     : chr  "Southampton" "Southampton" "Southampton" "Southampton" ...
 $ Class       : chr  "3" "Crew" "3" "3" ...
 $ MWC         : chr  "Man" "Man" "Child" "Man" ...
 $ Age         : num  42 21 14 16 39 16 25 30 28 20 ...
 $ Adut_or_Chld: chr  "Adult" "Adult" "Child" "Adult" ...
 $ Sex         : chr  "Male" "Male" "Male" "Male" ...
 $ Paid        : num  7.55 NA 20.25 20.25 20.25 ...
 $ Ticket_No   : chr  "5547" NA "CA2673" "CA2673" ...
 $ Boat_or_Body: chr  NA NA NA "[190]" ...
 $ Job         : chr  "Blacksmith" "Lounge Pantry Steward" "Scholar" "Jeweller" ...
 $ Class_Dept  : chr  "3rd Class Passenger" "Victualling Crew" "3rd Class Passenger" "3rd Class Passenger" ...
 $ Class_Full  : chr  "3" "V" "3" "3" ...

Verkar variablerna vara definierade som de ska?

Låt oss undersöka variabeln Survived i datasetet. Detta är en kategorisk variabel med två kategorier Dead och Alive. När en variabel bara har två kategorier brukar man också säga binär variabel. Man kan räkna antalet observationer som tillfaller varje kategori och på så sätt skapa en frekvenstabell med funktionen tally() i mosaic-paketet enligt nedan.

tally(~ Survived, data = titanic)
Survived
Alive  Dead 
  712  1496 

Tilde-tecknet ~ används i mosaic-paketet och är en del av formula-syntax dialekten i R som omnämndes i Lab 1. I det här fallet talar tecknet ~ om för R att variabeln Survived ska hämtas från datamaterialet titanic. Annars skulle vi ju vara tvungna att skriva titanic$Survived (kom ihåg från Lab 1 att $-tecknet säger åt R att ‘plocka ut variabeln Survived från datamaterialet titanic’). Så blir man t ex tvungen att skriva i dialekten base-R (klicka i marginalen om du är intresserad). Fördelen med mosaic’s formula-syntax kommer bli ännu tydligare när vi har många fler variabler att jobba med.

Lägg märke till att frekvenstabellen inte är sparad. Detta är bara ett kommando som ofta också duger gott och väl. Men ibland vill man också spara en tabell under sin session. Det kan göras genom att skapa ett passande variabelnamn och tilldela den nya variabeln värdet vi fick ovan (namnet på variabeln kan man välja som man vill):

tab_survived <- tally(~ Survived, data = titanic)
Observera

Tabellen är nu sparad (i R’s arbetsminne, men inte på datorns hårddisk) och syns också i Environment fliken längst upp till höger. Men vill man skriva ut resultatet i sitt dokument måste man också skriva ut den nya tabellens namn i sin code-chunk likt nedan

tab_survived
Survived
Alive  Dead 
  712  1496 

men det är vanligare att skriva allt i samma code-chunk:

tab_survived <- tally(~ Survived, data = titanic)
tab_survived
Survived
Alive  Dead 
  712  1496 

Ibland kan det vara svårt att titta på antalet inom varje kategori och jämföra siffrorna sinsemellan. Att titta på relativa frekvenser istället gör ofta jämförelserna mycket enklare att uppfatta. Genom att lägga till argumentet format = proportion i tally() räknas de relativa frekvenserna istället.

tally(~ Survived, data = titanic, format = "proportion")
Survived
    Alive      Dead 
0.3224638 0.6775362 

Vill man ha detta presenterat i procent kan man enkelt skriva format = percent istället för proportion

tally(~ Survived, data = titanic, format = "percent")
Survived
   Alive     Dead 
32.24638 67.75362 

Alltså överlevde endast 32.2% av de som befann sig på Titanic, medan 67.8% dog.

Observera

tab_survived är inte en vanlig numerisk variabel. Man kan använder sig av funktionen class() för att ta reda på vilken typ av objekt den är sparad som:

class(tab_survived)
[1] "table"

💪 Uppgift 1.1

Variabeln Class talar om biljettklass passageraren reste med (1:a, 2:a, 3:e eller Crew (besättning)). Presentera det totala antalet inom varje biljettklass. Vilken kategori är störst?

# Write your code here

💪 Uppgift 1.2

Beräkna den relativa frekvensen (i procent) inom varje biljettklass.

# Write your code here

2. Grafisk illustration av kategoriska variabler

För att presentera kategoriska variabler grafiskt används oftast pajdiagram (pie charts) eller stapeldiagram (bar charts). Oftast räcker det med att använda sig av ett av dessa diagram i sin presentation. I R kan man använda sig av funktionerna pie()och bargraph() för respektive diagram. Det går då smidigt att använda sig av en sparad tabell som argument i funktionen.

table_rel_freq = tally(~ Survived, data = titanic, format = "proportion")
pie(x = table_rel_freq)

Ovan ser vi att vi först har sparat de relativa frekvenserna bland de som överlevde och de som dog i en tabell table_rel_freq. Detta är inte nödvändigt för att skapa ett pajdiagram. Men eftersom siffrorna redan finns i tabellen så kan man lika gärna använda sig av dem. Ett annat alternativ hade varit att skapa en vektor och manuellt skriva in värden för de olika kategorierna exempelvis likt: relative_frequencies = c(0.32, 0.68)

Grafen ovan är dock inte så informativ. Det finns generellt många argument man kan använda sig av i R för att göra sina grafer så informativa som möjligt. Koden nedan är ett exempel på hur man kan gå tillväga

rel_frequencies = round(table_rel_freq, 2) # round the numbers to two decimals
rel_frequencies
Survived
Alive  Dead 
 0.32  0.68 
category_names = names(table_rel_freq)
category_names
[1] "Alive" "Dead" 
colors = c("lightblue", "purple")
pie(x =  table_rel_freq, labels = rel_frequencies, col = colors)
legend("topright", legend = category_names, fill = colors)

Funktionen round() används för att avrunda till önskat antal decimaler, i detta fall två så att grafen blir mer lättläslig.

Funktionen names() som användes i Datorlaboration 1 för att få ut kolumnnamn från dataframes kan även här används för att få ut kolumnnamn från tabeller. Återigen är denna funktion inte nödvändig för att bilda ett pajdiagram, men den kan utnyttjas för att ge passande etiketter för olika kategorier.

Observera

Ett alternativ är att skriva ut namnen manuellt, exempelvis category_names = c("Alive", "Dead"). Lägg då märke till att ordningen spelar roll. Kom även då ihåg att använda citattecken ” ” i vektorn ovan för att markera att det är text! Skriver vi inte ut citattecken runt kategorinamnen kommer R tro att vi kallar på variablerna Alive och Dead som inte är definierade, och Quarto dokumentet kan inte kompileras.

Man kan även specificera färgerna på pajbitarna. Det finns väldigt många färger i R och man kan specificera dem antingen med text eller med siffror. Använder man sig av text är stavningen viktig. Generellt används då endast gemener (små bokstäver).

I funktionen pie() läggs de olika argumenten in för att bilda ett pajdiagram. Det första argumentet kommer att avgöra hur stora pajbitarna blir. Det andra argumentet markerar endast etiketterna bredvid varje pajbit (i detta fall hur stora andelar det finns i varje kategori) och det tredje argumentet col bestämmer färgen i själva grafen.

Nedanför det används även funktionen legend() som flitigt kan användas då man vill rita flera olika variabler eller flera olika kategorier. Det första argumentet säger var man vill placera etiketterna för de olika kategorierna (i detta fall högst upp till höger). Det andra argumentet säger vilka namn man vill ha på dessa etiketter (category_names används här) och det tredje argumentet säger till vilka färger man vill ha. Det är då viktigt att man använder sig av samma färger som man använde sig av i pie() funktionen ovan och att färgerna också kommer i samma ordning som ovan.

💪 Uppgift 2.1

Skapa ett pajdiagram av variabeln Class i titanic. Använd dig gärna av uträkningarna från Uppgift 1.2 för att skapa grafen. Välj själv om du vill illustrera det som andelar eller i procent.

# Write your code here

💪 Uppgift 2.2

Vad är det för fel på denna graf?

rel_frequencies = c(0.1, 0.9)
category_names = names(table_rel_freq)
colors = c("lightblue", "purple")
pie(x =  table_rel_freq, labels = rel_frequencies, col = colors)
legend("topright", legend = category_names, fill = colors)

Nedan syns ett exempel på hur man kan använda sig av stapeldiagram. Detta görs enklast med funktionen bargraph(), som liknar tally() funktionen i och med att den börjar med ett ~tecken följt av variabeln som vi vill rita och sedan datasetet det kommer ifrån. Lägg dock märke till att istället för att skriva format = proportion skriver man type = proportion om man vill visa staplarna som relativa frekvenser.

Observera

I det här fallet kommer variabeln Survived från en dataframe. Det är oftast smidigare att arbeta med dataframes i mosaic paketet men inte alltid nödvändigt. Funktionen hade också fungerat ifall man hade haft en enskild variabel som inte var i dataframe-format (se den utkommenterade raden i koden).

bargraph(~ Survived, data = titanic, type = "proportion")

# bargraph(~ titanic$Survived, type = "proportion") # without dataframe format

Men detta diagram säger kanske inte allt om det vi tittar på. I vilket sammanhang är “Alive” och “Dead” tagit ifrån? Det finns ingen rubrik! Man skulle kanske även vilja justera sin y-axel, antingen så att den blir lite kortare eller lite längre.

Först kan man börja med att skapa en rubrik för sin graf. Detta görs nedan genom att skapa en ny variabel my_title som är en textsträng. Sedan kan man även definiera passande namn för både x-axeln och y-axeln, dessa är också textsträngar.

För att justera längden på y-axeln kan man skapa en vektor med passande värden. Här används en vektor med namnet length_y_axis som börjar på 0 och slutar på 0.75. Man kan även justera så att staplarna får valfria färger.

Sedan kan man enkelt sätta in argumenten i bargraph() funktionen till dessa värden:

my_title = "Figur 1: Relative frequency of Survival on the Titanic"
x_axis_title = "Survival"
y_axis_title = "Frequency"
length_y_axis = c(0, 0.80)
colors = c("lightblue", "purple")

bargraph(~ Survived, data = titanic, type = "proportion", main = my_title, 
         xlab = x_axis_title, ylab = y_axis_title, ylim = length_y_axis, col = colors)

När man skriver en Quarto-rapport är det inte så bra att skriva in figur-numret i själva grafen, dvs Figur 1, som vi skrev ovan. Problemet med det är att om man sen lägger in en graf mellan två grafer så måste man gå in och ändra alla figurers numrering. Om vi sen även har hänvisat till en figur i texten (t ex, se Figur 1 för en trevlig plott) så måste vi också ändra numret där. Men vi kan lösa detta genom att låta Quarto hålla koll på figurernas numrering. Så här:

x_axis_title = "Survival"
y_axis_title = "Frequency"
length_y_axis = c(0, 0.80)
colors = c("lightblue", "purple")

bargraph(~ Survived, data = titanic, type = "proportion", 
         xlab = x_axis_title, ylab = y_axis_title, ylim = length_y_axis, col = colors)

Figur 1: Relative frequency of Survival on the Titanic

Man kan nämligen ge lite extra kommandon i varje code-chunk genom att använda tecknet #| (uttalas hash-pipe, du kommer ihåg det genom denna Weezer-video). I det här fallet använde vi nyckelordet label för att ge figuren namnet fig-andelar och nyckelordet fig-cap för att ange texten till figuren. Notera att vi också tog bort argumentet main = my_title eftersom titel inte längre behövs i själva grafen. Vi kan nu hänvisa till figuren i texten med hjälp av @-tecknet (notera att du också kan klicka för transportera dig till figuren!): Se Figur 1 för en trevlig plott.

💪 Uppgift 2.3

Justera diagrammet nedan så att allt stämmer och så att det ser mer presentabelt ut. Byt också ut färgerna mot två andra bland R’s standardfärger.

x_axis_title = "Survival"
y_axis_title = "Frequency"
length_y_axis = c(0, 0.1)

bargraph(~ Survived, data = titanic, type = "proportion",  
         xlab = x_axis_title, ylab = y_axis_title, ylim = length_y_axis, col = colors)

Figur 2: Relative Frequency of Survival on the Titanic

💪 Uppgift 2.4

Kan du se något ovanligt med stapeldiagrammet nedan? Rätta till det.

x_axis_title = "Survival"
y_axis_title = "Relative frequency"

bargraph(~ Survived, data = titanic, type = "count", 
         xlab = x_axis_title, ylab = y_axis_title, col = colors)

Figur 3: Frequency of Survival on the Titanic

💪 Uppgift 2.5

Skapa ett stapeldiagram med funktionen bargraph() för variabeln Class i titanic. Använd relativa frekvenser denna gång.

# Write your code here

3. Dataset som består av saknade värden

Låt oss titta närmare på variabeln Age (ålder) i datasetet titanic. Denna variabel har en del saknade värden och vissa standard-funktioner i R är känsliga för sådana. Man kan enkelt se om en variabel har saknade värden genom att använda summary() funktionen, som räknar ute lite sammanfattningsmått (mer om det senare) för variablerna i datamaterialet. R skriver NA (Not Available) eller (NaN) (Not A Number) för saknade värden, och vi kan se att variabeln Age har 3 st saknade värden (NA's :3):

summary(titanic)
     Name             Survived           Boarded             Class          
 Length:2208        Length:2208        Length:2208        Length:2208       
 Class :character   Class :character   Class :character   Class :character  
 Mode  :character   Mode  :character   Mode  :character   Mode  :character  
                                                                            
                                                                            
                                                                            
                                                                            
     MWC                 Age        Adut_or_Chld           Sex           
 Length:2208        Min.   : 0.08   Length:2208        Length:2208       
 Class :character   1st Qu.:22.00   Class :character   Class :character  
 Mode  :character   Median :29.00   Mode  :character   Mode  :character  
                    Mean   :30.15                                        
                    3rd Qu.:37.00                                        
                    Max.   :74.00                                        
                    NA's   :3                                            
      Paid          Ticket_No         Boat_or_Body           Job           
 Min.   :  0.000   Length:2208        Length:2208        Length:2208       
 1st Qu.:  7.896   Class :character   Class :character   Class :character  
 Median : 14.400   Mode  :character   Mode  :character   Mode  :character  
 Mean   : 33.010                                                           
 3rd Qu.: 31.000                                                           
 Max.   :512.329                                                           
 NA's   :890                                                               
  Class_Dept         Class_Full       
 Length:2208        Length:2208       
 Class :character   Class :character  
 Mode  :character   Mode  :character  
                                      
                                      
                                      
                                      

Det finns olika sätt att hantera saknade värden. Många funktioner kan hantera uträkningar för variabler med saknade värden om man specificerar det i funktionen. I detta fall är vi bara intresserade av en variabel och inte hela datasetet så vi kommer att ta bort de observationer som har saknade värden. Men i vanliga fall måste man tänka efter innan man tar bort sådana observationer, speciellt om man tittar på flera variabler samtidigt. Det finns mer att säga om att bara ta bort saknade värden när vi kommer till den statistiska analysen.

Funktionen na.omit() tar bort alla observationer som har NA eller NaN, dvs saknade värden.

length(titanic$Age) # number of observations originally
[1] 2208
Age = na.omit(titanic$Age)
length(Age) # the number of observations when missing values are removed
[1] 2205

💪 Uppgift 3.1

Definiera en ny variabel Paid från kolumnen Paid i datasetet titanic på liknande sätt som ovan. Rensa bort eventuella saknade värden med funktionen na.omit().

# Write your code here

4. Grafisk presentation av numeriska variabler

Numeriska variabler är sådana som naturligt består av numeriska värden. Numeriska variabler kan ha olika skaltyper. Numeriska variabler innehåller rikare information än kategoriska variabler, där man kan få ut mer information både numeriskt och grafiskt. En numerisk variabel kan alltid kodas om till en kategorisk variabel (en variabel på en lägre skalnivå) men det omvända gäller inte.

Att illustrera numeriska variabler grafiskt är betydelsefullt för att upptäcka ifall en fördelning har avvikande värden (så kallade outliers), eller om fördelningen ser symmetrisk eller skev ut, men också för att upptäcka om det är en unimodal eller multimodal fördelning. Vid de två senare fallen är histogram och täthetsplot särskilt användbara.

De vanligaste graferna för numeriska variabler är histogram och låddiagram, s.k. boxplots. Ni kommer lära er att plotta låddiagram i Datorlaboration 3 efter att ni gått igenom dom på Föreläsning 5. En täthetsplot är en utjämnad version av ett histogram.

Histogram kan ritas med hjälp av funktionen histogram() som finns i mosaic paketet, eller med funktionen hist() som inte kräver något paket. Båda har sina fördelar, där histogram är mer smidig när man vill rita flera histogram samtidigt (mer om detta i Datorlaboration 3). Här är ett exempel med funktionen histogram():

histogram(~ Age, data = titanic, col = "navyblue")

Figur 4: Distribution of Age onboard the Titanic

Fördelningen är inte symmetrisk här utan snarare skev åt höger, dvs. det finns en lång högersvans. Men det finns även en hel del observationer bestående av barn under fem år. Eftersom fördelningen är skev är det svårare att gissa sig till medelvärdet. De flesta individerna verkar dock ha varit mellan 15-45 år.

Argumentet breaks = kan användas inuti funktionen histogram() för att ange hur många staplar man vill ha. R kommer då i så hög mån som möjligt rita ett histogram med så många staplar.

Ett histograms utseende beror på antalet staplar man väljer. En täthetsplot är ett sätt att plotta fördelningen av data som inte beror på antalet staplar. En täthetsplot kan ritas med hjälp av funktionen densityplot() som finns i mosaic paketet.

densityplot(~ Age, data = titanic, col = "navyblue")

Figur 5: Distribution of Age onboard the Titanic

💪 Uppgift 4.1

Rita ett histogram likt ovan, med samma variabel men med en annan färg. Testa dig fram med breaks argumentet tills du hittar vad du tycker är ett passande antal staplar. Rita sedan ett till likadant histogram men använd dig av Sturges regel denna gång för att bestämma hur många staplar som ska användas. Ser histogrammet bättre ut än det du ritade utan Sturges regel?

# Write your code here
Tips

Struges regel ges av \(1 + log_2(n)\), där n är antalet dataobservationer. I R kan funktionen för logaritmen med basen 2 fås som log2().

Använd listan i Appendix för olika argument som kan användas i grafer för att göra dem mer informativa.

💪 Uppgift 4.2

Rita ett histogram över variabeln Paid.

# Write your code here

💪 Uppgift 4.3

Vilket mått av medelvärdet eller medianen beskriver centralpunkten i fördelningen för Paid bäst?

💪 Uppgift 4.4

Rita täthetsplottar för variablerna Age och Paid.

# Write your code here
Extra: Från histogram till stapeldiagram (detta avsnitt kan skippas)

Histogram kan ses som en motsvarighet till stapeldiagram när man har en numerisk variabel. Från funktionen hist() kan man även hämta ut hur många observationer det är som tillfaller varje åldersintervall. Låt oss först rita ett histogram nedan och spara detta med namnet hist_Age. Sedan kan man extrahera antalet inom varje åldersintervall med hjälp av $-tecknet följt av count som räknar ut antal observationer inom varje intervall.

hist_Age = hist(x = Age,  col = "coral")

frequencies = hist_Age$count
frequencies
 [1]  62  38  33 271 432 400 321 264 158 103  49  37  28   5   4

Dessa summeras inte överraskande nog till 2205 (dvs antal observerade värden). Härnäst kan man titta på hur R definierar gränserna för varje stapel med hjälp av breaks som också finns i hist() funktionen:

hist_Age$breaks
 [1]  0  5 10 15 20 25 30 35 40 45 50 55 60 65 70 75

Vi har alltså åldersintervallen “0-4”, “5-9”, “10-14”, “15-19”, “20-24”, “25-29”, “30-34”, “35-39”, “40-44”, “45-49”, “50-54”, “55-59”, “60-64”, “65-69”, “70-74”. Dessa kan användas för att skapa ett stapeldiagram likt nedan, denna gång med funktionen barplot() som finns inbyggd i R.

I det första argumentet i funktionen barplot() lägger vi in frekvenserna som nyss räknades ut. Det andra argumentet names.arg är till för att namnge de olika åldersintervallen ovan, på x-axeln. Argumentet las = 3 gör endast så att texten på x-axeln blir lodrät.

Age_Intervals = c("0-4", "5-9", "10-14", "15-19", "20-24", "25-29", "30-34", 
              "35-39", "40-44", "45-49", "50-54", "55-59", "60-64", "65-69",
              "70-74")

barplot(frequencies, names.arg = Age_Intervals, las = 3)

Figur 6: Distribution of Age onboard the Titanic

Histogrammet som skapades innan går alltså i princip att göra om till ett stapeldiagram, där höjden på stapeln illustrerar hur många observationer det är som tillfaller varje ålderskategori.

5. Numerisk beskrivning av kvantitiva variabler

Om man använder sig av en frekvenstabell för en numerisk variabel riskerar man i värsta fall att få en tabell som är lika lång som antal observationer man har. Kanske har man inte ens ett enda fall där två olika observationer har samma värden. Därför används ofta andra beskrivande mått. Bland de viktigaste är lägesmåtten som fångar fördelningens mittpunkt

  • medelvärde
  • median

och spridningsmåtten som mäter variationen kring fördelningens mittpunkt:

  • varians
  • standardavvikelse
  • variationsbredd (range på engelska: skillnaden mellan maximum och minimumvärdet)
  • Interkvartila avståndet (IQR).

Funktionen favstats() i mosaic-paketet beräknar dessa mått:

favstats(~ Age, data = titanic)
  min Q1 median Q3 max     mean       sd    n missing
 0.08 22     29 37  74 30.14689 11.97386 2205       3

Funktionen räknar ut olika fördelningsmått, såsom minimumvärdet, maximumvärdet, första och tredje kvartilen samt medelvärdet och medianen. Både medelvärdet och medianen är mått på en fördelnings mittpunkt men hur lämpliga de är som mått beror på fördelningens utseende. Vi ser även att funktionen också skriver ut hur många värden datasetet består av och antalet saknade värden.

Ibland vill man dock inte skriva ut all denna information för en variabel. I Datorlaboration 1 använde vi oss av funktionen mean() för att räkna ut medelvärdet av en variabel. Några andra vanliga funktioner utöver dessa är var() och sd(). Matematiskt motvaras dessa tre funktioner av: \[\begin{align}\nonumber \overline{y}= \frac{1}{n} \sum_{i=1}^n y_i \\ \nonumber s^2 =\frac{\sum_{i=1}^n(y_i-\overline{y})^2}{n-1} \end{align}\] och \[\begin{align} s = \sqrt{s^2} \end{align}\]

💪 Uppgift 5.1

Använd funktionerna ovan för att räkna ut medelvärdet, variansen och standardavvikelsen för variabeln Age. Kan man räkna ut standardavvikelsen på något annat sätt i R?

# Write your code here

💪 Uppgift 5.2

Räkna ut det variationsbredden samt det interkvartila avståndet av variabeln Age från utskriften vi fick från funktionen favstats().

# Write your code here

6. Indexering och upprepning (loopar)

Låt oss titta på ett dataset över UFC’s top 10 kampsportsutövare i Welterweight klassen bland män (december 2022). Nedan matas värdena in i vektorer och sedan sätts alla variabler ihop i en och samma tabell med funktionen data.frame():

# Defining variables:
Name = c("Kamaru Usman", "Colby Covington", "Khamzat Chimaev", "Belal Muhammed",
         "Gilbert Burns","Stephen Thompson", "Geoff Neal", "Sean Brady", 
         "Vicente Luque", "Shavkat Rakhmanov" )
Rank = c(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
Wins_by_knockout = c(9, 4, 6, 5, 6, 8, 9, 3, 11, 8)
Takedown_avg = c(3.01, 4.05, 3.98, 2.19, 2, 0.27, 0.59, 2.8, 0.51, 2.31)
Age_fighters = c(35,34,27, 34, 35, 39, 31, 29, 30, 27)

# Creating a dataframe with all the variables just defined above:
UFC = data.frame(Name, Rank, Wins_by_knockout, Takedown_avg, Age_fighters)
UFC
                Name Rank Wins_by_knockout Takedown_avg Age_fighters
1       Kamaru Usman    1                9         3.01           35
2    Colby Covington    2                4         4.05           34
3    Khamzat Chimaev    3                6         3.98           27
4     Belal Muhammed    4                5         2.19           34
5      Gilbert Burns    5                6         2.00           35
6   Stephen Thompson    6                8         0.27           39
7         Geoff Neal    7                9         0.59           31
8         Sean Brady    8                3         2.80           29
9      Vicente Luque    9               11         0.51           30
10 Shavkat Rakhmanov   10                8         2.31           27

Datasetet består av fem stycken variabler och är sorterat efter Rank. I Lab 1 tittade vi lite på indexering och detta bygger vidare på det. Låt säga att vi vill veta vad åldern är för den 6:e rankade utövaren. I detta fall är datasetet väldigt litet och man kan genast identifiera alla individer. Ibland har vi dataset som är väldigt stora och då kan man behöva använda sig av indexering för att få ut information om en enskild (eller ett fåtal) observationer av intresse. För att ta reda på åldern på den 6:e rankade utövaren kan man då använda sig av koden UFC[6, 5]. Där siffran till vänster om kommatecknet i hakparantesen anger radtalet och siffran till höger om kommatecknet anger kolumntalet. Detta ger oss svaret 39.

💪 Uppgift 6.1

Använd indexering för att skriva ut hur många wins by knockout Gilbert Burns har haft.

# Write your code here

💪 Uppgift 6.2

Använd indexering för att skriva ut all information om Kamaru Usman (dvs den första raden). [Ledtråd: om man inte skriver något alls efter kommatecknet i indexeringen får man alla värden i den raden]

# Write your code here

💪 Uppgift 6.3

Använd indexering för att skriva ut alla värden för variabeln Takedown_avg (dvs den 4:e kolumnen).

# Write your code here

En loop kan väldigt kort beskrivas som en procedur som återupprepas så länge ett visst förhållande är uppfyllt. Det finns tre vanliga loopar i R. Dessa är for-loop, while-loop och repeat-loop. De två första är de vanligaste men vi kommer än så länge bara titta på for-loopen.

Säg att du vill skriva en kod som skriver ut alla tal mellan 1 och 10 på skärmen. Du skulle kunna skriva print(1) följt av print(2) osv, men skulle vara jobbigt. Kan vi få datorn att göra det jobbet åt oss genom att använda en for-loop? Svar ja. Nedan ges ett exempel på en loop som skriver ut talen mellan 1-10 med hjälp av print() funktionen. Det är ett exempel på den kanske mest grundläggande loopen, men den illustrerar ändå en viktig princip. För att starta loopen används ordet for följt av en parentes. Vad som står inom parentesen är väldigt viktigt och det första argumentet är namnet på en så kallad indexvariabel, i detta fall i. Efter detta specificerar man från vilken siffra i börjar på samt vilken siffra i slutar på. Här börjar den på 1 och slutar på 10. Efter parentesen bildar man en ny så kallad klammerparentes (som ser ut som måsvingar). Där inne specificerar man allt som ska hända i varje upprepningen i loopen. I det här exemplet vill vi att loopen ska skriva ut indexnumret, ett i taget:

for (i in 1:10){
  print(i)
}
[1] 1
[1] 2
[1] 3
[1] 4
[1] 5
[1] 6
[1] 7
[1] 8
[1] 9
[1] 10

Alltså skriver loopen ut vad i är under varje iteration (dvs upprepning).

💪 Uppgift 6.4

Använd loopen ovan men byt ut indexvariabeln i till k istället. Kör sedan loopen. Vad är det som händer?

# Write your code here

💪 Uppgift 6.5

Använd återigen loopen i exemplet ovan. Men ändra variabeln is definitionsmängd från 1:10 till 24:33.

# Write your code here

💪 Uppgift 6.6

Gör på samma vis som i övningen ovan men ändra nu definitionsmängden från 1:10 till -3:5

# Write your code here

Nedan ges ett exempel på en for-loop som skriver ut namnet på en enskild variabel (Name) i tur och ordning. Här används indexering av variabeln Name för att endast ett namn ska skrivas ut i varje iteration, och då i samma ordning som den förekommer i variabeln.

for(i in 1:10){
  print(Name[i])
}
[1] "Kamaru Usman"
[1] "Colby Covington"
[1] "Khamzat Chimaev"
[1] "Belal Muhammed"
[1] "Gilbert Burns"
[1] "Stephen Thompson"
[1] "Geoff Neal"
[1] "Sean Brady"
[1] "Vicente Luque"
[1] "Shavkat Rakhmanov"
Observera

Här användes endast en variabel Name (som faktiskt definierades innan dataframen UFC). Därför används inte något kommatecken inuti hakparantesen. Det beror alltså på att det här är en enskild definierad variabel utanför dataframen UFC.

💪 Uppgift 6.7

Använd en for-loop för att skriva ut varje värde på variabeln Wins_by_knockout.

# Write your code here

Den introduktionen till loopar kan räcka för tillfället. Men om du tyckte det var intressant kan du fortsätta läsa lite mer om loopar nedan. Annars kan du hoppas till Sammanfattningen av Lab 2.

Man kan även göra matematiska uträkningar med hjälp av en loop. Låt säga att vi vill räkna ut vad \(2^6\) är (där 2 är basen och 6 är exponenten). Detta kan enkelt göras med den matematiska operationen ^ i R vilket ger oss resultatet 64. Men eftersom vi älskar att loopa så kommer vi också älska följande exempel där vi räknar ut detta värde för hand med en loop.

Först måste man definiera ett startvärde. Detta görs med variabeln myProduct nedan. Eftersom uträkningen av \(2^6 = 2\cdot 2\cdot 2\cdot 2\cdot 2\cdot 2 = 64\) egentligen bara är multiplikation, måste startvärdet vara like med 1 (används 0 kommer slutresultatet också att bli 0). Därefter kan loopen startas. Den kommer att iterera från värdet 1 till 6 (eftersom exponenten är 6). Efter första iterationen (loop-omgången) kommer myProduct att vara 1 multiplicerat med 2, dvs 2. Detta värde sparas i myProduct och syns när man skriver ut resultatet med print(myProduct) inuti loopen. I den andra iterationen multipliceras myProduct med 2 igen, och detta värde sparas nu i myProduct. Resultatet är \(2\cdot2=4\). Den tredje iterationen multipliceras 4 med 2 och myProduct uppdateras till detta nya värde 8. Denna procedur upprepas tills antal iterationer i har nått upp till 6 gånger. Därefter avslutas loopen och myProduct visar då svaret på vad \(2^6\) är:

myProduct = 1 # We have to start with 1 here since it's multiplication

for (i in 1:6){
  myProduct = myProduct * 2  # multiplying with 2 in each iteration
  print(myProduct) # prints the result after each iteration
}
[1] 2
[1] 4
[1] 8
[1] 16
[1] 32
[1] 64
myProduct # final result
[1] 64

💪 Uppgift 6.8

Funktionen sum() i R kan användas för att summera numeriska värden i en vektor. Använd denna funktion för att räkna ut medelvärdet för variabeln Age_fighters ovan.

# Write your code here
Tips

Medelvärdet ges av formeln: \[\begin{align} \nonumber \overline{y}= \frac{1}{n} \sum_{i=1}^n y_i \end{align}\]

💪 Uppgift 6.9

Använd en for-loop för att räkna ut medelvärdet för variabeln Age_fighters.

# Write your code here
Tips

Skapa ett startvärde för summan och sätt detta värde till 0. Sedan inuti loopen måste du också använda dig av indexering för att säga till R vilket värde i denna variabel du vill addera till din befintliga summa.

7. Sammanfattning

I den här laborationen har du lärt dig:
  • Metoder för att presentera en variabels fördelning och att man använder olika metoder beroende på om en variabel är numerisk eller kategorisk.

  • Hur man praktiskt kan presentera kategoriska variabler i tabellform samt illustrera dem grafiskt med paj- och stapeldiagram.

  • Hur man kan rita ett histogram och en täthetsplot.

  • Kopplingen mellan histogram och stapeldiagram.

  • Vilka beskrivande mått man kan använda sig av för numeriska variabler.

  • Några exempel på vad en for-loop kan användas till.

A. Appendix

Lista över några vanliga argument i grafer

  • col = färg, kan markeras med siffror eller med namnet på färgen, oftast med små bokstäver. Glöm ej att texten måste ligga inom citattecken.

  • main = rubrik på plotten, detta sätts till en textsträng, alltså en text inom citattecken.

  • xlab = rubrik på x-axeln, detta sätts till en textsträng, alltså en text inom citattecken.

  • ylab = rubrik på y-axeln, detta sätts till en textsträng, alltså en text inom citattecken.

  • xlim = definitionsområde för x-axeln. Exempelvis betyder xlim = c(0, 14.3) att det lägsta värdet som ritas kommer att vara 0 och det högsta värdet kommer att vara 14.3 (på x-axeln).

  • ylim = definitionsområde för y-axeln. Exempelvis betyder ylim = c(-2, 20.7) att det lägsta värdet som ritas kommer att vara -2 och det högsta värdet kommer att vara 20.7 (på y-axeln).

  • lwd = tjocklecken på linjer (eller prickar) i ett linjediagram (spridningsdiagram), anges med ett nummer.

  • lty = typ av linje (rak, streckad, prickad etc) i ett linjediagram, anges med ett nummer.

  • pch = typ av prick (rund, fyrkantig + * etc), sätts till ett nummer.

  • breaks = antal staplar i ett histogram.

  • cex = justering av etiketternas storlek i en figur (exempelvis cex = 0.5 i en legend() funktion minskar storleken som “legend-texten” tar upp i en figur med hälften). Finns även exempelvis cex.axis, cex.main för att justera storleken av texter på axlar respektive rubrik.

  • bg = bakgrundsfärg i en figur.

  • col.main = rubrikens färg.

  • col.lab = färger för rubrikerna på axlarna.

  • font = specificerar vilken typ av text man vill ha, exempelvis ger font = 3 kursiv text.