Kapitel 3 Datamanipulering med dplyr

Det sägs ofta att en Data Scientist ägnar 80% av sin tid till att manipulera data så att den går att visualisera och modellera. Därför är det klokt att välja en metod och ett paket som underlättar det arbetet för dig.

I den här introduktionen kommer vi att fokusera på att använda paketet dplyr för att göra datamanipuleringar. dplyr är ett av de mest populära paketen i R och ger dig en bred verktygslåda för att manipulera data. dplyr ingår också i ett samlingspaket tidyverse och samlar flertalet paket för datamanipulering, visualisering och modellering.

dplyr har ett antal verb för att göra manipuleringar:

  • filter() där du väljer observationer baserat på deras värden
  • arrange() som ändrar ordningen på rader
  • select() för att välja variabler baserat på deras namn
  • mutate() för att skapa nya variabler baserat på funktioner
  • summarise() för att summera många värden till ett värde

Samtliga av dessa verb kan användas i kombination med funktionen group_by() som innebär att du utför verben på flera grupper.

Alla verb i dplyr är konsekventa. Det första argumentet är din data och i det andra argumentet specificerar du vad du vill göra med din data. Resultatet är alltid en ny data.frame.

3.1 Filter

Med filter kan du enkelt filtrera din data baserat på villkor.

Dessa villkor uttrycks med hjälp av relationsoperatorer och logical operators.

I R är dessa:

Relationsoperator Symbol i R
och (and) &
eller(or) |
icke(not) !
Logical Operators Symbol i R
lika ==
inte lika !=
större än eller lika >=
mindre än eller lika <=
större än >
mindre än <
finns i %in%

Dessa kan du använda i filter().

PS: Det vanligaste misstaget i början av din R-karriär är att skriva = istället för ==.

Så här använder du operatorerna:

Hitta alla flyg som kom fram 08:30 under februari

## # A tibble: 9 x 19
##    year month   day dep_time sched_dep_time dep_delay arr_time
##   <int> <int> <int>    <int>          <int>     <dbl>    <int>
## 1  2013     2     2      656            700        -4      830
## 2  2013     2     4      652            600        52      830
## 3  2013     2     6      629            630        -1      830
## 4  2013     2    13      633            636        -3      830
## 5  2013     2    18      717            700        17      830
## 6  2013     2    24      557            600        -3      830
## 7  2013     2    25      532            540        -8      830
## 8  2013     2    26      615            615         0      830
## 9  2013     2    28      621            630        -9      830
## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
## #   time_hour <dttm>

Hitta alla flygbolag som finns i c("UA", "DL") i februari eller mars och som inte var försenade.

## # A tibble: 10,346 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     2     1      520            525        -5      816
##  2  2013     2     1      527            530        -3      837
##  3  2013     2     1      554            601        -7      920
##  4  2013     2     1      558            600        -2      738
##  5  2013     2     1      559            600        -1      923
##  6  2013     2     1      600            600         0      833
##  7  2013     2     1      601            608        -7      703
##  8  2013     2     1      601            608        -7      723
##  9  2013     2     1      604            610        -6      752
## 10  2013     2     1      608            615        -7      837
## # … with 10,336 more rows, and 12 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>

3.1.1 Övning

Hur många plan…

  1. var försenade mer än 1 timme?
  2. skulle till Boston (“BOS”)
  3. lämnade JFK och var försenade
  4. lämnade JFK på julafton
  5. var försenade, men inte kom fram försent
  6. flög United Airlines (UA) eller American Airlines?

3.2 Arrange

arrange() kastar om ordningen på dina rader enligt en av dig vald variabel. Exempelvis kanske vi vill sortera data på försenade avgångar dep_delay.

## # A tibble: 336,776 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013    12     7     2040           2123       -43       40
##  2  2013     2     3     2022           2055       -33     2240
##  3  2013    11    10     1408           1440       -32     1549
##  4  2013     1    11     1900           1930       -30     2233
##  5  2013     1    29     1703           1730       -27     1947
##  6  2013     8     9      729            755       -26     1002
##  7  2013    10    23     1907           1932       -25     2143
##  8  2013     3    30     2030           2055       -25     2213
##  9  2013     3     2     1431           1455       -24     1601
## 10  2013     5     5      934            958       -24     1225
## # … with 336,766 more rows, and 12 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>

arrange() sorterar per default på sjunkande värde (ascending). Vill du sortera på stigande värde (descending) sätter du desc() runt din variabel.

## # A tibble: 336,776 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     1     9      641            900      1301     1242
##  2  2013     6    15     1432           1935      1137     1607
##  3  2013     1    10     1121           1635      1126     1239
##  4  2013     9    20     1139           1845      1014     1457
##  5  2013     7    22      845           1600      1005     1044
##  6  2013     4    10     1100           1900       960     1342
##  7  2013     3    17     2321            810       911      135
##  8  2013     6    27      959           1900       899     1236
##  9  2013     7    22     2257            759       898      121
## 10  2013    12     5      756           1700       896     1058
## # … with 336,766 more rows, and 12 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>

