6  Inspisere data

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.2     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.4.2     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     
── Conflicts ────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the conflicted package (<http://conflicted.r-lib.org/>) to force all conflicts to become errors

Er du vant til å jobbe i programvare som er bygd mer rundt det grafiske brukergrensesnittet vil du nok på dette tidspunktet føle deg noe klaustrofobisk. Hvor er dataene mine? Hvordan ser de ut? Det er bra å inspisere dataene sine jevnlig for å sjekke at antakelsene dine om dem stemmer. Rett som det er kan du oppdaga at det du trodde var et levende datasett egentlig bare er et NULL-objekt. Derfor bør vi kjenne til en del ulike måter å inspisere datasetta våre.

6.1 View

Kommandoen View() gir deg det nærmeste vi kommer SPSS’ Data view-vindu. Her kan du se rader, celler og kolonner. Merk at kommandoen har stor forbokstav - noe som er uvanlig. Du bruker det simpelthen slik View(starwars), og et nytt vindu vil dukke opp hvor du kan bivåne data i ro og mak. Har du store mengder data er min erfaring at scrollinga blir litt treig, og det tar litt tid å laste inn hvert nye skjermbilde. Hvis du er lei av å skrive, kan du også dobbeltklikke på et data.frame/tibble-objekt i miljø-vinduet.

6.2 Del-inspisering

Den enkleste måten å inspisere et datasett på er å bare skrive navnet i konsollen. Da blir (et utdrag) av datasettet skrevet ut.

# For å gjøre disse eksemplene tydligere legger jeg på en rad-ID med 
# `rowid_to_column()` slik at vi lettere ser hvilken rad vi ser på.
# Datasettet har biltype som "radnavn", så vi putter disse inn i en egen
# kolonne først med `rownames_to_column()`.
biler <- mtcars %>% 
  rownames_to_column("bil") %>% 
  rowid_to_column("rowid")

biler
   rowid                 bil  mpg cyl  disp  hp drat    wt  qsec vs am gear
1      1           Mazda RX4 21.0   6 160.0 110 3.90 2.620 16.46  0  1    4
2      2       Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4
3      3          Datsun 710 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4
4      4      Hornet 4 Drive 21.4   6 258.0 110 3.08 3.215 19.44  1  0    3
5      5   Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3
6      6             Valiant 18.1   6 225.0 105 2.76 3.460 20.22  1  0    3
7      7          Duster 360 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3
8      8           Merc 240D 24.4   4 146.7  62 3.69 3.190 20.00  1  0    4
9      9            Merc 230 22.8   4 140.8  95 3.92 3.150 22.90  1  0    4
10    10            Merc 280 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4
11    11           Merc 280C 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4
12    12          Merc 450SE 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3
13    13          Merc 450SL 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3
14    14         Merc 450SLC 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3
15    15  Cadillac Fleetwood 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3
16    16 Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3
17    17   Chrysler Imperial 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3
18    18            Fiat 128 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4
19    19         Honda Civic 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4
20    20      Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4
21    21       Toyota Corona 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3
22    22    Dodge Challenger 15.5   8 318.0 150 2.76 3.520 16.87  0  0    3
23    23         AMC Javelin 15.2   8 304.0 150 3.15 3.435 17.30  0  0    3
24    24          Camaro Z28 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3
25    25    Pontiac Firebird 19.2   8 400.0 175 3.08 3.845 17.05  0  0    3
26    26           Fiat X1-9 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4
27    27       Porsche 914-2 26.0   4 120.3  91 4.43 2.140 16.70  0  1    5
28    28        Lotus Europa 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5
29    29      Ford Pantera L 15.8   8 351.0 264 4.22 3.170 14.50  0  1    5
30    30        Ferrari Dino 19.7   6 145.0 175 3.62 2.770 15.50  0  1    5
31    31       Maserati Bora 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5
32    32          Volvo 142E 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4
   carb
1     4
2     4
3     1
4     1
5     2
6     1
7     4
8     2
9     2
10    4
11    4
12    3
13    3
14    3
15    4
16    4
17    4
18    1
19    2
20    1
21    1
22    2
23    2
24    4
25    2
26    1
27    2
28    2
29    4
30    6
31    8
32    2

I seg sjøl greit. Men man risikerer å overse noe dersom man alltid bare inspiserer de øverste ti radene. Da er de nyttig å se på et tilfeldig utvalg av rader

biler %>% slice_sample(n = 10)
   rowid                 bil  mpg cyl  disp  hp drat    wt  qsec vs am gear
1     24          Camaro Z28 13.3   8 350.0 245 3.73 3.840 15.41  0  0    3
2     21       Toyota Corona 21.5   4 120.1  97 3.70 2.465 20.01  1  0    3
3      5   Hornet Sportabout 18.7   8 360.0 175 3.15 3.440 17.02  0  0    3
4     32          Volvo 142E 21.4   4 121.0 109 4.11 2.780 18.60  1  1    4
5      2       Mazda RX4 Wag 21.0   6 160.0 110 3.90 2.875 17.02  0  1    4
6     31       Maserati Bora 15.0   8 301.0 335 3.54 3.570 14.60  0  1    5
7     12          Merc 450SE 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3
8     16 Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3
9      7          Duster 360 14.3   8 360.0 245 3.21 3.570 15.84  0  0    3
10    15  Cadillac Fleetwood 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3
   carb
1     4
2     1
3     2
4     2
5     4
6     8
7     3
8     4
9     4
10    4

Denne funksjonen er en avart av slice() som gir deg spesifikke rader. Hvis du f.eks. vil ha rad 10-20:

biler %>% slice(10:20)
   rowid                 bil  mpg cyl  disp  hp drat    wt  qsec vs am gear
1     10            Merc 280 19.2   6 167.6 123 3.92 3.440 18.30  1  0    4
2     11           Merc 280C 17.8   6 167.6 123 3.92 3.440 18.90  1  0    4
3     12          Merc 450SE 16.4   8 275.8 180 3.07 4.070 17.40  0  0    3
4     13          Merc 450SL 17.3   8 275.8 180 3.07 3.730 17.60  0  0    3
5     14         Merc 450SLC 15.2   8 275.8 180 3.07 3.780 18.00  0  0    3
6     15  Cadillac Fleetwood 10.4   8 472.0 205 2.93 5.250 17.98  0  0    3
7     16 Lincoln Continental 10.4   8 460.0 215 3.00 5.424 17.82  0  0    3
8     17   Chrysler Imperial 14.7   8 440.0 230 3.23 5.345 17.42  0  0    3
9     18            Fiat 128 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4
10    19         Honda Civic 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4
11    20      Toyota Corolla 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4
   carb
1     4
2     4
3     3
4     3
5     3
6     4
7     4
8     4
9     1
10    2
11    1

Dette gir oss en mulighet til å se fordelen med å arbeide med tibbles: På noen skjermer blir den forrige tabellen stygg fordi den siste kolonna presses ned til ei ny side. (Jeg kan ikke garantere at det skjer på din side.) Men om vi gjør om biler (som arver data.fram-klassen fra mtcars) til en tibble, får den siste kolonna plass på samme linje som resten. (Jeg kan forsåvidt heller ikke garantere at dette vil se helt likt ut på din skjerm.) Og vi får vite kolonnetypen til hver kolonne. Stilig!

biler %>% 
  tibble() %>% 
  slice(10:20)
# A tibble: 11 × 13
   rowid bil     mpg   cyl  disp    hp  drat    wt  qsec    vs    am  gear  carb
   <int> <chr> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
 1    10 Merc…  19.2     6 168.    123  3.92  3.44  18.3     1     0     4     4
 2    11 Merc…  17.8     6 168.    123  3.92  3.44  18.9     1     0     4     4
 3    12 Merc…  16.4     8 276.    180  3.07  4.07  17.4     0     0     3     3
 4    13 Merc…  17.3     8 276.    180  3.07  3.73  17.6     0     0     3     3
 5    14 Merc…  15.2     8 276.    180  3.07  3.78  18       0     0     3     3
 6    15 Cadi…  10.4     8 472     205  2.93  5.25  18.0     0     0     3     4
 7    16 Linc…  10.4     8 460     215  3     5.42  17.8     0     0     3     4
 8    17 Chry…  14.7     8 440     230  3.23  5.34  17.4     0     0     3     4
 9    18 Fiat…  32.4     4  78.7    66  4.08  2.2   19.5     1     1     4     1
10    19 Hond…  30.4     4  75.7    52  4.93  1.62  18.5     1     1     4     2
11    20 Toyo…  33.9     4  71.1    65  4.22  1.84  19.9     1     1     4     1

Noen ganger er det likevel nyttig å kikke på toppen eller bunnen av et datasett. Da kan vi bruke de komplementære funksjonene head() og tail().

# `head()` viser toppen
biler %>% head()
  rowid               bil  mpg cyl disp  hp drat    wt  qsec vs am gear carb
1     1         Mazda RX4 21.0   6  160 110 3.90 2.620 16.46  0  1    4    4
2     2     Mazda RX4 Wag 21.0   6  160 110 3.90 2.875 17.02  0  1    4    4
3     3        Datsun 710 22.8   4  108  93 3.85 2.320 18.61  1  1    4    1
4     4    Hornet 4 Drive 21.4   6  258 110 3.08 3.215 19.44  1  0    3    1
5     5 Hornet Sportabout 18.7   8  360 175 3.15 3.440 17.02  0  0    3    2
6     6           Valiant 18.1   6  225 105 2.76 3.460 20.22  1  0    3    1
# `tail()` viser bunnen
biler %>% tail()
   rowid            bil  mpg cyl  disp  hp drat    wt qsec vs am gear carb
27    27  Porsche 914-2 26.0   4 120.3  91 4.43 2.140 16.7  0  1    5    2
28    28   Lotus Europa 30.4   4  95.1 113 3.77 1.513 16.9  1  1    5    2
29    29 Ford Pantera L 15.8   8 351.0 264 4.22 3.170 14.5  0  1    5    4
30    30   Ferrari Dino 19.7   6 145.0 175 3.62 2.770 15.5  0  1    5    6
31    31  Maserati Bora 15.0   8 301.0 335 3.54 3.570 14.6  0  1    5    8
32    32     Volvo 142E 21.4   4 121.0 109 4.11 2.780 18.6  1  1    4    2

Disse er nyttig fordi de kan brukes på mer enn bare datasett.

# Viser de siste kolonnenavna i datasettet
biler %>% 
  colnames() %>% 
  tail()
[1] "wt"   "qsec" "vs"   "am"   "gear" "carb"
# Lager en strengvektor på 26 elementer (bokstaver)
bokstaver <- letters[1:26]

# Viser de siste bokstavene
bokstaver %>% tail()
[1] "u" "v" "w" "x" "y" "z"

6.3 Andre kolonner

På samme måte som det er begrensende å hele tida kikke på de øverste radene av et datasett er det begrensende å kikke på de fremste kolonnene. Vi kan bruke select() for å velge hvilke rader vi vil se på, eller vi kan bruke den nyttige glimpse(). Greier du å gjette hvor disse funksjonene kommer fra? De kommer fra dplyr!

som er en del av tidyverse.

6.3.1 select

select() gir oss muligheten til å diskutere en av de fantastiske innovasjonene i tidyverse: tidy evaluation. Vi dykker ikke dypt i det, men det er greit å vite om data masking og tidy select. De er diskutert mer inngående i Programming with Tidyverse. Tidy select lar oss velge en kolonne i et datasett uten å måtte hermetegn. Tenk på det! Neste gang du velger en kolonne slipper du å strekke lillefingeren til den fjerne shift-tasten og gå i spagat med langefingern til 2-tasten. Faktisk gjør tidy select mye mer enn dette, som vi vil se etter hvert. F.eks. kan du velge kolonner ut fra navn, posisjon, eller type. La oss se noen eksempler

# Slik ser starwars-datasettet ut. 
starwars %>% head()
# A tibble: 6 × 14
  name      height  mass hair_color skin_color eye_color birth_year sex   gender
  <chr>      <int> <dbl> <chr>      <chr>      <chr>          <dbl> <chr> <chr> 
1 Luke Sky…    172    77 blond      fair       blue            19   male  mascu…
2 C-3PO        167    75 <NA>       gold       yellow         112   none  mascu…
3 R2-D2         96    32 <NA>       white, bl… red             33   none  mascu…
4 Darth Va…    202   136 none       white      yellow          41.9 male  mascu…
5 Leia Org…    150    49 brown      light      brown           19   fema… femin…
6 Owen Lars    178   120 brown, gr… light      blue            52   male  mascu…
# ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
#   vehicles <list>, starships <list>
# Det er 14 kolonner. 
# Med mindre du har en svær skjerm kan vi ikke se alle på en gang.
starwars %>% colnames()
 [1] "name"       "height"     "mass"       "hair_color" "skin_color"
 [6] "eye_color"  "birth_year" "sex"        "gender"     "homeworld" 
[11] "species"    "films"      "vehicles"   "starships" 
# Vi kikker på noen spesifikke kolonner. 
# Films er ei liste, så den ser vi ikke direkte.
starwars %>% select(name, species, films)
# A tibble: 87 × 3
   name               species films    
   <chr>              <chr>   <list>   
 1 Luke Skywalker     Human   <chr [5]>
 2 C-3PO              Droid   <chr [6]>
 3 R2-D2              Droid   <chr [7]>
 4 Darth Vader        Human   <chr [4]>
 5 Leia Organa        Human   <chr [5]>
 6 Owen Lars          Human   <chr [3]>
 7 Beru Whitesun lars Human   <chr [3]>
 8 R5-D4              Droid   <chr [1]>
 9 Biggs Darklighter  Human   <chr [1]>
10 Obi-Wan Kenobi     Human   <chr [6]>
# ℹ 77 more rows
# Vi vil ha 1, 3, 5, og 7 kolonne
starwars %>% select(1, 3, 5, 7)
# A tibble: 87 × 4
   name                mass skin_color  birth_year
   <chr>              <dbl> <chr>            <dbl>
 1 Luke Skywalker        77 fair              19  
 2 C-3PO                 75 gold             112  
 3 R2-D2                 32 white, blue       33  
 4 Darth Vader          136 white             41.9
 5 Leia Organa           49 light             19  
 6 Owen Lars            120 light             52  
 7 Beru Whitesun lars    75 light             47  
 8 R5-D4                 32 white, red        NA  
 9 Biggs Darklighter     84 light             24  
10 Obi-Wan Kenobi        77 fair              57  
# ℹ 77 more rows
# Alle kolonner som inneholder en viss tekststreng
starwars %>% select(contains("color"))
# A tibble: 87 × 3
   hair_color    skin_color  eye_color
   <chr>         <chr>       <chr>    
 1 blond         fair        blue     
 2 <NA>          gold        yellow   
 3 <NA>          white, blue red      
 4 none          white       yellow   
 5 brown         light       brown    
 6 brown, grey   light       blue     
 7 brown         light       blue     
 8 <NA>          white, red  red      
 9 black         light       brown    
10 auburn, white fair        blue-gray
# ℹ 77 more rows
# Alle kolonner som er numeriske
starwars %>% select(where(is.numeric))
# A tibble: 87 × 3
   height  mass birth_year
    <int> <dbl>      <dbl>
 1    172    77       19  
 2    167    75      112  
 3     96    32       33  
 4    202   136       41.9
 5    150    49       19  
 6    178   120       52  
 7    165    75       47  
 8     97    32       NA  
 9    183    84       24  
10    182    77       57  
# ℹ 77 more rows

6.3.2 glimpse

Tilbake til det opprinnelige formålet, som bare var å ta en kjapp titt på dataene vi har. Til dette er glimpse() utmerka. Den snur rett og slett datasettet 90 grader og skriver ut kolonnenavna nedover. Dermed får du med flere. Du får også en oversikt over hva hver kolonne inneholder, skjønt det er mer utydelig hva som er på samme rad. En fordel med glimpse() er at den viser oss innholdet i lister som er element av datasettet. Her ser vi f.eks. innholdet i kolonna films .

starwars %>% glimpse()
Rows: 87
Columns: 14
$ name       <chr> "Luke Skywalker", "C-3PO", "R2-D2", "Darth Vader", "Leia Or…
$ height     <int> 172, 167, 96, 202, 150, 178, 165, 97, 183, 182, 188, 180, 2…
$ mass       <dbl> 77.0, 75.0, 32.0, 136.0, 49.0, 120.0, 75.0, 32.0, 84.0, 77.…
$ hair_color <chr> "blond", NA, NA, "none", "brown", "brown, grey", "brown", N…
$ skin_color <chr> "fair", "gold", "white, blue", "white", "light", "light", "…
$ eye_color  <chr> "blue", "yellow", "red", "yellow", "brown", "blue", "blue",…
$ birth_year <dbl> 19.0, 112.0, 33.0, 41.9, 19.0, 52.0, 47.0, NA, 24.0, 57.0, …
$ sex        <chr> "male", "none", "none", "male", "female", "male", "female",…
$ gender     <chr> "masculine", "masculine", "masculine", "masculine", "femini…
$ homeworld  <chr> "Tatooine", "Tatooine", "Naboo", "Tatooine", "Alderaan", "T…
$ species    <chr> "Human", "Droid", "Droid", "Human", "Human", "Human", "Huma…
$ films      <list> <"The Empire Strikes Back", "Revenge of the Sith", "Return…
$ vehicles   <list> <"Snowspeeder", "Imperial Speeder Bike">, <>, <>, <>, "Imp…
$ starships  <list> <"X-wing", "Imperial shuttle">, <>, <>, "TIE Advanced x1",…

6.4 Oppsummeringer

Hittil har vi bare prata om måter å set utdrag av data på. Noen ganger er det nyttig å se en oppsummering av dataene. Detaljer som snitt, standardavvik, minimum og maksimum-verdier, for eksempel.

summary() fra base R er nyttig her. Den gir enkelt og greit en oversikt over diverse statistikk for hver numeriske variabel.

biler %>% summary()
     rowid           bil                 mpg             cyl       
 Min.   : 1.00   Length:32          Min.   :10.40   Min.   :4.000  
 1st Qu.: 8.75   Class :character   1st Qu.:15.43   1st Qu.:4.000  
 Median :16.50   Mode  :character   Median :19.20   Median :6.000  
 Mean   :16.50                      Mean   :20.09   Mean   :6.188  
 3rd Qu.:24.25                      3rd Qu.:22.80   3rd Qu.:8.000  
 Max.   :32.00                      Max.   :33.90   Max.   :8.000  
      disp             hp             drat             wt       
 Min.   : 71.1   Min.   : 52.0   Min.   :2.760   Min.   :1.513  
 1st Qu.:120.8   1st Qu.: 96.5   1st Qu.:3.080   1st Qu.:2.581  
 Median :196.3   Median :123.0   Median :3.695   Median :3.325  
 Mean   :230.7   Mean   :146.7   Mean   :3.597   Mean   :3.217  
 3rd Qu.:326.0   3rd Qu.:180.0   3rd Qu.:3.920   3rd Qu.:3.610  
 Max.   :472.0   Max.   :335.0   Max.   :4.930   Max.   :5.424  
      qsec             vs               am              gear      
 Min.   :14.50   Min.   :0.0000   Min.   :0.0000   Min.   :3.000  
 1st Qu.:16.89   1st Qu.:0.0000   1st Qu.:0.0000   1st Qu.:3.000  
 Median :17.71   Median :0.0000   Median :0.0000   Median :4.000  
 Mean   :17.85   Mean   :0.4375   Mean   :0.4062   Mean   :3.688  
 3rd Qu.:18.90   3rd Qu.:1.0000   3rd Qu.:1.0000   3rd Qu.:4.000  
 Max.   :22.90   Max.   :1.0000   Max.   :1.0000   Max.   :5.000  
      carb      
 Min.   :1.000  
 1st Qu.:2.000  
 Median :2.000  
 Mean   :2.812  
 3rd Qu.:4.000  
 Max.   :8.000  

Vi kan også sette sammen vår eget sammendrag med summarise fra dplyr. Her kombinerer vi det med grupperingsfunksjonen group_by().

mtcars %>% 
  group_by(cyl) %>% 
  summarise(
    mpg_m = mean(mpg),
    mpg_sd = sd(mpg)
  )
# A tibble: 3 × 3
    cyl mpg_m mpg_sd
  <dbl> <dbl>  <dbl>
1     4  26.7   4.51
2     6  19.7   1.45
3     8  15.1   2.56

Tips: Jeg bruker både summary() og summarise() ofte. Og jeg bruker nesten konsekvent den ene når jeg egentlig mener å bruke den andre. Får du feilmelding når du arbeider med disse funksjonene, sjekk først at du ikke egentlig mente å bruke den andre.