Role from Awesome ChatGPT Prompts (
prompts.csv, CC0-1.0). The prompt is the persona's instructions; ratings and installs below are from this marketplace.
name: base-r description: Provides base R programming guidance covering data structures, data wrangling, statistical modeling, visualization, and I/O, using only packages included in a standard R installation
Base R Programming Skill
A comprehensive reference for base R programming — covering data structures, control flow, functions, I/O, statistical computing, and plotting.
Quick Reference
Data Structures
# Vectors (atomic)
x <- c(1, 2, 3) # numeric
y <- c("a", "b", "c") # character
z <- c(TRUE, FALSE, TRUE) # logical
# Factor
f <- factor(c("low", "med", "high"), levels = c("low", "med", "high"), ordered = TRUE)
# Matrix
m <- matrix(1:6, nrow = 2, ncol = 3)
m[1, ] # first row
m[, 2] # second column
# List
lst <- list(name = "ali", scores = c(90, 85), passed = TRUE)
lst$name # access by name
lst[[2]] # access by position
# Data frame
df <- data.frame(
id = 1:3,
name = c("a", "b", "c"),
value = c(10.5, 20.3, 30.1),
stringsAsFactors = FALSE
)
df[df$value > 15, ] # filter rows
df$new_col <- df$value * 2 # add column
Subsetting
# Vectors
x[1:3] # by position
x[c(TRUE, FALSE)] # by logical
x[x > 5] # by condition
x[-1] # exclude first
# Data frames
df[1:5, ] # first 5 rows
df[, c("name", "value")] # select columns
df[df$value > 10, "name"] # filter + select
subset(df, value > 10, select = c(name, value))
# which() for index positions
idx <- which(df$value == max(df$value))
Control Flow
# if/else
if (x > 0) {
"positive"
} else if (x == 0) {
"zero"
} else {
"negative"
}
# ifelse (vectorized)
ifelse(x > 0, "pos", "neg")
# for loop
for (i in seq_along(x)) {
cat(i, x[i], "\n")
}
# while
while (condition) {
# body
if (stop_cond) break
}
# switch
switch(type,
"a" = do_a(),
"b" = do_b(),
stop("Unknown type")
)
Functions
# Define
my_func <- function(x, y = 1, ...) {
result <- x + y
return(result) # or just: result
}
# Anonymous functions
sapply(1:5, function(x) x^2)
# R 4.1+ shorthand:
sapply(1:5, \(x) x^2)
# Useful: do.call for calling with a list of args
do.call(paste, list("a", "b", sep = "-"))
Apply Family
# sapply — simplify result to vector/matrix
sapply(lst, length)
# lapply — always returns list
lapply(lst, function(x) x[1])
# vapply — like sapply but with type safety
vapply(lst, length, integer(1))
# apply — over matrix margins (1=rows, 2=cols)
apply(m, 2, sum)
# tapply — apply by groups
tapply(df$value, df$group, mean)
# mapply — multivariate
mapply(function(x, y) x + y, 1:3, 4:6)
# aggregate — like tapply for data frames
aggregate(value ~ group, data = df, FUN = mean)
String Operations
paste("a", "b", sep = "-") # "a-b"
paste0("x", 1:3) # "x1" "x2" "x3"
sprintf("%.2f%%", 3.14159) # "3.14%"
nchar("hello") # 5
substr("hello", 1, 3) # "hel"
gsub("old", "new", text) # replace all
grep("pattern", x) # indices of matches
grepl("pattern", x) # logical vector
strsplit("a,b,c", ",") # list("a","b","c")
trimws(" hi ") # "hi"
tolower("ABC") # "abc"
Data I/O
# CSV
df <- read.csv("data.csv", stringsAsFactors = FALSE)
write.csv(df, "output.csv", row.names = FALSE)
# Tab-delimited
df <- read.delim("data.tsv")
# General
df <- read.table("data.txt", header = TRUE, sep = "\t")
# RDS (single R object, preserves types)
saveRDS(obj, "data.rds")
obj <- readRDS("data.rds")
# RData (multiple objects)
save(df1, df2, file = "data.RData")
load("data.RData")
# Connections
con <- file("big.csv", "r")
chunk <- readLines(con, n = 100)
close(con)
Base Plotting
# Scatter
plot(x, y, main = "Title", xlab = "X", ylab = "Y",
pch = 19, col = "steelblue", cex = 1.2)
# Line
plot(x, y, type = "l", lwd = 2, col = "red")
lines(x, y2, col = "blue", lty = 2) # add line
# Bar
barplot(table(df$category), main = "Counts",
col = "lightblue", las = 2)
# Histogram
hist(x, breaks = 30, col = "grey80",
main = "Distribution", xlab = "Value")
# Box plot
boxplot(value ~ group, data = df,
col = "lightyellow", main = "By Group")
# Multiple plots
par(mfrow = c(2, 2)) # 2x2 grid
# ... four plots ...
par(mfrow = c(1, 1)) # reset
# Save to file
png("plot.png", width = 800, height = 600)
plot(x, y)
dev.off()
# Add elements
legend("topright", legend = c("A", "B"),
col = c("red", "blue"), lty = 1)
abline(h = 0, lty = 2, col = "grey")
text(x, y, labels = names, pos = 3, cex = 0.8)
Statistics
# Descriptive
mean(x); median(x); sd(x); var(x)
quantile(x, probs = c(0.25, 0.5, 0.75))
summary(df)
cor(x, y)
table(df$category) # frequency table
# Linear model
fit <- lm(y ~ x1 + x2, data = df)
summary(fit)
coef(fit)
predict(fit, newdata = new_df)
confint(fit)
# t-test
t.test(x, y) # two-sample
t.test(x, mu = 0) # one-sample
t.test(before, after, paired = TRUE)
# Chi-square
chisq.test(table(df$a, df$b))
# ANOVA
fit <- aov(value ~ group, data = df)
summary(fit)
TukeyHSD(fit)
# Correlation test
cor.test(x, y, method = "pearson")
Data Manipulation
# Merge (join)
merged <- merge(df1, df2, by = "id") # inner
merged <- merge(df1, df2, by = "id", all = TRUE) # full outer
merged <- merge(df1, df2, by = "id", all.x = TRUE) # left
# Reshape
wide <- reshape(long, direction = "wide",
idvar = "id", timevar = "time", v.names = "value")
long <- reshape(wide, direction = "long",
varying = list(c("v1", "v2")), v.names = "value")
# Sort
df[order(df$value), ] # ascending
df[order(-df$value), ] # descending
df[order(df$group, -df$value), ] # multi-column
# Remove duplicates
df[!duplicated(df), ]
df[!duplicated(df$id), ]
# Stack / combine
rbind(df1, df2) # stack rows (same columns)
cbind(df1, df2) # bind columns (same rows)
# Transform columns
df$log_val <- log(df$value)
df$category <- cut(df$value, breaks = c(0, 10, 20, Inf),
labels = c("low", "med", "high"))
Environment & Debugging
ls() # list objects
rm(x) # remove object
rm(list = ls()) # clear all
str(obj) # structure
class(obj) # class
typeof(obj) # internal type
is.na(x) # check NA
complete.cases(df) # rows without NA
traceback() # after error
debug(my_func) # step through
browser() # breakpoint in code
system.time(expr) # timing
Sys.time() # current time
Reference Files
For deeper coverage, read the reference files in references/:
Function Gotchas & Quick Reference (condensed from R 4.5.3 Reference Manual)
Non-obvious behaviors, surprising defaults, and tricky interactions — only what Claude doesn't already know:
- data-wrangling.md — Read when: subsetting returns wrong type, apply on data frame gives unexpected coercion, merge/split/cbind behaves oddly, factor levels persist after filtering, table/duplicated edge cases.
- modeling.md — Read when: formula syntax is confusing (
I(),*vs:,/), aov gives wrong SS type, glm silently fits OLS, nls won't converge, predict returns wrong scale, optim/optimize needs tuning. - statistics.md — Read when: hypothesis test gives surprising result, need to choose correct p.adjust method, clustering parameters seem wrong, distribution function naming is confusing (
d/p/q/rprefixes). - visualization.md — Read when: par settings reset unexpectedly, layout/mfrow interaction is confusing, axis labels are clipped, colors don't look right, need specialty plots (contour, persp, mosaic, pairs).
- io-and-text.md — Read when: read.table silently drops data or misparses columns, regex behaves differently than expected, sprintf formatting is tricky, write.table output has unwanted row names.
- dates-and-system.md — Read when: Date/POSIXct conversion gives wrong day, time zones cause off-by-one, difftime units are unexpected, need to find/list/test files programmatically.
- misc-utilities.md — Read when: do.call behaves differently than direct call, need Reduce/Filter/Map, tryCatch handler doesn't fire, all.equal returns string not logical, time series functions need setup.
Tips for Writing Good R Code
- Use
vapply()oversapply()in production code — it enforces return types - Prefer
seq_along(x)over1:length(x)— the latter breaks whenxis empty - Use
stringsAsFactors = FALSEinread.csv()/data.frame()(default changed in R 4.0) - Vectorize operations instead of writing loops when possible
- Use
stop(),warning(),message()for error handling — notprint() <<-assigns to parent environment — use sparingly and intentionallywith(df, expr)avoids repeatingdf$everywhereSys.setenv()and.Renvironfor environment variables FILE:references/misc-utilities.md
Miscellaneous Utilities — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
do.call
do.call(fun, args_list)—argsmust be a list, even for a single argument.quote = TRUEprevents evaluation of arguments before the call — needed when passing expressions/symbols.- Behavior of
substituteinsidedo.calldiffers from direct calls. Semantics are not fully defined for this case. - Useful pattern:
do.call(rbind, list_of_dfs)to combine a list of data frames.
Reduce / Filter / Map / Find / Position
R's functional programming helpers from base — genuinely non-obvious.
Reduce(f, x)applies binary functionfcumulatively:Reduce("+", 1:4)=((1+2)+3)+4. Direction matters for non-commutative ops.Reduce(f, x, accumulate = TRUE)returns all intermediate results — equivalent to Python'sitertools.accumulate.Reduce(f, x, right = TRUE)folds from the right:f(x1, f(x2, f(x3, x4))).Reducewithinitadds a starting value:Reduce(f, x, init = v)=f(f(f(v, x1), x2), x3).Filter(f, x)keeps elements wheref(elem)isTRUE. Unlikex[sapply(x, f)], handlesNULL/empty correctly.Map(f, ...)is a simple wrapper formapply(f, ..., SIMPLIFY = FALSE)— always returns a list.Find(f, x)returns the first element wheref(elem)isTRUE.Find(f, x, right = TRUE)for last.Position(f, x)returns the index of the first match (likeFindbut returns position, not value).
lengths
lengths(x)returns the length of each element of a list. Equivalent tosapply(x, length)but faster (implemented in C).- Works on any list-like object. Returns integer vector.
conditions (tryCatch / withCallingHandlers)
tryCatchunwinds the call stack — handler runs in the calling environment, not where the error occurred. Cannot resume execution.withCallingHandlersdoes NOT unwind — handler runs where the condition was signaled. Can inspect/log then let the condition propagate.tryCatch(expr, error = function(e) e)returns the error condition object.tryCatch(expr, warning = function(w) {...})catches the first warning and exits. UsewithCallingHandlers+invokeRestart("muffleWarning")to suppress warnings but continue.tryCatchfinallyclause always runs (like Java try/finally).globalCallingHandlers()registers handlers that persist for the session (useful for logging).- Custom conditions:
stop(errorCondition("msg", class = "myError"))then catch withtryCatch(..., myError = function(e) ...).
all.equal
- Tests near equality with tolerance (default
1.5e-8, i.e.,sqrt(.Machine$double.eps)). - Returns
TRUEor a character string describing the difference — NOTFALSE. UseisTRUE(all.equal(x, y))in conditionals. toleranceargument controls numeric tolerance.scalefor absolute vs relative comparison.- Checks attributes, names, dimensions — more thorough than
==.
combn
combn(n, m)orcombn(x, m): generates all combinations ofmitems fromx.- Returns a matrix with
mrows; each column is one combination. FUNargument applies a function to each combination:combn(5, 3, sum)returns sums of all 3-element subsets.simplify = FALSEreturns a list instead of a matrix.
modifyList
modifyList(x, val)replaces elements of listxwith those invalby name.- Setting a value to
NULLremoves that element from the list. - Does add new names not in
x— it usesx[names(val)] <- valinternally, so any name invalgets added or replaced.
relist
- Inverse of
unlist: given a flat vector and a skeleton list, reconstructs the nested structure. relist(flesh, skeleton)—fleshis the flat data,skeletonprovides the shape.- Works with factors, matrices, and nested lists.
txtProgressBar
txtProgressBar(min, max, style = 3)— style 3 shows percentage + bar (most useful).- Update with
setTxtProgressBar(pb, value). Close withclose(pb). - Style 1: rotating
|/-\, style 2: simple progress. Only style 3 shows percentage.
object.size
- Returns an estimate of memory used by an object. Not always exact for shared references.
format(object.size(x), units = "MB")for human-readable output.- Does not count the size of environments or external pointers.
installed.packages / update.packages
installed.packages()can be slow (scans all packages). Usefind.package()orrequireNamespace()to check for a specific package.update.packages(ask = FALSE)updates all packages without prompting.lib.locspecifies which library to check/update.
vignette / demo
vignette()lists all vignettes;vignette("name", package = "pkg")opens a specific one.demo()lists all demos;demo("topic")runs one interactively.browseVignettes()opens vignette browser in HTML.
Time series: acf / arima / ts / stl / decompose
ts(data, start, frequency):frequencyis observations per unit time (12 for monthly, 4 for quarterly).acfdefaulttype = "correlation". Usetype = "partial"for PACF.plot = FALSEto suppress auto-plotting.arima(x, order = c(p,d,q))for ARIMA models.seasonal = list(order = c(P,D,Q), period = S)for seasonal component.arimahandlesNAvalues in the time series (via Kalman filter).stlrequiress.window(seasonal window) — must be specified, no default.s.window = "periodic"assumes fixed seasonality.decompose: simpler thanstl, uses moving averages.type = "additive"or"multiplicative".stlresult components:$time.seriesmatrix with columnsseasonal,trend,remainder. FILE:references/data-wrangling.md
Data Wrangling — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
Extract / Extract.data.frame
Indexing pitfalls in base R.
m[j = 2, i = 1]ism[2, 1]notm[1, 2]— argument names are ignored in[, positional matching only. Never name index args.- Factor indexing:
x[f]uses integer codes of factorf, not its character labels. Usex[as.character(f)]for label-based indexing. x[[]]with no index is always an error.x$namedoes partial matching by default;x[["name"]]does not (exact by default).- Assigning
NULLviax[[i]] <- NULLorx$name <- NULLdeletes that list element. - Data frame
[with single column:df[, 1]returns a vector (drop=TRUE default for columns), butdf[1, ]returns a data frame (drop=FALSE for rows). Usedrop = FALSEexplicitly. - Matrix indexing a data frame (
df[cbind(i,j)]) coerces to matrix first — avoid.
subset
Use interactively only; unsafe for programming.
subsetargument uses non-standard evaluation — column names are resolved in the data frame, which can silently pick up wrong variables in programmatic use. Use[with explicit logic in functions.NAs in the logical condition are treated asFALSE(rows silently dropped).- Factors may retain unused levels after subsetting; call
droplevels().
match / %in%
%in%never returns NA — this makes it safe forif()conditions unlike==.match()returns position of first match only; duplicates intableare ignored.- Factors, raw vectors, and lists are all converted to character before matching.
NaNmatchesNaNbut notNA;NAmatchesNAonly.
apply
- On a data frame,
applycoerces to matrix viaas.matrixfirst — mixed types become character. - Return value orientation is transposed: if FUN returns length-n vector, result has dim
c(n, dim(X)[MARGIN]). Row results become columns. - Factor results are coerced to character in the output array.
...args cannot share names withX,MARGIN, orFUN(partial matching risk).
lapply / sapply / vapply
sapplycan return a vector, matrix, or list unpredictably — usevapplyin non-interactive code with explicitFUN.VALUEtemplate.- Calling primitives directly in
lapplycan cause dispatch issues; wrap infunction(x) is.numeric(x)rather than bareis.numeric. sapplywithsimplify = "array"can produce higher-rank arrays (not just matrices).
tapply
- Returns an array (not a data frame). Class info on return values is discarded (e.g., Date objects become numeric).
...args to FUN are not divided into cells — they apply globally, so FUN should not expect additional args with same length as X.default = NAfills empty cells; setdefault = 0for sum-like operations. Before R 3.4.0 this was hard-coded toNA.- Use
array2DF()to convert result to a data frame.
mapply
- Argument name is
SIMPLIFY(all caps) notsimplify— inconsistent withsapply. MoreArgsmust be a list of args not vectorized over.- Recycles shorter args to common length; zero-length arg gives zero-length result.
merge
- Default
byisintersect(names(x), names(y))— can silently merge on unintended columns if data frames share column names. by = 0orby = "row.names"merges on row names, adding a "Row.names" column.by = NULL(or bothby.x/by.ylength 0) produces Cartesian product.- Result is sorted on
bycolumns by default (sort = TRUE). For unsorted output usesort = FALSE. - Duplicate key matches produce all combinations (one row per match pair).
split
- If
fis a list of factors, interaction is used; levels containing"."can cause unexpected splits unlesssepis changed. drop = FALSE(default) retains empty factor levels as empty list elements.- Supports formula syntax:
split(df, ~ Month).
cbind / rbind
cbindon data frames callsdata.frame(...), notcbind.matrix. Mixing matrices and data frames can give unexpected results.rbindon data frames matches columns by name, not position. Missing columns getNA.cbind(NULL)returnsNULL(not a matrix). For consistency,rbind(NULL)also returnsNULL.
table
- By default excludes NA (
useNA = "no"). UseuseNA = "ifany"orexclude = NULLto count NAs. - Setting
excludenon-empty and non-default impliesuseNA = "ifany". - Result is always an array (even 1D), class "table". Convert to data frame with
as.data.frame(tbl). - Two kinds of NA (factor-level NA vs actual NA) are treated differently depending on
useNA/exclude.
duplicated / unique
duplicatedmarks the second and later occurrences as TRUE, not the first. UsefromLast = TRUEto reverse.- For data frames, operates on whole rows. For lists, compares recursively.
uniquekeeps the first occurrence of each value.
data.frame (gotchas)
stringsAsFactors = FALSEis the default since R 4.0.0 (was TRUE before).- Atomic vectors recycle to match longest column, but only if exact multiple. Protect with
I()to prevent conversion. - Duplicate column names allowed only with
check.names = FALSE, but many operations will de-dup them silently. - Matrix arguments are expanded to multiple columns unless protected by
I().
factor (gotchas)
as.numeric(f)returns integer codes, not original values. Useas.numeric(levels(f))[f]oras.numeric(as.character(f)).- Only
==and!=work between factors; factors must have identical level sets. Ordered factors support<,>. c()on factors unions level sets (since R 4.1.0), but earlier versions converted to integer.- Levels are sorted by default, but sort order is locale-dependent at creation time.
aggregate
- Formula interface (
aggregate(y ~ x, data, FUN)) dropsNAgroups by default. - The data frame method requires
byas a list (not a vector). - Returns columns named after the grouping variables, with result column keeping the original name.
- If FUN returns multiple values, result column is a matrix column inside the data frame.
complete.cases
- Returns a logical vector: TRUE for rows with no NAs across all columns/arguments.
- Works on multiple arguments (e.g.,
complete.cases(x, y)checks both).
order
- Returns a permutation vector of indices, not the sorted values. Use
x[order(x)]to sort. - Default is ascending; use
-xfor descending numeric, ordecreasing = TRUE. - For character sorting, depends on locale. Use
method = "radix"for locale-independent fast sorting. sort.int()withmethod = "radix"is much faster for large integer/character vectors. FILE:references/dates-and-system.md
Dates and System — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
Dates (Date class)
Dateobjects are stored as integer days since 1970-01-01. Arithmetic works in days.Sys.Date()returns current date as Date object.seq.Date(from, to, by = "month")— "month" increments can produce varying-length intervals. Adding 1 month to Jan 31 gives Mar 3 (not Feb 28).diff(dates)returns adifftimeobject in days.format(date, "%Y")for year,"%m"for month,"%d"for day,"%A"for weekday name (locale-dependent).- Years before 1CE may not be handled correctly.
length(date_vector) <- npads withNAs if extended.
DateTimeClasses (POSIXct / POSIXlt)
POSIXct: seconds since 1970-01-01 UTC (compact, a numeric vector).POSIXlt: list with components$sec,$min,$hour,$mday,$mon(0-11!),$year(since 1900!),$wday(0-6, Sunday=0),$yday(0-365).- Converting between POSIXct and Date:
as.Date(posixct_obj)usestz = "UTC"by default — may give different date than intended if original was in another timezone. Sys.time()returns POSIXct in current timezone.strptimereturns POSIXlt;as.POSIXct(strptime(...))to get POSIXct.difftimearithmetic: subtracting POSIXct objects gives difftime. Units auto-selected ("secs", "mins", "hours", "days", "weeks").
difftime
difftime(time1, time2, units = "auto")— auto-selects smallest sensible unit.- Explicit units:
"secs","mins","hours","days","weeks". No "months" or "years" (variable length). as.numeric(diff, units = "hours")to extract numeric value in specific units.units(diff_obj) <- "hours"changes the unit in place.
system.time / proc.time
system.time(expr)returnsuser,system, andelapsedtime.gcFirst = TRUE(default): runs garbage collection before timing for more consistent results.proc.time()returns cumulative time since R started — take differences for intervals.elapsed(wall clock) can be less thanuser(multi-threaded BLAS) or more (I/O waits).
Sys.sleep
Sys.sleep(seconds)— allows fractional seconds. Actual sleep may be longer (OS scheduling).- The process yields to the OS during sleep (does not busy-wait).
options (key options)
Selected non-obvious options:
options(scipen = n): positive biases toward fixed notation, negative toward scientific. Default 0. Applies toprint/format/catbut notsprintf.options(digits = n): significant digits for printing (1-22, default 7). Suggestion only.options(digits.secs = n): max decimal digits for seconds in time formatting (0-6, default 0).options(warn = n): -1 = ignore warnings, 0 = collect (default), 1 = immediate, 2 = convert to errors.options(error = recover): drop into debugger on error.options(error = NULL)resets to default.options(OutDec = ","): change decimal separator in output (affectsformat,print, NOTsprintf).options(stringsAsFactors = FALSE): global default fordata.frame(moot since R 4.0.0 where it's already FALSE).options(expressions = 5000): max nested evaluations. Increase for deep recursion.options(max.print = 99999): controls truncation inprintoutput.options(na.action = "na.omit"): default NA handling in model functions.options(contrasts = c("contr.treatment", "contr.poly")): default contrasts for unordered/ordered factors.
file.path / basename / dirname
file.path("a", "b", "c.txt")→"a/b/c.txt"(platform-appropriate separator).basename("/a/b/c.txt")→"c.txt".dirname("/a/b/c.txt")→"/a/b".file.pathdoes NOT normalize paths (no..resolution); usenormalizePath()for that.
list.files
list.files(pattern = "*.csv")—patternis a regex, not a glob! Useglob2rx("*.csv")or"\\.csv$".full.names = FALSE(default) returns basenames only. Usefull.names = TRUEfor complete paths.recursive = TRUEto search subdirectories.all.files = TRUEto include hidden files (starting with.).
file.info
- Returns data frame with
size,isdir,mode,mtime,ctime,atime,uid,gid. mtime: modification time (POSIXct). Useful forfile.info(f)$mtime.- On some filesystems,
ctimeis status-change time, not creation time.
file_test
file_test("-f", path): TRUE if regular file exists.file_test("-d", path): TRUE if directory exists.file_test("-nt", f1, f2): TRUE if f1 is newer than f2.- More reliable than
file.exists()for distinguishing files from directories. FILE:references/io-and-text.md
I/O and Text Processing — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
read.table (gotchas)
sep = ""(default) means any whitespace (spaces, tabs, newlines) — not a literal empty string.comment.char = "#"by default — lines with#are truncated. Usecomment.char = ""to disable (also faster).headerauto-detection: set to TRUE if first row has one fewer field than subsequent rows (the missing field is assumed to be row names).colClasses = "NULL"skips that column entirely — very useful for speed.read.csvdefaults differ fromread.table:header = TRUE,sep = ",",fill = TRUE,comment.char = "".- For large files: specifying
colClassesandnrowsdramatically reduces memory usage.read.tableis slow for wide data frames (hundreds of columns); usescanordata.table::freadfor matrices. stringsAsFactors = FALSEsince R 4.0.0 (was TRUE before).
write.table (gotchas)
row.names = TRUEby default — produces an unnamed first column that confuses re-reading. Userow.names = FALSEorcol.names = NAfor Excel-compatible CSV.write.csvfixessep = ",",dec = ".", and usesqmethod = "double"— cannot override these via....quote = TRUE(default) quotes character/factor columns. Numeric columns are never quoted.- Matrix-like columns in data frames expand to multiple columns silently.
- Slow for data frames with many columns (hundreds+); each column processed separately by class.
read.fwf
- Reads fixed-width format files.
widthsis a vector of field widths. - Negative widths skip that many characters (useful for ignoring fields).
buffersizecontrols how many lines are read at a time; increase for large files.- Uses
read.tableinternally after splitting fields.
count.fields
- Counts fields per line in a file — useful for diagnosing read errors.
sepandquotearguments match those ofread.table.
grep / grepl / sub / gsub (gotchas)
- Three regex modes: POSIX extended (default),
perl = TRUE,fixed = TRUE. They behave differently for edge cases. - Name arguments explicitly — unnamed args after
x/patternare matched positionally toignore.case,perl, etc. Common source of silent bugs. subreplaces first match only;gsubreplaces all matches.- Backreferences:
"\\1"in replacement (double backslash in R strings). Withperl = TRUE:"\\U\\1"for uppercase conversion. grep(value = TRUE)returns matching elements;grep(value = FALSE)(default) returns indices.greplreturns logical vector — preferred for filtering.regexprreturns first match position + length (as attributes);gregexprreturns all matches as a list.regexecreturns match + capture group positions;gregexecdoes this for all matches.- Character classes like
[:alpha:]must be inside[[:alpha:]](double brackets) in POSIX mode.
strsplit
- Returns a list (one element per input string), even for a single string.
split = ""orsplit = character(0)splits into individual characters.- Match at beginning of string: first element of result is
"". Match at end: no trailing"". fixed = TRUEis faster and avoids regex interpretation.- Common mistake: unnamed arguments silently match
fixed,perl, etc.
substr / substring
substr(x, start, stop): extracts/replaces substring. 1-indexed, inclusive on both ends.substring(x, first, last): same butlastdefaults to1000000L(effectively "to end"). Vectorized overfirst/last.- Assignment form:
substr(x, 1, 3) <- "abc"replaces in place (must be same length replacement).
trimws
which = "both"(default),"left", or"right".whitespace = "[ \\t\\r\\n]"— customizable regex for what counts as whitespace.
nchar
type = "bytes"counts bytes;type = "chars"(default) counts characters;type = "width"counts display width.nchar(NA)returnsNA(not 2).nchar(factor)works on the level labels.keepNA = TRUE(default since R 3.3.0); set toFALSEto count"NA"as 2 characters.
format / formatC
format(x, digits, nsmall):nsmallforces minimum decimal places.big.mark = ","adds thousands separator.formatC(x, format = "f", digits = 2): C-style formatting.format = "e"for scientific,"g"for general.formatreturns character vector; always right-justified by default (justify = "right").
type.convert
- Converts character vectors to appropriate types (logical, integer, double, complex, character).
as.is = TRUE(recommended): keeps characters as character, not factor.- Applied column-wise on data frames.
tryLogical = TRUE(R 4.3+) converts "TRUE"/"FALSE" columns.
Rscript
commandArgs(trailingOnly = TRUE)gets script arguments (excluding R/Rscript flags).#!line on Unix:/usr/bin/env Rscriptor full path.--vanillaor--no-init-fileto skip.Rprofileloading.- Exit code:
quit(status = 1)for error exit.
capture.output
- Captures output from
cat,print, or any expression that writes to stdout. file = NULL(default) returns character vector.file = "out.txt"writes directly to file.type = "message"captures stderr instead.
URLencode / URLdecode
URLencode(url, reserved = FALSE)by default does NOT encode reserved chars (/,?,&, etc.).- Set
reserved = TRUEto encode a URL component (query parameter value).
glob2rx
- Converts shell glob patterns to regex:
glob2rx("*.csv")→"^.*\\.csv$". - Useful with
list.files(pattern = glob2rx("data_*.RDS")). FILE:references/modeling.md
Modeling — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
formula
Symbolic model specification gotchas.
I()is required to use arithmetic operators literally:y ~ x + I(x^2). WithoutI(),^means interaction crossing.*= main effects + interaction:a*bexpands toa + b + a:b.(a+b+c)^2= all main effects + all 2-way interactions (not squaring).-removes terms:(a+b+c)^2 - a:bdrops only thea:binteraction./means nesting:a/b=a + b %in% a=a + a:b..in formula means "all other columns in data" (interms.formulacontext) or "previous contents" (inupdate.formula).- Formula objects carry an environment used for variable lookup;
as.formula("y ~ x")usesparent.frame().
terms / model.matrix
model.matrixcreates the design matrix including dummy coding. Default contrasts:contr.treatmentfor unordered factors,contr.polyfor ordered.termsobject attributes:order(interaction order per term),intercept,factorsmatrix.- Column names from
model.matrixcan be surprising: e.g.,factorLevelNameconcatenation.
glm
- Default
family = gaussian(link = "identity")—glm()with nofamilysilently fits OLS (same aslm, but slower and with deviance-based output). - Common families:
binomial(link = "logit"),poisson(link = "log"),Gamma(link = "inverse"),inverse.gaussian(). binomialaccepts response as: 0/1 vector, logical, factor (second level = success), or 2-column matrixcbind(success, failure).weightsinglmmeans prior weights (not frequency weights) — for frequency weights, use the cbind trick or offset.predict.glm(type = "response")for predicted probabilities; defaulttype = "link"returns log-odds (for logistic) or log-rate (for Poisson).anova(glm_obj, test = "Chisq")for deviance-based tests;"F"is invalid for non-Gaussian families.- Quasi-families (
quasibinomial,quasipoisson) allow overdispersion — no AIC is computed. - Convergence:
control = glm.control(maxit = 100)if default 25 iterations isn't enough.
aov
aovis a wrapper aroundlmthat stores extra info for balanced ANOVA. For unbalanced designs, Type I SS (sequential) are computed — order of terms matters.- For Type III SS, use
car::Anova()or set contrasts tocontr.sum/contr.helmert. - Error strata for repeated measures:
aov(y ~ A*B + Error(Subject/B)). summary.aovgives ANOVA table;summary.lm(aov_obj)gives regression-style summary.
nls
- Requires good starting values in
start = list(...)or convergence fails. - Self-starting models (
SSlogis,SSasymp, etc.) auto-compute starting values. - Algorithm
"port"allows bounds on parameters (lower/upper). - If data fits too exactly (no residual noise), convergence check fails — use
control = list(scaleOffset = 1)or jitter data. weightsargument for weighted NLS;na.actionfor missing value handling.
step / add1
stepdoes stepwise model selection by AIC (default). Usek = log(n)for BIC.- Direction:
direction = "both"(default),"forward", or"backward". add1/drop1evaluate single-term additions/deletions;stepcalls these iteratively.scopeargument defines the upper/lower model bounds for search.stepmodifies the model object in place — can be slow for large models with many candidate terms.
predict.lm / predict.glm
predict.lmwithinterval = "confidence"gives CI for mean response;interval = "prediction"gives PI for new observation (wider).newdatamust have columns matching the original formula variables — factors must have the same levels.predict.glmwithtype = "response"gives predictions on the response scale (e.g., probabilities for logistic);type = "link"(default) gives on the link scale.se.fit = TRUEreturns standard errors; forpredict.glmthese are on the link scale regardless oftype.predict.lmwithtype = "terms"returns the contribution of each term.
loess
spancontrols smoothness (default 0.75). Span < 1 uses that proportion of points; span > 1 uses all points with adjusted distance.- Maximum 4 predictors. Memory usage is roughly quadratic in n (1000 points ~ 10MB).
degree = 0(local constant) is allowed but poorly tested — use with caution.- Not identical to S's
loess; conditioning is not implemented. normalize = TRUE(default) standardizes predictors to common scale; setFALSEfor spatial coords.
lowess vs loess
lowessis the older function; returnslist(x, y)— cannot predict at new points.loessis the newer formula interface withpredictmethod.lowessparameter isf(span, default 2/3);loessparameter isspan(default 0.75).lowessiterdefault is 3 (robustifying iterations);loessdefaultfamily = "gaussian"(no robustness).
smooth.spline
- Default smoothing parameter selected by GCV (generalized cross-validation).
cv = TRUEuses ordinary leave-one-out CV instead — do not use with duplicate x values.sparandlambdacontrol smoothness;dfcan specify equivalent degrees of freedom.- Returns object with
predict,print,plotmethods. Thefitcomponent has knots and coefficients.
optim
- Minimizes by default. To maximize: set
control = list(fnscale = -1). - Default method is Nelder-Mead (no gradients, robust but slow). Poor for 1D — use
"Brent"oroptimize(). "L-BFGS-B"is the only method supporting box constraints (lower/upper). Bounds auto-select this method with a warning."SANN"(simulated annealing): convergence code is always 0 — it never "fails".maxit= total function evals (default 10000), no other stopping criterion.parscale: scale parameters so unit change in each produces comparable objective change. Critical for mixed-scale problems.hessian = TRUE: returns numerical Hessian of the unconstrained problem even if box constraints are active.fncan returnNA/Inf(except"L-BFGS-B"which requires finite values always). Initial value must be finite.
optimize / uniroot
optimize: 1D minimization on a bounded interval. Returnsminimumandobjective.uniroot: finds a root offin[lower, upper]. Requiresf(lower)andf(upper)to have opposite signs.unirootwithextendInt = "yes"can auto-extend the interval to find sign change — but can find spurious roots for functions that don't actually cross zero.nlm: Newton-type minimizer. Gradient/Hessian as attributes of the return value fromfn(unusual interface).
TukeyHSD
- Requires a fitted
aovobject (notlm). - Default
conf.level = 0.95. Returns adjusted p-values and confidence intervals for all pairwise comparisons. - Only meaningful for balanced or near-balanced designs; can be liberal for very unbalanced data.
anova (for lm)
anova(model): sequential (Type I) SS — order of terms matters.anova(model1, model2): F-test comparing nested models.- For Type II or III SS use
car::Anova(). FILE:references/statistics.md
Statistics — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
chisq.test
correct = TRUE(default) applies Yates continuity correction for 2x2 tables only.simulate.p.value = TRUE: Monte Carlo withB = 2000replicates (min p ~ 0.0005). Simulation assumes fixed marginals (Fisher-style sampling, not the chi-sq assumption).- For goodness-of-fit: pass a vector, not a matrix.
pmust sum to 1 (or setrescale.p = TRUE). - Return object includes
$expected,$residuals(Pearson), and$stdres(standardized).
wilcox.test
exact = TRUEby default for small samples with no ties. With ties, normal approximation used.correct = TRUEapplies continuity correction to normal approximation.conf.int = TRUEcomputes Hodges-Lehmann estimator and confidence interval (not just the p-value).- Paired test:
paired = TRUEuses signed-rank test (Wilcoxon), not rank-sum (Mann-Whitney).
fisher.test
- For tables larger than 2x2, uses simulation (
simulate.p.value = TRUE) or network algorithm. workspacecontrols memory for the network algorithm; increase if you get errors on large tables.orargument tests a specific odds ratio (default 1) — only for 2x2 tables.
ks.test
- Two-sample test or one-sample against a reference distribution.
- Does not handle ties well — warns and uses asymptotic approximation.
- For composite hypotheses (parameters estimated from data), p-values are conservative (too large). Use
dgoforks.testwithexact = NULLfor discrete distributions.
p.adjust
- Methods:
"holm"(default),"BH"(Benjamini-Hochberg FDR),"bonferroni","BY","hochberg","hommel","fdr"(alias for BH),"none". nargument: total number of hypotheses (can be larger thanlength(p)if some p-values are excluded).- Handles
NAs: adjusted p-values areNAwhere input isNA.
pairwise.t.test / pairwise.wilcox.test
p.adjust.methoddefaults to"holm". Change to"BH"for FDR control.pool.sd = TRUE(default for t-test): uses pooled SD across all groups (assumes equal variances).- Returns a matrix of p-values, not test statistics.
shapiro.test
- Sample size must be between 3 and 5000.
- Tests normality; low p-value = evidence against normality.
kmeans
nstart > 1recommended (e.g.,nstart = 25): runs algorithm from multiple random starts, returns best.- Default
iter.max = 10— may be too low for convergence. Increase for large/complex data. - Default algorithm is "Hartigan-Wong" (generally best). Very close points may cause non-convergence (warning with
ifault = 4). - Cluster numbering is arbitrary; ordering may differ across platforms.
- Always returns k clusters when k is specified (except Lloyd-Forgy may return fewer).
hclust
method = "ward.D2"implements Ward's criterion correctly (using squared distances). The older"ward.D"did not square distances (retained for back-compatibility).- Input must be a
distobject. Useas.dist()to convert a symmetric matrix. hang = -1inplot()aligns all labels at the bottom.
dist
method = "euclidean"(default). Other options:"manhattan","maximum","canberra","binary","minkowski".- Returns a
distobject (lower triangle only). Useas.matrix()to get full matrix. "canberra": terms with zero numerator and denominator are omitted from the sum (not treated as 0/0).Infvalues: Euclidean distance involvingInfisInf. MultipleInfs in same obs giveNaNfor some methods.
prcomp vs princomp
prcompuses SVD (numerically superior);princompuseseigenon covariance (less stable, N-1 vs N scaling).scale. = TRUEinprcompstandardizes variables; important when variables have very different scales.princompstandard deviations differ fromprcompby factorsqrt((n-1)/n).- Both return
$rotation(loadings) and$x(scores); sign of components may differ between runs.
density
- Default bandwidth:
bw = "nrd0"(Silverman's rule of thumb). For multimodal data, consider"SJ"or"bcv". adjust: multiplicative factor on bandwidth.adjust = 0.5halves the bandwidth (less smooth).- Default kernel:
"gaussian". Range of density extends beyond data range (controlled bycut, default 3 bandwidths). n = 512: number of evaluation points. Increase for smoother plotting.from/to: explicitly bound the evaluation range.
quantile
- Nine
typeoptions (1-9). Defaulttype = 7(R default, linear interpolation). Type 1 = inverse of empirical CDF (SAS default). Types 4-9 are continuous; 1-3 are discontinuous. na.rm = FALSEby default — returns NA if any NAs present.names = TRUEby default, adding "0%", "25%", etc. as names.
Distributions (gotchas across all)
All distribution functions follow the d/p/q/r pattern. Common non-obvious points:
nargument inr*()functions: iflength(n) > 1, useslength(n)as the count, notnitself. Sornorm(c(1,2,3))generates 3 values, not 1+2+3.log = TRUE/log.p = TRUE: compute on log scale for numerical stability in tails.lower.tail = FALSEgives survival function P(X > x) directly (more accurate than 1 - pnorm() in tails).- Gamma: parameterized by
shapeandrate(= 1/scale). Defaultrate = 1. Specifying bothrateandscaleis an error. - Beta:
shape1(alpha),shape2(beta) — nomean/sdparameterization. - Poisson
dpois:xcan be non-integer (returns 0 with a warning for non-integer values iflog = FALSE). - Weibull:
shapeandscale(norate). R's parameterization:f(x) = (shape/scale)(x/scale)^(shape-1) exp(-(x/scale)^shape). - Lognormal:
meanlogandsdlogare mean/sd of the log, not of the distribution itself.
cor.test
- Default method:
"pearson". Also"kendall"and"spearman". - Returns
$estimate,$p.value,$conf.int(CI only for Pearson). - Formula interface:
cor.test(~ x + y, data = df)— note the~with no LHS.
ecdf
- Returns a function (step function). Call it on new values:
Fn <- ecdf(x); Fn(3.5). plot(ecdf(x))gives the empirical CDF plot.- The returned function is right-continuous with left limits (cadlag).
weighted.mean
- Handles
NAin weights: observation is dropped if weight isNA. - Weights do not need to sum to 1; they are normalized internally. FILE:references/visualization.md
Visualization — Quick Reference
Non-obvious behaviors, gotchas, and tricky defaults for R functions. Only what Claude doesn't already know.
par (gotchas)
par()settings are per-device. Opening a new device resets everything.- Setting
mfrow/mfcolresetscexto 1 andmexto 1. With 2x2 layout, basecexis multiplied by 0.83; with 3+ rows/columns, by 0.66. mai(inches),mar(lines),pin,plt,ptyall interact. Restoring all saved parameters after device resize can produce inconsistent results — last-alphabetically wins.bgset viapar()also setsnew = FALSE. Settingfgviapar()also setscol.xpd = NAclips to device region (allows drawing in outer margins);xpd = TRUEclips to figure region;xpd = FALSE(default) clips to plot region.mgp = c(3, 1, 0): controls title line (mgp[1]), label line (mgp[2]), axis line (mgp[3]). All inmexunits.las: 0 = parallel to axis, 1 = horizontal, 2 = perpendicular, 3 = vertical. Does not respond tosrt.tck = 1draws grid lines across the plot.tcl = -0.5(default) gives outward ticks.usrwith log scale: contains log10 of the coordinate limits, not the raw values.- Read-only parameters:
cin,cra,csi,cxy,din,page.
layout
layout(mat)wherematis a matrix of integers specifying figure arrangement.widths/heightsacceptlcm()for absolute sizes mixed with relative sizes.- More flexible than
mfrow/mfcolbut cannot be queried once set (unlikepar("mfrow")). layout.show(n)visualizes the layout for debugging.
axis / mtext
axis(side, at, labels):side1=bottom, 2=left, 3=top, 4=right.- Default gap between axis labels controlled by
par("mgp"). Labels can overlap if not managed. mtext:lineargument positions text in margin lines (0 = adjacent to plot, positive = outward).adjcontrols horizontal position (0-1).mtextwithouter = TRUEwrites in the outer margin (set bypar(oma = ...)).
curve
- First argument can be an expression in
xor a function:curve(sin, 0, 2*pi)orcurve(x^2 + 1, 0, 10). add = TRUEto overlay on existing plot. Defaultn = 101evaluation points.xname = "x"by default; change if your expression uses a different variable name.
pairs
panelfunction receives(x, y, ...)for each pair.lower.panel,upper.panel,diag.panelfor different regions.gapcontrols spacing between panels (default 1).- Formula interface:
pairs(~ var1 + var2 + var3, data = df).
coplot
- Conditioning plots:
coplot(y ~ x | a)orcoplot(y ~ x | a * b)for two conditioning variables. panelfunction can be customized;rows/columnscontrol layout.- Default panel draws points; use
panel = panel.smoothfor loess overlay.
matplot / matlines / matpoints
- Plots columns of one matrix against columns of another. Recycles
col,lty,pchacross columns. type = "l"by default (unlikeplotwhich defaults to"p").- Useful for plotting multiple time series or fitted curves simultaneously.
contour / filled.contour / image
contour(x, y, z):zmust be a matrix withdim = c(length(x), length(y)).filled.contourhas a non-standard layout — it creates its own plot region for the color key. Cannot usepar(mfrow)with it. Adding elements requires theplot.axesargument.image: plots z-values as colored rectangles. Default color scheme may be misleading; setcolexplicitly.- For
image,xandyspecify cell boundaries or midpoints depending on context.
persp
persp(x, y, z, theta, phi):theta= azimuthal angle,phi= colatitude.- Returns a transformation matrix (invisible) for projecting 3D to 2D — use
trans3d()to add points/lines to the perspective plot. shadeandcolcontrol surface shading.border = NAremoves grid lines.
segments / arrows / rect / polygon
- All take vectorized coordinates; recycle as needed.
arrows:code = 1(head at start),code = 2(head at end, default),code = 3(both).polygon: last point auto-connects to first. Fill withcol;bordercontrols outline.rect(xleft, ybottom, xright, ytop)— note argument order is not the same as other systems.
dev / dev.off / dev.copy
dev.new()opens a new device.dev.off()closes current device (and flushes output for file devices likepdf).dev.off()on the last open device reverts to null device.dev.copy(pdf, file = "plot.pdf")followed bydev.off()to save current plot.dev.list()returns all open devices;dev.cur()the active one.
- Must call
dev.off()to finalize the file. Without it, file may be empty/corrupt. onefile = TRUE(default): multiple pages in one PDF.onefile = FALSE: one file per page (uses%din filename for numbering).useDingbats = FALSErecommended to avoid issues with certain PDF viewers and pch symbols.- Default size: 7x7 inches.
familycontrols font family.
png / bitmap devices
rescontrols DPI (default 72). For publication:res = 300with appropriatewidth/heightin pixels or inches (withunits = "in").type = "cairo"(on systems with cairo) gives better antialiasing than default.bg = "transparent"for transparent background (PNG supports alpha).
colors / rgb / hcl / col2rgb
colors()returns all 657 named colors.col2rgb("color")returns RGB matrix.rgb(r, g, b, alpha, maxColorValue = 255)— notemaxColorValuedefault is 1, not 255.hcl(h, c, l): perceptually uniform color space. Preferred for color scales.adjustcolor(col, alpha.f = 0.5): easy way to add transparency.
colorRamp / colorRampPalette
colorRampreturns a function mapping [0,1] to RGB matrix.colorRampPalettereturns a function takingnand returningninterpolated colors.space = "Lab"gives more perceptually uniform interpolation than"rgb".
palette / recordPlot
palette()returns current palette (default 8 colors).palette("Set1")sets a built-in palette.- Integer colors in plots index into the palette (with wrapping). Index 0 = background color.
recordPlot()/replayPlot(): save and restore a complete plot — device-dependent and fragile across sessions. FILE:assets/analysis_template.R
============================================================
Analysis Template — Base R
Copy this file, rename it, and fill in your details.
============================================================
Author :
Date :
Data :
Purpose :
============================================================
── 0. Setup ─────────────────────────────────────────────────
Clear environment (optional — comment out if loading into existing session)
rm(list = ls())
Set working directory if needed
setwd("/path/to/your/project")
Reproducibility
set.seed(42)
Libraries — uncomment what you need
library(haven) # read .dta / .sav / .sas
library(readxl) # read Excel files
library(openxlsx) # write Excel files
library(foreign) # older Stata / SPSS formats
library(survey) # survey-weighted analysis
library(lmtest) # Breusch-Pagan, Durbin-Watson etc.
library(sandwich) # robust standard errors
library(car) # Type II/III ANOVA, VIF
── 1. Load Data ─────────────────────────────────────────────
df <- read.csv("your_data.csv", stringsAsFactors = FALSE)
df <- readRDS("your_data.rds")
df <- haven::read_dta("your_data.dta")
First look — always run these
dim(df) str(df) head(df, 10) summary(df)
── 2. Data Quality Check ────────────────────────────────────
Missing values
na_report <- data.frame( column = names(df), n_miss = colSums(is.na(df)), pct_miss = round(colMeans(is.na(df)) * 100, 1), row.names = NULL ) print(na_report[na_report$n_miss > 0, ])
Duplicates
n_dup <- sum(duplicated(df)) cat(sprintf("Duplicate rows: %d\n", n_dup))
Unique values for categorical columns
cat_cols <- names(df)[sapply(df, function(x) is.character(x) | is.factor(x))] for (col in cat_cols) { cat(sprintf("\n%s (%d unique):\n", col, length(unique(df[[col]])))) print(table(df[[col]], useNA = "ifany")) }
── 3. Clean & Transform ─────────────────────────────────────
Rename columns (example)
names(df)[names(df) == "old_name"] <- "new_name"
Convert types
df$group <- as.factor(df$group)
df$date <- as.Date(df$date, format = "%Y-%m-%d")
Recode values (example)
df$gender <- ifelse(df$gender == 1, "Male", "Female")
Create new variables (example)
df$log_income <- log(df$income + 1)
df$age_group <- cut(df$age,
breaks = c(0, 25, 45, 65, Inf),
labels = c("18-25", "26-45", "46-65", "65+"))
Filter rows (example)
df <- df[df$year >= 2010, ]
df <- df[complete.cases(df[, c("outcome", "predictor")]), ]
Drop unused factor levels
df <- droplevels(df)
── 4. Descriptive Statistics ────────────────────────────────
Numeric summary
num_cols <- names(df)[sapply(df, is.numeric)] round(sapply(df[num_cols], function(x) c( n = sum(!is.na(x)), mean = mean(x, na.rm = TRUE), sd = sd(x, na.rm = TRUE), median = median(x, na.rm = TRUE), min = min(x, na.rm = TRUE), max = max(x, na.rm = TRUE) )), 3)
Cross-tabulation
table(df$group, df$category, useNA = "ifany")
prop.table(table(df$group, df$category), margin = 1) # row proportions
── 5. Visualization (EDA) ───────────────────────────────────
par(mfrow = c(2, 2))
Histogram of main outcome
hist(df$outcome_var, main = "Distribution of Outcome", xlab = "Outcome", col = "steelblue", border = "white", breaks = 30)
Boxplot by group
boxplot(outcome_var ~ group_var, data = df, main = "Outcome by Group", col = "lightyellow", las = 2)
Scatter plot
plot(df$predictor, df$outcome_var, main = "Predictor vs Outcome", xlab = "Predictor", ylab = "Outcome", pch = 19, col = adjustcolor("steelblue", alpha.f = 0.5), cex = 0.8) abline(lm(outcome_var ~ predictor, data = df), col = "red", lwd = 2)
Correlation matrix (numeric columns only)
cor_mat <- cor(df[num_cols], use = "complete.obs") image(cor_mat, main = "Correlation Matrix", col = hcl.colors(20, "RdBu", rev = TRUE))
par(mfrow = c(1, 1))
── 6. Analysis ───────────────────────────────────────────────
·· 6a. Comparison of means ··
t.test(outcome_var ~ group_var, data = df)
·· 6b. Linear regression ··
fit <- lm(outcome_var ~ predictor1 + predictor2 + group_var, data = df) summary(fit) confint(fit)
Check VIF for multicollinearity (requires car)
car::vif(fit)
Robust standard errors (requires lmtest + sandwich)
lmtest::coeftest(fit, vcov = sandwich::vcovHC(fit, type = "HC3"))
·· 6c. ANOVA ··
fit_aov <- aov(outcome_var ~ group_var, data = df)
summary(fit_aov)
TukeyHSD(fit_aov)
·· 6d. Logistic regression (binary outcome) ··
fit_logit <- glm(binary_outcome ~ x1 + x2,
data = df,
family = binomial(link = "logit"))
summary(fit_logit)
exp(coef(fit_logit)) # odds ratios
exp(confint(fit_logit)) # OR confidence intervals
── 7. Model Diagnostics ─────────────────────────────────────
par(mfrow = c(2, 2)) plot(fit) par(mfrow = c(1, 1))
Residual normality
shapiro.test(residuals(fit))
Homoscedasticity (requires lmtest)
lmtest::bptest(fit)
── 8. Save Output ────────────────────────────────────────────
Cleaned data
write.csv(df, "data_clean.csv", row.names = FALSE)
saveRDS(df, "data_clean.rds")
Model results to text file
sink("results.txt")
cat("=== Linear Model ===\n")
print(summary(fit))
cat("\n=== Confidence Intervals ===\n")
print(confint(fit))
sink()
Plots to file
png("figure1_distributions.png", width = 1200, height = 900, res = 150)
par(mfrow = c(2, 2))
# ... your plots ...
par(mfrow = c(1, 1))
dev.off()
============================================================
END OF TEMPLATE
============================================================
FILE:scripts/check_data.R
check_data.R — Quick data quality report for any R data frame
Usage: source("check_data.R") then call check_data(df)
Or: source("check_data.R"); check_data(read.csv("yourfile.csv"))
check_data <- function(df, top_n_levels = 8) {
if (!is.data.frame(df)) stop("Input must be a data frame.")
n_row <- nrow(df) n_col <- ncol(df)
cat("══════════════════════════════════════════\n") cat(" DATA QUALITY REPORT\n") cat("══════════════════════════════════════════\n") cat(sprintf(" Rows: %d Columns: %d\n", n_row, n_col)) cat("══════════════════════════════════════════\n\n")
── 1. Column overview ──────────────────────
cat("── COLUMN OVERVIEW ────────────────────────\n")
for (col in names(df)) { x <- df[[col]] cls <- class(x)[1] n_na <- sum(is.na(x)) pct <- round(n_na / n_row * 100, 1) n_uniq <- length(unique(x[!is.na(x)]))
na_flag <- if (n_na == 0) "" else sprintf(" *** %d NAs (%.1f%%)", n_na, pct)
cat(sprintf(" %-20s %-12s %d
Truncated - read the full file at https://github.com/f/awesome-chatgpt-prompts/blob/main/prompts.csv.
