Skip to content
Development
Skill

/r-performance

R performance best practices including profiling, benchmarking, vctrs, and optimization strategies. Use when optimizing R code.

From plugin
r-skills
2128 skills3 agents4 commands4 hooks

Claude Code

$ npx -y skills add ab604/claude-code-r-skills --skill r-performance --agent claude-code

SKILL.md

r-performance.SKILL.md
name: r-performance
description: R performance best practices including profiling, benchmarking, vctrs, and optimization strategies. Use when optimizing R code.

R Performance Best Practices

*Profiling, benchmarking, and optimization strategies for R code*

Performance Tool Selection Guide

When to Use Each Performance Tool

Profiling Tools Decision Matrix

| Tool | Use When | Don't Use When | What It Shows | |------|----------|----------------|---------------| | **`profvis`** | Complex code, unknown bottlenecks | Simple functions, known issues | Time per line, call stack | | **`bench::mark()`** | Comparing alternatives | Single approach | Relative performance, memory | | **`system.time()`** | Quick checks | Detailed analysis | Total runtime only | | **`Rprof()`** | Base R only environments | When profvis available | Raw profiling data |

Step-by-Step Performance Workflow

# 1. Profile first - find the actual bottlenecks
library(profvis)
profvis({
  # Your slow code here
})

# 2. Focus on the slowest parts (80/20 rule)
# Don't optimize until you know where time is spent

# 3. Benchmark alternatives for hot spots
library(bench)
bench::mark(
  current = current_approach(data),
  vectorized = vectorized_approach(data),
  parallel = map(data, in_parallel(func))
)

# 4. Consider tool trade-offs based on bottleneck type

When Each Tool Helps vs Hurts

Parallel Processing (`in_parallel()`)

# Helps when:
# - CPU-intensive computations
# - Embarassingly parallel problems
# - Large datasets with independent operations
# - I/O bound operations (file reading, API calls)

# Hurts when:
# - Simple, fast operations (overhead > benefit)
# - Memory-intensive operations (may cause thrashing)
# - Operations requiring shared state
# - Small datasets

# Example decision point:
expensive_func <- function(x) Sys.sleep(0.1) # 100ms per call
fast_func <- function(x) x^2                 # microseconds per call

# Good for parallel
map(1:100, in_parallel(expensive_func))  # ~10s -> ~2.5s on 4 cores

# Bad for parallel (overhead > benefit)
map(1:100, in_parallel(fast_func))       # 100us -> 50ms (500x slower!)

vctrs Backend Tools

# Use vctrs when:
# - Type safety matters more than raw speed
# - Building reusable package functions
# - Complex coercion/combination logic
# - Consistent behavior across edge cases

# Avoid vctrs when:
# - One-off scripts where speed matters most
# - Simple operations where base R is sufficient
# - Memory is extremely constrained

# Decision point:
simple_combine <- function(x, y) c(x, y)           # Fast, simple
robust_combine <- function(x, y) vec_c(x, y)      # Safer, slight overhead

# Use simple for hot loops, robust for package APIs

Data Backend Selection

# Use data.table when:
# - Very large datasets (>1GB)
# - Complex grouping operations
# - Reference semantics desired
# - Maximum performance critical

# Use dplyr when:
# - Readability and maintainability priority
# - Complex joins and window functions
# - Team familiarity with tidyverse
# - Moderate sized data (<100MB)

# Use base R when:
# - No dependencies allowed
# - Simple operations
# - Teaching/learning contexts

Profiling Best Practices

# 1. Profile realistic data sizes
profvis({
  # Use actual data size, not toy examples
  real_data |> your_analysis()
})

# 2. Profile multiple runs for stability
bench::mark(
  your_function(data),
  min_iterations = 10,  # Multiple runs
  max_iterations = 100
)

# 3. Check memory usage too
bench::mark(
  approach1 = method1(data),
  approach2 = method2(data),
  check = FALSE,  # If outputs differ slightly
  filter_gc = FALSE  # Include GC time
)

