Pre-Course Assignment

The goal is to test your software installation, to demonstrate competency in Markdown, and in the basics of ggplot.

Task 2: gapminder country comparison

glimpse(gapminder)
## Rows: 1,704
## Columns: 6
## $ country   <fct> "Afghanistan", "Afghanistan", "Afghanistan", "Afghanistan", …
## $ continent <fct> Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, Asia, …
## $ year      <int> 1952, 1957, 1962, 1967, 1972, 1977, 1982, 1987, 1992, 1997, …
## $ lifeExp   <dbl> 28.801, 30.332, 31.997, 34.020, 36.088, 38.438, 39.854, 40.8…
## $ pop       <int> 8425333, 9240934, 10267083, 11537966, 13079460, 14880372, 12…
## $ gdpPercap <dbl> 779.4453, 820.8530, 853.1007, 836.1971, 739.9811, 786.1134, …
head(gapminder, 20) # look at the first 20 rows of the dataframe
## # A tibble: 20 × 6
##    country     continent  year lifeExp      pop gdpPercap
##    <fct>       <fct>     <int>   <dbl>    <int>     <dbl>
##  1 Afghanistan Asia       1952    28.8  8425333      779.
##  2 Afghanistan Asia       1957    30.3  9240934      821.
##  3 Afghanistan Asia       1962    32.0 10267083      853.
##  4 Afghanistan Asia       1967    34.0 11537966      836.
##  5 Afghanistan Asia       1972    36.1 13079460      740.
##  6 Afghanistan Asia       1977    38.4 14880372      786.
##  7 Afghanistan Asia       1982    39.9 12881816      978.
##  8 Afghanistan Asia       1987    40.8 13867957      852.
##  9 Afghanistan Asia       1992    41.7 16317921      649.
## 10 Afghanistan Asia       1997    41.8 22227415      635.
## 11 Afghanistan Asia       2002    42.1 25268405      727.
## 12 Afghanistan Asia       2007    43.8 31889923      975.
## 13 Albania     Europe     1952    55.2  1282697     1601.
## 14 Albania     Europe     1957    59.3  1476505     1942.
## 15 Albania     Europe     1962    64.8  1728137     2313.
## 16 Albania     Europe     1967    66.2  1984060     2760.
## 17 Albania     Europe     1972    67.7  2263554     3313.
## 18 Albania     Europe     1977    68.9  2509048     3533.
## 19 Albania     Europe     1982    70.4  2780097     3631.
## 20 Albania     Europe     1987    72    3075321     3739.
country_data <- gapminder %>% 
            filter(country == "Italy") # just choosing Italy, as this is where I come from

continent_data <- gapminder %>% 
            filter(continent == "Europe")
plot1 <- ggplot(data = country_data, mapping = aes(x = year, y = lifeExp))+
  geom_point() +
  geom_smooth(se = FALSE)+
  NULL 
plot1 <- plot1 +
  labs(title = "Life Expectancy in Italy from 1952 to 2007",
      x = "Year",
      y = "Life Expectancy") +
  NULL


plot1
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

 ggplot(data = continent_data, mapping = aes(x =  year, y = lifeExp  , colour = country, group = country))+
  geom_point() + 
  geom_smooth(se = FALSE) +
  NULL +
  ggtitle("Life Expectancy in Europe from 1952 to 2007")
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

ggplot(data = gapminder , mapping = aes(x = year, y = lifeExp, colour= country))+
  geom_point() + 
  geom_smooth(se = FALSE) +
  facet_wrap(~continent) +
  theme(legend.position="none") + #remove all legends
  NULL
## `geom_smooth()` using method = 'loess' and formula 'y ~ x'

With only minor exemptions (e.g. bump in Europe in the 80s, probably Baltic states), it is visible that life expectancy in the Americas, Europe and Oceania has increased fairly steadily. This data supports the common believe, that advancements in medicine and hygiene, stable nutrition supply, less wars and overall enhancements in quality of life have contributed to an increase in life expectancy.

In Asia and Africa, however, there is once again an overall trend to increasing life expectancy but fluctuations and exemptions are more common. Especially in some African countries we see a sharp decline in life expectancy starting from the 80s and 90s. It can be speculated that this is due to epidemics - especially HIV – but also due to civil wars or famines. The average life expectancy in Asia and Africa reached in 2007 is well below that of Europe and Oceania. The standard deviation is also higher, which leads to the conclusion that there are major difference among single countries.

Task 3: Brexit vote analysis

# read data directly off github repo
brexit_results <- read_csv("https://raw.githubusercontent.com/kostis-christodoulou/am01/master/data/brexit_results.csv")


