Written and maintained by CASRAI Editorial Board
Last updated
To select columns in R, use select(df, col1, col2) from the dplyr package, or base R’s df[, c("col1", "col2")]. The two look interchangeable but they differ in one way that catches many people out: selecting a single column with df[, "col1"] returns a vector, while select(df, col1) and df["col1"] keep a data frame. This page covers selecting by name, position, range and pattern, then explains that difference and when each tool is the right one.
What it is used for in research
Survey exports, instrument output and registry extracts usually arrive with far more columns than any one analysis needs. Selecting the columns you need in a script, instead of deleting columns by hand in a spreadsheet, leaves a written record of exactly which variables entered the analysis, which is a basic ingredient of computational reproducibility. Selection usually comes right after you tidy the names with renaming columns in R and before you reshape or summarise, for example with grouping in R. If you are new to the structure that holds these columns, see data frames in R.
Install or access
Base R’s [ ], [[ ]], $ and subset() ship with R itself, so nothing needs installing. select() belongs to dplyr, which the dplyr project site describes as available in two ways:
# The easiest way to get dplyr is to install the whole tidyverse:
install.packages("tidyverse")
# Alternatively, install just dplyr:
install.packages("dplyr")
Then load it once per session with library(dplyr). The examples below use the iris data frame that is built into R, whose columns are Sepal.Length, Sepal.Width, Petal.Length, Petal.Width and Species.
Step-by-step: select columns with dplyr select()
The dplyr reference gives the usage as select(.data, ...). The first argument is a data frame, a data frame extension such as a tibble, or a lazy data frame (for example from dbplyr or dtplyr). The reference states that the output columns are a subset of the input columns, potentially in a different order, and that rows are not affected.
1. Select by name
List the columns you want, without quotation marks. The columns come back in the order you list them.
library(dplyr)
iris |> select(Sepal.Length, Petal.Length)
2. Select a range, or everything except a range
The dplyr reference lists : for a range, ! for the complement, & and | for intersection and union, and c() to combine selections. Its own examples use name:mass to keep a range and !(name:mass) to keep everything else. The same pattern on iris:
iris |> select(Sepal.Length:Petal.Length)
iris |> select(!(Sepal.Length:Petal.Length))
3. Select by pattern or type
The reference documents these helpers: everything(), last_col() (optionally with an offset), starts_with(), ends_with(), contains(), matches(), num_range(), all_of(), any_of() and where(). The last one takes a function that tests each column and selects the columns for which it returns TRUE. Two of the reference’s own examples are iris |> select(!ends_with("Width")) and iris |> select(starts_with("Petal") & ends_with("Width")). To keep only numeric columns:
iris |> select(where(is.numeric))
4. Select and rename in one step
Inside select() you can rename a column as you keep it, using new_name = old_name:
iris |> select(sepal_len = Sepal.Length, Species)
5. Select columns whose names are stored in a variable
When the column names sit in a character vector, wrap the vector in all_of() or any_of(). The reference says all_of() is for strict selection and throws an error if any of the variables is missing, whereas any_of() does not check for missing variables. The reference’s own example builds a named character vector and passes it to select(all_of(selection)), which selects and renames at once.
wanted <- c("Sepal.Length", "Species")
iris |> select(all_of(wanted))
iris |> select(any_of(c(wanted, "No.Such.Column")))
Select columns in base R
By name or position with [ ]
The base R manual for extracting from a data frame gives the usage x[i, j, drop = ], where j picks the columns. Leave i empty to keep every row.
iris[, c("Sepal.Length", "Petal.Length")]
iris[, c(1, 3)]
One column with [[ ]] or $
With a single index, [[ returns a column, or NULL if there is no such column. The manual notes that there is no data frame method for $, so df$name uses the list method, which allows partial matching of the name when it is unique.
iris[["Sepal.Length"]]
iris$Sepal.Length
With subset()
The manual’s usage is subset(x, subset, select, drop = FALSE, ...). The select argument is an expression indicating the columns to keep; column names are replaced by column numbers, ranges are easy to write, and single columns can be dropped. The manual’s example drops a column with a minus sign: subset(airquality, Day == 1, select = -Temp). The same page says the function is intended for interactive use, so prefer select() or [ ] inside scripts and functions.
subset(iris, select = c(Sepal.Length, Species))
Why you get a vector instead of a data frame
The base R manual states the default for drop: it drops if only one column is left, but not if only one row is left. So selecting one column with a comma returns a plain vector:
iris[, "Sepal.Length"] # vector
iris[, "Sepal.Length", drop = FALSE] # data frame
iris["Sepal.Length"] # data frame
iris |> select(Sepal.Length) # data frame
If the next step needs a data frame, for example a join or a column bind, use drop = FALSE, single-bracket indexing without a comma, or select().
Output and how to read it
Every dplyr call above returns the same rows with fewer columns; the reference states that rows are not affected. If the data frame is grouped, the reference says groups are maintained and that you cannot select off the grouping variables, so the grouping columns remain in the result even when you did not name them. Selection does not change the original object unless you assign the result, for example slim <- iris |> select(Species). To change the row order afterwards, see ordering by a column in R.
Troubleshooting
- An error naming a missing column: a name inside
all_of()does not exist in the data frame. Check spelling and case, or useany_of()if absence is acceptable. - The result is a vector, not a data frame: see the section above; add
drop = FALSEor useselect(). - An extra column you did not ask for appears: the data frame is grouped, and grouping variables are kept.
$returns a column you did not expect: the manual says$allows partial matching when the name is unique; use[[ ]], which returnsNULLwhen the name is not found.- A
subset()call that worked at the console fails inside a function: the manual warns that its non-standard evaluation can have unanticipated consequences when programming.
Free alternatives: which tool returns what
The approaches below all select columns using only R and dplyr; they differ in what they return and where the manuals say to use them.
| Approach | Returns | Note from the documentation |
|---|---|---|
select(df, ...) (dplyr) |
Data frame, a subset of the input columns | Rows unaffected; grouping variables kept; supports renaming with new_name = old_name |
df[, j] (base R) |
Vector if one column is left, otherwise a data frame | Default drop behaviour; use drop = FALSE to keep a data frame |
df[j] (base R) |
Data frame | One index, no comma |
df[["name"]] |
A single column, or NULL |
One column only |
df$name |
A single column | List method; allows partial matching when unique |
subset(df, select = ...) (base R) |
Data frame | Documented as a convenience function for interactive use |
FAQ
How do I select a column in R?
For a data frame df with a column x, select(df, x) returns it as a one-column data frame, df[["x"]] or df$x returns the values as a vector, and df["x"] returns a one-column data frame.
How do I select column names that start with the same text?
Use select(df, starts_with("Petal")). The dplyr reference documents starts_with(), ends_with() and contains() for matching on part of a name.
How do I select multiple columns in R?
With dplyr, list them: select(df, a, b, c), or use a range such as a:c. In base R, pass a vector of names or positions: df[, c("a", "b", "c")].
How do I select every column except one?
With dplyr, put ! in front of the name or range, as in select(df, !x). With subset(), use a minus sign, as in the manual’s select = -Temp example.
How do I select columns by data type?
Use where() with a test function, for example select(df, where(is.numeric)).
Sources (official documentation, checked 2026-10-29)
- dplyr reference, select(): keep or drop columns using their names and types (dplyr project site)
- R manual, Extract.data.frame: extract or replace parts of a data frame
- R manual, subset: subsetting vectors, matrices and data frames







