Как удалить несколько значений из вектора?


125

У меня есть вектор вроде: a = c(1:10)и мне нужно удалить несколько значений, например:2, 3, 5

Как удалить эти числа (они НЕ являются позициями в векторе) в векторе?

в данный момент я зацикливаю вектор и делаю что-то вроде:

a[!a=NUMBER_TO_REMOVE]

Но я думаю, что есть функция, которая делает это автоматически.

Ответы:


192

%in%Оператор говорит вам , какие элементы являются одними из numers удалить:

> 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

Обратите внимание, что это незаметно удалит несравнимые элементы (такие как NAили) Inf)(при этом будут сохраняться повторяющиеся значения, aпока они не указаны в списке remove).

  • Если aможет содержать несравнимые, но removeне будет, мы можем использовать match, сообщив ему, что нужно возвращать 0несопоставимые и несравнимые ( %in%это удобный ярлык для 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 = 0не требуется, так как несравненные в любом случае не будут совпадать, но я бы добавил его для удобства чтения.
    Это, кстати, то, что setdiffработает внутри (но без того, uniqueчтобы выбросить дубликаты, в aкоторых нет remove).

  • Если removeсодержит несравненные, вам придется проверять их индивидуально, например

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

    (Это не отличает NAот, NaNно руководство R в любом случае предупреждает, что не следует полагаться на разницу между ними)

    Для Inf/ -Infвам нужно будет проверить оба signиis.finite


1
setdiffлучше, поскольку он делает все за одну операцию и ссылается на измененный вектор только один раз.
Олекса

1
@Olexa: разница в наборах не всегда совпадает с удалением всех вхождений заданного набора чисел из вектора: он удалит дубликаты a, которых removeтакже нет. Если это не проблема, вы также можете использовать setdiff. setdiff, кстати, использует matchдля этого %in%ярлык.
cbeleites недовольны SX

97

Вы можете использовать setdiff.

Дано

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

затем

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

1
очень полезно, когда aэто результат другой функции, поэтому вы можете делать что-то в одной строке вместо 3 и временной переменной
jf328

14
Это приведет к другим результатам, чем %in%решение, если входной вектор содержит дубликаты (и в этом случае setdiffбудет возвращен только уникальный набор , то есть без дубликатов)
talat

2
@docendodiscimus: fsetdiffу data.tableпакета есть allфлаг (по умолчанию F), который позволяет сохранять дубликаты во входном векторе.
Юрген

9

Сделать это можно следующим образом:

> 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

вскоре

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

1
то, что вы называете списком в своем примере, является вектором, верно?
Патрик

Да я про вектор. Спасибо за комментарий.
ykpemre

Здесь нет необходимости which. Это в основном то же самое, что и ответ @cbeleites.
Дэвид Аренбург

да, это похоже, но отличается с нескольких точек зрения. whichвозвращает индексы ИСТИННЫХ значений. Таким образом, знак минус может использоваться, чтобы сказать «индексы, отличные от этих индексов». Также whichон более читабелен, поскольку он ближе к естественному языку.
ykpemre

4

вместо того

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

используя пакеты purrrи magrittr, вы можете:

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

это позволяет subsetиспользовать имя вектора только один раз. И можно использовать в трубах :)


не могли бы вы объяснить ваше последнее утверждение о длине имени переменных? Почему тебе это не нравится? Почему лучше, чем наоборот? Или удалите этот абзац, поскольку он не связан с основной проблемой / вопросом.
Rodrigoap

2

Сначала мы можем определить новый оператор,

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

Тогда это похоже на x не в удалении

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

или зачем идти на удаление, идти прямо

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

3
В вопросе конкретно говорится, что 2, 3 и 5 не являются позициями в векторе.
Blakeoft

1

ОБНОВИТЬ:

Все приведенные выше ответы не будут работать для повторяющихся значений, ответ @BenBolker с использованием duplicated()предиката решает это:

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

Исходный ответ: здесь я пишу для этого небольшую функцию:

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

так, скажем так full_vector=c(1,2,3,4,1)и searched_vector=c(1,2,3).

exclude_val(full_vector,searched_vector)вернет (4,1), однако приведенные выше ответы вернутся просто (4).


1
о чем full_vector[!full_vector %in% searched_vector | duplicated(full_vector)]?
Бен Болкер

@BenBolker ах, я не знал этого "дублированного" предиката: ((что теперь, мне удалить свой ответ или изменить его, чтобы вместо него отображался только ваш?
Озгюр

@BenBolker, ваше решение неверно; просто попробуйте: full_vector = c(1,1,1,2,3); searched_vector = c(1,1,3);- 1, 1, 2вместо правильного ответа 1, 2.
fnl

Просто чтобы добавить возможное правильное решение для повторяющихся значений: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

Это устанавливает 13 в векторе как не число (NAN), это показывает ложное удаление (q [c (11,12,13)]), если вы попробуете это, вы увидите, что функция удаления не работает с векторным номером. вы удаляете весь вектор, но, возможно, ни один элемент.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.