glimpse(brexit_results)
## Rows: 632
## Columns: 11
## $ Seat        <chr> "Aldershot", "Aldridge-Brownhills", "Altrincham and Sale W…
## $ con_2015    <dbl> 50.592, 52.050, 52.994, 43.979, 60.788, 22.418, 52.454, 22…
## $ lab_2015    <dbl> 18.333, 22.369, 26.686, 34.781, 11.197, 41.022, 18.441, 49…
## $ ld_2015     <dbl> 8.824, 3.367, 8.383, 2.975, 7.192, 14.828, 5.984, 2.423, 1…
## $ ukip_2015   <dbl> 17.867, 19.624, 8.011, 15.887, 14.438, 21.409, 18.821, 21.…
## $ leave_share <dbl> 57.89777, 67.79635, 38.58780, 65.29912, 49.70111, 70.47289…
## $ born_in_uk  <dbl> 83.10464, 96.12207, 90.48566, 97.30437, 93.33793, 96.96214…
## $ male        <dbl> 49.89896, 48.92951, 48.90621, 49.21657, 48.00189, 49.17185…
## $ unemployed  <dbl> 3.637000, 4.553607, 3.039963, 4.261173, 2.468100, 4.742731…
## $ degree      <dbl> 13.870661, 9.974114, 28.600135, 9.336294, 18.775591, 6.085…
## $ age_18to24  <dbl> 9.406093, 7.325850, 6.437453, 7.747801, 5.734730, 8.209863…
# histogram
ggplot(brexit_results, aes(x = leave_share)) +
  geom_histogram(binwidth = 2.5) +
  labs(title = "Histogram of leave % during Brexit Vote",
       subtitle = "All constituencies",
       x = "leave %-share",
       y = "# constituencies")

# density plot-- think smoothed histogram
ggplot(brexit_results, aes(x = leave_share)) +
  geom_density() + 
  labs(title = "Density plot of leave % during Brexit Vote",
       subtitle = "All constituencies",
       x = "leave %-share",
       y = "Constituencies density")

# The empirical cumulative distribution function (ECDF) 
ggplot(brexit_results, aes(x = leave_share)) +
  stat_ecdf(geom = "step", pad = FALSE) +
  scale_y_continuous(labels = scales::percent) +
  labs(title = "Cumulative Distribution of leave % during Brexit Vote",
       subtitle = "All constituencies",
       x = "leave %-share",
       y = "Cumulated share of constituencies")

brexit_results %>% 
  select(leave_share, born_in_uk) %>% 
  cor()
##             leave_share born_in_uk
## leave_share   1.0000000  0.4934295
## born_in_uk    0.4934295  1.0000000

The correlation is almost 0.5, which shows that the two variables are positively correlated.

ggplot(brexit_results, aes(x = born_in_uk, y = leave_share)) +
  geom_point(alpha=0.3) +
  
  # add a smoothing line, and use method="lm" to get the best straight-line
  geom_smooth(method = "lm") + 
  
  # use a white background and frame the plot with a black box
  theme_bw() +
  
  # Add titles
  labs(title = "Relationship between native borne residents and leave share",
       subtitle = "All constituencies",
       x = "native borne uk residents %-share",
       y = "leave %-share") +
  NULL
## `geom_smooth()` using formula 'y ~ x'

The graph shows a correlation (0.5) between the % of native born residents within a constituency and its leave %-share. A large bulk of constituencies has a born_in_uk rate of 90% and above whereby the average of leave %-share among this majority-group seems to lie around 55%. In constituencies where the % of native born residents is below 80% on the other hand, the average submitted votes would have kept the UK within the EU. These findings support the statement that patriotic, UK born citizens are more likely to oppose the EU and its regulations (among which looser immigration policies).

However, a significant standard deviation can be observed across all %-shares of native borne uk residents. In other words, this means that two constituencies with a similiar 80% “native share” have voted in favor of Brexit with 70% as well as 20%. Thus, it is suggested not to regard native born % and fear of immigration as only explanation for the Brexit outcome.

Task 4: Animal rescue incidents attended by the London Fire Brigade

url <- "https://data.london.gov.uk/download/animal-rescue-incidents-attended-by-lfb/f43b485e-fb35-419c-aa7a-fa75676e5835/Animal%20Rescue%20incidents%20attended%20by%20LFB%20from%20Jan%202009.csv"


animal_rescue <- read_csv(url,
                          locale = locale(encoding = "CP1252")) %>% 
  janitor::clean_names()


