307

I have a data frame named "mydata" that looks like this this:

   A  B  C   D 
1. 5  4  4   4 
2. 5  4  4   4 
3. 5  4  4   4 
4. 5  4  4   4 
5. 5  4  4   4 
6. 5  4  4   4 
7. 5  4  4   4 

I'd like to delete row 2,4,6. For example, like this:

   A  B  C   D
1. 5  4  4  4 
3. 5  4  4  4 
5. 5  4  4  4 
7. 5  4  4  4 
zx8754
  • 52,746
  • 12
  • 114
  • 209
R newbie
  • 3,127
  • 2
  • 13
  • 5
  • 17
    Also, you might want to become familiar with some common terminology for working with data. This is usually referred to as subsetting, which, if you searched in Google for "r subset data frame" you would get to the very helpful [UCLA R FAQ page](http://www.ats.ucla.edu/stat/r/faq/subset_R.htm). Welcome to Stackoverflow, by the way! – A5C1D2H2I1M1N2O1R2T1 Sep 08 '12 at 04:55
  • Added some additional ways of subsetting using boolean vectors, in addition to @mrdwab's excellent answer. – Paul Hiemstra Sep 08 '12 at 10:57
  • 2
    @A5C1D2H2I1M1N2O1R2T1: The UCLA FAQ for R subsetting has moved. Now it's [here](https://stats.idre.ucla.edu/r/faq/frequently-asked-questions-about-rhow-can-i-subset-a-data-setthe-r-program-as-a-text-file-for-all-the-code-on-this-page-subsetting-is-a-very-important-component/). – Mike Sherrill 'Cat Recall' Jun 13 '17 at 13:10

10 Answers10

461

The key idea is you form a set of the rows you want to remove, and keep the complement of that set.

In R, the complement of a set is given by the '-' operator.

So, assuming the data.frame is called myData:

myData[-c(2, 4, 6), ]   # notice the -

Of course, don't forget to "reassign" myData if you wanted to drop those rows entirely---otherwise, R just prints the results.

myData <- myData[-c(2, 4, 6), ]
Gregor Thomas
  • 136,190
  • 20
  • 167
  • 294
A5C1D2H2I1M1N2O1R2T1
  • 190,393
  • 28
  • 405
  • 485
  • 81
    Don't forget to note the `,` in there! ;) – Steven Jeuris Jan 22 '15 at 20:59
  • 7
    what if your dataframe is only one column. It seems to drop the whole structure and outputs a vector of the values – road_to_quantdom Mar 19 '15 at 18:37
  • 10
    @road_to_quantdom, add a `drop = FALSE` in there. – A5C1D2H2I1M1N2O1R2T1 Mar 20 '15 at 01:26
  • 7
    "In R, the complement of a set is given by the '-' operator" -> This is a very misleading wording. Negative indexes are removed and that's it, there is no notion of complement. If you work with logical and try using `-` it won't work, because the complement operator for logicals is `!`. The complement of c(2,4,6) in the rows would rather be setdiff(c(2,4,6),1:nrow(myData)), which is not c(-2, -4, -6), although both would yield the same rows when used with `[`. – asachet Dec 04 '15 at 11:14
  • 4
    @Speldosa, `myData[-c(2, 4, 6),,drop=F]`. In fact, I would suggest that you always insert `,drop=F` just before the `]` in any matrix access. – Aaron McDaid Apr 22 '16 at 12:20
  • 2
    Please have a look at https://bugs.r-project.org/bugzilla3/show_bug.cgi?id=17282 that treats a special corner case when the set to remove is empty. – U. Windl May 31 '17 at 06:39
102

You can also work with a so called boolean vector, aka logical:

row_to_keep = c(TRUE, FALSE, TRUE, FALSE, TRUE, FALSE, TRUE)
myData = myData[row_to_keep,]

Note that the ! operator acts as a NOT, i.e. !TRUE == FALSE:

myData = myData[!row_to_keep,]

This seems a bit cumbersome in comparison to @mrwab's answer (+1 btw :)), but a logical vector can be generated on the fly, e.g. where a column value exceeds a certain value:

myData = myData[myData$A > 4,]
myData = myData[!myData$A > 4,] # equal to myData[myData$A <= 4,]

You can transform a boolean vector to a vector of indices:

row_to_keep = which(myData$A > 4)

Finally, a very neat trick is that you can use this kind of subsetting not only for extraction, but also for assignment:

myData$A[myData$A > 4,] <- NA

where column A is assigned NA (not a number) where A exceeds 4.

Paul Hiemstra
  • 59,984
  • 12
  • 142
  • 149
82

Problems with deleting by row number

For quick and dirty analyses, you can delete rows of a data.frame by number as per the top answer. I.e.,

newdata <- myData[-c(2, 4, 6), ] 

However, if you are trying to write a robust data analysis script, you should generally avoid deleting rows by numeric position. This is because the order of the rows in your data may change in the future. A general principle of a data.frame or database tables is that the order of the rows should not matter. If the order does matter, this should be encoded in an actual variable in the data.frame.

For example, imagine you imported a dataset and deleted rows by numeric position after inspecting the data and identifying the row numbers of the rows that you wanted to delete. However, at some later point, you go into the raw data and have a look around and reorder the data. Your row deletion code will now delete the wrong rows, and worse, you are unlikely to get any errors warning you that this has occurred.

Better strategy

A better strategy is to delete rows based on substantive and stable properties of the row. For example, if you had an id column variable that uniquely identifies each case, you could use that.

newdata <- myData[ !(myData$id %in% c(2,4,6)), ]

Other times, you will have a formal exclusion criteria that could be specified, and you could use one of the many subsetting tools in R to exclude cases based on that rule.

Jeromy Anglim
  • 33,939
  • 30
  • 115
  • 173
15

Create id column in your data frame or use any column name to identify the row. Using index is not fair to delete.

Use subset function to create new frame.

updated_myData <- subset(myData, id!= 6)
print (updated_myData)

updated_myData <- subset(myData, id %in% c(1, 3, 5, 7))
print (updated_myData)
Nilesh Khisadiya
  • 1,560
  • 2
  • 15
  • 27
12

By simplified sequence :

mydata[-(1:3 * 2), ]

By sequence :

mydata[seq(1, nrow(mydata), by = 2) , ]

By negative sequence :

mydata[-seq(2, nrow(mydata), by = 2) , ]

Or if you want to subset by selecting odd numbers:

mydata[which(1:nrow(mydata) %% 2 == 1) , ]

Or if you want to subset by selecting odd numbers, version 2:

mydata[which(1:nrow(mydata) %% 2 != 0) , ]

Or if you want to subset by filtering even numbers out:

mydata[!which(1:nrow(mydata) %% 2 == 0) , ]

Or if you want to subset by filtering even numbers out, version 2:

mydata[!which(1:nrow(mydata) %% 2 != 1) , ]
12

For completeness, I'll add that this can be done with dplyr as well using slice. The advantage of using this is that it can be part of a piped workflow.

df <- df %>%
  .
  .
  slice(-c(2, 4, 6)) %>%
  .
  .

Of course, you can also use it without pipes.

df <- slice(df, -c(2, 4, 6))

The "not vector" format, -c(2, 4, 6) means to get everything that is not at rows 2, 4 and 6. For an example using a range, let's say you wanted to remove the first 5 rows, you could do slice(df, 6:n()). For more examples, see the docs.

Ryan H.
  • 7,374
  • 4
  • 39
  • 46
8

Delete Dan from employee.data - No need to manage a new data.frame.

employee.data <- subset(employee.data, name!="Dan")
SQLWolfe
  • 81
  • 1
  • 1
0

Here's a quick and dirty function to remove a row by index.

removeRowByIndex <- function(x, row_index) {
  nr <- nrow(x)
  if (nr < row_index) {
    print('row_index exceeds number of rows')
  } else if (row_index == 1)
  {
    return(x[2:nr, ])
  } else if (row_index == nr) {
    return(x[1:(nr - 1), ])
  } else {
    return (x[c(1:(row_index - 1), (row_index + 1):nr), ])
  }
}

It's main flaw is it the row_index argument doesn't follow the R pattern of being a vector of values. There may be other problems as I only spent a couple of minutes writing and testing it, and have only started using R in the last few weeks. Any comments and improvements on this would be very welcome!

0

To identify by a name:

  1. Call out the unique ID and identify the location in your data frame (DF).
  2. Mark to delete. If the unique ID applies to multiple rows, all these rows will be removed.

Code:

Rows<-which(grepl("unique ID", DF$Column))
DF2<-DF[-c(Rows),]
DF2
RJR
  • 1
  • 1
0

Another approach when working with Unique IDs is to subset data: *This came from an actual report where I wanted to remove the chemical standard

Chem.Report<-subset(Chem.Report, Chem_ID!="Standard")

Chem_ID is the column name. The ! is important for excluding

RJR
  • 1
  • 1