49

I have the two following data frames (example):

df1:

name    profile    type    strand
A       4.5        1       +
B       3.2        1       +
C       5.5        1       +
D       14.0       1       -
E       45.1       1       -
F       32.8       1       -
G       19.9       1       +

df2:

name
A
B
C
G

I would like to delete the rows in df1 for which df1$name = df2$name to get the following:

Output:

name    profile    type    strand
D       14.0       1       -
E       45.1       1       -
F       32.8       1       -

If anyone could tell me which piece of code to use it would be a lot of help, seemed simple at first but I've been messing it up since yesterday.

Unihedron
  • 10,902
  • 13
  • 62
  • 72
biohazard
  • 2,017
  • 10
  • 28
  • 41

3 Answers3

69

You need the %in% operator. So,

df1[!(df1$name %in% df2$name),]

should give you what you want.

  • df1$name %in% df2$name tests whether the values in df1$name are in df2$name
  • The ! operator reverses the result.
csgillespie
  • 59,189
  • 14
  • 150
  • 185
  • 1
    Thank you so much! Do you have any idea what I should do to make it symmetric? I noticed that `df1[!(df1$name %in% df2$name),]` and `df2[!(df2$name %in% df1$name),]` give me different results... – biohazard Jun 27 '13 at 13:21
  • 1
    This helped me a lot just now. Not sure if I could've found the `%in%` operator. It's not really a searchable thing.. – userABC123 Nov 06 '15 at 08:59
  • If I would does not remove but modify for NA how could I do that? – Wilson Souza Sep 13 '22 at 20:21
44

This is sometimes called an anti-join:

library(dplyr)
anti_join(df1, df2, by = "name")
Hugh
  • 15,521
  • 12
  • 57
  • 100
3
df1[!(as.character(df1$jobId) %in% as.character(df2$name)), ]

I had to add as.character to my execution because name is not a character but a factor instead. Isn't %in% supposed to convert this directly?

Kim
  • 4,080
  • 2
  • 30
  • 51