3.2.1 Övning

Hitta det flyg som…

  1. flög längst
  2. var mest försenat (när det kom fram)

3.3 Select

Medan arrange() kastar om raderna så kastar select() om kolumnerna. Men mest används den för att välja ut kolumner av intresse.

## # A tibble: 336,776 x 2
##    dep_delay carrier
##        <dbl> <chr>  
##  1         2 UA     
##  2         4 UA     
##  3         2 AA     
##  4        -1 B6     
##  5        -6 DL     
##  6        -4 UA     
##  7        -5 B6     
##  8        -3 EV     
##  9        -3 B6     
## 10        -2 AA     
## # … with 336,766 more rows

Om du av något skäl vill flytta en kolumn till början kan du skriva:

## # A tibble: 336,776 x 19
##    carrier  year month   day dep_time sched_dep_time dep_delay arr_time
##    <chr>   <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1 UA       2013     1     1      517            515         2      830
##  2 UA       2013     1     1      533            529         4      850
##  3 AA       2013     1     1      542            540         2      923
##  4 B6       2013     1     1      544            545        -1     1004
##  5 DL       2013     1     1      554            600        -6      812
##  6 UA       2013     1     1      554            558        -4      740
##  7 B6       2013     1     1      555            600        -5      913
##  8 EV       2013     1     1      557            600        -3      709
##  9 B6       2013     1     1      557            600        -3      838
## 10 AA       2013     1     1      558            600        -2      753
## # … with 336,766 more rows, and 11 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, flight <int>, tailnum <chr>, origin <chr>,
## #   dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
## #   time_hour <dttm>

Du kan även välja alla kolumner mellan två kolumner:

## # A tibble: 336,776 x 3
##     year month   day
##    <int> <int> <int>
##  1  2013     1     1
##  2  2013     1     1
##  3  2013     1     1
##  4  2013     1     1
##  5  2013     1     1
##  6  2013     1     1
##  7  2013     1     1
##  8  2013     1     1
##  9  2013     1     1
## 10  2013     1     1
## # … with 336,766 more rows

Genom att sätta ett minus framför variabelnamnet exkluderar du variabeln.

## # A tibble: 336,776 x 18
##    month   day dep_time sched_dep_time dep_delay arr_time sched_arr_time
##    <int> <int>    <int>          <int>     <dbl>    <int>          <int>
##  1     1     1      517            515         2      830            819
##  2     1     1      533            529         4      850            830
##  3     1     1      542            540         2      923            850
##  4     1     1      544            545        -1     1004           1022
##  5     1     1      554            600        -6      812            837
##  6     1     1      554            558        -4      740            728
##  7     1     1      555            600        -5      913            854
##  8     1     1      557            600        -3      709            723
##  9     1     1      557            600        -3      838            846
## 10     1     1      558            600        -2      753            745
## # … with 336,766 more rows, and 11 more variables: arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
## #   time_hour <dttm>

3.3.0.1 select() plus hjälpfunktioner

select() kommer med ett antal hjälpfunktioner:

  • starts_with("asd")
  • ends_with("air")
  • contains("flyg")
  • matches("asd")
  • num_range("flyg", 1:10)

De används för att identifiera kolumner baserat på text.

Exempelvis kan du hitta alla delay-kolumner med contains.

## # A tibble: 336,776 x 2
##    dep_delay arr_delay
##        <dbl>     <dbl>
##  1         2        11
##  2         4        20
##  3         2        33
##  4        -1       -18
##  5        -6       -25
##  6        -4        12
##  7        -5        19
##  8        -3       -14
##  9        -3        -8
## 10        -2         8
## # … with 336,766 more rows

3.3.0.2 rename()

En annan nyttig funktion är rename() som kort och gott döper om variabler.

Formeln är rename(data, ny_variabel = gammal_variabel)

3.3.1 Övning

  1. Som innehåller “dep”
  2. Som börjar med “dep”
  3. Döp om dep_delay till försenad_avgång

3.4 Mutate

mutate() används för att skapa nya variabler.

Exempelvis kan vi räkna ut hur mycket tid man vunnit om exempelvis flyget landar tidigare än avsett.

## # A tibble: 336,776 x 20
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     1     1      517            515         2      830
##  2  2013     1     1      533            529         4      850
##  3  2013     1     1      542            540         2      923
##  4  2013     1     1      544            545        -1     1004
##  5  2013     1     1      554            600        -6      812
##  6  2013     1     1      554            558        -4      740
##  7  2013     1     1      555            600        -5      913
##  8  2013     1     1      557            600        -3      709
##  9  2013     1     1      557            600        -3      838
## 10  2013     1     1      558            600        -2      753
## # … with 336,766 more rows, and 13 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>, beer_time <dbl>