glimpse(animal_rescue)
## Rows: 8,751
## Columns: 31
## $ incident_number               <chr> "139091", "275091", "2075091", "2872091"…
## $ date_time_of_call             <chr> "01/01/2009 03:01", "01/01/2009 08:51", …
## $ cal_year                      <dbl> 2009, 2009, 2009, 2009, 2009, 2009, 2009…
## $ fin_year                      <chr> "2008/09", "2008/09", "2008/09", "2008/0…
## $ type_of_incident              <chr> "Special Service", "Special Service", "S…
## $ pump_count                    <chr> "1", "1", "1", "1", "1", "1", "1", "1", …
## $ pump_hours_total              <chr> "2", "1", "1", "1", "1", "1", "1", "1", …
## $ hourly_notional_cost          <dbl> 255, 255, 255, 255, 255, 255, 255, 255, …
## $ incident_notional_cost        <chr> "510", "255", "255", "255", "255", "255"…
## $ final_description             <chr> "Redacted", "Redacted", "Redacted", "Red…
## $ animal_group_parent           <chr> "Dog", "Fox", "Dog", "Horse", "Rabbit", …
## $ originof_call                 <chr> "Person (land line)", "Person (land line…
## $ property_type                 <chr> "House - single occupancy", "Railings", …
## $ property_category             <chr> "Dwelling", "Outdoor Structure", "Outdoo…
## $ special_service_type_category <chr> "Other animal assistance", "Other animal…
## $ special_service_type          <chr> "Animal assistance involving livestock -…
## $ ward_code                     <chr> "E05011467", "E05000169", "E05000558", "…
## $ ward                          <chr> "Crystal Palace & Upper Norwood", "Woods…
## $ borough_code                  <chr> "E09000008", "E09000008", "E09000029", "…
## $ borough                       <chr> "Croydon", "Croydon", "Sutton", "Hilling…
## $ stn_ground_name               <chr> "Norbury", "Woodside", "Wallington", "Ru…
## $ uprn                          <chr> "NULL", "NULL", "NULL", "1.00E+11", "NUL…
## $ street                        <chr> "Waddington Way", "Grasmere Road", "Mill…
## $ usrn                          <chr> "20500146", "NULL", "NULL", "21401484", …
## $ postcode_district             <chr> "SE19", "SE25", "SM5", "UB9", "RM3", "RM…
## $ easting_m                     <chr> "NULL", "534785", "528041", "504689", "N…
## $ northing_m                    <chr> "NULL", "167546", "164923", "190685", "N…
## $ easting_rounded               <dbl> 532350, 534750, 528050, 504650, 554650, …
## $ northing_rounded              <dbl> 170050, 167550, 164950, 190650, 192350, …
## $ latitude                      <chr> "NULL", "51.39095371", "51.36894086", "5…
## $ longitude                     <chr> "NULL", "-0.064166887", "-0.161985191", …
animal_rescue %>% 
  dplyr::group_by(cal_year) %>% 
  summarise(count=n())
## # A tibble: 14 × 2
##    cal_year count
##       <dbl> <int>
##  1     2009   568
##  2     2010   611
##  3     2011   620
##  4     2012   603
##  5     2013   585
##  6     2014   583
##  7     2015   540
##  8     2016   604
##  9     2017   539
## 10     2018   610
## 11     2019   604
## 12     2020   758
## 13     2021   885
## 14     2022   641
animal_rescue %>% 
  count(cal_year, name="count")
## # A tibble: 14 × 2
##    cal_year count
##       <dbl> <int>
##  1     2009   568
##  2     2010   611
##  3     2011   620
##  4     2012   603
##  5     2013   585
##  6     2014   583
##  7     2015   540
##  8     2016   604
##  9     2017   539
## 10     2018   610
## 11     2019   604
## 12     2020   758
## 13     2021   885
## 14     2022   641
animal_rescue %>% 
  group_by(animal_group_parent) %>% 
  
  #group_by and summarise will produce a new column with the count in each animal group
  summarise(count = n()) %>% 
  
  # mutate adds a new column; here we calculate the percentage
  mutate(percent = round(100*count/sum(count),2)) %>% 
  
  # arrange() sorts the data by percent. Since the default sorting is min to max and we would like to see it sorted
  # in descending order (max to min), we use arrange(desc()) 
  arrange(desc(percent))
## # A tibble: 28 × 3
##    animal_group_parent              count percent
##    <chr>                            <int>   <dbl>
##  1 Cat                               4232   48.4 
##  2 Bird                              1803   20.6 
##  3 Dog                               1341   15.3 
##  4 Fox                                455    5.2 
##  5 Unknown - Domestic Animal Or Pet   215    2.46
##  6 Horse                              201    2.3 
##  7 Deer                               152    1.74
##  8 Unknown - Wild Animal              102    1.17
##  9 Squirrel                            75    0.86
## 10 Unknown - Heavy Livestock Animal    50    0.57
## # … with 18 more rows
animal_rescue %>% 
  
  #count does the same thing as group_by and summarise
  # name = "count" will call the column with the counts "count" ( exciting, I know)
  # and 'sort=TRUE' will sort them from max to min
  count(animal_group_parent, name="count", sort=TRUE) %>% 
  mutate(percent = round(100*count/sum(count),2))
