10  Practice aggregations

In this second exercise, we’re going to practice to :

The examples in this chapter might look a bit repetitive, the purpose is to be comfortable to aggregate data with different dimensions, and to illustrate a common ETL flow : Get data => Filter => Transform .

Let’s start by uploading the needed libraries. Here, the usual tidyverse.

# ETL
library(tidyverse)

Upload raw data

The data frame is located on the GitHub repository.

We’re uploading a large data frame with :

There are 2 dimensions, Country and Product.Description, and some sales quantities per period.

11 Create a tidy data frame

We’re going to transform the initial data frame into a “tidy format”, which means that each variable is either a dimension or a measure. We follow the same steps that we did in the first practice.

#-------------------
# Upload raw data
#-------------------

# Define the URL of the raw CSV file
url <- "https://raw.githubusercontent.com/nguyennico/etl_practice/main/ETL_practice2_data.csv"

# Read the CSV file from the URL
df1 <- read.csv(url)


#-------------------
# Create a tidy dataframe
#-------------------

# pivot
df1 <- df1 |> gather(key = "period", 
                     value = "sales_qty", 
                     3:length(df1))

# replace missing values (NA) by zero
df1$sales_qty <- df1$sales_qty |> replace_na(0)

# remove the "X" in front of the period
df1$period <- gsub("X", "",df1$period)

# Format Date
df1$period <- as.Date(df1$period, format = '%m.%d.%Y')

# add Calendar Year
df1$calendar_year <- year(df1$period)

# keep results
ETL_practice2_data <- df1

glimpse(df1)
Rows: 410,000
Columns: 5
$ Country             <chr> "France", "France", "France", "France", "France", …
$ Product.Description <chr> "Product 1", "Product 2", "Product 3", "Product 4"…
$ period              <date> 2016-10-01, 2016-10-01, 2016-10-01, 2016-10-01, 2…
$ sales_qty           <int> 1370, 461, 765, 0, 4496, 1623, 950, 230, 143, 720,…
$ calendar_year       <dbl> 2016, 2016, 2016, 2016, 2016, 2016, 2016, 2016, 20…

We obtain a data frame with 5 variables and 410.000 rows.

The 5 variables are :

  • Country : 4 values, “France”, “Germany”, “Spain”, “Italy”.

  • Product.Description : 2.500 products.

  • period : a date, with months from October 2016 until February 2020.

  • sales_qty : amount of sales, in units.

  • calendar_year : the calendar year related to the period.

12 Monthly Sales by Country

In this example, we want to create a summary, i.e an aggregation, of the monthly sales per country.

The operation is similar to a pivot table in excel. Here, we are going to use the 2 functions group_by() and summarise() to perform this aggregation.

We will aggregate using 2 dimensions : Country and period. Those 2 dimensions are written within the group_by() function.

Then we will use the function spread() to spread the variable “period” into distinct columns.

# set a working df
df1 <- ETL_practice2_data

# Aggregate by Country
df1 <- df1 |> group_by(Country, period) |>
    summarise(sales_qty = sum(sales_qty))

# spread data
df1 <- df1 |> spread(period, sales_qty)

# display
df1
# A tibble: 4 × 42
# Groups:   Country [4]
  Country `2016-10-01` `2016-11-01` `2016-12-01` `2017-01-01` `2017-02-01`
  <chr>          <int>        <int>        <int>        <int>        <int>
1 France       1250319      1286042      1266616      1254652      1237272
2 Germany        61656        61719        62753        63054        62434
3 Italy          25199        24717        25209        25353        24844
4 Spain        1246446      1234329      1273446      1241711      1252289
# ℹ 36 more variables: `2017-03-01` <int>, `2017-04-01` <int>,
#   `2017-05-01` <int>, `2017-06-01` <int>, `2017-07-01` <int>,
#   `2017-08-01` <int>, `2017-09-01` <int>, `2017-10-01` <int>,
#   `2017-11-01` <int>, `2017-12-01` <int>, `2018-01-01` <int>,
#   `2018-02-01` <int>, `2018-03-01` <int>, `2018-04-01` <int>,
#   `2018-05-01` <int>, `2018-06-01` <int>, `2018-07-01` <int>,
#   `2018-08-01` <int>, `2018-09-01` <int>, `2018-10-01` <int>, …

13 Countries and Calendar Year

In this example, we want to create another aggregation, this time of the yearly sales per country.

We’re going to aggregate using 2 dimensions : Country and calendar_year.

Then we will spread as we did previously.

# set a working df
df1 <- ETL_practice2_data

# Aggregate by Country
df1<- df1 |> group_by(Country, calendar_year) |>
    summarise(sales_qty = sum(sales_qty)
)

