PC Slower Than It Used to Be?
A free scan shows the junk files, broken settings and background clutter dragging Windows down - then fixes them in one click.Free scan · Windows 10 & 11Outdated Drivers Are Slowing You Down
One free scan finds every outdated or missing driver and matches the right update for your exact hardware.Free scan · exact hardware matchManipulating data in R means applying a deliberate sequence of transformations to a data frame: keep the rows and columns you need, create or change variables, order records, and reduce groups to summaries. The example below uses dplyr to make each step explicit, then shows the equivalent base R approaches so you can choose the style and execution path that fit your project.
Start with a small, explicit example
Suppose sales contains one row per order:
sales <- data.frame(
order_id = c(101, 102, 103, 104),
region = c("North", "South", "North", "South"),
product = c("A", "A", "B", "B"),
units = c(3, 5, 2, 8),
price = c(10, 10, 15, 15),
returned = c(FALSE, FALSE, TRUE, FALSE)
)
Our target is a table of non-returned orders, with a calculated revenue column, sorted from largest to smallest sale. We can express that result as a left-to-right pipeline:
library(dplyr)
result <- sales |>
filter(!returned) |>
mutate(revenue = units * price) |>
select(order_id, region, product, units, revenue) |>
arrange(desc(revenue))
The pipe (|>) passes the result of each operation to the next one. Assigning the pipeline to result is what preserves the transformed data; printing a pipeline alone does not replace the original object.
Inspect data before transforming it
Many transformation errors come from incorrect assumptions about names, types, missing values, or row counts. Check the input first:
Free tools Windows power users keep installed
One-click scans. No signup required.
#1 Best Overall
names(sales)
str(sales)
head(sales)
sum(is.na(sales))
nrow(sales)
- Names: confirm spelling and capitalization.
- Types: verify that numbers are numeric, dates are dates, and categories have the intended representation.
- Missing values: decide whether to remove, retain, or explicitly handle
NAvalues. - Row count: record the starting size so filtering and joins can be checked later.
Filter rows with filter()
filter() keeps cases whose conditions evaluate to TRUE. Multiple comma-separated conditions are combined with logical AND.
sales |> filter(region == "North")
sales |> filter(units >= 5, !returned)
sales |> filter(product %in% c("A", "B"))
Use is.na() and !is.na() when missing values matter. A comparison such as price > 10 returns NA for a missing price, so that row will not pass the filter unless you handle it explicitly.
Choose columns with select()
select() returns only the variables needed for the next task or final output.
sales |> select(order_id, region, revenue)
sales |> select(-returned)
sales |> select(starts_with("unit"), ends_with("price"))
Reducing columns early can make later code easier to read and prevents accidental use of irrelevant fields.
Order rows with arrange()
sales |> arrange(region, product)
sales |> arrange(desc(units), product)
Ordering does not change the values or remove rows; it changes their display and stored order. Use desc() for descending order and add a second variable to make ties deterministic.
Create and modify variables with mutate()
mutate() adds columns or replaces existing ones. New expressions can use columns created earlier in the same call.
sales |>
mutate(
revenue = units * price,
net_revenue = if_else(returned, 0, revenue),
high_value = revenue >= 75
)
For more than two possible outcomes, use case_when():
sales |>
mutate(
tier = case_when(
revenue >= 100 ~ "large",
revenue >= 50 ~ "medium",
TRUE ~ "small"
)
)
Make sure the replacement expression has a compatible type. Also decide how missing inputs should propagate; arithmetic involving NA normally produces NA unless you supply an explicit rule.
The Tool Desk
Outbyte PC Repair FREERepair Windows errors before they cause bigger problemsFix Now →Outbyte Driver Updater FREEFix the driver behind crashes, sound loss and screen glitchesFind Drivers →Group and summarize data
group_by() changes the meaning of subsequent operations. summarise() then reduces each group to summary rows.
Rank #4
regional_sales <- sales |>
filter(!returned) |>
mutate(revenue = units * price) |>
group_by(region) |>
summarise(
orders = n(),
units_sold = sum(units),
revenue = sum(revenue),
average_order = mean(revenue),
.groups = "drop"
)
With one grouping variable, the output has one row per region; with several, it has one row for each combination. The .groups argument controls whether grouping is dropped, kept, or simplified after summarising. This matters when another operation follows, because a still-grouped data frame can produce grouped rather than overall results. Backend implementations can differ, so verify grouping after a summary when working beyond a local data frame.
Inspect the result rather than assuming the aggregation did what you intended:
nrow(regional_sales)
regional_sales
group_vars(regional_sales)
Join related tables as a separate task
Transformation often requires combining tables, such as orders and a product lookup. Joins match keys; they are not substitutes for row filtering or summarising.
Best Value
orders |> left_join(products, by = "product_id")
orders |> inner_join(products, by = "product_id")
orders |> full_join(products, by = "product_id")
- Left join: keeps every row from the first table and adds matches.
- Inner join: keeps only rows with a match in both tables.
- Full join: keeps all rows from both tables, using missing values where no match exists.
Before and after a join, check row counts and key uniqueness. A duplicated key on either side can legitimately multiply rows, while an unexpected key mismatch can introduce missing columns. dplyr documents joins and set operations as a distinct two-table verbs topic.
A complete, checkable workflow
- Define the desired shape. Write down whether the output should retain individual records or contain one row per group.
- Inspect the input. Check names, types, missing values, key columns, and
nrow(). - Filter and select. Remove irrelevant cases and variables before more complex work.
- Mutate. Create calculated fields and document rules for missing or exceptional values.
- Arrange or summarise. Order detail rows, or group and reduce them to the intended grain.
- Join deliberately. Confirm key uniqueness and compare row counts before and after.
- Validate the output. Inspect a sample, names, types, missingness, grouping, and summary totals.
- Save the result. Assign it to an object or write it to the required file or database table.
dplyr compared with base R
Both approaches are valid. dplyr offers a consistent data-frame grammar and named verbs; base R uses indexing and a collection of vector, data-frame, and statistical functions. The correspondence is practical rather than perfectly identical in every edge case.
| Task | dplyr | Typical base R equivalent |
|---|---|---|
| Keep rows | filter(df, x > 0) |
df[df$x > 0, ] or subset(df, x > 0) |
| Choose columns | select(df, a, b) |
df[c("a", "b")] |
| Add a column | mutate(df, z = x + y) |
df$z <- df$x + df$y or transform(df, z = x + y) |
| Sort rows | arrange(df, desc(x)) |
df[order(-df$x), ] |
| Remove duplicate rows | distinct(df) |
unique(df) |
| Summarise by group | group_by(df, g) |> summarise(m = mean(x)) |
aggregate(x ~ g, df, mean) or tapply(df$x, df$g, mean) |
Choose based on the task and environment:
- Readability and team conventions: dplyr’s verbs and pipelines make a multi-step transformation read from left to right; a base-R codebase may be clearer when it consistently uses indexing and standard functions.
- Dependencies: base R avoids an additional package dependency. dplyr requires installation and loading, but gives a coherent vocabulary.
- Grouped work: dplyr makes grouping state explicit with
group_by(); base R offers several capable functions with different interfaces. - Data location and scale: ordinary data frames run in memory. For larger-than-memory or remote data, dplyr-related options include Arrow, dbplyr for relational databases, dtplyr for large in-memory data, duckplyr for DuckDB, and sparklyr for Spark. These are backend choices, not automatic guarantees of a particular speed improvement.
Common failure modes and recovery checks
- Unexpected zero rows: print the condition’s inputs and check spelling, factor or character values, and
NAhandling. - Too many rows after a join: test whether the join key is unique in each table and inspect unmatched keys.
- Wrong summary grain: check
group_vars()and confirm that each output row represents the intended group. - Missing calculated values: inspect source columns for
NAand decide whether a default or an omission rule is appropriate. - Changes do not persist: assign the result to an object; a pipeline that is only printed has not overwritten the input.
Further learning
The official dplyr documentation covers introductions, grouped data, two-table verbs, column-wise and row-wise operations, programming, and a comparison with base R. New users are also directed to the data-transformation chapter of R for Data Science.
Quick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.
Quick wins for a faster PC:
Repair Windows errors before they cause bigger problemsFix Now →Fix the driver behind crashes, sound loss and screen glitchesFind Drivers →