# 4. Profile with realistic usage patterns
# Not just isolated function calls

Performance Anti-Patterns to Avoid

# Don't optimize without measuring
# BAD: "This looks slow" -> immediately rewrite
# GOOD: Profile first, optimize bottlenecks

# Don't over-engineer for performance
# BAD: Complex optimizations for 1% gains
# GOOD: Focus on algorithmic improvements

# Don't assume - measure
# BAD: "for loops are always slow in R"
# GOOD: Benchmark your specific use case

# Don't ignore readability costs
# BAD: Unreadable code for minor speedups
# GOOD: Readable code with targeted optimizations

Backend Tools for Performance

  • **Consider lower-level tools when speed is critical**
  • **Use vctrs, rlang backends when appropriate**
  • **Profile to identify true bottlenecks**
# For packages - consider backend tools
# vctrs for type-stable vector operations
# rlang for metaprogramming
# data.table for large data operations

When to Use vctrs

Core Benefits

  • **Type stability** - Predictable output types regardless of input values
  • **Size stability** - Predictable output sizes from input sizes
  • **Consistent coercion rules** - Single set of rules applied everywhere
  • **Robust class design** - Proper S3 vector infrastructure

Use vctrs when

Building Custom Vector Classes

# Good - vctrs-based vector class
new_percent <- function(x = double()) {
  vec_assert(x, double())
  new_vctr(x, class = "pkg_percent")
}

# Automatic data frame compatibility, subsetting, etc.

Type-Stable Functions in Packages

# Good - Guaranteed output type
my_function <- function(x, y) {
  # Always returns double, regardless of input values
  vec_cast(result, double())
}

# Avoid - Type depends on data
sapply(x, function(i) if(condition) 1L else 1.0)

Consistent Coercion/Casting

# Good - Explicit casting with clear rules
vec_cast(x, double())  # Clear intent, predictable behavior

# Good - Common type finding
vec_ptype_common(x, y, z)  # Finds richest compatible type

# Avoid - Base R inconsistencies
c(factor("a"), "b")  # Unpredictable behavior

Size/Length Stability

# Good - Predictable sizing
vec_c(x, y)  # size = vec_size(x) + vec_size(y)
vec_rbind(df1, df2)  # size = sum of input sizes

#
Read more
@ab604
Ships withr-skills

A curated collection of Claude Code configurations for modern R use. These skills, rules, commands, and agents help Claude Code understand R best practices and generate idiomatic, high-quality R code.

2128 skills3 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
212
Star history of ab604/claude-code-r-skills on GitHub, a chart by star-history.com

Other skills on r-skills.

r-bayes

r-bayes

Patterns for Bayesian inference in R using brms, including multilevel models, DAG validation, and marginal effects. Use when…

@ab604@ab604Install Skill
r-oop

r-oop

R object-oriented programming guide for S7, S3, S4, and vctrs. Use when designing R classes or choosing an OOP system.

@ab604@ab604Install Skill
r-package-development

r-package-development

R package development guide covering dependencies, API design, testing, and documentation. Use when developing R packages.

@ab604@ab604Install Skill
r-style-guide

r-style-guide

R style guide covering naming conventions, spacing, layout, and function design best practices. Use when writing R code.

@ab604@ab604Install Skill
rlang-patterns

rlang-patterns

rlang metaprogramming patterns for data-masking, injection operators, and dynamic dots. Use when writing functions that use tidy…

@ab604@ab604Install Skill
tdd-workflow

tdd-workflow

Test-driven development workflow for R using testthat. Use when writing new features, fixing bugs, or refactoring code. Enforces…

@ab604@ab604Install Skill

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills12d309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc13d293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react3d252k
@facebook@facebookInstall Skill

Questions about r-performance.

Which coding agents can use r-performance?
r-performance installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.