Skip to main content
v2026.11,858 entries · CC-BY 4.0
LAC HealthMedical & Research SuppliesReagents, PPE & instruments — chain-of-custody documented.Fast, traceable sourcing built for regulated research environments, from bench consumables to instrumentation.Shop lac.us CodeCASRAIlac.us

Removing Rows in R: filter_out(), slice() and Base R

Remove rows in R by condition, position or duplicates with dplyr and base R, including how filter() and filter_out() treat NA rows differently.

Written and maintained by CASRAI Editorial Board

Last updated

Removing rows in R means producing a data frame that no longer contains the observations you chose to exclude. In current dplyr you do it by condition with filter_out() or filter(), by position with slice(), by repetition with distinct(), or in base R with negative indexing and subset(). The tools differ in one way that matters for research data: how they treat NA. A condition such as “drop every row where class is suv” can silently delete your missing-value rows in one function and keep them in another.

What it is used for in research

Row removal is part of preparing an analysis dataset: excluding participants who fail an eligibility rule, dropping test or pilot records, removing a withdrawn participant’s data, deleting exact duplicate entries, or removing a flagged observation after a documented decision. Each of these changes the sample size, so keep the original data frame, record the rule you applied, and compare row counts before and after (see the checklist below). For the wider workflow, see data cleaning steps.

Two neighbouring topics have their own guides: removing rows that contain missing values is covered in omitting rows with NA in R, and deciding whether an extreme value should be removed at all is covered in outliers in R.

Install or access