I mutate() kan du även använda funktioner såsom mean().

## # A tibble: 336,776 x 20
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     1     1      517            515         2      830
##  2  2013     1     1      533            529         4      850
##  3  2013     1     1      542            540         2      923
##  4  2013     1     1      544            545        -1     1004
##  5  2013     1     1      554            600        -6      812
##  6  2013     1     1      554            558        -4      740
##  7  2013     1     1      555            600        -5      913
##  8  2013     1     1      557            600        -3      709
##  9  2013     1     1      557            600        -3      838
## 10  2013     1     1      558            600        -2      753
## # … with 336,766 more rows, and 13 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>, mean_delay <dbl>

3.4.1 if_else()

En vanlig funktion i databearbetning är ifelse-satser.

I R gör du det enklast med funktionen if_else() från dplyr. Det finns även en inbyggd funktion som heter ifelse() som mestadels fungerar bra men den från dplyr är något mer stabil.

Du kan använda den i mutate:

## # A tibble: 336,776 x 20
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     1     1      517            515         2      830
##  2  2013     1     1      533            529         4      850
##  3  2013     1     1      542            540         2      923
##  4  2013     1     1      544            545        -1     1004
##  5  2013     1     1      554            600        -6      812
##  6  2013     1     1      554            558        -4      740
##  7  2013     1     1      555            600        -5      913
##  8  2013     1     1      557            600        -3      709
##  9  2013     1     1      557            600        -3      838
## 10  2013     1     1      558            600        -2      753
## # … with 336,766 more rows, and 13 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>, försenad <chr>

Ibland vill man göra flera stycken if_else() i samma, exempelvis om man vill dela upp en variabel i flera kategorier beroende på ett logiskt villkor. För att göra det kan du använda funktionen case_when().

## # A tibble: 336,776 x 20
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     1     1      517            515         2      830
##  2  2013     1     1      533            529         4      850
##  3  2013     1     1      542            540         2      923
##  4  2013     1     1      544            545        -1     1004
##  5  2013     1     1      554            600        -6      812
##  6  2013     1     1      554            558        -4      740
##  7  2013     1     1      555            600        -5      913
##  8  2013     1     1      557            600        -3      709
##  9  2013     1     1      557            600        -3      838
## 10  2013     1     1      558            600        -2      753
## # … with 336,766 more rows, and 13 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>, försenad_kat <chr>

3.4.2 Andra funktioner

I mutate() kan du använda de allra flesta funktionerna i R. Här är exempel på några funktioner som kan vara nyttiga i databearbetning:

  • Funktioner för att ranka variabler: rank(), min_rank(), dense_rank(), percent_rank()
  • För att logaritmiska funktioner: log(), log10()
  • För kumulativa beräkningar: cumsum(), cummean()
  • För att bara generera radnummer: row_number()
  • För att ta observation innan eller efter: lead() och lag()
  • För skapa variabler baserat på värde i andra variabler if_else() och case_when()

3.4.3 Övningar

  1. Skapa en variabel som innehåller den totala förseningen
  2. Rangordna flygens distans. Hur hanterar du fall där distansen är lika lång?
  3. Skapa en variabel som anger om flyget går på våren, hösten, vintern eller sommaren.

3.5 Summarise

Ofta vill man summera variabler för att få ut intressant information. Exempelvis vill vi här kanske veta en rad medelvärden.

## # A tibble: 1 x 1
##   mean_dist
##       <dbl>
## 1     1040.
## # A tibble: 1 x 1
##    sum_dist
##       <dbl>
## 1 350217607
## # A tibble: 1 x 1
##    count
##    <int>
## 1 336776

Men dessa värden är inte så intressanta i sig, utan vi vill kunna göra jämförelse. Då använder vi group_by().

## # A tibble: 16 x 4
##    carrier mean_air_time mean_dep_delay mean_arr_delay
##    <chr>           <dbl>          <dbl>          <dbl>
##  1 9E               86.8          16.7           7.38 
##  2 AA              189.            8.59          0.364
##  3 AS              326.            5.80         -9.93 
##  4 B6              151.           13.0           9.46 
##  5 DL              174.            9.26          1.64 
##  6 EV               90.1          20.0          15.8  
##  7 F9              230.           20.2          21.9  
##  8 FL              101.           18.7          20.1  
##  9 HA              623.            4.90         -6.92 
## 10 MQ               91.2          10.6          10.8  
## 11 OO               83.5          12.6          11.9  
## 12 UA              212.           12.1           3.56 
## 13 US               88.6           3.78          2.13 
## 14 VX              337.           12.9           1.76 
## 15 WN              148.           17.7           9.65 
## 16 YV               65.7          19.0          15.6

