I'm not convinced any of these are faster than the two step method, just doing it with less keystrokes. Here are some benchmarks:
library(microbenchmark)
microbenchmark(dplyr = {df<-data.frame(a=1:5,b=101:105,c=201:205);df<-transmute(df, a = log(a), b = b)},
transform = {df<-data.frame(a=1:5,b=101:105,c=201:205);df<-transform(df, a = log(a))},
within = {df<-data.frame(a=1:5,b=101:105,c=201:205);df<-within(df[1:2], a <- log(a))},
twosteps = {df<-data.frame(a=1:5,b=101:105,c=201:205);df<-df[,1:2];df[,1]<-log(df[,1])})
Unit: microseconds
expr min lq mean median uq max neval
dplyr 1374.710 1438.453 1657.3807 1534.0680 1658.2910 5231.572 100
transform 489.597 508.413 764.6921 524.9240 569.4680 18127.718 100
within 493.436 518.396 593.6254 534.9085 585.7880 1554.420 100
twosteps 421.245 438.909 501.6850 450.6210 491.5165 2101.231 100
To demonstrate Gregor's comment below, first with 5 rows but putting the object creation outside of the benchmarking:
n = 5
df = data.frame(a = runif(n), b = rnorm(n), c = 1:n)
microbenchmark(dplyr = {df2 <- transmute(df, a = log(a), b = b)},
subset = {df2 <- `[`(transform(df, a = log(a)),1:2)},
within = {df2 <- within(df[1:2], a <- log(a))},
twosteps = {df2 <- df[,1:2]; df2[,1]<-log(df2[,1])})
# twosteps looks much better!
But if you increase the number of rows to be big enough where you might care about the speed differences:
n = 1e6
df = data.frame(a = runif(n), b = rnorm(n), c = 1:n)
microbenchmark(dplyr = {df2 <- transmute(df, a = log(a), b = b)},
subset = {df2 <- `[`(transform(df, a = log(a)),1:2)},
within = {df2 <- within(df[1:2], a <- log(a))},
twosteps = {df2 <- df[,1:2]; df2[,1]<-log(df2[,1])})
The differences go away.