使用者 系統 流逝
0.008 0.000 0.009
Chapter 24: Optimizing R Programs
Shih Chien University
2026-08-03
The golden rule: never optimize blindly. Find where time and memory actually go, then fix that. R gives you tools for both.
The simplest measurement — wrap any expression:
Three numbers: user time (work R itself did), system time (work the OS did on R’s behalf), elapsed time (wall clock). gcFirst=TRUE (the default) runs garbage collection first for a cleaner reading. (For careful microbenchmarks the modern microbenchmark and bench packages repeat and compare.)
To see where the time goes across a whole program, profile it:
Rprof samples the call stack every interval seconds and writes to a file; Rprof(NULL) stops it. summaryRprof ranks functions by self- and total time (and, with memory=, by allocation). This is how you find the one line consuming most of the runtime — often a surprise.
used (Mb) gc trigger (Mb) limit (Mb) max used (Mb)
Ncells 622036 33.3 1408715 75.3 NA 1408715 75.3
Vcells 1153062 8.8 8388608 64.0 24576 2012802 15.4
120 bytes
gc() forces garbage collection and reports memory in use.object.size(x) estimates an object’s footprint — invaluable when a “small” data frame is secretly huge.memory.profile() breaks usage down by object type. (The old Windows-only memory.size()/memory.limit() were retired in R 4.2.)Rprofmem(filename, threshold=) logs large allocations (R must be built with memory profiling).R’s single biggest speed lever: replace iterative element-by-element code with whole-vector operations. The Chapter 8 example, dramatized — growing a vector in a loop versus working on it at once:
elapsed
0.005
elapsed
0
The vectorized version is dramatically faster and clearer. Two reasons: the loop’s body re-dispatches R functions tens of thousands of times, and growing a vector reallocates it on every step. Pre-allocating (v <- numeric(n)) helps; vectorizing helps far more.
Many loops can be rephrased as calls to functions implemented in C:
sapply, lapply, vapply, mapply, tapply (Chapters 9, 12);%*%, crossprod, rowSums, colMeans instead of nested loops;outer, cumsum, diff, tabulate, findInterval for common patterns.elapsed
0.003
elapsed
0
The lesson: a built-in that does the loop inside C beats any R-level loop.
Repeatedly looking values up by name? A named vector or list does a linear scan; an environment is a hash table with near-constant-time lookup. For thousands of keyed lookups, store the data in an environment:
[1] 42
The book benchmarks this against named-vector lookup and finds environments dramatically faster as the table grows — the trick behind many high-performance R packages.
R ships a byte-code compiler (compiler package) that speeds up pure-R functions — and since R 2.14, base and recommended packages are pre-compiled; since R 3.4, functions are JIT-compiled on use:
elapsed
0.003
Tip
The optimization ladder. (1) Vectorize. (2) Use built-in/C functions and matrix algebra. (3) Pre-allocate; use environments for lookups. (4) Compile hot functions. (5) Only then go parallel (Chapter 26) or rewrite the bottleneck in C++ (Rcpp). Always re-profile after each step — and stop when it’s fast enough.
Copyright. These slides are adapted from R in a Nutshell: A Desktop Quick Reference (2nd ed.) by Joseph Adler, O’Reilly Media. All rights reserved by the original author and publisher.
Non-commercial use only. These materials are strictly for educational purposes and may not be used for commercial gain.
Attribution. Any reproduction, distribution, or use of these materials must properly credit the original source.
R in a Nutshell: A Desktop Quick Reference