Tidy Tuesday - 18-02-2020

February 20, 2020

It’s been quite a while since I took part in Tidy Tuesday, and this one is slightly late in the week but good to get back into the habbit of doing some different analysis outside of work.

The rest of this post will be pretty much a record of what I was thinking as I did my initial analysis. Hoping to spend an hour or two on this in total and see where I end up…

Read in the data:

Following the guidelines from the official repo, I can grab the data using the tidytuedayR package - see here

# Install the tidytuesday package to get the data:
# devtools::install_github("thebioengineer/tidytuesdayR")
library(tidytuesdayR)
library(tidyverse)

dat <- tidytuesdayR::tt_load('2020-02-18')$food_consumption

First take a look at the first few rows of the file:

head(dat)
## # A tibble: 6 x 4
##   country   food_category consumption co2_emmission
##   <chr>     <chr>               <dbl>         <dbl>
## 1 Argentina Pork                10.5          37.2 
## 2 Argentina Poultry             38.7          41.5 
## 3 Argentina Beef                55.5        1712   
## 4 Argentina Lamb & Goat          1.56         54.6 
## 5 Argentina Fish                 4.36          6.96
## 6 Argentina Eggs                11.4          10.5

This looks like it is a nicely formatted table, containing values of “consumption” and “co2 emmission” split by country and food type.

Referring to the tidytuesday data dictionary, it looks like these are per person figures based on typical consumption patterns by country. Looking at the original data source we can see that the food category CO2 values are based on global median values. There is some more detail on this on the website, and it’s a reasonable approach to take. However, it’s important to think about what this means for how you use and interpet the data. Whenever stats around the pros/cons of meat vs plant based diets you can get some pretty different results based on the methodologies used, and it’s pretty common for people to pick the data source which best fits their agenda.

Generally, you tend to see that eating beef is pretty bad for the environment, but you can get some pretty different figures depending on what is included in the carbon footprint figures (e.g. clearing rainforest to replace it with cattle pasture is doubly bad) and using averages will make some countries look better/worse than they are in reality.

It’s also worth keeping in mind that there’s more to think about than just CO2, and the overall impact at a topline level may not be the same as the local impacts. For example, almond farming in California is very water intensive in an area which suffers from droughts and is seemingly having a negative impact on the insect population in that part of the world meaning replacing dairy with almond milk isn’t without consequences even if at a topline level it’s much better from a water consumption and CO2 perspective to do so (conversely continue to use local dairy products if you live in Northern Europe might be worse overall but might have a much smaller impact on the immediate local area in the short term).

Let’s get back to the data - based on what I’ve read of the data, I’d expect to be able to divide the two numeric columns and then see consistent values for each food in every country:

dat %>%
  mutate(co2_per_kg=co2_emmission/consumption) %>%
  arrange(food_category,co2_per_kg) %>%
  head()
## # A tibble: 6 x 5
##   country    food_category consumption co2_emmission co2_per_kg
##   <chr>      <chr>               <dbl>         <dbl>      <dbl>
## 1 India      Beef                 0.81          25.0       30.9
## 2 Sri Lanka  Beef                 1.38          42.6       30.9
## 3 Mozambique Beef                 1.04          32.1       30.9
## 4 Togo       Beef                 1.53          47.2       30.9
## 5 Gambia     Beef                 2.16          66.6       30.9
## 6 Bulgaria   Beef                 3.84         118.        30.9

We do indeed seem to get the same value, so I can be happy I’ve understood the data dictionary.

First graph - country level differences

As the data is presented here, the most interesting metric is probably the CO2 emmissions. This is measured in kg/person/year.

Let’s take a look at how this varies by country at an overall level:

dat %>%
  group_by(country) %>%
  summarise(co2_emmission=sum(co2_emmission)) %>%
  mutate(country=as.factor(country),
         country=fct_reorder(country,co2_emmission)) %>%
  arrange(co2_emmission) -> co2_emmission_by_country

Now we have this table, we can print out the top and bottom 10 rows to see which countries appear where:

