dplyr transmute() in R: Mutate and Drop Old Columns
The transmute() function in dplyr is like mutate() but DROPS all columns not mentioned. As of dplyr 1.1, it is superseded by mutate(.keep = "none"), which is preferred in new code.
transmute(df, kpm = mpg * 1.609) # only kpm column survives transmute(df, mpg, kpm = mpg * 1.609) # mpg + kpm; rest dropped mutate(df, kpm = mpg * 1.609, .keep = "none") # modern equivalent mutate(df, kpm = mpg * 1.609, .keep = "used") # mpg + kpm; rest dropped mutate(df, .keep = "all") # all columns; default df |> select(mpg) |> mutate(kpm = mpg * 1.609)# explicit alternative
Need explanation? Read on for examples and pitfalls.
What transmute() does in one sentence
transmute(df, ...) evaluates each ... expression to create new columns, then drops EVERY column not named in the call. It is mutate() plus a select() to keep only the new (and explicitly mentioned) columns.
transmute() is "superseded" in dplyr 1.1: still works, but mutate(.keep = ...) is the recommended replacement. The old function remains for backward compatibility.
Syntax
transmute(.data, ...). Same expression syntax as mutate; output keeps only mentioned columns.
mutate(.keep = "none") over transmute(). Same result, modern API, easier to discover via mutate docs.Five common patterns
1. Single derived column
2. Keep some original columns
Bare column names mean "keep this column unchanged".
3. Multiple new columns
Just like mutate, all references in the right side resolve against the input frame.
4. Rename via transmute
For rename-only, rename() is clearer; transmute happens to support it as a side effect.
5. Modern equivalent with mutate(.keep)
.keep = "none" drops all input columns. .keep = "used" keeps only those referenced in the right-hand side.
mutate(.keep = ...) covers four cases that previously required transmute, mutate, or select+mutate. Options: "all" (default, keeps everything), "used" (keeps used + new), "unused" (keeps unused + new), "none" (keeps only new). One verb, four behaviors.transmute() vs mutate() vs select+mutate
Three ways to "compute new columns and drop the rest" in dplyr.
| Approach | Style | Status | |
|---|---|---|---|
transmute(df, x = ...) |
Old | Superseded (still works) | |
mutate(df, x = ..., .keep = "none") |
Modern | Recommended | |
| `select(df, kept_cols) | > mutate(x = ...)` | Explicit | Always clear |
When to use which:
mutate(.keep = "none")for new code.transmute()if you encounter it in legacy code (no need to rewrite).select() |> mutate()when you want fine-grained column control before computation.
A practical workflow
The most common transmute pattern is "convert units" or "extract derived metrics" with no need to keep the source columns.
Examples:
- Unit conversion:
transmute(kpl = mpg * 0.425, kg = wt * 453.6) - Index calculation:
transmute(id, total = price * qty, margin = (price - cost) / price) - Z-score normalization:
transmute(across(everything(), ~ (.x - mean(.x)) / sd(.x)))
When the source columns are no longer needed downstream (and you don't want to clutter), transmute (or mutate(.keep = "none")) is the cleanest pattern.
Common pitfalls
Pitfall 1: forgot to keep needed columns. transmute(kpl = mpg * 0.425) drops mpg, cyl, etc. If downstream code needs them, list them explicitly: transmute(mpg, cyl, kpl = mpg * 0.425).
Pitfall 2: doesn't preserve grouping vars unless mentioned. A grouped tibble's grouping columns ARE kept by transmute (dplyr 1.0+); but if you ungroup AND transmute, expect them to be dropped.
transmute() is "superseded" in dplyr 1.1: mutate(.keep = ...) is preferred. Superseded means "still works, no plans to remove, but new code should use the alternative". You don't need to rewrite existing transmute calls.Try it yourself
Try it: From mtcars, create a result with ONLY two columns: mpg_per_cyl = mpg / cyl and power_to_weight = hp / wt. Save to ex_metrics.
Click to reveal solution
Explanation: transmute() (or mutate(.keep = "none")) creates the two new columns and drops all originals. Result: 32 rows × 2 columns.
Related dplyr functions
After mastering transmute, look at:
mutate(.keep = ...): modern replacementmutate(): keep all columns + new onesselect(): pick specific columns (no computation)rename(): rename without computingsummarise(): collapse rows (transmute keeps row count)mutate(across(...)): apply same transformation across columns
For computing new columns ALONGSIDE all originals, just use mutate() (default .keep = "all").
FAQ
What is the difference between transmute and mutate in dplyr?
mutate() keeps ALL columns and adds the new ones. transmute() keeps ONLY the columns you mention (new or explicitly named originals); everything else is dropped.
Is transmute deprecated in dplyr?
Superseded, not deprecated. As of dplyr 1.1, mutate(.keep = "none") is the preferred replacement. transmute() still works and is not slated for removal.
How do I keep some original columns with transmute?
Mention them by bare name: transmute(df, mpg, kpl = mpg * 0.425) keeps mpg and the new kpl; drops everything else.
What is mutate(.keep = "none") in dplyr?
.keep = "none" is an argument to mutate() that drops all input columns, keeping only the new ones. It is the modern equivalent of transmute().
Does transmute respect group_by?
Yes. On a grouped tibble, transmute computes per-group expressions and keeps the grouping columns automatically (dplyr 1.0+).