Summary

Check that you can select and replace parts of an object by position, name, or condition, while checking the structure of the result.

Before you start: vectors, tables, matrices and lists.
Setup: No data files are needed. Run each object definition before its indexing examples.
Your check: Filter known measurements and change a chosen value in a copy. Practise in the unit summary.

What you learned

Task Syntax Remember
Select vector elements x[c(1, 3)] R positions start at 1.
Exclude vector elements x[-2] Do not mix positive and negative positions, except zero.
Select by a condition x[x > 10] The condition produces a logical vector. Handle missing values explicitly.
Select a matrix or data-frame rectangle x[rows, columns] The comma separates the two dimensions; a blank selects all entries in that dimension.
Keep a one-column table df[, "height", drop = FALSE] Without drop = FALSE, selecting one column this way can return a vector.
Select one list component x[[1]] or x[["name"]] x[1] instead returns a list containing that component.
Select a named component df$height Convenient for a known column name; use df[[column_name]] if the name is stored in a variable.

For a data frame, df["height"] selects a column as a data frame; df[1, ] selects a row. For a matrix, a single index such as m[3] counts through columns. Always consider the object’s structure before interpreting brackets.

which() returns positions that meet a condition. %in% tests membership, while match() finds positions of matches. Use &, |, and ! for element-by-element AND, OR, and NOT. Test equality with ==; <- assigns a value.

A short recap in R

observations <- data.frame(
  site = c("A", "B", "C", "D"),
  height_cm = c(12, NA, 18, 9)
)
keep <- !is.na(observations$height_cm) & observations$height_cm >= 12
selected <- observations[keep, c("site", "height_cm"), drop = FALSE]
selected

The result contains sites A and C, with heights 12 and 18 cm. The explicit !is.na() check excludes the missing measurement. A comparison with an NA alone can leave NA entries in a logical index and produce missing rows in the result.

You can also put an indexed expression on the left of <- to replace selected values. Check the selection first so that you change the intended entries. subset() provides another way to select rows and columns; sample() selects a random sample. Use set.seed() when an example’s random selection needs to be reproducible.

Try it yourself

Use the table below. Select known temperatures of at least 10 °C, excluding site W; retain a table with columns site and temperature_c. Then make a copy of the original table and change only site E’s temperature to 13 °C. Check that the original is unchanged.

readings <- data.frame(site = c("N", "S", "E", "W"),
                       temperature_c = c(7, NA, 12, 15))

Expected selection: one row, site E at 12 °C; the modified copy has E at 13 °C and retains all four rows.

Hint

Combine the known-value check, comparison and site exclusion with &. Put the row condition before the comma. Assign the original table to a new name before replacing a value.

Compare a possible solution
keep <- !is.na(readings$temperature_c) &
        readings$temperature_c >= 10 & readings$site != "W"
chosen <- readings[keep, c("site", "temperature_c"), drop = FALSE]
changed <- readings
changed$temperature_c[changed$site == "E"] <- 13
chosen
dim(chosen)
changed
readings

dim(chosen) is 1 2; the S measurement remains missing in both full tables. Selecting and inspecting the intended row before replacement helps avoid changing another observation.

Ready to continue: you can select by position/name/condition, replace a chosen value and check the result’s structure.

Check your understanding

Try these questions before opening the suggested answers.

  1. Explain the difference between observations[1, ] and observations[, 1].
  2. How would you select only site C using its name rather than its row number?
  3. Why do my_list[1] and my_list[[1]] sometimes give very different results?
Suggested answers
  1. observations[1, ] selects the first row; observations[, 1] selects the first column and normally returns a vector. Use drop = FALSE when you need a one-column data frame.
  2. Use observations[observations$site == "C", , drop = FALSE]. Here the site labels contain no missing values. A name-based condition keeps its meaning after row reordering.
  3. Single brackets return a list containing the selected component. Double brackets extract that component, which may itself be a vector, data frame or another list.

Revisit indexing and subsetting for more examples.

Test

Updated: