🚧 Under construction — VoTechWorks is being built. A free tech program — complimentary, as our commitment to get America working.
voTechWorksGrade 13 · a vocational technology learning center, by urbanicity
newSchoolWorks.com › VoTechWorks › Technology & Design › Data Science & Analytics › Python and R for Data Science & Analytics › Lesson 7
TEC-DATA85-03 · Lesson 7 · 12 clock hours · practice

Exploratory Data Analysis with the Tidyverse

Objective. Students use tidyverse packages (dplyr, tidyr, stringr) in R to group, aggregate, reshape, and summarize the same dataset used in the pandas lesson, and compare findings between the two language outputs.

⚠ Pending professional review

This lesson, its worked examples and its practice questions has not yet been verified by an industry-certified professional or by a certification or approval body. It is a study draft and may contain errors. Do not use it as instructions for work on a job site or on live equipment. Always follow your instructor, your supervising professional, and current official references and regulations.

VoTechWorks program approval and accreditation are still in progress. Credentials are issued only by the certifying bodies named in each program, after their own exams.

Exploratory Data Analysis with the Tidyverse

In the previous lesson you explored a dataset using pandas in Python. Now you will perform the same exploration in R using the tidyverse — a collection of packages designed around a consistent philosophy of tidy data. By the end of this lesson you will be able to group and summarize data with dplyr, clean messy text with stringr, and reshape tables with tidyr. Comparing your R results to the pandas output you already produced is a built-in accuracy check: if the numbers agree (within rounding caused by floating-point differences), both analyses are likely correct.

Why the Tidyverse?

The tidyverse packages share a common grammar and pipe-friendly design. A pipe (`|>` in base R 4.1+ or `%>%` from magrittr) passes the output of one function directly into the next, making code read like a series of English instructions. This reduces the need for intermediate variables and makes the data-transformation story easier to audit — an important quality in professional analytics work.

Grouping and Summarizing with dplyr

The two workhorses are `group_by()` and `summarize()` (also spelled `summarise()`). `group_by()` tags each row with its group membership without changing the data; `summarize()` then collapses each group into a single row of statistics.

```r

library(tidyverse)

df <- read_csv("lesson6_dataset.csv")

summary_tbl <- df |>

group_by(region) |>

summarize(

n = n(),

mean_sales = mean(sales, na.rm = TRUE),

med_sales = median(sales, na.rm = TRUE)

) |>

arrange(desc(mean_sales))

write_csv(summary_tbl, "region_summary.csv")

```

Key points:

When you compare these results to your pandas output, minor decimal differences (e.g., 1234.56 vs. 1234.5600000001) are acceptable; they arise from floating-point arithmetic and do not indicate an error. Larger discrepancies should be investigated — a common cause is one tool dropping NAs while the other includes them.

Cleaning Text with stringr

Real datasets often contain inconsistent formatting: city names like `"New York"`, `"new york"`, and `" New York "` are all different strings to a computer. The stringr package provides a predictable, pipe-friendly interface to string operations.

| Function | Purpose |

|---|---|

| `str_to_lower()` | Convert all characters to lowercase |

| `str_trim()` | Remove leading and trailing whitespace |

| `str_replace_all()` | Replace a pattern with a new string |

```r

before_cities <- n_distinct(df$city)

df <- df |>

mutate(

city = str_trim(city),

city = str_to_lower(city)

)

after_cities <- n_distinct(df$city)

cat("Unique city values before:", before_cities, "\n")

cat("Unique city values after: ", after_cities, "\n")

```

Record both counts in your lab log. A decrease in distinct values after cleaning confirms that duplicates caused by formatting differences have been merged. This documentation is important for reproducibility: a future analyst (or your future self) can see exactly what changed and why.

Reshaping Data with tidyr

Data comes in two shapes. Wide format places each variable in its own column — convenient for reading but awkward for many ggplot2 visualizations and statistical models. Long format stacks variable names into one column and their values into another — ideal for grouped operations and plotting.

```r

long_tbl <- summary_tbl |>

pivot_longer(

cols = c(mean_sales, med_sales),

names_to = "metric",

values_to = "value"

)

wide_again <- long_tbl |>

pivot_wider(

names_from = "metric",

values_from = "value"

)

stopifnot(nrow(wide_again) == nrow(summary_tbl))

stopifnot(ncol(wide_again) == ncol(summary_tbl))

```

The `stopifnot()` calls act as automatic checks: if row or column counts do not match, R stops and reports an error so you catch the problem immediately.

Documenting in R Markdown

Your deliverable is an R Markdown (`.Rmd`) file that knits to HTML or PDF without errors. Each code chunk should be followed by a plain-English explanation. For the reshape section, write at least one sentence explaining when long format is preferable (modeling, plotting) and when wide format is preferable (display, export to spreadsheets).

Before submitting, knit the document and confirm it completes without errors. A clean knit is the R equivalent of a Python script that runs from top to bottom without exceptions.

Data Integrity and Professional Practice

Although this lesson involves no electrical equipment or chemicals, professional data work carries its own integrity obligations. Never alter the original source file; always read from it and write outputs to new files. Keep your lab log entries factual — record what the data showed, not what you hoped it would show. Misrepresenting data quality or cleaning steps is an ethical violation with real consequences in business and public-sector analytics.

Key terms10

