Comment supprimer plusieurs valeurs d'un vecteur?


125

J'ai un vecteur comme: a = c(1:10)et je dois supprimer plusieurs valeurs, comme:2, 3, 5

Comment supprimer ces nombres (ce ne sont PAS les positions dans le vecteur) dans le vecteur?

au moment où je boucle le vecteur et fais quelque chose comme:

a[!a=NUMBER_TO_REMOVE]

Mais je pense qu'il existe une fonction qui le fait automatiquement.

Réponses:


192

L' %in%opérateur vous indique quels éléments figurent parmi les nombres à supprimer:

> a <- sample (1 : 10)
> remove <- c (2, 3, 5)
> a
 [1] 10  5  2  7  1  6  3  4  8  9
> a %in% remove
 [1] FALSE  TRUE  TRUE FALSE FALSE FALSE  TRUE FALSE FALSE FALSE
> a [! a %in% remove]
 [1] 10  7  1  6  4  8  9

Notez que cela supprimera silencieusement les incomparables (des trucs comme NAou Inf)aussi (alors que cela conservera les valeurs en double atant qu'elles ne sont pas répertoriées dans remove).

  • Si apeut contenir des incomparables, mais removene le fera pas, nous pouvons l'utiliser match, en lui disant de retourner 0pour les non-matches et les incomparables ( %in%est un raccourci conventionnel pour match):

    > a <- c (a, NA, Inf)
    > a
     [1]  10   5   2   7   1   6   3   4   8   9  NA Inf
    > match (a, remove, nomatch = 0L, incomparables = 0L)
     [1] 0 3 1 0 0 0 2 0 0 0 0 0
    > a [match (a, remove, nomatch = 0L, incomparables = 0L) == 0L]
    [1]  10   7   1   6   4   8   9  NA Inf
    

    incomparables = 0n'est pas nécessaire car les incomparables ne correspondent de toute façon pas, mais je l'inclurais pour des raisons de lisibilité.
    C'est, btw., Ce qui setdifffait en interne (mais sans uniquejeter les doublons dans alesquels ne sont pas remove).

  • Si removecontient des incomparables, vous devrez les vérifier individuellement, par exemple

    if (any (is.na (remove))) 
      a <- a [! is.na (a)]
    

    (Cela ne distingue pas NAde NaNmais le manuel de R avertit de toute façon que l' on ne doit pas compter sur avoir une différence entre eux)

    Pour Inf/ -Infvous devrez cocher à la fois signetis.finite


1
setdiffest mieux, car il fait tout en une seule opération et référence le vecteur modifié une seule fois.
Olexa

1
@Olexa: la différence d'ensemble n'est pas toujours la même chose que de supprimer toutes les occurrences d'un ensemble donné de nombres d'un vecteur: cela supprimera les doublons aqui ne sont pas removeégalement présents. Si ce n'est pas un problème, vous pouvez également utiliser setdiff. setdiff, btw, utilise matchpour qui %in%est un raccourci.
cbeleites mécontent de SX

97

Vous pouvez utiliser setdiff.

Donné

a <- sample(1:10)
remove <- c(2, 3, 5)

ensuite

> a
 [1] 10  8  9  1  3  4  6  7  2  5
> setdiff(a, remove)
[1] 10  8  9  1  4  6  7

1
très utile quand aest le résultat d'une autre fonction afin que vous puissiez faire des choses sur une ligne au lieu de 3 et une variable temporaire
jf328

14
Cela produira des résultats différents de la %in%solution si le vecteur d'entrée contient des doublons (auquel cas setdiffne renverra que l' ensemble unique , c'est-à-dire sans doublons)
talat

2
@docendodiscimus: fsetdiffdu data.tablepackage a un allflag (F par défaut) qui permet de conserver les doublons dans le vecteur d'entrée.
Juergen

9

Vous pouvez le faire comme suit:

> x<-c(2, 4, 6, 9, 10) # the list
> y<-c(4, 9, 10) # values to be removed

> idx = which(x %in% y ) # Positions of the values of y in x
> idx
[1] 2 4 5
> x = x[-idx] # Remove those values using their position and "-" operator
> x
[1] 2 6

Prochainement

> x = x[ - which(x %in% y)]

1
ce que vous appelez une liste dans votre exemple est un vecteur, non?
patrick

Oui, je veux dire le vecteur. Merci pour le commentaire.
ykpemre

Il n'y a aucun besoin whichici. C'est fondamentalement la même chose que la réponse @cbeleites.
David Arenburg

oui c'est similaire, mais différent à quelques points de vue. whichrenvoie des index de valeurs TRUE. Le signe moins peut donc être utilisé pour dire "les index autres que ces index". Est également whichplus lisible car il est plus proche du langage naturel.
ykpemre

4

au lieu de

x <- x[! x %in% c(2,3,5)]

en utilisant les packages purrret magrittr, vous pouvez faire:

your_vector %<>% discard(~ .x %in% c(2,3,5))

cela permet d' subsetutiliser le nom du vecteur une seule fois. Et vous pouvez l'utiliser dans les tuyaux :)


pouvez-vous expliquer votre dernière déclaration sur la longueur du nom des variables? Pourquoi tu n'aimes pas ça? Pourquoi est-ce mieux que l'inverse? Ou supprimez ce paragraphe car il n'est pas lié au problème / question principal.
rodrigoap

2

Tout d'abord, nous pouvons définir un nouvel opérateur,

"%ni%" = Negate( "%in%" )

Ensuite, c'est comme x pas en retrait

x <- 1:10
remove <- c(2,3,5)
x <- x[ x %ni% remove ]

ou pourquoi opter pour la suppression, allez directement

x <- x[ x %ni% c(2,3,5)]

3
La question dit spécifiquement que 2, 3 et 5 ne sont pas des positions dans le vecteur.
blakeoft

1

METTRE À JOUR:

Toutes les réponses ci-dessus ne fonctionneront pas pour les valeurs répétées, la réponse de @ BenBolker utilisant le duplicated()prédicat résout ceci:

full_vector[!full_vector %in% searched_vector | duplicated(full_vector)]

Réponse originale: ici, j'écris une petite fonction pour cela:

exclude_val<-function(full_vector,searched_vector){

      found=c()

      for(i in full_vector){  

        if(any(is.element(searched_vector,i))){
          searched_vector[(which(searched_vector==i))[1]]=NA
        }
        else{
          found=c(found,i)
        }
    }

    return(found)
}

alors, disons full_vector=c(1,2,3,4,1)et searched_vector=c(1,2,3).

exclude_val(full_vector,searched_vector)retournera (4,1), mais les réponses ci-dessus ne retourneront que (4).


1
et quoi full_vector[!full_vector %in% searched_vector | duplicated(full_vector)]?
Ben Bolker

@BenBolker ah je ne savais pas que le prédicat "dupliqué": ((que dois-je supprimer ma réponse ou la modifier pour afficher uniquement la vôtre à la place?
Özgür

@BenBolker, votre solution est fausse; essayez simplement: full_vector = c(1,1,1,2,3); searched_vector = c(1,1,3);- cela produit 1, 1, 2au lieu de la bonne réponse 1, 2.
fnl

Juste pour ajouter une solution possible et correcte pour les valeurs répétées:removeif <- function(from, where) { for (i in where) if (i %in% from) {from = from[-match(i, from)]}; from}
fnl

1
q <- c(1,1,2,2,3,3,3,4,4,5,5,7,7)
rm <- q[11]
remove(rm)
q
q[13] = NaN
q
q %in% 7

Cela définit le 13 dans un vecteur à pas un nombre (NAN), il montre false remove (q [c (11,12,13)]) si vous essayez cela, vous verrez que la fonction de suppression ne fonctionne pas sur le nombre de vecteur. vous supprimez le vecteur entier mais peut-être pas un seul élément.


1

Il y a aussi subsetce qui peut être utile parfois:

a <- sample(1:10)
bad <- c(2, 3, 5)

> subset(a, !(a %in% bad))
[1]  9  7 10  6  8  1  4
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.