I summarise() kan du använda en rad olika funktioner såsom sum() för summeringar, median() etc.

3.5.0.1 Övningar

  1. Vilken flygplats har högst medelvärde förförseningar från flygplatsen?
  2. Vilken flygplats tar emot minst flyg?

3.5.0.2 Väv ihop verben med %>%

Med %>% (som kallas för pipe and kan uttalas som and then) kan länka ihop flera uttryck i R. Det gör framför allt din kod mer lättläst.

Med %>% kan du exempelvis först filtrera, sen gruppera och till sist summera, allt i samma uttryck.

## # A tibble: 16 x 2
##    carrier mean_dep_delay
##    <chr>            <dbl>
##  1 9E               2.96 
##  2 AA               0.890
##  3 AS              -0.719
##  4 B6               3.26 
##  5 DL               1.76 
##  6 EV               4.65 
##  7 F9               5.09 
##  8 FL               4.72 
##  9 HA              -2.47 
## 10 MQ               1.48 
## 11 OO              -2.88 
## 12 UA               4.33 
## 13 US              -0.744
## 14 VX               2.70 
## 15 WN               6.60 
## 16 YV               2.25

Du läser alltså: Första tar vi flights and then filtrerar vi på dep_delay and then grupperar vi på carrier and then räknar vi ut medelvärde på dep_delay.

Vilket är mycket mer lättläst än motsvarigheten med parenteser:

3.5.0.3 count()

Du kan i summarise() räkna antalet observationer med funktionen n().

## # A tibble: 16 x 2
##    carrier count
##    <chr>   <int>
##  1 9E      18460
##  2 AA      32729
##  3 AS        714
##  4 B6      54635
##  5 DL      48110
##  6 EV      54173
##  7 F9        685
##  8 FL       3260
##  9 HA        342
## 10 MQ      26397
## 11 OO         32
## 12 UA      58665
## 13 US      20536
## 14 VX       5162
## 15 WN      12275
## 16 YV        601

Men istället för att göra det här kan du använda funktionen count()

## # A tibble: 16 x 2
## # Groups:   carrier [16]
##    carrier     n
##    <chr>   <int>
##  1 9E      18460
##  2 AA      32729
##  3 AS        714
##  4 B6      54635
##  5 DL      48110
##  6 EV      54173
##  7 F9        685
##  8 FL       3260
##  9 HA        342
## 10 MQ      26397
## 11 OO         32
## 12 UA      58665
## 13 US      20536
## 14 VX       5162
## 15 WN      12275
## 16 YV        601

3.6 sample_n()

Att göra slumpmässiga urval är en vanlig arbetsuppgift för en data scientist. Det gör du enkelt med sample_n() från dplyr.

Om du vill ta ett slumpmässigt urval om 10 från exempelvis flights gör du bara:

## # A tibble: 10 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     4    19     1858           1825        33     2307
##  2  2013     7    27     1522           1520         2     1736
##  3  2013     7    19     1053           1100        -7     1328
##  4  2013     9    17      826            830        -4     1020
##  5  2013     8     6     1716           1720        -4     1850
##  6  2013    11     3     1725           1730        -5     2013
##  7  2013     3    21     1810           1815        -5     1948
##  8  2013     9    17      752            800        -8      912
##  9  2013     7    12     1651           1655        -4     1821
## 10  2013     1    20     1257           1300        -3     1510
## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
## #   carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
## #   air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
## #   time_hour <dttm>

Om du istället vill ta ett urval som baseras på procent kan du använda sample_frac, här för 0.01%

## # A tibble: 337 x 19
##     year month   day dep_time sched_dep_time dep_delay arr_time
##    <int> <int> <int>    <int>          <int>     <dbl>    <int>
##  1  2013     4     5     2036           2035         1     2343
##  2  2013     4    21      846            850        -4     1252
##  3  2013     2    18      626            630        -4      812
##  4  2013     6     2     1445           1445         0     1734
##  5  2013     7     9     1136           1125        11     1359
##  6  2013     2    25      532            530         2      854
##  7  2013    12    31     1713           1650        23     1935
##  8  2013    12    15       NA            755        NA       NA
##  9  2013     9    11     1227           1159        28     1512
## 10  2013     1    18     1500           1457         3     1817
## # … with 327 more rows, and 12 more variables: sched_arr_time <int>,
## #   arr_delay <dbl>, carrier <chr>, flight <int>, tailnum <chr>,
## #   origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>, hour <dbl>,
## #   minute <dbl>, time_hour <dttm>

3.6.1 Övning

  1. Vilken månad ska du flyga under för att undvika förseningar?
  2. Vilken tid ska du flyga för att undvika förseningar?
  3. Hitta det flygbolag som flyger till flest destinationer, rangordna flygbolagen baserat på den informationen.