Frente a% en%

262

Una variable categórica V1 en un marco de datos D1 puede tener valores representados por las letras de la A a la Z. Quiero crear un subconjunto D2, que excluye algunos valores, por ejemplo, B, N y T. Básicamente, quiero un comando que sea lo contrario a %in%

D2 = subset(D1, V1 %in% c('B','N',T'))
usuario702432
fuente
66
no en%? ( !(x %in% y)) La vida puede ser fácil a veces ...
Joris Meys

Respuestas:

355

Puedes usar el !operador para hacer básicamente cualquier VERDADERO FALSO y cada FALSO VERDADERO. entonces:

D2 = subset(D1, !(V1 %in% c('B','N','T')))

EDITAR: También puede hacer un operador usted mismo:

'%!in%' <- function(x,y)!('%in%'(x,y))

c(1,3,11)%!in%1:10
[1] FALSE FALSE  TRUE
Sacha Epskamp
fuente
55
El uso de la segunda opción se ilustra en la página de ayuda (coincidencia) (donde llegaría si escribiera ?"%in%") donde se llama al nuevo operador %w/o%.
IRTFM
23
ver también, ?Negatepor ejemplo"%ni%" <- Negate("%in%")
baptiste
2
Negate trabajó para mí cuando lo usé después de definir el nuevo operador, como lo sugirió baptiste, por ejemplo subset(df, variable %ni% c("A", "B")), pero no cuando lo usé directamente, por ejemplosubset(df, variable Negate("%in%") c("A", "B"))
PatrickT
2
@PatrickT es porque solo los operadores pueden ser utilizados como operadores. y los operadores están integrados o comienzan y terminan con %. Para crear un operador, debe asignar una función con dos operandos a un nombre que comience y termine con %.
ovejas voladoras
31

Si nos fijamos en el código de %in%

 function (x, table) match(x, table, nomatch = 0L) > 0L

entonces deberías poder escribir tu versión de opuesto. yo suelo

`%not in%` <- function (x, table) is.na(match(x, table, nomatch=NA_integer_))

Otra forma es:

function (x, table) match(x, table, nomatch = 0L) == 0L
Marek
fuente
excelente solución ... funcionó cuando la negación regular falló.
agatha
17

Aquí hay una versión que usa filterin dplyrque aplica la misma técnica que la respuesta aceptada al negar la lógica con!

D2 <- D1 %>% dplyr::filter(!V1 %in% c('B','N','T'))
usuario29609
fuente
12

Usar negatefrom purrrtambién hace el truco de forma rápida y ordenada:

`%not_in%` <- purrr::negate(`%in%`)

Entonces el uso es, por ejemplo,

c("cat", "dog") %not_in% c("dog", "mouse")
EllaK
fuente
2
También hay un incorporado Negateque hace lo mismo. La única diferencia es que el ronroneo llama as_mappera lo que pasa, mientras que las Negatellamadas match.fun. rdocumentation.org/packages/purrr/versions/0.2.5/topics/… stat.ethz.ch/R-manual/R-devel/library/base/html/match.fun.html
ovejas voladoras el
7

purrr::compose() Es otra forma rápida de definir esto para su uso posterior, como en:

`%!in%` <- compose(`!`, `%in%`)
edavidaja
fuente
3

Otra solución podría estar usando setdiff

D1 = c("A",..., "Z") ; D0 = c("B","N","T")

D2 = setdiff(D1, D0)

D2 es tu subconjunto deseado.

usuario3373954
fuente
0

Creo que el uso más claro es solo

!('Spain' %in% c('Germany', 'France', 'Italy'))
luissevillano
fuente
¿Cómo difiere esto sustancialmente de las respuestas ya publicadas aquí?
camille
0
library(roperators)

1 %ni% 2:10
Benbob
fuente
Si bien esta puede ser una respuesta correcta, sería más útil con una explicación adicional de por qué funciona. Considere editarlo para incluir más detalles, y si cree que es mejor que la respuesta aceptada que se publicó hace casi una década.
Jeremy Caney
-1

La ayuda para% en%, help("%in%")incluye, en la sección de Ejemplos, esta definición de no en,

"%w/o%" <- function(x, y) x[!x %in% y] #-- x without y

Vamos a intentarlo:

c(2,3,4) %w/o% c(2,8,9)
[1] 3 4

Alternativamente

"%w/o%" <- function(x, y) !x %in% y #--  x without y
c(2,3,4) %w/o% c(2,8,9)
# [1] FALSE  TRUE  TRUE
Tony Ladson
fuente