287

Does anyone know how to remove an entire column from a data.frame in R? For example if I am given this data.frame:

> head(data)
   chr       genome region
1 chr1 hg19_refGene    CDS
2 chr1 hg19_refGene   exon
3 chr1 hg19_refGene    CDS
4 chr1 hg19_refGene   exon
5 chr1 hg19_refGene    CDS
6 chr1 hg19_refGene   exon

and I want to remove the 2nd column.

user227710
  • 3,124
  • 14
  • 32
Nanami
  • 3,029
  • 2
  • 16
  • 19
  • 2
    Possible duplicate of [Drop columns in R data frame](http://stackoverflow.com/questions/4605206/drop-columns-in-r-data-frame) – jangorecki Dec 08 '15 at 18:49

6 Answers6

451

You can set it to NULL.

> Data$genome <- NULL
> head(Data)
   chr region
1 chr1    CDS
2 chr1   exon
3 chr1    CDS
4 chr1   exon
5 chr1    CDS
6 chr1   exon

As pointed out in the comments, here are some other possibilities:

Data[2] <- NULL    # Wojciech Sobala
Data[[2]] <- NULL  # same as above
Data <- Data[,-2]  # Ian Fellows
Data <- Data[-2]   # same as above

You can remove multiple columns via:

Data[1:2] <- list(NULL)  # Marek
Data[1:2] <- NULL        # does not work!

Be careful with matrix-subsetting though, as you can end up with a vector:

Data <- Data[,-(2:3)]             # vector
Data <- Data[,-(2:3),drop=FALSE]  # still a data.frame
Joshua Ulrich
  • 163,034
  • 29
  • 321
  • 400
  • 53
    or you can use: Data – Ian Fellows Jun 08 '11 at 23:09
  • @Ian do you even need the ","? – Brandon Bertelsen Jun 09 '11 at 03:56
  • 2
    with the comma you can also control the "drop" argument, which when FALSE means the data.frame stays a data.frame when the result consists of only one column - without the comma you will always get a data.frame whether multiple columns are left or just one - drop is ignored for the [-2] extraction – mdsumner Jun 09 '11 at 06:17
  • 3
    @mdsumner `Data[-2]` don't need `drop` argument cause it always return `data.frame` from `data.frame`. And I think this is much better way to localized columns (and only columns) in `data.frame` (and it's faster). Check: `cars[-1]` (one col `data.frame`) or better `cars[-(1:2)]`: `data frame with 0 columns and 50 rows`. – Marek Jun 09 '11 at 06:41
  • 1
    You can also write Data[2] – Wojciech Sobala Jun 09 '11 at 06:52
  • 12
    Minor tip: When removing multiple columns `Data[c(1,2)] – Marek Jun 09 '11 at 06:59
  • how to remove them by calling names of columns? – Cina Jun 15 '15 at 11:33
  • does anyone know when this would fail? Calling it twice in a row works. But, calling names(x), x$y – 3pitt Nov 08 '17 at 21:41
  • @MikePalmice: You should ask a new question. – Joshua Ulrich Nov 10 '17 at 13:38
74

To remove one or more columns by name, when the column names are known (as opposed to being determined at run-time), I like the subset() syntax. E.g. for the data-frame

df <- data.frame(a=1:3, d=2:4, c=3:5, b=4:6)

to remove just the a column you could do

Data <- subset( Data, select = -a )

and to remove the b and d columns you could do

Data <- subset( Data, select = -c(d, b ) )

You can remove all columns between d and b with:

Data <- subset( Data, select = -c( d : b )

As I said above, this syntax works only when the column names are known. It won't work when say the column names are determined programmatically (i.e. assigned to a variable). I'll reproduce this Warning from the ?subset documentation:

Warning:

This is a convenience function intended for use interactively. For programming it is better to use the standard subsetting functions like '[', and in particular the non-standard evaluation of argument 'subset' can have unanticipated consequences.

Brian Diggs
  • 53,289
  • 11
  • 151
  • 179
Prasad Chalasani
  • 18,647
  • 5
  • 43
  • 71
30

(For completeness) If you want to remove columns by name, you can do this:

cols.dont.want <- "genome"
cols.dont.want <- c("genome", "region") # if you want to remove multiple columns

data <- data[, ! names(data) %in% cols.dont.want, drop = F]

Including drop = F ensures that the result will still be a data.frame even if only one column remains.

Gregor Thomas
  • 104,719
  • 16
  • 140
  • 257
ceiling cat
  • 4,553
  • 6
  • 32
  • 47
22

The posted answers are very good when working with data.frames. However, these tasks can be pretty inefficient from a memory perspective. With large data, removing a column can take an unusually long amount of time and/or fail due to out of memory errors. Package data.table helps address this problem with the := operator:

library(data.table)
> dt <- data.table(a = 1, b = 1, c = 1)
> dt[,a:=NULL]
     b c
[1,] 1 1

I should put together a bigger example to show the differences. I'll update this answer at some point with that.

Chase
  • 62,262
  • 16
  • 135
  • 160
  • 3
    The `data.table::set` function can be used on `data.frame`s to remove or modify a column instantly, without making copies. See [here](http://stackoverflow.com/questions/17891519/is-it-possible-to-modify-a-data-frame-in-place-destructively/17891970#17891970) – GSee Aug 09 '14 at 14:56
9

There are several options for removing one or more columns with dplyr::select() and some helper functions. The helper functions can be useful because some do not require naming all the specific columns to be dropped. Note that to drop columns using select() you need to use a leading - to negate the column names.

Using the dplyr::starwars sample data for some variety in column names:

library(dplyr)

starwars %>% 
  select(-height) %>%                  # a specific column name
  select(-one_of('mass', 'films')) %>% # any columns named in one_of()
  select(-(name:hair_color)) %>%       # the range of columns from 'name' to 'hair_color'
  select(-contains('color')) %>%       # any column name that contains 'color'
  select(-starts_with('bi')) %>%       # any column name that starts with 'bi'
  select(-ends_with('er')) %>%         # any column name that ends with 'er'
  select(-matches('^v.+s$')) %>%       # any column name matching the regex pattern
  select_if(~!is.list(.)) %>%          # not by column name but by data type
  head(2)

# A tibble: 2 x 2
homeworld species
  <chr>     <chr>  
1 Tatooine  Human  
2 Tatooine  Droid 

You can also drop by column number:

starwars %>% 
  select(-2, -(4:10)) # column 2 and columns 4 through 10
sbha
  • 6,700
  • 2
  • 55
  • 49
  • Great answer. Any idea on how to drop a column that contains a certain value in any of its rows (not in its column name as you proposed above)? – Laura K Jun 19 '19 at 11:13
  • df[,-which(sapply(df, function(x) any(x == a)))], where df is your data frame and a is your specific value, e.g.: mtcars[,-which(sapply(mtcars, function(x) any(x==4)))] – Nanami Jul 31 '19 at 00:11
8

With this you can remove the column and store variable into another variable.

df = subset(data, select = -c(genome) )
Rohit Poudel
  • 1,604
  • 2
  • 16
  • 19
Nirali Khoda
  • 320
  • 4
  • 17