Written and maintained by CASRAI Editorial Board
Last updated
Subset in R means keeping only the rows, columns or elements of a vector, matrix, list or data frame that meet a condition or position. The base function subset() does this for a condition, [ ] and [[ ]] do it by index, and dplyr’s slice() does it by row position. This guide shows which one to use, with the examples from R’s own documentation, and the rule that trips people up: subset() treats NA as false and is documented as an interactive convenience, not a scripting tool.
What subsetting is used for in research
Research analysis rarely runs on a whole dataset. You restrict to a cohort, a time window, a treatment arm or a set of variables, then analyse that part. In R this is the step between loading data (see data frames in R) and modelling. Choosing the right tool matters because the tools differ on missing values, on what they return and on whether they are safe inside a function or script.
Install or access
subset(), [ ] and [[ ]] are part of base R, so there is nothing to install beyond R itself, which is distributed by CRAN (cran.r-project.org). slice() belongs to the dplyr package, installed once from CRAN and loaded in each session:
install.packages("dplyr")
library(dplyr)
Step-by-step: subset a data frame with subset()
The documented usage for data frames and matrices is subset(x, subset, select, drop = FALSE, ...). The examples below use airquality, a data frame that ships with R and is used in the R manual’s own examples.
- Keep rows by a condition. The
subsetargument is a logical expression, evaluated inside the data frame, so you name columns directly:subset(airquality, Temp > 80). - Keep rows and chosen columns. Add
select:subset(airquality, Temp > 80, select = c(Ozone, Temp)). - Drop a column. Use a negative:
subset(airquality, Day == 1, select = -Temp). - Keep a range of columns. Column names are converted to positions, so a range works:
subset(airquality, select = Ozone:Wind). - Combine conditions. Join logical tests with
&(and) or|(or), for examplesubset(airquality, Temp > 80 & Month == 7). See the OR operator in R for how|differs from||. - Subset a vector. Use
with(airquality, subset(Ozone, Temp > 80)), which returns theOzonevalues where the condition holds.
Output and how to read it
For a data frame, subset() returns a data frame with the same columns (or the ones you selected) and only the matching rows; row names keep their original numbers, so gaps in the row labels are expected. For a vector it returns a vector. Two behaviours in the R documentation affect how you read the result:
- Missing values count as false. Rows where the condition evaluates to
NAare dropped, not kept. For vectors,subset()is essentiallyx[subset & !is.na(subset)]. Inairquality, whereOzonehas missing values, a filter onOzonesilently removes theNArows. Check how many rows you lost withnrow()before and after. - Factors keep unused levels. After subsetting, a factor column still lists levels that no longer occur. Apply
droplevels()to remove them before tabulating or plotting.
Subset with [ ] and [[ ]]
An Introduction to R describes four kinds of index vector for [ ]: a logical vector, positive integers (select), negative integers (exclude) and character strings (match names). For example, y <- x[!is.na(x)] keeps the non-missing values. Data frames follow matrix conventions, df[rows, columns].
Unlike subset(), an NA in a logical index passed to [ ] yields an NA element or row rather than silently dropping it, which makes the problem visible. This is one reason the documentation points scripts and functions towards [ ] and [[ ]].
What does [[ 1 ]] do in R?
[[ 1 ]] extracts the single first element of a list, as the element itself. [ 1 ] returns a sub-list of length one that still has its name. An Introduction to R puts it this way: “It is very important to distinguish Lst[[1]] from Lst[1].” Also, Lst$name is equivalent to Lst[["name"]], but $ allows a unique abbreviation and [[ ]] accepts a variable holding the name, which $ does not.
What does slice() do in R?
dplyr’s slice() indexes rows by their integer positions. Negative positions drop rows, and positions can repeat, which duplicates rows. Its helpers cover common cases: slice_head() and slice_tail() take the first or last rows (by n or prop), slice_sample() takes a random set (see sample in R), and slice_min() and slice_max() take rows by the smallest or largest values of a column. On grouped data the helpers run per group. Because slice() depends on row order, it does not work with relational databases; dplyr’s documentation suggests filter() with row_number() there.
Which tool to use
| Tool | Selects by | Missing values in the condition | Best for |
|---|---|---|---|
subset() |
Logical condition (rows) and column names (select) |
Treated as false, row dropped | Interactive exploration; documented as “a convenience function intended for use interactively” |
[ ] |
Logical, positive, negative or character index | Produces NA entries |
Scripts and functions |
[[ ]] |
One position or name | Not applicable (single element) | Extracting one list element or column |
slice() (dplyr) |
Integer row position | Not applicable (position based) | First, last, random or extreme rows |
The R manual states that for programming use, [ or [[ are preferred, because the non-standard evaluation in subset() can behave unexpectedly, for instance when a column name clashes with a variable of the same name in your function. Related tasks: selecting columns in R, removing rows in R and ordering data in R.
Troubleshooting
- Fewer rows than expected. Missing values in the tested column are dropped by
subset(). Addis.na()logic explicitly if you want to keep or inspect them. - Odd results inside a function. The condition is evaluated within the data frame, so a column can shadow your variable. Use
[ ]in functions and scripts. - A factor still shows empty categories. Wrap the result in
droplevels(). - A one-column result becomes a vector. The
dropargument is passed to[; the documented default forsubset()isdrop = FALSE, whereas plaindf[, "col"]drops to a vector by default. - “Object not found” for a column name. Outside
subset()columns are not in scope; writedf$color usewith().
Free alternatives
| Option | Where it comes from | Use it for |
|---|---|---|
Base R: [ ], [[ ]], $ |
Included in R (CRAN) | Everything in this guide, without extra packages |
dplyr slice() family |
dplyr package (CRAN, tidyverse project) | Row selection by position, with grouping support |
Questions about the same operation in Python or C++ are different tools with different syntax; for pandas, see the CASRAI guide on pandas drop_duplicates(), whose subset argument is a separate concept.
FAQ
How to subset your data in R?
Use subset(df, condition, select = columns) for quick interactive work, or df[rows, columns] with a logical, positive, negative or named index for scripts. Use slice() from dplyr to select rows by position.
What is a subset in simple terms?
A subset is a smaller part of a larger collection that satisfies a condition or is chosen by position: for example, the rows of a dataset where the temperature is above 80, or only the first column.
What does [[ 1 ]] do in R?
It returns the first element of a list as the element itself, whereas [ 1 ] returns a list of length one containing that element.
What does slice() do in R?
It selects rows of a data frame by integer position, including negative positions to drop rows, with helpers such as slice_head(), slice_sample() and slice_max().
Sources
- R Core Team, R documentation for
subset, base package: stat.ethz.ch/R-manual/R-devel/library/base/html/subset.html (read 2026-11-07). - R Core Team, An Introduction to R, sections 2.7, 6.1 and 6.3: cran.r-project.org/doc/manuals/r-release/R-intro.html (read 2026-11-07).
- tidyverse, dplyr reference for
slice(): dplyr.tidyverse.org/reference/slice.html (read 2026-11-07).