## # A tibble: 28 × 3
##    animal_group_parent              count percent
##    <chr>                            <int>   <dbl>
##  1 Cat                               4232   48.4 
##  2 Bird                              1803   20.6 
##  3 Dog                               1341   15.3 
##  4 Fox                                455    5.2 
##  5 Unknown - Domestic Animal Or Pet   215    2.46
##  6 Horse                              201    2.3 
##  7 Deer                               152    1.74
##  8 Unknown - Wild Animal              102    1.17
##  9 Squirrel                            75    0.86
## 10 Unknown - Heavy Livestock Animal    50    0.57
## # … with 18 more rows
# what type is variable incident_notional_cost from dataframe `animal_rescue`
typeof(animal_rescue$incident_notional_cost)
## [1] "character"
# readr::parse_number() will convert any numerical values stored as characters into numbers
animal_rescue <- animal_rescue %>% 

  # we use mutate() to use the parse_number() function and overwrite the same variable
  mutate(incident_notional_cost = parse_number(incident_notional_cost))

# incident_notional_cost from dataframe `animal_rescue` is now 'double' or numeric
typeof(animal_rescue$incident_notional_cost)
## [1] "double"
animal_rescue %>% 
  
  # group by animal_group_parent
  group_by(animal_group_parent) %>% 
  
  # filter resulting data, so each group has at least 6 observations
  filter(n()>6) %>% 
  
  # summarise() will collapse all values into 3 values: the mean, median, and count  
  # we use na.rm=TRUE to make sure we remove any NAs, or cases where we do not have the incident cos
  summarise(mean_incident_cost = mean (incident_notional_cost, na.rm=TRUE),
            median_incident_cost = median (incident_notional_cost, na.rm=TRUE),
            sd_incident_cost = sd (incident_notional_cost, na.rm=TRUE),
            min_incident_cost = min (incident_notional_cost, na.rm=TRUE),
            max_incident_cost = max (incident_notional_cost, na.rm=TRUE),
            count = n()) %>% 
  
  # sort the resulting data in descending order. You choose whether to sort by count or mean cost.
  arrange(desc(mean_incident_cost))
## # A tibble: 17 × 7
##    animal_group_parent             mean_…¹ media…² sd_in…³ min_i…⁴ max_i…⁵ count
##    <chr>                             <dbl>   <dbl>   <dbl>   <dbl>   <dbl> <int>
##  1 Horse                              735.    596    536.      255    3480   201
##  2 Cow                                599.    436    451.      260    1560     9
##  3 Unknown - Wild Animal              422.    333    318.      260    2296   102
##  4 Deer                               421.    339    276.      260    2340   152
##  5 Fox                                382.    339    200.      255    2034   455
##  6 Snake                              375.    352    122.      260     704    20
##  7 Unknown - Heavy Livestock Anim…    374.    260    263.      255    1560    50
##  8 Sheep                              355.    339    114.      255     596     7
##  9 Dog                                353.    326    182.        0    3168  1341
## 10 Cat                                351.    326    163.        0    3912  4232
## 11 Bird                               349.    328    138.      255    1788  1803
## 12 Unknown - Domestic Animal Or P…    331.    298    119.      255    1300   215
## 13 cat                                329.    310.    87.4     260     596    20
## 14 Squirrel                           318.    328     55.6     255     678    75
## 15 Hamster                            317.    290     92.5     260     652    17
## 16 Rabbit                             315.    330.    34.4     255     364    16
## 17 Ferret                             314.    336     41.1     260     364    10
## # … with abbreviated variable names ¹​mean_incident_cost, ²​median_incident_cost,
## #   ³​sd_incident_cost, ⁴​min_incident_cost, ⁵​max_incident_cost

Median usually lower, this lets us conclude that we have outliers on the top end of the cost range (single animals very difficult to rescue).

# base_plot
base_plot <- animal_rescue %>% 
  group_by(animal_group_parent) %>% 
  filter(n()>6) %>% 
  ggplot(aes(x=incident_notional_cost))+
  facet_wrap(~animal_group_parent, scales = "free")+
  theme_bw()

base_plot + geom_histogram()

base_plot + geom_density()

base_plot + geom_boxplot()

base_plot + stat_ecdf(geom = "step", pad = FALSE) +
  scale_y_continuous(labels = scales::percent)

Variability is best shown in the boxplot graph as single outliers get lost in the other graphs due to the significant number of observations.  As expected, large animals such as horses, cows, and deer are on average the most expensive to rescue. It is speculated that it takes more working-hours and machinery to recover heavier animals. While the minimal cost is similiar across the categories, the maximum cost seams to have some positive correlation with animal size.  Correspondingly, the sd is significant in these categories, with the maximum value as high as 10x the median rescue cost. Animals such as Rabbits and Ferrets have the least outliers, a fact that could lead to the conclusion that the rescue effort for these animals is fairly predictable.