r-bayes
Patterns for Bayesian inference in R using brms, including multilevel models, DAG validation, and marginal effects. Use when performing Bayesian analysis.
Modern tidyverse patterns for R including pipes, joins, grouping, purrr, and stringr. Use when writing tidyverse R code.
$ npx -y skills add ab604/claude-code-r-skills --skill tidyverse-patterns --agent claude-codeHow it fires
How this skill gets triggered: by you, by Claude, or both.
/tidyverse-patternsContext preview
The summary Claude sees to decide when to auto-load this skill.
Modern tidyverse patterns for R including pipes, joins, grouping, purrr, and stringr. Use when writing tidyverse R code.
name: tidyverse-patterns description: Modern tidyverse patterns for R including pipes, joins, grouping, purrr, and stringr. Use when writing tidyverse R code.
*Best practices for modern tidyverse development with dplyr 1.1+ and R 4.3+*
1. **Use modern tidyverse patterns** - Prioritize dplyr 1.1+ features, native pipe, and current APIs 2. **Profile before optimizing** - Use profvis and bench to identify real bottlenecks 3. **Write readable code first** - Optimize only when necessary and after profiling 4. **Follow tidyverse style guide** - Consistent naming, spacing, and structure
# Good - Modern native pipe data |> filter(year >= 2020) |> summarise(mean_value = mean(value)) # Avoid - Legacy magrittr pipe data %>% filter(year >= 2020) %>% summarise(mean_value = mean(value))
# Good - Modern join syntax
transactions |>
inner_join(companies, by = join_by(company == id))
# Good - Inequality joins
transactions |>
inner_join(companies, join_by(company == id, year >= since))
# Good - Rolling joins (closest match)
transactions |>
inner_join(companies, join_by(company == id, closest(year >= since)))
# Avoid - Old character vector syntax
transactions |>
inner_join(companies, by = c("company" = "id"))# Validate 1:1 relationship — errors if violated inner_join(x, y, by = join_by(id), relationship = "one-to-one") # Validate many-to-one (left has duplicates, right does not) left_join(transactions, companies, by = join_by(company == id), relationship = "many-to-one") # Ensure all rows from left match something in right inner_join(x, y, by = join_by(id), unmatched = "error") # Prevent NA values from matching each other silently left_join(x, y, by = join_by(id), na_matches = "never") # Combine for strict joins inner_join(x, y, by = join_by(id), relationship = "one-to-one", unmatched = "error", na_matches = "never") # Interactive verification with tidylog # tidylog prints a summary of rows matched/dropped tidylog::inner_join(x, y, by = join_by(id))
# Data masking functions: arrange(), filter(), mutate(), summarise()
# Tidy selection functions: select(), relocate(), across()
# Function arguments - embrace with {{}}
my_summary <- function(data, group_var, summary_var) {
data |>
group_by({{ group_var }}) |>
summarise(mean_val = mean({{ summary_var }}))
}
# Character vectors - use .data[[]]
for (var in names(mtcars)) {
mtcars |> count(.data[[var]]) |> print()
}
# Multiple columns - use across()
data |>
summarise(across({{ summary_vars }}, ~ mean(.x, na.rm = TRUE)))# Good - Per-operation grouping (always returns ungrouped)
data |>
summarise(mean_value = mean(value), .by = category)
# Good - Multiple grouping variables
data |>
summarise(total = sum(revenue), .by = c(company, year))
# Good - pick() for column selection
data |>
summarise(
n_x_cols = ncol(pick(starts_with("x"))),
n_y_cols = ncol(pick(starts_with("y")))
)
# Good - across() for applying functions
data |>
summarise(across(where(is.numeric), mean, .names = "mean_{.col}"), .by = group)
# Good - reframe() for multi-row results
data |>
reframe(quantiles = quantile(x, c(0.25, 0.5, 0.75)), .by = group)
# Avoid - Old persistent grouping pattern
data |>
group_by(category) |>
summarise(mean_value = mean(value)) |>
ungroup()# Problem: negation silently drops rows where condition is NA filter(data, !(value < 0)) # drops rows where value is NA — silent! # Good - filter_out() passes NAs through safely filter_out(data, value < 0) # rows where value is NA are kept # Good - when_any() for OR across columns (dplyr 1.2+) filter(data, when_any(x, y, z, \(col) col > 0)) # any column > 0 # Good - when_all() for AND across columns filter(data, when_all(x, y, z, \(col) !is.na(col))) # no NAs in any # Avoid - verbose base patterns filter(data, !(value < 0) | is.na(value)) # workaround, not idiomatic
# Good - replace_when() for in-place updates (type-stable, NAs unaffected) mutate(data, status = replace_when(status, value < 0 ~ "negative", value == 0 ~ "zero" )) # Avoid - case_when() requires restating the variable in .default mutate(data, status = case_when( value < 0 ~ "negative", value == 0 ~ "zero", .default = status # repetitive )) # Good - case_when() with strict exhaustiveness check mutate(data, grade = case_when( score >= 90 ~ "A", score >= 80 ~ "B", s
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.
Repo: ab604/claude-code-r-skills
Patterns for Bayesian inference in R using brms, including multilevel models, DAG validation, and marginal effects. Use when performing Bayesian analysis.
R object-oriented programming guide for S7, S3, S4, and vctrs. Use when designing R classes or choosing an OOP system.
R package development guide covering dependencies, API design, testing, and documentation. Use when developing R packages.
R performance best practices including profiling, benchmarking, vctrs, and optimization strategies. Use when optimizing R code.
R style guide covering naming conventions, spacing, layout, and function design best practices. Use when writing R code.
rlang metaprogramming patterns for data-masking, injection operators, and dynamic dots. Use when writing functions that use tidy evaluation.