Como excluir vários valores de um vetor?


125

Eu tenho um vetor como: a = c(1:10)e preciso remover vários valores, como:2, 3, 5

Como excluir esses números (eles NÃO são as posições do vetor) no vetor?

No momento, faço um loop no vetor e faço algo como:

a[!a=NUMBER_TO_REMOVE]

Mas acho que existe uma função que faz isso automaticamente.

Respostas:


192

O %in%operador informa quais elementos estão entre os números para remover:

> 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

Observe que isso removerá silenciosamente incomparáveis ​​(coisas como essa NAou Inf)também (enquanto manterá valores duplicados aenquanto não estiverem listados remove).

  • Se apode conter incomparáveis, mas removenão, podemos usá- matchlo, dizendo para retornar 0para não correspondências e incomparáveis ​​( %in%é um atalho conveniente para 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ão é necessário, pois incomparáveis ​​de qualquer maneira não corresponderão, mas eu o incluiria por questões de legibilidade.
    Isto é, aliás, o que setdifffaz internamente (mas sem o uniquepara jogar fora as duplicatas nas aquais não estão remove).

  • Se removecontiver incomparáveis, você deverá verificá-las individualmente, por exemplo

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

    (Isso não distingue NAdeNaN , mas o manual R qualquer maneira adverte que não se deve confiar em ter uma diferença entre eles)

    Para Inf/ -Infvocê terá que verificar ambos signeis.finite


1
setdiffé melhor, pois faz tudo em uma operação e faz referência ao vetor alterado apenas uma vez.
Olexa

1
@Olexa: definir diferença nem sempre é o mesmo que remover todas as ocorrências de um determinado conjunto de números de um vetor: ele removerá duplicatas aque não estão removetambém. Se isso não for um problema, você também pode usar setdiff. setdiff, btw, usa matchpara o qual %in%é um atalho.
cbeleites descontente com SX

97

Você pode usar setdiff.

Dado

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

Então

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

1
muito útil quando aé o resultado de outra função que você pode fazer coisas em uma linha, em vez de 3 e uma variável temporário
jf328

14
Isto irá produzir resultados diferentes do que a %in%solução se o vector de entrada contém duplicados (caso em que setdiffsó irá devolver o único conjunto , isto é, sem as repetições)
Talat

2
@docendodiscimus: fsetdiffof data.tablepackage possui uma allflag (padrão F) que permite manter duplicatas no vetor de entrada.
Juergen

9

Você pode fazer o seguinte:

> 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

Em breve

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

1
o que você está chamando de lista no seu exemplo é um vetor, certo?
patrick

Sim, eu quero dizer o vetor. Obrigado pelo comentário.
Ykpemre

Não há necessidade whichaqui. É basicamente o mesmo que a resposta @cbeleites.
David Arenburg 26/03

sim, é semelhante, mas diferente em alguns pontos de vista. whichretorna índices de valores TRUE. Portanto, o sinal de menos pode ser usado para dizer "os índices diferentes desses índices". Também whiché mais legível, pois está mais próximo da linguagem natural.
Ykpemre

4

ao invés de

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

usando os pacotes purrre magrittr, você pode:

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

isso permite subsetusar o nome do vetor apenas uma vez. E você pode usá-lo em tubos :)


você pode explicar sua última afirmação sobre o tamanho do nome das variáveis? Por que você não gosta disso? Por que é melhor que o contrário? Ou remova esse parágrafo, pois não está relacionado à questão / questão principal.
Rodrigoap

2

Primeiro, podemos definir um novo operador,

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

Então, é como x não remover

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

ou por que optar por remover, vá diretamente

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

3
A pergunta diz especificamente que 2, 3 e 5 não são posições no vetor.
blakeoft

1

ATUALIZAR:

Todas as respostas acima não funcionarão para os valores repetidos, a resposta do @ BenBolker usando duplicated()predicado resolve isso:

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

Resposta original: aqui escrevo uma pequena função para isso:

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)
}

então, digamos full_vector=c(1,2,3,4,1)e searched_vector=c(1,2,3).

exclude_val(full_vector,searched_vector)retornará (4,1), no entanto, as respostas acima retornarão apenas (4).


1
que tal full_vector[!full_vector %in% searched_vector | duplicated(full_vector)]?
quer

@BenBolker ah eu não sabia que "duplicado" predicado: ((agora o que hei de apagar a minha resposta, ou alterá-lo para mostrar apenas seu em vez?
Özgür

@BenBolker, sua solução está errada; tente: full_vector = c(1,1,1,2,3); searched_vector = c(1,1,3);- que produz em 1, 1, 2vez da resposta correta 1, 2.
FNL

Apenas para adicionar uma solução possível e correta para valores repetidos:removeif <- function(from, where) { for (i in where) if (i %in% from) {from = from[-match(i, from)]}; from}
fnl 13/06/2015

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

Isso define os 13 em um vetor para não um número (NAN). Ele mostra remoção falsa (q [c (11,12,13)]). Se você tentar isso, verá que a função remover não funciona no número do vetor. você remove o vetor inteiro, mas talvez não seja um único elemento.


1

Há também o subsetque pode ser útil às vezes:

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

> subset(a, !(a %in% bad))
[1]  9  7 10  6  8  1  4
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.