tidyverseA collection of R packages — including dplyr, tidyr, ggplot2, and stringr — that share a common design philosophy centered on tidy data and pipe-friendly function signatures.
pipe operatorA symbol (`|>` or `%>%`) that passes the result of one expression as the first argument of the next, allowing data-transformation steps to be chained in readable order.
group_by()A dplyr function that tags rows by one or more categorical variables so that subsequent operations (such as summarize) are applied separately within each group.
summarize()A dplyr function that collapses each group produced by group_by() into a single row, typically computing aggregate statistics such as count, mean, or median.
pivot_longer()A tidyr function that converts a wide-format table to long format by stacking selected column names into a single 'names' column and their values into a single 'values' column.
pivot_wider()A tidyr function that converts a long-format table to wide format by spreading unique values from a names column into separate columns, each filled with corresponding values.
str_trim()A stringr function that removes leading and trailing whitespace characters from a string, eliminating a common source of duplicate values in categorical columns.
tidy dataA standard way of organizing tabular data in which each variable has its own column, each observation has its own row, and each value occupies exactly one cell.
R MarkdownA file format that combines R code chunks with narrative prose; knitting the file executes the code and produces a formatted report (HTML, PDF, or Word).
na.rmAn argument available in many R statistical functions that, when set to TRUE, causes the function to ignore NA (missing) values rather than returning NA as the result.

Worked examples4

1. A summary table has 4 regions and 2 numeric metrics (mean_sales, med_sales). After pivot_longer(), how many rows and columns should the long table have?
  1. Identify the number of groups: 4 regions.
  2. Identify the number of metrics being pivoted: 2 (mean_sales, med_sales).
  3. Rows in long format = groups × metrics = 4 × 2 = 8 rows.
  4. Columns in long format = the non-pivoted identifier column (region) + the names column (metric) + the values column (value) = 3 columns.
Answer: 8 rows and 3 columns.
2. Before cleaning, a city column has 47 distinct values. After applying str_trim() and str_to_lower(), it has 39 distinct values. How many duplicate-by-formatting entries were merged, and what percentage reduction does that represent?
  1. Calculate the number of merged entries: 47 − 39 = 8 distinct values collapsed.
  2. Calculate percentage reduction: (8 ÷ 47) × 100.
  3. 8 ÷ 47 ≈ 0.1702.
  4. 0.1702 × 100 ≈ 17.02%, which rounds to approximately 17%.
Answer: 8 duplicate-by-formatting entries were merged, representing approximately a 17% reduction in distinct city values.
3. A grouped summarize produces the following mean_sales values by region: North = 1,200.40, South = 980.75, East = 1,450.10, West = 1,100.00. After arrange(desc(mean_sales)), what is the correct order of regions in the output table?
  1. List the values: North 1200.40, South 980.75, East 1450.10, West 1100.00.
  2. Sort from largest to smallest: East 1450.10 is largest.
  3. Next largest: North 1200.40.
  4. Next: West 1100.00. Smallest: South 980.75.
Answer: East, North, West, South (descending by mean_sales).
4. A long-format table has 8 rows and 3 columns (region, metric, value). After pivot_wider() restores it to wide format, how many rows and columns should result, assuming 'region' is the id column and 'metric' contains exactly 2 unique values?
  1. Rows in wide format = number of unique id values = 8 rows ÷ 2 metrics per region = 4 rows.
  2. Columns in wide format = id column (region) + one column per unique metric value = 1 + 2 = 3 columns.
  3. Verify: 4 rows × 3 columns matches the original wide table dimensions.
Answer: 4 rows and 3 columns — matching the original wide-format table.
In class: Use dplyr group_by() and summarize() to calculate count, mean, and median for at least three categorical groupings; pipe the result into arrange(desc()) and export to CSV. · Identify at least two columns with inconsistent formatting (e.g., mixed-case city names, extra whitespace) and use stringr functions str_to_lower(), str_trim(), and str_replace_all() to standardize them; document before/after counts in the lab log. · Use tidyr pivot_longer() and pivot_wider() to reshape a wide summary table into long format and back; verify row and column counts match expectations and write a brief R Markdown explanation of when each shape is preferable.
Materials: RStudio, tidyverse documentation (tidyverse.org), stringr documentation, same open dataset from Lesson 6, R Markdown template, lab log
Check: R Markdown document knits cleanly; group summaries match pandas output from Lesson 6 within rounding; string-cleaning documented with before/after counts; reshape round-trip row/column counts verified — pass requires all four checks.

Practice check8

Answer each question, then check it. Nothing is recorded; this is your own practice.

Data wrangling and transformation
1. Which dplyr function tags rows by a categorical variable so that subsequent operations are applied separately within each group?
Data quality and cleaning
2. A data analyst applies str_trim() to a city column and the number of distinct values drops from 52 to 44. What is the most likely explanation?
Data wrangling and transformation
3. An analyst uses pivot_longer() to convert a wide table with 5 rows and 4 metric columns into long format. How many rows will the resulting long table have?
Programming concepts for data analytics
4. In an R pipe chain, what does the pipe operator (`|>`) do?
Data validation and quality assurance
5. A group_by() and summarize() operation in R produces a mean_sales figure of 1,234.57 for a category, while the equivalent pandas groupby produced 1,234.5700000002. Which statement best describes this situation?
Data wrangling and transformation
6. Which tidyr function would you use to convert a long-format table back into wide format?
Reporting and communication of data findings
7. An R Markdown document fails to knit due to an error in a code chunk. What is the most appropriate first step?
Data wrangling and transformation
8. An analyst wants to count the number of rows per product category, calculate the mean revenue, and sort results from highest to lowest mean revenue. Which sequence of dplyr verbs is correct?
Record this lesson on my transcript. Sign in with your key and enrollment email to record lessons (enroll free if you have no key). This page stays open to read and practise.