New survey
Guldølsopgave
New deadline for assignment 1
Data manipulation tools
- split-apply-combine approach to data manipulation
- tidy data
October, 2015
New survey
Guldølsopgave
New deadline for assignment 1
Data manipulation tools
Please spend the next 3 minutes completing our second survey
Do you the chance to win one of these?!
Then the non-mandatory part of Assignment 1 is for you!
The newly elected Danish government has proposed a federal budget for 2016
This is a great data visualization exercise
The assignment is not mandatory, so only do it if you're interested (but remember the incentives!)
Deadline the same as Assignment 1: October 14
Here's how Berlingske solved it - can you do better?
Find something interesting in the budget proposal for 2016
Visualize it
Send the result to me (along with the R
script and a few lines explaining what you've done)
The best answer wins a Guldøl - and I'll send your visualization to Berlingske
Data is available through the Danish Ministry of Finance
… in a horrible format
Data in nice, tidy format available here
Script here
"Herein lies the dirty secret about most data scientists' work – it's more data munging than deep learning. The best minds of my generation are deleting commas from log files, and that makes me sad. A Ph.D. is a terrible thing to waste."
Raw data
Processed data
Data manipulation involves going from raw to processed data.
This can include merging, subsetting, transforming, etc.
All steps that take you from raw to processed data should be scripted
In this part of the lecture we will work with the federal budget proposal for 2016
library("readr") df = read_csv("https://raw.githubusercontent.com/sebastianbarfort/sds/gh-pages/data/finanslov_tidy.csv")
Some nice guy has already cleaned this data for you
Useful functions:
str
: displays the structure of your data framehead
: displays the first rowssummary
: gives summary statisticsglimpse
(from the dplyr
package): modern alternative to str
str
str(df)
## Classes 'tbl_df', 'tbl' and 'data.frame': 8430 obs. of 6 variables: ## $ paragraf : chr "Dronningen " "Medlemmer af det kongelige hus m.fl. " "Folketinget " "Folketinget " ... ## $ hovedomrode: chr "Statsydelse " "Ã…rpenge mv. " "Udgifter ved Folketinget " "Udgifter ved Folketinget " ... ## $ aktivitet : chr "Statsydelse " "Ã…rpenge mv. " "Folketinget " "Folketinget " ... ## $ hovedkonto : chr "Statsydelse " "Ã…rpenge mv. " "Folketinget " "Folketingets medlemmer " ... ## $ aar : int 2014 2014 2014 2014 2014 2014 2014 2014 2014 2014 ... ## $ udgift : num 77.7 26.4 387.8 264.2 6.5 ...
head
head(df)
## paragraf hovedomrode ## 1 Dronningen Statsydelse ## 2 Medlemmer af det kongelige hus m.fl. Ã…rpenge mv. ## 3 Folketinget Udgifter ved Folketinget ## 4 Folketinget Udgifter ved Folketinget ## 5 Folketinget Udgifter ved Folketinget ## 6 Folketinget Udgifter ved Folketinget ## aktivitet hovedkonto aar udgift ## 1 Statsydelse Statsydelse 2014 77.7 ## 2 Ã…rpenge mv. Ã…rpenge mv. 2014 26.4 ## 3 Folketinget Folketinget 2014 387.8 ## 4 Folketinget Folketingets medlemmer 2014 264.2 ## 5 Folketinget Erhvervelse af medlemsboliger 2014 6.5 ## 6 Folketinget Medlemsboliger 2014 2.2
summary
summary(df)
## paragraf hovedomrode aktivitet ## Length:8430 Length:8430 Length:8430 ## Class :character Class :character Class :character ## Mode :character Mode :character Mode :character ## ## ## ## hovedkonto aar udgift ## Length:8430 Min. :2014 Min. :-306424.10 ## Class :character 1st Qu.:2015 1st Qu.: 0.00 ## Mode :character Median :2016 Median : 7.00 ## Mean :2016 Mean : 223.18 ## 3rd Qu.:2018 3rd Qu.: 89.95 ## Max. :2019 Max. : 132541.40
glimpse
library("dplyr") glimpse(df)
## Observations: 8,430 ## Variables: 6 ## $ paragraf (chr) "Dronningen ", "Medlemmer af det kongelige hus m.f... ## $ hovedomrode (chr) "Statsydelse ", "Ã…rpenge mv. ", "Udgifter ved Folk... ## $ aktivitet (chr) "Statsydelse ", "Ã…rpenge mv. ", "Folketinget ", "F... ## $ hovedkonto (chr) "Statsydelse ", "Ã…rpenge mv. ", "Folketinget ", "F... ## $ aar (int) 2014, 2014, 2014, 2014, 2014, 2014, 2014, 2014, 20... ## $ udgift (dbl) 77.7, 26.4, 387.8, 264.2, 6.5, 2.2, 63.3, 5.0, 202...
Many data analysis problems involve the application of a split-apply-combine strategy, where you break up a big problem into manageable pieces, opereate on each piece independetly and then put the pieces back together
dplyr
packagedplyr
: (efficiently) split-apply-combine for data frames
Verbs a verb is a function that takes a data frame as it's first argument
filter
: select rowsarrange
: order rowsselect
: select columnsrename
: rename columnsdistinct
: find distinct rowsmutate
: add new variablessummarise
: summarize across a data setsample_n
: sample from a data setfilter
function Ifilter(df, udgift == min(udgift))
## Source: local data frame [1 x 6] ## ## paragraf hovedomrode aktivitet ## (chr) (chr) (chr) ## 1 Skatter og afgifter Skatter på indkomst og formue Personskatter ## Variables not shown: hovedkonto (chr), aar (int), udgift (dbl)
filter(df, paragraf == "Skatter og afgifter ")
## Source: local data frame [174 x 6] ## ## paragraf hovedomrode ## (chr) (chr) ## 1 Skatter og afgifter Skatter på indkomst og formue ## 2 Skatter og afgifter Skatter på indkomst og formue ## 3 Skatter og afgifter Skatter på indkomst og formue ## 4 Skatter og afgifter Skatter på indkomst og formue ## 5 Skatter og afgifter Skatter på indkomst og formue ## 6 Skatter og afgifter Skatter på indkomst og formue ## 7 Skatter og afgifter Skatter på indkomst og formue ## 8 Skatter og afgifter Skatter på indkomst og formue ## 9 Skatter og afgifter Told- og forbrugsafgifter ## 10 Skatter og afgifter Told- og forbrugsafgifter ## .. ... ... ## Variables not shown: aktivitet (chr), hovedkonto (chr), aar (int), udgift ## (dbl)
and
You can easily combine conditions
filter(df, paragraf == "Skatter og afgifter " & aktivitet == "Personskatter ")
## Source: local data frame [12 x 6] ## ## paragraf hovedomrode aktivitet ## (chr) (chr) (chr) ## 1 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 2 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 3 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 4 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 5 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 6 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 7 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 8 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 9 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 10 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 11 Skatter og afgifter Skatter på indkomst og formue Personskatter ## 12 Skatter og afgifter Skatter på indkomst og formue Personskatter ## Variables not shown: hovedkonto (chr), aar (int), udgift (dbl)
or
filter(df, paragraf == "Skatter og afgifter " | aktivitet == "Personskatter ")
## Source: local data frame [174 x 6] ## ## paragraf hovedomrode ## (chr) (chr) ## 1 Skatter og afgifter Skatter på indkomst og formue ## 2 Skatter og afgifter Skatter på indkomst og formue ## 3 Skatter og afgifter Skatter på indkomst og formue ## 4 Skatter og afgifter Skatter på indkomst og formue ## 5 Skatter og afgifter Skatter på indkomst og formue ## 6 Skatter og afgifter Skatter på indkomst og formue ## 7 Skatter og afgifter Skatter på indkomst og formue ## 8 Skatter og afgifter Skatter på indkomst og formue ## 9 Skatter og afgifter Told- og forbrugsafgifter ## 10 Skatter og afgifter Told- og forbrugsafgifter ## .. ... ... ## Variables not shown: aktivitet (chr), hovedkonto (chr), aar (int), udgift ## (dbl)
select
functionselect(df, aar, udgift)
## Source: local data frame [8,430 x 2] ## ## aar udgift ## (int) (dbl) ## 1 2014 77.7 ## 2 2014 26.4 ## 3 2014 387.8 ## 4 2014 264.2 ## 5 2014 6.5 ## 6 2014 2.2 ## 7 2014 63.3 ## 8 2014 5.0 ## 9 2014 202.5 ## 10 2014 76.7 ## .. ... ...
arrange
functionarrange(df, hovedomrode, udgift)
## Source: local data frame [8,430 x 6] ## ## paragraf hovedomrode ## (chr) (chr) ## 1 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 2 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 3 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 4 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 5 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 6 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 7 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 8 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 9 Min. for Børn, Undervisning og Ligestilling Administration mv. ## 10 Min. for Børn, Undervisning og Ligestilling Administration mv. ## .. ... ... ## Variables not shown: aktivitet (chr), hovedkonto (chr), aar (int), udgift ## (dbl)
arrange(df, -aar)
## Source: local data frame [8,430 x 6] ## ## paragraf ## (chr) ## 1 Dronningen ## 2 Medlemmer af det kongelige hus m.fl. ## 3 Folketinget ## 4 Folketinget ## 5 Folketinget ## 6 Folketinget ## 7 Folketinget ## 8 Folketinget ## 9 Folketinget ## 10 Folketinget ## .. ... ## Variables not shown: hovedomrode (chr), aktivitet (chr), hovedkonto (chr), ## aar (int), udgift (dbl)
mutate
functionmutate
let's you add new variables to your data frame
df.mutated = mutate(df, newVar = udgift/2) select(df.mutated, newVar, udgift)
## Source: local data frame [8,430 x 2] ## ## newVar udgift ## (dbl) (dbl) ## 1 38.85 77.7 ## 2 13.20 26.4 ## 3 193.90 387.8 ## 4 132.10 264.2 ## 5 3.25 6.5 ## 6 1.10 2.2 ## 7 31.65 63.3 ## 8 2.50 5.0 ## 9 101.25 202.5 ## 10 38.35 76.7 ## .. ... ...
sample_n
functionsample_n(df, 3)
## Source: local data frame [3 x 6] ## ## paragraf hovedomrode ## (chr) (chr) ## 1 Beskæftigelsesministeriet Arbejdsmarkedsservice ## 2 Finansministeriet Grønland og Færøerne ## 3 Uddannelses- og Forskningsministeriet Støtteordninger ## Variables not shown: aktivitet (chr), hovedkonto (chr), aar (int), udgift ## (dbl)
The pipe operator %>%
(RStudio has keyboard shortcuts, learn to use them!) let's you write sequences instead of nested functions
x %>% f(y)
-> f(x,y)
x %>% f(z, .)
-> f(z, x)
Read %>%
as "then". First do this, then do this, etc…
It's implemented in R
by a Danish econometrician
dplyr
and the pipedplyr
is designed to work with the pipe.
So
df %>% select(aar, udgift) %>% filter(aar == 2014)
returns the same as
filter(select(df, aar, udgift), aar == 2014)
Show me a random sample of the data from 2014, where paragraf == Folketinget
and udgift
is above the mean.
df.1 = filter(df, aar == 2014 & paragraf == "Folketinget ") df.2 = filter(df.1, udgift > mean(udgift, na.rm = TRUE)) df.3 = sample_n(df.2, 3) df.3
## Source: local data frame [3 x 6] ## ## paragraf hovedomrode ## (chr) (chr) ## 1 Folketinget Statsrevisorerne og Rigsrevisionen ## 2 Folketinget Udgifter ved Folketinget ## 3 Folketinget Udgifter ved Folketinget ## Variables not shown: aktivitet (chr), hovedkonto (chr), aar (int), udgift ## (dbl)
df %>% filter(aar == 2014 & paragraf == "Folketinget ") %>% filter(udgift > mean(udgift, na.rm = TRUE)) %>% sample_n(3)
## Source: local data frame [3 x 6] ## ## paragraf hovedomrode ## (chr) (chr) ## 1 Folketinget Udgifter ved Folketinget ## 2 Folketinget Udgifter ved Folketinget ## 3 Folketinget Statsrevisorerne og Rigsrevisionen ## Variables not shown: aktivitet (chr), hovedkonto (chr), aar (int), udgift ## (dbl)
Note how readable the code is. Almost like a grammer of data manipulation?
So far, we have primarily learned how to manipulate data frames.
The dplyr
package becomes really powerful when we introduce the group_by
function
group_by
breaks down a dataset into specified groups of rows. When you then apply the verbs above on the resulting object they’ll be automatically applied "by group".
Use in conjunction with mutate
(to add existing rows to your data frame) or summarise
(to create a new data frame)
mutate
/summarise
optionsmean
: mean within groupssum
: sum within groupssd
: standard deviation within groupsmax
: max within groupsn()
: number in each groupfirst
: first in grouplast
: last in groupnth(n = 3)
: nth in group (3rd here)group_by
in action IWhich ministry has the largest expenses?
df %>% filter(udgift >= 0) %>% group_by(paragraf) %>% summarise(totale.udgifter = sum(udgift, na.rm = TRUE)) %>% arrange(-totale.udgifter)
## Source: local data frame [28 x 2] ## ## paragraf totale.udgifter ## (chr) (dbl) ## 1 Beskæftigelsesministeriet 1302463.4 ## 2 Social- og Indenrigsministeriet 1232885.0 ## 3 Uddannelses- og Forskningsministeriet 298811.5 ## 4 Min. for Børn, Undervisning og Ligestilling 216024.7 ## 5 Finansministeriet 161103.4 ## 6 Pensionsvæsenet 139325.5 ## 7 Forsvarsministeriet 125691.9 ## 8 Transport- og Bygningsministeriet 112422.0 ## 9 Afdrag på statsgælden (netto) 104312.3 ## 10 Renter 103464.2 ## .. ... ...
group_by
in action IIAdd totale.udgifter
to the existing data frame
df %>% filter(udgift >= 0) %>% group_by(paragraf) %>% mutate(totale.udgifter = sum(udgift, na.rm = TRUE)) %>% select(aar, udgift, totale.udgifter)
## Source: local data frame [7,609 x 4] ## Groups: paragraf [28] ## ## paragraf aar udgift totale.udgifter ## (chr) (int) (dbl) (dbl) ## 1 Dronningen 2014 77.7 474.7 ## 2 Medlemmer af det kongelige hus m.fl. 2014 26.4 161.2 ## 3 Folketinget 2014 387.8 6137.6 ## 4 Folketinget 2014 264.2 6137.6 ## 5 Folketinget 2014 6.5 6137.6 ## 6 Folketinget 2014 2.2 6137.6 ## 7 Folketinget 2014 63.3 6137.6 ## 8 Folketinget 2014 5.0 6137.6 ## 9 Folketinget 2014 202.5 6137.6 ## 10 Folketinget 2014 76.7 6137.6 ## .. ... ... ... ...
group_by
in action IIIYou can group by several variables
df %>% filter(udgift >= 0) %>% group_by(aar, paragraf) %>% summarise(totale.udgifter = sum(udgift, na.rm = TRUE)) %>% arrange(-totale.udgifter)
## Source: local data frame [168 x 3] ## Groups: aar [6] ## ## aar paragraf totale.udgifter ## (int) (chr) (dbl) ## 1 2014 Beskæftigelsesministeriet 219491.3 ## 2 2014 Social- og Indenrigsministeriet 203209.1 ## 3 2014 Afdrag på statsgælden (netto) 68672.5 ## 4 2014 Uddannelses- og Forskningsministeriet 49393.7 ## 5 2014 Min. for Børn, Undervisning og Ligestilling 35775.8 ## 6 2014 Renter 34449.0 ## 7 2014 Finansministeriet 26022.6 ## 8 2014 Pensionsvæsenet 22896.7 ## 9 2014 Forsvarsministeriet 20232.7 ## 10 2014 Transport- og Bygningsministeriet 19597.0 ## .. ... ... ...
group_by
in action IVYou can group by several variables
df %>% filter(udgift >= 0) %>% group_by(paragraf, hovedomrode) %>% summarise(totale.udgifter = sum(udgift, na.rm = TRUE)) %>% arrange(-totale.udgifter)
## Source: local data frame [120 x 3] ## Groups: paragraf [28] ## ## paragraf ## (chr) ## 1 Afdrag på statsgælden (netto) ## 2 Beholdningsbevægelser mv. ## 3 Beholdningsbevægelser mv. ## 4 Beholdningsbevægelser mv. ## 5 Beskæftigelsesministeriet ## 6 Beskæftigelsesministeriet ## 7 Beskæftigelsesministeriet ## 8 Beskæftigelsesministeriet ## 9 Beskæftigelsesministeriet ## 10 Beskæftigelsesministeriet ## .. ... ## Variables not shown: hovedomrode (chr), totale.udgifter (dbl)
Merging two data sets can be tricky and depends on your needs. It's important to think about what you want before joining.
https://stat545-ubc.github.io/bit001_dplyr-cheatsheet.html
superheroes = c(" name, alignment, gender, publisher", " Magneto, bad, male, Marvel", " Storm, good, female, Marvel", "Mystique, bad, female, Marvel", " Batman, good, male, DC", " Joker, bad, male, DC", "Catwoman, bad, female, DC", " Hellboy, good, male, Dark Horse Comics") superheroes = read.csv(text = superheroes, strip.white = TRUE) head(superheroes)
## name alignment gender publisher ## 1 Magneto bad male Marvel ## 2 Storm good female Marvel ## 3 Mystique bad female Marvel ## 4 Batman good male DC ## 5 Joker bad male DC ## 6 Catwoman bad female DC
publishers = c("publisher, yr_founded", " DC, 1934", " Marvel, 1939", " Image, 1992") publishers = read.csv(text = publishers, strip.white = TRUE) head(publishers)
## publisher yr_founded ## 1 DC 1934 ## 2 Marvel 1939 ## 3 Image 1992
ijsp = inner_join(superheroes, publishers)
## Joining by: "publisher"
## Warning in inner_join_impl(x, y, by$x, by$y): joining factors with ## different levels, coercing to character vector
ijsp
## name alignment gender publisher yr_founded ## 1 Magneto bad male Marvel 1939 ## 2 Storm good female Marvel 1939 ## 3 Mystique bad female Marvel 1939 ## 4 Batman good male DC 1934 ## 5 Joker bad male DC 1934 ## 6 Catwoman bad female DC 1934
ljsp = left_join(superheroes, publishers)
## Joining by: "publisher"
## Warning in left_join_impl(x, y, by$x, by$y): joining factors with different ## levels, coercing to character vector
ljsp
## name alignment gender publisher yr_founded ## 1 Magneto bad male Marvel 1939 ## 2 Storm good female Marvel 1939 ## 3 Mystique bad female Marvel 1939 ## 4 Batman good male DC 1934 ## 5 Joker bad male DC 1934 ## 6 Catwoman bad female DC 1934 ## 7 Hellboy good male Dark Horse Comics NA
superheroes = mutate(superheroes, seblikes = (publisher=="Marvel")) publishers = mutate(publishers, seb = (publisher == "Marvel")) ij2 = inner_join(superheroes,publishers)
## Joining by: "publisher"
## Warning in inner_join_impl(x, y, by$x, by$y): joining factors with ## different levels, coercing to character vector
ij2
## name alignment gender publisher seblikes yr_founded seb ## 1 Magneto bad male Marvel TRUE 1939 TRUE ## 2 Storm good female Marvel TRUE 1939 TRUE ## 3 Mystique bad female Marvel TRUE 1939 TRUE ## 4 Batman good male DC FALSE 1934 FALSE ## 5 Joker bad male DC FALSE 1934 FALSE ## 6 Catwoman bad female DC FALSE 1934 FALSE
ij2 = inner_join(superheroes,publishers, by=c("publisher"="publisher", "seblikes"="seb"))
## Warning in inner_join_impl(x, y, by$x, by$y): joining factors with ## different levels, coercing to character vector
ij2
## name alignment gender publisher seblikes yr_founded ## 1 Magneto bad male Marvel TRUE 1939 ## 2 Storm good female Marvel TRUE 1939 ## 3 Mystique bad female Marvel TRUE 1939 ## 4 Batman good male DC FALSE 1934 ## 5 Joker bad male DC FALSE 1934 ## 6 Catwoman bad female DC FALSE 1934
strsplit
functionSplit the elements of a character vector
x
into substrings according to the matches to substring split within them.
strsplit(names(df), "t")
## [[1]] ## [1] "paragraf" ## ## [[2]] ## [1] "hovedomrode" ## ## [[3]] ## [1] "ak" "ivi" "e" ## ## [[4]] ## [1] "hovedkon" "o" ## ## [[5]] ## [1] "aar" ## ## [[6]] ## [1] "udgif"
gsub
functiongsub("t", " ", names(df))
## [1] "paragraf" "hovedomrode" "ak ivi e " "hovedkon o" "aar" ## [6] "udgif "
substr
functionExtract or replace substrings in a character vector.
substr(names(df), 1, 3)
## [1] "par" "hov" "akt" "hov" "aar" "udg"
grep
functionRegular expression matching
grep("t", names(df))
## [1] 3 4 6
grepl("t", names(df))
## [1] FALSE FALSE TRUE TRUE FALSE TRUE
tolower
and toupper
tolower(names(df))
## [1] "paragraf" "hovedomrode" "aktivitet" "hovedkonto" "aar" ## [6] "udgift"
toupper(names(df))
## [1] "PARAGRAF" "HOVEDOMRODE" "AKTIVITET" "HOVEDKONTO" "AAR" ## [6] "UDGIFT"
stringr
packagelibrary("stringr") str_detect(names(df), "t")
## [1] FALSE FALSE TRUE TRUE FALSE TRUE
str_subset(names(df), "t")
## [1] "aktivitet" "hovedkonto" "udgift"
str_trim("Sebastian ")
## [1] "Sebastian"
paste0("Sebastian", "Barfort")
## [1] "SebastianBarfort"
nchar("SebastianBarfort")
## [1] 16
Tidy data
Regular expressions