Appendix: Try It Yourself!
A ready-made pandas, dplyr, and SQL exercise
Part 1: Group, summarise, and sort
The most common data-wrangling task: total revenue by category, sorted descending.
In R β the dplyr pipe
In Python β pandas groupby
Side-by-side comparison
Key idiom differences
| Concept | dplyr (R) | pandas (Python) |
|---|---|---|
| Start a chain | df |> ... |
(df...) |
| Group rows | group_by(category) |
.groupby("category") |
| Summarise | summarise(name = fn(col)) |
.agg(name=("col", "fn")) |
| Sort descending | arrange(desc(col)) |
.sort_values("col", ascending=False) |
| Column names quoted? | Bare names: category |
Always strings: "category" |
Part 2: Filter, then group
Now: average revenue per unit, for months that arenβt February.
In R
In Python
Idiom flags
filter()β.query()β both accept an expression, but pandas requires a string.mutate()β.assign()β pandas uses alambdato reference the DataFrame mid-chain..groups = "drop"in dplyr β.reset_index()in pandas β both un-nest the groups.
Part 3: SQL βοΈ tidyverse cameo
The same aggregation in all three languages. Notice how SQL is the conceptual middle ground β its GROUP BY maps directly to both group_by() and .groupby().
π SQL
SELECT category, SUM(revenue) AS total_revenue, SUM(units) AS total_units FROM sales GROUP BY category ORDER BY total_revenue DESC;
π¦ dplyr (R)
sales |>
group_by(category) |>
summarise(
total_revenue = sum(revenue),
total_units = sum(units)
) |>
arrange(desc(total_revenue))
π pandas (Python)
(sales
.groupby("category")
.agg(
total_revenue=("revenue","sum"),
total_units =("units", "sum"))
.sort_values("total_revenue",
ascending=False)
.reset_index()
)
| SQL clause | dplyr verb | pandas method |
|---|---|---|
WHERE |
filter() |
.query() |
SELECT col, fn(col) |
summarise() |
.agg() |
GROUP BY |
group_by() |
.groupby() |
ORDER BY ... DESC |
arrange(desc(...)) |
.sort_values(..., ascending=False) |
AS name |
name = expr inside summarise() |
name=("col","fn") inside .agg() |
Match the syntax!
For each dplyr snippet, choose its pandas equivalent.
| dplyr (R) | pandas (Python) | |
|---|---|---|
filter(month == "Jan") |
||
group_by(category) |
||
summarise(total = sum(revenue)) |
||
arrange(desc(revenue)) |
||
mutate(rev_per_unit = revenue / units) |
||
select(month, revenue) |
Your turn β fill in the blanks
Hereβs the complete R version of a new task: total units sold per month, keeping only months with more than 30 total units.
Now complete the pandas equivalent below and run it:
Concept check
In dplyr you can write filter(total_units > 30) immediately after summarise() because the pipe passes the result forward as a new data frame. In pandas, why do you need .reset_index() before .query("total_units > 30") β and what happens if you skip it?