Course outline

R Programming / Language and data foundations / Lesson 3

Indexing, missingness, and shape preservation

Select the intended observations without losing dimensions or converting unknown conditions into accidental rows.

About 4 min readContent reviewed
On this page

Lesson goals

  • Use positive, negative, logical, and named indices deliberately.
  • Distinguish missing values from ordinary strings and NaN.
  • Preserve matrix and data-frame dimensions where required.

Selection has an ordering and coverage contract

R uses one-based positive indices for ordinary positional selection. A positive index vector can reorder and repeat elements; negative indices exclude positions and are not generally mixed with positive ones except for zero. Character indices select names under the object’s extraction rules. The first fixture shows ordering, exclusion, exact single-value extraction, and an empty selection. These operations answer different questions. Repeating an index repeats a measurement and can change its effective weight in a later summary. Preserve observation identifiers when selection is part of an analysis so repeated or dropped records remain auditable.

Single and multiple extraction have different results

For list-like objects, [ selects a subobject while [[ extracts one contained element. The $ operator uses a literal component name and can allow partial matching in some contexts, so exact programmatic extraction deserves care. Matrix or data-frame selection may drop dimensions when only one row or column remains. Use drop=FALSE where the caller requires a two-dimensional object, and test both ordinary and singleton cases. A downstream operation can receive the same numbers with a different structure after dropping, producing an error or a plausible calculation on an unintended axis.

r Illustrative base-R script; R runtime not available during review
x <- c(alpha = 10, beta = 20, gamma = 30)
cat("positive=", paste(x[c(3L, 1L)], collapse = ","), "\n", sep = "")
cat("negative=", paste(x[-2L], collapse = ","), "\n", sep = "")
cat("named=", x[["beta"]], "\n", sep = "")
cat("empty length=", length(x[integer(0)]), "\n", sep = "")
Expected output
positive=30,10
negative=10,30
named=20
empty length=0

Positive indices select and reorder, negative indices exclude, exact named extraction returns one value, and an empty index selects no elements.

Missingness is a value state with logic

NA denotes missing information and is distinct from the character string "NA". Numeric NaN denotes an undefined numeric result and is also detected by is.na; is.nan distinguishes that case, while is.finite excludes infinities as well. Equality to NA does not test missingness because a comparison involving an unknown value is generally unknown. Use is.na and an explicit missingness policy. Logical operations can sometimes resolve a result despite an unknown operand, as false AND unknown is false. That rule explains why a carefully constructed mask can exclude missing observations without inventing their values.

A missing comparison can enter a subset

The second fixture creates a mask that first requires an observed value and then checks a threshold. Indexing by a logical mask containing NA can otherwise produce unknown selected entries rather than merely dropping them. The observed mean uses na.rm=TRUE and reports its observed count beside the original total. This is a missing-data policy, not an automatic statistical repair. If missingness depends on the measurement or collection process, the observed-only mean may not represent the intended population. An all-missing subset needs a defined result or rejection rather than an unexplained NaN.

r Illustrative base-R script; R runtime not available during review
x <- c(5, NA_real_, 15)
keep <- !is.na(x) & x > 7
cat("selected=", paste(x[keep], collapse = ","), "\n", sep = "")
cat("observed=", sum(!is.na(x)), "; total=", length(x), "\n", sep = "")
cat("observed mean=", mean(x, na.rm = TRUE), "\n", sep = "")
cat("unknown comparison=", is.na(x[2] > 7), "\n", sep = "")
Expected output
selected=15
observed=2; total=3
observed mean=10
unknown comparison=TRUE

Missingness is checked explicitly; the observed-only mean has two observations and does not claim that the third value was zero.

Test boundary selections explicitly

Include an empty selection, one observation, duplicate indices, unknown names, missing masks, and a full selection in a small test set. Keep mask length aligned with the object because logical recycling can select unintended positions. Decide whether unknown names are errors or expected missing results under the chosen extraction operation. In analysis pipelines, count retained and removed observations and preserve reasons for exclusion. Structure checks and count checks complement each other: a correct retained count cannot detect a reordered target vector, while matching dimensions cannot detect wrong names. The examples are documented expected behavior, not executed R validation.

Common errors and fixes

A filter returns extra missing entries

Why it happens
The logical selection mask contained unknown values.
How to fix it
Build an explicit observed-and-condition mask or another documented policy.
Prevent it next time
Test input missingness and inspect mask length and NA values.

A one-column result stops supporting two-dimensional operations

Why it happens
Subsetting dropped a dimension.
How to fix it
Use drop=FALSE where a matrix or data frame is required.
Prevent it next time
Test empty, singleton, and multi-column selections.

x == NA fails to identify missing measurements

Why it happens
Comparison with an unknown value is itself unknown.
How to fix it
Use is.na and distinguish NaN or nonfinite values where needed.
Prevent it next time
Keep explicit missingness tests in the input contract.

Check your understanding

1. For x=c(8,NA,12), what are the observed count and observed-only mean?

Show worked solution

There are two observed values and their mean is ten. The original total remains three. Reporting both counts makes the missing-data decision visible. Replacing the missing value with zero would produce 20/3 and define a different, unjustified measurement unless zero had an explicit domain meaning.

2. Why should a reusable column-selection function test a one-column result?

Show worked solution

Default simplification can return a vector where a later step expects a two-dimensional object. A test should assert class or dimensions as well as values, using drop=FALSE when that is the contract. An ordinary two-column fixture would not expose this boundary.

Key takeaways

  • Selection can reorder, repeat, exclude, or simplify.
  • Unknown values require explicit logical handling.
  • Preserve structure and observation identity together.

Official references