Hands-on Data Science
My learning DE

Exercise60 min

Self-assessment: Exploratory data analysis with R

Thirteen tasks on real product data: getting an overview, transforming, visualising and looking closely. This is how you check whether you are ready for exploratory data analysis.

Topics:Exploring and describingTransforming dataVisualising

What you will learn

This self-assessment uses real product data from the REWE online shop to let you check whether you are ready for exploratory data analysis, that is, whether you can:

  • get an overview of columns, types and values with glimpse() and uncover duplicates with distinct()
  • answer specific questions about a table with arrange(), select(), filter(), count() and mutate()
  • select columns by their type with where() and convert them with as.character() or across()
  • draw a bar chart, a histogram, box plots and stacked share bars with position = "fill" in ggplot2
  • spot implausible values in a distribution, such as kilojoules entered as kilocalories

Download as a script eda-self-assessment.R with the task as comments, to run in VS Code or Positron

With this self-assessment you check whether you master the basics that exploratory data analysis starts with. If you have worked through the Whole game part of R for Data Science, or the paths Getting started with R and Data transformation with R and dplyr, most tasks should come easily. Try each one on your own first; you can open the solution if you get stuck or want to compare.

In every box the table rewe is ready, with a good 9,400 products from the REWE online shop: name, category, origin, price, organic label and nutrition values per 100 g. dplyr and ggplot2 are loaded. On the first click, loading takes a few seconds, and again for the first chart. Categories, countries and product names are in German.

Part 1: Overview

Task 1. Get an overview of rewe: which columns are there, what type do they have, and what do the values look like?

rewe
SHOW THE SOLUTION
glimpse(rewe)

glimpse() shows all 22 columns one below the other, with type and first values. The nutrition values are decimal numbers, bio is a logical value, and product_id and gtin are numbers although nobody calculates with them.

Task 2. The table has 9,438 rows. How many different products does it contain? Each product has its own product_id.

rewe
SHOW THE SOLUTION
rewe |>
  distinct(product_id) |>
  nrow()

There are 7,959 products; almost 1,500 rows are duplicates. For every count in the following tasks this means that some products count twice. For a self-assessment that is fine; in a real analysis you would remove the duplicates with distinct() first.

Part 2: Transforming

Task 3. Show the ten most expensive products, with name and price only.

rewe
SHOW THE SOLUTION
rewe |>
  arrange(desc(price)) |>
  select(product_name, price) |>
  head(10)

At the very top are a cast-iron casserole and cigarettes, no food at all. Some products appear twice; these are the duplicates from task 2.

Task 4. Which countries do the products come from? Show each country with the number of its products, the most frequent first.

rewe
SHOW THE SOLUTION
rewe |>
  count(country_of_origin, sort = TRUE)

Most products come from Germany, by a wide margin. In second place is NA: for about a fifth, the origin is missing.

Task 5. Calculate a new column fat_unsat_in_gram, the fat content without the saturated fatty acids, and show it with name, fat and saturated fat.

rewe
SHOW THE SOLUTION
rewe |>
  mutate(fat_unsat_in_gram = fat_in_gram - fat_sat_in_gram) |>
  select(product_name, fat_in_gram, fat_sat_in_gram, fat_unsat_in_gram)

Where one of the two values is missing, the new column is NA too.

Task 6. Which products have more than 99 g of fat per 100 g? Show only name and fat.

rewe
SHOW THE SOLUTION
rewe |>
  filter(fat_in_gram > 99) |>
  select(product_name, fat_in_gram)

There are seven rows: oil, lard and vegetable fat.

Task 7. Keep only the columns that hold numbers.

rewe
SHOW THE SOLUTION
rewe |>
  select(where(is.numeric))

where() selects columns by a property of their content, here by type. product_id and gtin are included too, because R takes them for numbers.

Task 8. product_id and gtin are numbers nobody calculates with. Convert both to text.

rewe
SHOW THE SOLUTION
rewe |>
  mutate(
    product_id = as.character(product_id),
    gtin = as.character(gtin)
  ) |>
  select(product_id, gtin, product_name)

It is shorter with mutate(across(c(product_id, gtin), as.character)); across() applies a function to several columns.

Part 3: Visualising

Task 9. Show in a bar chart how many products there are in each category.

rewe |>
  ggplot() +
  aes()
SHOW THE SOLUTION
rewe |>
  ggplot() +
  aes(y = product_category) +
  geom_bar()

With the categories on the y axis, long names stay readable.

Task 10. Show in a histogram how the energy content in kcal is distributed across all products.

rewe |>
  ggplot() +
  aes()
SHOW THE SOLUTION
rewe |>
  ggplot() +
  aes(x = energy_in_kcal) +
  geom_histogram(binwidth = 50)

The warning about removed rows refers to the products without nutrition values. Look at the x axis: it reaches far beyond what any food can have. Task 13 is about that.

Task 11. Compare the fat content of the categories with box plots.

rewe |>
  ggplot() +
  aes()
SHOW THE SOLUTION
rewe |>
  ggplot() +
  aes(x = fat_in_gram, y = product_category) +
  geom_boxplot()

Task 12. Show with stacked bars what share of the products in each category is organic.

rewe |>
  ggplot() +
  aes()
SHOW THE SOLUTION
rewe |>
  ggplot() +
  aes(y = product_category, fill = bio) +
  geom_bar(position = "fill")

position = "fill" stretches every bar to full length, so that the shares become comparable even though the categories differ in size.

Part 4: Looking closely

Task 13. A food has at most about 900 kcal per 100 g; not even pure fat has more. Find the products that have more, and show name, energy and fat. What has probably happened there?

rewe
SHOW THE SOLUTION
rewe |>
  filter(energy_in_kcal > 900) |>
  select(product_name, energy_in_kcal, fat_in_gram)

Five products, among them pasta with 1,521 kcal and 2 g of fat. That cannot be right, but 1,521 kilojoules would be just right for pasta, about 360 kcal. Presumably the value in kilojoules was entered as kilocalories. You only find such errors if you look at the distribution and ask what is possible at all; that is exactly what exploratory data analysis is about.

Where to go next

If you managed almost everything without the solutions, you are well prepared. Where you got stuck, these help:

  • Tasks 1 to 8: the path Data transformation with R and dplyr and the Transform part of R for Data Science.
  • Tasks 9 to 12: the Visualize part of R for Data Science and, for the question of which chart fits, Fundamentals of Data Visualization.
  • Task 13: there is no recipe here, only the habit of distrusting every result at first.
Back
More on this
Details
Level
Foundations
Modules
Empirical Research
Code
6731
Updated
1 November 2026
Status
published

    A four-digit code takes you straight to the item.