--- 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 ```r # 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 ```r # 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 ```r # 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 ```r # 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 ```r # 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 ```r 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 ```r # 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 ```r # 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 ```r # 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 ```r # 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 ```r 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`/`r` prefixes). - **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()` over `sapply()` in production code — it enforces return types - Prefer `seq_along(x)` over `1:length(x)` — the latter breaks when `x` is empty - Use `stringsAsFactors = FALSE` in `read.csv()` / `data.frame()` (default changed in R 4.0) - Vectorize operations instead of writing loops when possible - Use `stop()`, `warning()`, `message()` for error handling — not `print()` - `<<-` assigns to parent environment — use sparingly and intentionally - `with(df, expr)` avoids repeating `df$` everywhere - `Sys.setenv()` and `.Renviron` for 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)` — `args` must be a **list**, even for a single argument. - `quote = TRUE` prevents evaluation of arguments before the call — needed when passing expressions/symbols. - Behavior of `substitute` inside `do.call` differs 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 function `f` cumulatively: `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's `itertools.accumulate`. - `Reduce(f, x, right = TRUE)` folds from the right: `f(x1, f(x2, f(x3, x4)))`. - `Reduce` with `init` adds a starting value: `Reduce(f, x, init = v)` = `f(f(f(v, x1), x2), x3)`. - `Filter(f, x)` keeps elements where `f(elem)` is `TRUE`. Unlike `x[sapply(x, f)]`, handles `NULL`/empty correctly. - `Map(f, ...)` is a simple wrapper for `mapply(f, ..., SIMPLIFY = FALSE)` — always returns a list. - `Find(f, x)` returns the **first** element where `f(elem)` is `TRUE`. `Find(f, x, right = TRUE)` for last. - `Position(f, x)` returns the **index** of the first match (like `Find` but returns position, not value). --- ## lengths - `lengths(x)` returns the length of **each element** of a list. Equivalent to `sapply(x, length)` but faster (implemented in C). - Works on any list-like object. Returns integer vector. --- ## conditions (tryCatch / withCallingHandlers) - `tryCatch` **unwinds** the call stack — handler runs in the calling environment, not where the error occurred. Cannot resume execution. - `withCallingHandlers` does 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. Use `withCallingHandlers` + `invokeRestart("muffleWarning")` to suppress warnings but continue. - `tryCatch` `finally` clause 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 with `tryCatch(..., myError = function(e) ...)`. --- ## all.equal - Tests **near equality** with tolerance (default `1.5e-8`, i.e., `sqrt(.Machine$double.eps)`). - Returns `TRUE` or a **character string** describing the difference — NOT `FALSE`. Use `isTRUE(all.equal(x, y))` in conditionals. - `tolerance` argument controls numeric tolerance. `scale` for absolute vs relative comparison. - Checks attributes, names, dimensions — more thorough than `==`. --- ## combn - `combn(n, m)` or `combn(x, m)`: generates all combinations of `m` items from `x`. - Returns a **matrix** with `m` rows; each column is one combination. - `FUN` argument applies a function to each combination: `combn(5, 3, sum)` returns sums of all 3-element subsets. - `simplify = FALSE` returns a list instead of a matrix. --- ## modifyList - `modifyList(x, val)` replaces elements of list `x` with those in `val` by **name**. - Setting a value to `NULL` **removes** that element from the list. - **Does** add new names not in `x` — it uses `x[names(val)] <- val` internally, so any name in `val` gets added or replaced. --- ## relist - Inverse of `unlist`: given a flat vector and a skeleton list, reconstructs the nested structure. - `relist(flesh, skeleton)` — `flesh` is the flat data, `skeleton` provides 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 with `close(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). Use `find.package()` or `requireNamespace()` to check for a specific package. - `update.packages(ask = FALSE)` updates all packages without prompting. - `lib.loc` specifies 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)`: `frequency` is observations per unit time (12 for monthly, 4 for quarterly). - `acf` default `type = "correlation"`. Use `type = "partial"` for PACF. `plot = FALSE` to 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. - `arima` handles `NA` values in the time series (via Kalman filter). - `stl` requires `s.window` (seasonal window) — must be specified, no default. `s.window = "periodic"` assumes fixed seasonality. - `decompose`: simpler than `stl`, uses moving averages. `type = "additive"` or `"multiplicative"`. - `stl` result components: `$time.series` matrix with columns `seasonal`, `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]` is `m[2, 1]` not `m[1, 2]` — argument names are **ignored** in `[`, positional matching only. Never name index args. - Factor indexing: `x[f]` uses integer codes of factor `f`, not its character labels. Use `x[as.character(f)]` for label-based indexing. - `x[[]]` with no index is always an error. `x$name` does partial matching by default; `x[["name"]]` does not (exact by default). - Assigning `NULL` via `x[[i]] <- NULL` or `x$name <- NULL` **deletes** that list element. - Data frame `[` with single column: `df[, 1]` returns a **vector** (drop=TRUE default for columns), but `df[1, ]` returns a **data frame** (drop=FALSE for rows). Use `drop = FALSE` explicitly. - Matrix indexing a data frame (`df[cbind(i,j)]`) coerces to matrix first — avoid. --- ## subset Use interactively only; unsafe for programming. - `subset` argument 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. - `NA`s in the logical condition are treated as `FALSE` (rows silently dropped). - Factors may retain unused levels after subsetting; call `droplevels()`. --- ## match / %in% - `%in%` **never returns NA** — this makes it safe for `if()` conditions unlike `==`. - `match()` returns position of **first** match only; duplicates in `table` are ignored. - Factors, raw vectors, and lists are all converted to character before matching. - `NaN` matches `NaN` but not `NA`; `NA` matches `NA` only. --- ## apply - On a **data frame**, `apply` coerces to matrix via `as.matrix` first — 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 with `X`, `MARGIN`, or `FUN` (partial matching risk). --- ## lapply / sapply / vapply - `sapply` can return a vector, matrix, or list unpredictably — use `vapply` in non-interactive code with explicit `FUN.VALUE` template. - Calling primitives directly in `lapply` can cause dispatch issues; wrap in `function(x) is.numeric(x)` rather than bare `is.numeric`. - `sapply` with `simplify = "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 = NA` fills empty cells; set `default = 0` for sum-like operations. Before R 3.4.0 this was hard-coded to `NA`. - Use `array2DF()` to convert result to a data frame. --- ## mapply - Argument name is `SIMPLIFY` (all caps) not `simplify` — inconsistent with `sapply`. - `MoreArgs` must be a **list** of args not vectorized over. - Recycles shorter args to common length; zero-length arg gives zero-length result. --- ## merge - Default `by` is `intersect(names(x), names(y))` — can silently merge on unintended columns if data frames share column names. - `by = 0` or `by = "row.names"` merges on row names, adding a "Row.names" column. - `by = NULL` (or both `by.x`/`by.y` length 0) produces **Cartesian product**. - Result is sorted on `by` columns by default (`sort = TRUE`). For unsorted output use `sort = FALSE`. - Duplicate key matches produce **all combinations** (one row per match pair). --- ## split - If `f` is a list of factors, interaction is used; levels containing `"."` can cause unexpected splits unless `sep` is changed. - `drop = FALSE` (default) retains empty factor levels as empty list elements. - Supports formula syntax: `split(df, ~ Month)`. --- ## cbind / rbind - `cbind` on data frames calls `data.frame(...)`, not `cbind.matrix`. Mixing matrices and data frames can give unexpected results. - `rbind` on data frames matches columns **by name**, not position. Missing columns get `NA`. - `cbind(NULL)` returns `NULL` (not a matrix). For consistency, `rbind(NULL)` also returns `NULL`. --- ## table - By default **excludes NA** (`useNA = "no"`). Use `useNA = "ifany"` or `exclude = NULL` to count NAs. - Setting `exclude` non-empty and non-default implies `useNA = "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 - `duplicated` marks the **second and later** occurrences as TRUE, not the first. Use `fromLast = TRUE` to reverse. - For data frames, operates on whole rows. For lists, compares recursively. - `unique` keeps the **first** occurrence of each value. --- ## data.frame (gotchas) - `stringsAsFactors = FALSE` is 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. Use `as.numeric(levels(f))[f]` or `as.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)`) drops `NA` groups by default. - The data frame method requires `by` as 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 `-x` for descending numeric, or `decreasing = TRUE`. - For character sorting, depends on locale. Use `method = "radix"` for locale-independent fast sorting. - `sort.int()` with `method = "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) - `Date` objects 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 a `difftime` object 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) <- n` pads with `NA`s 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)` uses `tz = "UTC"` by default — may give different date than intended if original was in another timezone. - `Sys.time()` returns POSIXct in current timezone. - `strptime` returns POSIXlt; `as.POSIXct(strptime(...))` to get POSIXct. - `difftime` arithmetic: 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)` returns `user`, `system`, and `elapsed` time. - `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 than `user` (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 to `print`/`format`/`cat` but not `sprintf`. - `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 (affects `format`, `print`, NOT `sprintf`). - `options(stringsAsFactors = FALSE)`: global default for `data.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 in `print` output. - `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.path` does NOT normalize paths (no `..` resolution); use `normalizePath()` for that. --- ## list.files - `list.files(pattern = "*.csv")` — `pattern` is a **regex**, not a glob! Use `glob2rx("*.csv")` or `"\\.csv$"`. - `full.names = FALSE` (default) returns basenames only. Use `full.names = TRUE` for complete paths. - `recursive = TRUE` to search subdirectories. - `all.files = TRUE` to include hidden files (starting with `.`). --- ## file.info - Returns data frame with `size`, `isdir`, `mode`, `mtime`, `ctime`, `atime`, `uid`, `gid`. - `mtime`: modification time (POSIXct). Useful for `file.info(f)$mtime`. - On some filesystems, `ctime` is 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. Use `comment.char = ""` to disable (also faster). - `header` auto-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.csv` defaults differ from `read.table`: `header = TRUE`, `sep = ","`, `fill = TRUE`, `comment.char = ""`. - For large files: specifying `colClasses` and `nrows` dramatically reduces memory usage. `read.table` is slow for wide data frames (hundreds of columns); use `scan` or `data.table::fread` for matrices. - `stringsAsFactors = FALSE` since R 4.0.0 (was TRUE before). --- ## write.table (gotchas) - `row.names = TRUE` by default — produces an unnamed first column that confuses re-reading. Use `row.names = FALSE` or `col.names = NA` for Excel-compatible CSV. - `write.csv` fixes `sep = ","`, `dec = "."`, and uses `qmethod = "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. `widths` is a vector of field widths. - **Negative widths skip** that many characters (useful for ignoring fields). - `buffersize` controls how many lines are read at a time; increase for large files. - Uses `read.table` internally after splitting fields. --- ## count.fields - Counts fields per line in a file — useful for diagnosing read errors. - `sep` and `quote` arguments match those of `read.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`/`pattern` are matched positionally to `ignore.case`, `perl`, etc. Common source of silent bugs. - `sub` replaces **first** match only; `gsub` replaces **all** matches. - Backreferences: `"\\1"` in replacement (double backslash in R strings). With `perl = TRUE`: `"\\U\\1"` for uppercase conversion. - `grep(value = TRUE)` returns matching **elements**; `grep(value = FALSE)` (default) returns **indices**. - `grepl` returns logical vector — preferred for filtering. - `regexpr` returns first match position + length (as attributes); `gregexpr` returns all matches as a list. - `regexec` returns match + capture group positions; `gregexec` does 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 = ""` or `split = character(0)` splits into individual characters. - Match at beginning of string: first element of result is `""`. Match at end: no trailing `""`. - `fixed = TRUE` is 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 but `last` defaults to `1000000L` (effectively "to end"). Vectorized over `first`/`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)` returns `NA` (not 2). `nchar(factor)` works on the level labels. - `keepNA = TRUE` (default since R 3.3.0); set to `FALSE` to count `"NA"` as 2 characters. --- ## format / formatC - `format(x, digits, nsmall)`: `nsmall` forces minimum decimal places. `big.mark = ","` adds thousands separator. - `formatC(x, format = "f", digits = 2)`: C-style formatting. `format = "e"` for scientific, `"g"` for general. - `format` returns 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 Rscript` or full path. - `--vanilla` or `--no-init-file` to skip `.Rprofile` loading. - 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 = TRUE` to 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)`. Without `I()`, `^` means interaction crossing. - `*` = main effects + interaction: `a*b` expa
Pensando...
