如何从向量中删除多个值?

149

我有一个向量,如下所示:a = c(1:10),我需要删除多个值,如:2, 3, 5

如何从向量中删除这些数字(它们并不是向量中的位置)?

目前我循环遍历向量并执行以下操作:

a[!a=NUMBER_TO_REMOVE]

但我认为有一个可以自动完成这个任务的函数。

9个回答

225
< p > %in% 运算符告诉您哪些元素是要删除的数字之一:

> 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

请注意,这将悄无声息地删除不可比较的内容(例如NAInf),同时也会保留a中的重复值,只要它们未列在remove中。
  • If a can contain incomparables, but remove will not, we can use match, telling it to return 0 for non-matches and incomparables (%in% is a conventient shortcut for 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 is not needed as incomparables will anyways not match, but I'd include it for the sake of readability.
    This is, btw., what setdiff does internally (but without the unique to throw away duplicates in a which are not in remove).

  • If remove contains incomparables, you'll have to check for them individually, e.g.

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

    (This does not distinguish NA from NaN but the R manual anyways warns that one should not rely on having a difference between them)

    For Inf/ -Inf you'll have to check both sign and is.finite


4
setdiff 更好,因为它可以在一次操作中完成所有操作,并且仅对修订后的向量进行引用。 - Olexa
1
@Olexa:集合差异并不总是等同于从向量中删除给定数字集的所有出现:它也会删除a中不在remove中的重复项。如果这不是问题,您也可以使用setdiff。顺便说一下,setdiff使用match,而%in%是一个快捷方式。 - cbeleites unhappy with SX

116
你可以使用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是另一个函数的结果时,你可以在一行中完成操作,而不需要三个临时变量。 - jf328
17
如果输入向量包含重复值(此时setdiff仅返回不带重复值的唯一集合),则与%in%解决方案产生不同的结果。 - talat
2
@docendodiscimus:data.table包的fsetdiff函数有一个all标志(默认为F),允许在输入向量中保留重复项。 - Juergen

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

使用purrrmagrittr包,您可以进行以下操作:
your_vector %<>% discard(~ .x %in% c(2,3,5))

这使得使用向量名称仅一次进行子集成为可能。而且你可以在管道中使用它 :)

请问您能否解释一下关于变量名称长度的最后一句话?为什么您不喜欢那样做?为什么另一种方式更好?或者,删除该段落,因为它与主要问题/问题无关。 - rodrigoap

10

您可以按照以下步骤进行:

> 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
你在例子中所称呼的列表,其实是一个向量,对吧? - patrick
是的,我指的是向量。感谢您的评论。 - ibilgen
这里不需要用 which。它基本上与 @cbeleites 的答案相同。 - David Arenburg
1
是的,它们相似,但在一些观点上有所不同。which返回TRUE值的索引。因此,减号可以用来表示“除这些索引之外的索引”。此外,which更易读,因为它更接近自然语言。 - ibilgen

4

首先,我们可以定义一个新的运算符,

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

然后,就像 x 不在 remove 中一样。
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

3

有时候也可以使用 subset

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

> subset(a, !(a %in% bad))
[1]  9  7 10  6  8  1  4

2

更新:

以上所有答案都无法处理重复值,@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)] 是什么意思? - Ben Bolker
@BenBolker 啊,我不知道有“duplicated”谓词 :(( 现在怎么办,我应该删除我的答案还是改成只显示你的答案? - Özgür
@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
尝试使用此函数。
seq.int.exclude <- function(excluded, ...) {
    x <- seq.int(...)
    return(x[!(x %in% excluded)])
}

调用示例:

seq.int.exclude(from = 10L, to = 20L, excluded = c(12L, 30L, 19L))
seq.int.exclude(from = 10L, to = 20L, excluded = 15L)

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),它会显示false。 remove(q[c(11,12,13)])。 如果你尝试这样做,你会发现remove函数不能在向量数字上工作。 你可以删除整个向量,但可能不是单个元素。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接