# spread data
df1 <- df1 |> spread(calendar_year, sales_qty)

# display
df1
# A tibble: 4 × 6
# Groups:   Country [4]
  Country  `2016`   `2017`   `2018`   `2019`  `2020`
  <chr>     <int>    <int>    <int>    <int>   <int>
1 France  3802977 15069505 15108326 15171819 2515933
2 Germany  186128   753298   747328   751043  125266
3 Italy     75125   299119   301329   300171   49078
4 Spain   3754221 15039455 15085333 15011769 2472632

14 Filter on one selected Product

Now we’re going to create the same aggregated table, with the sales by Countries and Calendar Year.

However, instead of considering the whole products portfolio, we will look only at the “Product 1”.

We will then filter the data, before the aggregation, using the function filter().

Note : we actually can filter before or after. The interest to filter before is to have a smaller (already) filtered data frame to aggregate (making then the operation faster).

# set a working df
df1 <- ETL_practice2_data

# Filter on one Product
df1 <- df1 |> filter(Product.Description %in% c("Product 1"))

# Aggregate by Country
df1 <- df1 |> group_by(Country, calendar_year) |>
    summarise(sales_qty = sum(sales_qty)
)

# spread data
df1 <- df1 |> spread(calendar_year, sales_qty)

# display
df1
# A tibble: 4 × 6
# Groups:   Country [4]
  Country `2016` `2017` `2018` `2019` `2020`
  <chr>    <int>  <int>  <int>  <int>  <int>
1 France    3999  14037  12842  10414   1371
2 Germany     65    277    337    284     55
3 Italy       31    138    104    128     35
4 Spain     1666   5079   4849   6236   1485

15 Aggregation on 3 dimensions

Now, we are going to filter on a few selected Products, and add one more dimension, the Product.Description, to the aggregation.

# set a working df
df1 <- ETL_practice2_data

# Filter on Products
df1 <- df1 |> filter(Product.Description %in% c("Product 1", "Product 10", "Product 20"))

# Aggregate
df1 <- df1 |> group_by(Country, Product.Description, calendar_year) |>
    summarise(sales_qty = sum(sales_qty))


# spread data
df1 <- df1 |> spread(calendar_year, sales_qty)

# display
df1
# A tibble: 12 × 7
# Groups:   Country, Product.Description [12]
   Country Product.Description `2016` `2017` `2018` `2019` `2020`
   <chr>   <chr>                <int>  <int>  <int>  <int>  <int>
 1 France  Product 1             3999  14037  12842  10414   1371
 2 France  Product 10            2048   5552   6229   4872    248
 3 France  Product 20            1553   6754   5995   5477    738
 4 Germany Product 1               65    277    337    284     55
 5 Germany Product 10              65    245    266    274     57
 6 Germany Product 20             115    263    308    314     58
 7 Italy   Product 1               31    138    104    128     35
 8 Italy   Product 10              25    149    110    159     31
 9 Italy   Product 20              20    164    126     84     36
10 Spain   Product 1             1666   5079   4849   6236   1485
11 Spain   Product 10             413   6885   6746   5797   1159
12 Spain   Product 20            2483   7378   6768   5671    516

16 2 filters & aggregation

In this last part, we’re going to :

  • filter the initial data frame based on the variables Product.Description and Country.

  • then aggregate and spread the results.

Note : as we mentioned earlier, the 2 filters could also be placed after the aggregation and spread of the data

# set a working df
df1 <- ETL_practice2_data

# Filter on Products
df1 <- df1 |> filter(Product.Description %in% c("Product 1", "Product 10", "Product 20"))

# Filter on Countries
df1 <- df1 |> filter(Country %in% c("France", "Spain"))


# Aggregate
df1 <- df1 |> group_by(Country, Product.Description, calendar_year) |>
    summarise(sales_qty = sum(sales_qty))


# spread data
df1 <- df1 |> spread(calendar_year, sales_qty)

# display
df1
# A tibble: 6 × 7
# Groups:   Country, Product.Description [6]
  Country Product.Description `2016` `2017` `2018` `2019` `2020`
  <chr>   <chr>                <int>  <int>  <int>  <int>  <int>
1 France  Product 1             3999  14037  12842  10414   1371
2 France  Product 10            2048   5552   6229   4872    248
3 France  Product 20            1553   6754   5995   5477    738
4 Spain   Product 1             1666   5079   4849   6236   1485
5 Spain   Product 10             413   6885   6746   5797   1159
6 Spain   Product 20            2483   7378   6768   5671    516

Well done! We now master the aggregations in R!