head(co2_emmission_by_country,10)
## # A tibble: 10 x 2
##    country    co2_emmission
##    <fct>              <dbl>
##  1 Mozambique          141.
##  2 Rwanda              182.
##  3 Togo                188.
##  4 Liberia             203.
##  5 Malawi              208.
##  6 Ghana               218.
##  7 Zambia              225.
##  8 Ethiopia            242.
##  9 Congo               263.
## 10 Nigeria             268.
tail(co2_emmission_by_country,10)
## # A tibble: 10 x 2
##    country     co2_emmission
##    <fct>               <dbl>
##  1 Kazakhstan          1575.
##  2 Luxembourg          1598.
##  3 Brazil              1617.
##  4 Uruguay             1635.
##  5 USA                 1719.
##  6 Iceland             1731.
##  7 New Zealand         1751.
##  8 Albania             1778.
##  9 Australia           1939.
## 10 Argentina           2172.

We can see that there are a lot of African countries with low emissions per capita, and a slightly more geographically spread out set of (mostly) richer countries at the top end of emissions per capita.

We can visualise these two sets of results using a bar graph:

windowsFonts(Raleway="Raleway")

rbind(head(co2_emmission_by_country,10),tail(co2_emmission_by_country,10)) %>%
  ggplot() +
  geom_col(aes(x=country,y=co2_emmission)) +
  coord_flip() +
  theme_minimal(base_family = "Raleway")+
  theme(panel.grid=element_blank(),
        text=element_text(colour="grey50")) +
  labs(x="",
       y="CO2 Emissions from Food\nkg per Person per Year",
       caption="Design @stevejburr - Data source: nu3.de - #tidytuesday",
       title="Per capita CO2 emissions from food vary greatly by country") 

It might also be interesting to get a sense of the distribution of emissions by country -

co2_emmission_by_country %>%
  ggplot() +
  geom_histogram(aes(x=co2_emmission),
                 binwidth = 100,
                 fill="#9b0d0d") +
  geom_jitter(aes(x=co2_emmission,y=1),height=1,width=0,
              colour="grey50") +
  theme_minimal(base_family = "Raleway")+
  theme(panel.grid=element_blank(),
        text=element_text(colour="grey50"),
        axis.text.y=element_blank()) +
  labs(x="CO2 Emissions from Food\nkg per Person per Year",
       y="",
       caption="Design @stevejburr - Data source: nu3.de - #tidytuesday",
       title="Per capita CO2 emissions from food vary greatly by country",
       subtitle="There a small number of particularly bad countries") 

Understanding what drives country variation:

Given that the values used for each food are the same by country in this dataset, then the mix and amount of food consumed must drive all of the differences (this is still likely to be the case even if per country food figures were available).

First, let’s look at total kgs of food per person by country, and see how this is correlated with total CO2 emissions:

dat %>%
  group_by(country) %>%
  summarise(consumption=sum(consumption)) %>%
  left_join(co2_emmission_by_country,by="country") %>%
  ggplot(aes(x=consumption,y=co2_emmission)) +
  geom_point(colour="grey50") +
  geom_smooth(method="lm",se=FALSE,colour="#9b0d0d") +
  theme_minimal(base_family = "Raleway")+
  theme(panel.grid=element_blank(),
        text=element_text(colour="grey50"),
        axis.text.y=element_blank()) +
  labs(x="Total kg Food per Person Per Year",
       y="CO2 Emissions from Food\nkg per Person per Year",
       caption="Design @stevejburr - Data source: nu3.de - #tidytuesday",
       title="A lot of the variation in emissions can be explained by total consumption",
       subtitle="But the relationship isn't perfect, mix must play a part") 

To understand mix, let’s look at % of consumption by food type (in kgs):

dat %>%
  group_by(country) %>%
  mutate(percent=consumption/sum(consumption)) %>%
  select(country,food_category,percent) %>%
  left_join(co2_emmission_by_country,by="country") -> mix_data