Base R functions ([, subset(), duplicated()) ship with R and are documented in the R manuals on CRAN. The functions filter(), filter_out(), slice() and distinct() belong to the dplyr package, part of the tidyverse. Install and load it from CRAN:

install.packages("dplyr")
library(dplyr)

filter_out() appears in the current dplyr reference (version 1.2.1, checked 2026-10-29). If filter_out() is not found, update dplyr with install.packages("dplyr") and reload it. The examples below use the |> pipe; see the pipe in R if it is new to you.

Step-by-step: remove rows in R

1. Remove rows by condition

The dplyr reference says that filter() keeps rows that match a condition and filter_out() drops them: “When your intent is to keep rows, use filter(). When your intent is to drop rows, use filter_out().” To drop every row where class is "suv":

cars |> filter_out(class == "suv")

The equivalent with filter() reverses the test, and that is where the NA difference appears (see the next section):

cars |> filter(class != "suv")

Both functions accept a .by argument to evaluate the condition within groups, for example starwars |> filter(mass > mean(mass, na.rm = TRUE), .by = gender) from the dplyr reference. For group-wise work more generally, see grouping in R.

2. Remove rows by position

slice() indexes rows by integer location. Per the dplyr reference, you provide “either positive values to keep, or negative values to drop”, and the values “must be either all positive or all negative”. To drop the first four rows of mtcars:

slice(mtcars, -(1:4))

The result starts at the Hornet Sportabout row. slice_head() and slice_tail() take n or prop and select rows from the start or end of the data frame.

3. Remove duplicate rows

distinct() keeps only unique rows. Called with no columns it compares every column; name columns to compare only those. By default only the compared columns are returned, so add .keep_all = TRUE to retain all variables; the reference says that when several rows share the same combination, “only the first row will be preserved”.

df |> distinct(participant_id, .keep_all = TRUE)

Which of two duplicate rows is “first” depends on the current row order, so sort deliberately before this step if the choice matters (see order by in R). In base R, duplicated() returns a logical vector marking rows that duplicate a row with a smaller index, so df[!duplicated(df), ] keeps the first occurrence of each row.

4. Remove rows in base R

Base R subsets with [row, column]. The R manual on Extract states that indices “can also be negative integers, indicating elements/slices to leave out of the selection”:

df[-c(1, 3), ]            # drop rows 1 and 3
df[df$class != "suv", ]   # keep rows meeting a condition

subset(df, class != "suv") does the same for a condition. Its documentation describes the subset argument as a “logical expression indicating elements or rows to keep: missing values are taken as false”, and calls the function “a convenience function intended for use interactively”; for programming use, the manual points to standard subsetting with [.

Output and how to read it

Every method returns a new data frame; none of them changes the original object. Assign the result to a new name (clean <- df |> filter_out(...)) and verify what happened:

  • Compare nrow(df) and nrow(clean). The difference should equal the number of rows you intended to remove.
  • Check which rows went, not only how many: print the rows that the opposite condition selects and confirm they are the ones you meant to remove.
  • Record the rule and the counts in your analysis log so the sample-size change is reportable.

Which method to use

You want to remove rows by Use Behaviour stated in the documentation
A condition (drop what matches) filter_out() Drops rows where the condition is TRUE; keeps NA and FALSE rows
A condition (keep what matches) filter() Treats NA like FALSE, so rows with NA in the tested column are dropped
Row position slice() with negative indices All indices must be positive or all negative; out-of-range indices are silently ignored
Repetition distinct(.keep_all = TRUE) Preserves only the first row of each combination
Missing values See omit rows with NA in R Covered in its own guide
Base R position or condition df[-i, ], df[cond, ], subset() Negative indices leave rows out; subset() is intended for interactive use

Troubleshooting

Rows with NA disappeared when I only meant to drop one value

This is the filter() behaviour. The dplyr reference works through the case of dropping rows where class is "suv" from a column containing "suv", NA and "coupe". filter(class != "suv") returns only coupe, because “filter() drops the NA rows even though our goal was only to drop "suv" rows”. filter_out(class == "suv") returns the NA and coupe rows. With filter() you would need filter(class != "suv" | is.na(class)). If your protocol says missing values must stay in the dataset, this is the check that matters.

Base R [ returns rows full of NA

The dplyr reference notes that base subsetting with [ “doesn’t treat NA like TRUE or FALSE”; with an NA in the logical condition it generates a fully missing row instead of dropping or keeping the observation. Either guard the condition (df[!is.na(df$class) & df$class != "suv", ]) or use subset() or filter(), which treat NA as FALSE.

slice() errors or removes nothing

Mixing positive and negative indices, for example slice(df, 1, -2), violates the all-positive-or-all-negative rule. Indices beyond the number of rows are silently ignored, so a typo such as -(1:400) on a 40-row data frame will not warn you. Always check nrow() afterwards.

Grouped data frames behave differently

filter(), filter_out() and slice() respect existing grouping, so a condition like mass > mean(mass) is computed per group on a grouped data frame. The default .preserve = FALSE recalculates the grouping structure after rows are removed.

Free alternatives

Everything on this page is free and open source; both routes below ship with or install into R at no cost.

Tool Row-removal functions covered above
R, base functions [ with negative or logical indices, subset(), duplicated()
R, dplyr package filter(), filter_out(), slice(), distinct()

FAQ

How do I remove a row in R by row number?

Use slice(df, -3) in dplyr or df[-3, ] in base R. Both drop row 3 and return a new data frame.

How do I remove rows that meet a condition?

Use filter_out(df, condition) in current dplyr, which drops rows where the condition is TRUE and keeps NA rows. Use df[!(condition), ] or subset() in base R, mindful of how NA is handled.

Does removing rows change the original data frame?

No. These functions return a new object; the original changes only if you assign the result back to the same name.

How do I remove duplicate rows?

Use distinct(df, .keep_all = TRUE) for fully identical rows, or name the identifying columns to compare only those. In base R, use df[!duplicated(df), ].

Sources (official documentation)

Follow CASRAI

Research-administration guidance, standards updates and independent tool reviews.

Ask CASRAI · free to try

Ask about Removing Rows in R: filter_out(), slice() and Base R

Ask your first 2 questions free below. Subscribers get 150 a day for $29 a month.

An AI assistant specialized in research administration. It cites the sources behind every answer, labels web answers and says when it can't answer.

Answers draw on CASRAI's guides and dictionary plus the federal and funder documents we index: Federal Register, Grants.gov, Regulations.gov and UKRI.

Works on this site and inside Claude, Cursor and the AI tools you already use.

Everything CASRAI publishes — this page, the dictionary, the guides and the news — stays free to read, with no account and no card.

Referenced across the research world

University of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logoUniversity of Cambridge logoColumbia University logoCrossref logoUniversity of Edinburgh logoHarvard University logoUniversity of Oxford logoPrinceton University logoStanford School of Medicine logoUniversity College London logoORCID logo
  • University of Cambridge logo
  • Columbia University logo
  • Crossref logo
  • University of Edinburgh logo
  • Harvard University logo
  • University of Oxford logo
  • Princeton University logo
  • Stanford School of Medicine logo
  • University College London logo
  • ORCID logo

View CASRAI adoption →