--- title: "An Introduction to Exploring Election and Census Highly Informative Data Nationally for Australia" author: "Jeremy Forbes" date: "`r Sys.Date()`" output: rmarkdown::html_vignette: toc: true vignette: > %\VignetteIndexEntry{An Introduction to Exploring Election and Census Highly Informative Data Nationally for Australia} %\VignetteEngine{knitr::rmarkdown} %\usepackage[utf8]{inputenc} --- ```{r setup, include=FALSE} knitr::opts_chunk$set(echo = TRUE, fig.align = "center") ``` # Introduction `eechidna` (Exploring Election and Census Highly Informative Data Nationally for Australia) is an R package that makes it easy to look at the data from the Australian Federal elections and Censuses that occurred between 2001 and 2019. An Australian Federal election typically takes place every three years (2001, 2004, 2007, 2010, 2013, 2016 and 2019), and a Census of Population and Housing is conducted every five years (2001, 2006, 2011, 2016). The data in this package includes voting results for each polling booth and electoral division (electorate), Census information for each electorate and maps of the electorates that were in place at the time of each event. All data in this package is obtained from the [Australian Electoral Commission](https://results.aec.gov.au/), the [Australian Bureau of Statistics](https://www.abs.gov.au/websitedbs/D3310114.nsf/home/census) and the [Australian Government](https://data.gov.au/). This vignette documents how to access these datasets, and shows a few typical methods to explore the data. # Joining election and Census data Each electoral division has a unique ID (`UniqueID`) that can be used to match together Censuses and elections. ```{r message = F} library(knitr) library(dplyr) library(eechidna) data(tpp16) data(abs2016) # Join 2016 election and Census data16 <- left_join(tpp16 %>% select(LNP_Percent, UniqueID), abs2016, by = "UniqueID") # See what it looks like data16 %>% select(LNP_Percent, DivisionNm, Population, Area, AusCitizen, MedianPersonalIncome, Renting) %>% head() %>% kable ``` # Election results For each of the six elections, three types of votes are recorded: - First preference votes: a tally of primary votes (as Australia has a preferential voting system). These datasets are labelled `fp` (e.g. `fp16` for 2016). - Two party preferred vote: a measure of preference between the two major parties - the Australian Labor Party (Labor) and the Liberal/National Coalition (Liberal). These are labelled `tpp` (e.g. `tpp16` for 2016). - Two candidate votes: a measure of preference between the two leading candidates in that electorate. These are labelled `tcp` (e.g. `tcp16` for 2016). The same voting results are available for each polling booth (of which there are around 7500). This data is obtained by calling one of the three functions; `firstpref_pollingbooth_download`, `twoparty_pollingbooth_download` and `twocand_pollingbooth_download`, all of which pull (large) datasets from github. Geocoordinates for each polling booth are also detailed in these datasets (when available). Let's have a look at some of the results from the 2016 Federal election. ```{r echo = TRUE, message = FALSE} # Load data data(fp16) data(tcp16) ``` ### Which party won the election? The data can be summarized to reveal some basic details about the election. Start by reproducing the overall result of the election by finding out which party won the most electorates according to the two candidate preferred votes. ```{r who_won, message = FALSE} who_won <- tcp16 %>% filter(Elected == "Y") %>% group_by(PartyNm) %>% tally() %>% arrange(desc(n)) # Inspect who_won %>% kable() ``` We see that Liberal/National Coalition won with 76 seats, which is just enough to secure a majority in the House of Representatives. ### Which party received the most first preference votes? An alternative way to evaluate the outcome of the election is by counting the number of ordinary first preference votes for each party (not including postal votes, preference flows, etc.). Here we can find the total number of ordinary votes for each party. ```{r total_votes_for_parties, message = F} total_votes_for_parties <- fp16 %>% select(PartyNm, OrdinaryVotes) %>% group_by(PartyNm) %>% dplyr::summarise(total_votes = sum(OrdinaryVotes, rm.na = TRUE)) %>% ungroup() %>% arrange(desc(total_votes)) # Plot the total votes for each party library(ggplot2) ggplot(total_votes_for_parties, aes(reorder(PartyNm, total_votes), total_votes)) + geom_point(size = 2) + coord_flip() + scale_y_continuous(labels = scales::comma) + theme_bw() + ylab("Total number of first preference votes") + xlab("Party") + theme(text = element_text(size=8)) ``` ### Downloading and plotting the two party preferred vote The function `twoparty_pollingbooth_download()` downloads the two party preferred vote for each polling booth in each of the six elections. Boxplots can be used to compare the distributions of this vote across the six elections. ```{r} # Download TPP for all elections tpp_pollingbooth <- twoparty_pollingbooth_download() # Plot the densities of the TPP vote in each election tpp_pollingbooth %>% filter(StateAb == "NSW") %>% ggplot(aes(x = year, y = LNP_Percent, fill = factor(year))) + geom_boxplot(alpha = 0.3) + theme_minimal() + guides(fill=F) + labs(x = "Year", y = "Two party preferred % in favour \nof the Liberal/National Coalition") ``` ```{r echo = F, message = F, out.width="600px"} #knitr::include_graphics("fig/tpp_plot.png") ``` # Census data There are four Censuses included in this package, which consist of 85 variables relating to population characteristics of each electorate. The objects `abs2001`, `abs2006`, `abs2011` and `abs2016` correspond with each of the four Censuses. A description of each variable can be found in the corresponding help files. Let's have a look at data from the 2016 Census held in `abs2016`. ```{r} # Dimensions dim(abs2016) # Preview some of the data abs2016 %>% select(DivisionNm, State, Population, Area, AusCitizen, BachelorAbv, Indigenous, MedianAge, Unemployed) %>% head %>% kable ``` ### Income and unemployment by state We can visualize measures by splitting the electorates into their respective states to gain insight into how states compare with regards to income and unemployment. ```{r} ggplot(data = abs2016, aes(x = reorder(State, -Unemployed), y = Unemployed, colour = State)) + geom_boxplot() + labs(x = "State", y = "% Unemployment") + theme_minimal() + theme(legend.position = "none") ``` Adding `geom_jitter` gives us more details about a distribution. ```{r} ggplot(data = abs2016, aes(x = reorder(State, -MedianPersonalIncome), y = MedianPersonalIncome, colour = State)) + geom_boxplot() + geom_jitter(alpha = 0.35, size = 2, width = 0.3) + theme_minimal() + theme(legend.position = "none") + labs(x = "State", y = "Median Personal Income ($)") ``` ### Ageing population Australia's ageing population is clearly seen from observing the distribution of median age across the four Censuses. ```{r} # Load data(abs2011) data(abs2006) data(abs2001) # Bind and plot bind_rows(abs2016 %>% mutate(year = "2016"), abs2011 %>% mutate(year = "2011"), abs2006 %>% mutate(year = "2006"), abs2001 %>% mutate(year = "2001")) %>% ggplot(aes(x = year, y = MedianAge, col = year)) + geom_boxplot() + geom_jitter(alpha = 0.3) + guides(col = F) + labs(x = "Year", y = "Median Age") + theme_minimal() ``` # Maps of the Australian electoral divisions Electoral divisions change regularly, so many electorates represent different regions from one election to the next. A consequence of this is that the electorate Census data (for example, in 2011) may not align with those in place for any election. As a resource for addressing this problem, and also for plotting visualizations of Australia, a map of electorates for the years 2001, 2004, 2006, 2007, 2010, 2011, 2013 and 2016 are included. The `nat_map` objects (e.g. `nat_map16`) are data frames that contain the coordinates of each electoral polygon, and can be plotted using `ggplot2` graphics. The accompanying `nat_data` object (e.g. `nat_data16`) contains some information about each electoral polygon. These objects can be loaded using the `nat_map_download` and `nat_data_download` functions, respectively. As an example, let's plot a map of electorates in the 2016 election. ```{r} library(ggthemes) nat_map16 <- nat_map_download(2016) nat_data16 <- nat_data_download(2016) ggplot(aes(map_id=id), data=nat_data16) + geom_map(aes(fill=state), map=nat_map16, col = "grey50") + expand_limits(x=nat_map16$long, y=nat_map16$lat) + theme_map() + coord_equal() ``` ### Attaching election results We can fill each electorate by the victorious party in the 2016 election. ```{r} # Get the electorate winners map.winners <- fp16 %>% filter(Elected == "Y") %>% select(DivisionNm, PartyNm) %>% merge(nat_map16, by.x="DivisionNm", by.y="elect_div") # Grouping map.winners$PartyNm <- as.character(map.winners$PartyNm) map.winners <- map.winners %>% arrange(group, order) # Combine Liberal and National parties map.winners <- map.winners %>% mutate(PartyNm = ifelse(PartyNm %in% c("NATIONAL PARTY", "LIBERAL PARTY"), "LIBERAL NATIONAL COALITION", PartyNm)) # Colour cells to match that parties colours # Order = Australian Labor Party, Independent, Katters, Lib/Nats Coalition, Palmer, The Greens partycolours = c("#FF0033", "#000000", "#CC3300", "#0066CC", "#FFFF00", "#009900") ggplot(data=map.winners) + geom_polygon(aes(x=long, y=lat, group=group, fill=PartyNm)) + scale_fill_manual(name="Political Party", values=partycolours) + theme_map() + coord_equal() + theme(legend.position="bottom") ``` However, the Australian electoral map is not conducive to chloropleth map, because most of the population concentrate in the five big cities, Sydney, Melbourne, Brisbane, Adelaide and Perth, which means that there are lot of very geographical tiny regions that contribute substantially to the house of representative composition. An alternative is to plot a dorling cartogram, where each electorate is represented by a circle, approximately in the geographic center of each electorate, with an underlying map. The major population centers need to have their center locations ballooned to make this feasible visually. The coordinates corresponding for the dorling cartogram have been pre-processed and correspond with the variables `x` and `y` in the `nat_data` datasets distributed in this package. These can be reproduced using the `aec_add_carto_f` function in the package. A better approach would be to use a cartogram to display the election results, which maintains the geographic location but make the sizes of the electorate polygons approximately equal. This is very hard to perfect for Australia because the size differential between electorates is huge, resulting in a cartogram where all sense of geography is demolished. This data is used to create the display of electoral results below. ```{r} # Get winners cart.winners <- fp16 %>% filter(Elected == "Y") %>% select(DivisionNm, PartyNm) %>% merge(nat_data16, by.x="DivisionNm", by.y="elect_div") # Combine Liberal and National parties cart.winners <- cart.winners %>% mutate(PartyNm = ifelse(PartyNm %in% c("NATIONAL PARTY", "LIBERAL PARTY"), "LIBERAL NATIONAL COALITION", PartyNm)) # Plot dorling cartogram ggplot(data=nat_map16) + geom_polygon(aes(x=long, y=lat, group=group), fill="grey90", colour="white") + geom_point(data=cart.winners, aes(x=x, y=y, colour=PartyNm), size = 0.75, alpha=0.8) + scale_colour_manual(name="Political Party", values=partycolours) + theme_map() + coord_equal() + theme(legend.position="bottom") ``` # Modelling election results using Census data An interesting exercise is to see how we can model electorate voting outcomes as a function of Census information. In the years 2001 and 2016 both a Census and election occur. The Australian Bureau of Statistics aggregate Census information to electoral boundaries that exactly match those in the election for these years, so we can join this data together and fit some models. Let's look at modelling the two party preferred vote (in favour of the Liberal party). ```{r} # Join data16 <- left_join(tpp16 %>% select(LNP_Percent, UniqueID), abs2016, by = "UniqueID") # Fit a model using all of the available population characteristics lmod <- data16 %>% select(-c(ends_with("NS"), Area, Population, DivisionNm, UniqueID, State, EmuneratedElsewhere, InternetUse, Other_NonChrist, OtherChrist, EnglishOnly)) %>% lm(LNP_Percent ~ ., data = .) # See if the variables are jointly significant library(broom) lmod %>% glance %>% kable ``` We see that electoral socio-demographics from the Census are jointly significant in predicting the two party preferred vote. ```{r} # See which variables are individually significant lmod %>% tidy %>% filter(p.value < 0.05) %>% arrange(p.value) %>% kable ``` Many variables are individually significant too. ### Imputing Census data for the elections that do not have a Census that matches exactly The 2004, 2007, 2010 and 2013 elections do not have a Census that directly match. Instead of matching these elections with a Census in neighbouring years, we have imputed Census data to correspond with the both time of the election and the electorate boundaries in place. This uses the most disaggregate Census data available (Statistical Area 1). This was done using an areal interpolation method over space and linear interpolation over time, via the `allocate_electorate` and `weighted_avg_census_sa1` functions in this package. For the 2019 election, because there only exists a Census before (2016) and not after (as of Nov, 2019), we do an areal interpolation of the 2016 SA1 Census data. The resultant (imputed) Census objects are `abs2004`, `abs2007`, `abs2010`, `abs2013` and `abs2019`. They include all of the variables in the other Census objects, aside from population, area, state and question non-response. # For more details on how the data in this package was obtained... Please see the vignettes on our [webpage](https://jforbes14.github.io/eechidna/). These detail the procedures used to obtain the election data, Census data and electorate maps, as well as the Census imputation method.