mix_data %>%
  group_by(food_category) %>%
  summarise(r2=cor(percent,co2_emmission)^2) %>%
  mutate(title=paste0(food_category,"\nR2:",scales::number(r2,accuracy=0.01))) %>%
  inner_join(mix_data,by="food_category") %>%
  ggplot(aes(x=percent,y=co2_emmission))+
  geom_point(colour="grey50")+
  geom_smooth(method="lm",se=FALSE,colour="#9b0d0d")+
  facet_wrap(title~.,scale="free_x") +
  theme_minimal(base_family = "Raleway")+
  theme(panel.grid=element_blank(),
        text=element_text(colour="grey50"),
        axis.text.y=element_blank()) +
  labs(x="% of Food Consumed",
       y="CO2 Emissions from Food\nkg per Person per Year",
       caption="Design @stevejburr - Data source: nu3.de - #tidytuesday",
       title="The importance of Beef, Milk and Rice in diets explains a lot of the variation",
       subtitle="In addition to the differences in volumes consumed") 

Ranking the factors

We can use models to try and understand how much of the variation in the data can be explained by the variables we have explored here.

We can use a linear regression model as a simple approach to understand the degree of variability explained by a subset of the variables:

mix_data %>%
  filter(food_category %in% c("Beef","Milk - inc. cheese","Rice")) %>%
  pivot_wider(values_from=percent, names_from=food_category) -> model_data

dat %>%
  group_by(country) %>%
  summarise(consumption=sum(consumption)) %>%
  left_join(model_data,by="country") %>%
  select(-country) %>%
  lm(co2_emmission ~ .,data=.) %>%
  summary()
## 
## Call:
## lm(formula = co2_emmission ~ ., data = .)
## 
## Residuals:
##     Min      1Q  Median      3Q     Max 
## -348.41  -75.04  -16.89   53.71  590.27 
## 
## Coefficients:
##                       Estimate Std. Error t value Pr(>|t|)    
## (Intercept)          -493.4477    64.7925  -7.616 5.61e-12 ***
## consumption             2.9984     0.1214  24.706  < 2e-16 ***
## Beef                 9444.3706   517.4324  18.252  < 2e-16 ***
## `Milk - inc. cheese`  -58.2620   122.2255  -0.477   0.6344    
## Rice                  219.9463   108.9410   2.019   0.0456 *  
## ---
## Signif. codes:  0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
## 
## Residual standard error: 143.2 on 125 degrees of freedom
## Multiple R-squared:  0.9045, Adjusted R-squared:  0.9014 
## F-statistic:   296 on 4 and 125 DF,  p-value: < 2.2e-16

This model suggests that we can explain ~90% of the variation between countries CO2 per capita food emissions based off of total consumption levels and then the proportion of volume coming from Beef, Dairy and Rice.

Another approach is to use importance plots to rank the variables, these plots are provided by many modelling packages such as randomForest:

library(randomForest)

mix_data %>%
  pivot_wider(values_from=percent, names_from=food_category,
              names_repair ="universal") -> rf_data

dat %>%
  group_by(country) %>%
  summarise(consumption=sum(consumption)) %>%
  left_join(rf_data,by="country") %>%
  select(-country) %>%
  randomForest(co2_emmission  ~., data=., importance=T) %>%
  importance(type=2) -> rf_importance

data.frame(variable=row.names(rf_importance),
           importance=rf_importance / sum(rf_importance)) %>%
  mutate(variable=fct_reorder(variable,IncNodePurity)) %>%
  ggplot() +
  geom_col(aes(x=variable,y=IncNodePurity),fill="#9b0d0d")+
  geom_text(aes(x=variable,y=IncNodePurity,
                label=scales::percent_format(accuracy=1)(IncNodePurity)),
            hjust="right",
            colour="white")+
  coord_flip() +
  labs(x="",
       y="Relative Importance",
       title="Consumption levels are the most important factor in explaing country differences",
       caption="Design @stevejburr - Data source: nu3.de - #tidytuesday") + theme_minimal(base_family = "Raleway")+
  theme(panel.grid=element_blank(),
        text=element_text(colour="grey50"),
        axis.text.x=element_blank(),
        plot.title=element_text(size=10))

Summary

That’s the end of this post, it’s been a fun analysis to run on an important topic. I hope you’ve enjoyed reading it.

If you want to discuss it with me, then use the comments box below or find me on twitter.

comments powered by Disqus