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.
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 withdistinct() - answer specific questions about a table with
arrange(),select(),filter(),count()andmutate() - select columns by their type with
where()and convert them withas.character()oracross() - draw a bar chart, a histogram, box plots and stacked share bars with
position = "fill"inggplot2 - 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?
reweSHOW 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.
reweSHOW 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.
reweSHOW 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.
reweSHOW 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.
reweSHOW 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.
reweSHOW 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.
reweSHOW 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.
reweSHOW 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?
reweSHOW 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
dplyrand 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.
See also
Details
- Level
- Foundations
- Modules
- Empirical Research
- Code
6731- Updated
- 1 November 2026
- Status
- published