【问题标题】:"Set Difference" between two vectors with duplicate values具有重复值的两个向量之间的“设置差异”
【发布时间】:2021-01-28 16:09:54
【问题描述】:

我有 3 个向量

x <- c(1,3,5,7,3,8)
y <- c(3,5,7)
z <- c(3,3,8)

我想找到x 中不在yz 中的元素。是否有一个函数f 会给我以下输出:

> f(x,y)
1 3 8
> f(x,z)
1 5 7

换句话说,我想找到两个向量之间的“集合差异”,其中任何一个向量都可能有重复的值。 %in%matchsetdiff 函数在这种情况下不起作用,原因很明显。

【问题讨论】:

  • 你说你想要 2 个向量之间的差异,但你提供了 3 个向量...
  • 问题只涉及2个向量。向量yz 用于不同的情况。 z 包含重复项,而 y 没有。

标签: r


【解决方案1】:

应该有一些更好的方法来做到这一点,但这里有一个选择

get_diff_vectors <- function(x, y) {
  count_x <- table(x)
  count_y <- table(y)
  same_counts <- match(names(count_y), names(count_x))
  count_x[same_counts] <- count_x[same_counts] - count_y
  as.numeric(rep(names(count_x), count_x))
}

get_diff_vectors(x, y)
#[1] 1 3 8
get_diff_vectors(x, z)
#[1] 1 5 7
get_diff_vectors(x, c(5, 7))
#[1] 1 3 3 8

我们使用tablematch 计算xy 出现的频率,然后从x 中减去y 的计数。最后使用rep重新创建剩余的向量。


仍然无法找到更好的方法,但这里是dplyr 使用有点类似逻辑的方法。

library(dplyr)

get_diff_vectors_dplyr <- function(x, y) {
  df1 <- data.frame(x) %>% count(x)
  df2 <- data.frame(y) %>% count(y)
  final <- left_join(df1, df2, by = c("x" = "y")) %>%
           mutate_at(c("n.x", "n.y"), funs(replace(., is.na(.), 0))) %>%
           mutate(n = n.x - n.y)

  rep(final$x, final$n)
}

get_diff_vectors_dplyr(x, y)
#[1] 1 3 8
get_diff_vectors_dplyr(x, z)
#[1] 1 5 7
get_diff_vectors_dplyr(x, c(5, 7))
#[1] 1 3 3 8

OP 提到的vecsets 包有函数vsetdiff 很容易做到这一点

vecsets::vsetdiff(x, y)
#[1] 1 3 8
vecsets::vsetdiff(x, z)
#[1] 1 5 7
vecsets::vsetdiff(x, c(5, 7))
#[1] 1 3 3 8

【讨论】:

  • 这是一个很好的解决方案,谢谢,但我找到了一个包vecsets,它完全符合我的要求。不过我会接受这个答案。
【解决方案2】:

这里尝试使用make.unique 来解决重复问题:

dupdiff <- function(x,y) x[-match(
  make.unique(as.character(y)),
  make.unique(as.character(x)),
  nomatch=0
)]

测试:

dupdiff(x,y)
#[1] 1 3 8
dupdiff(x,z)
#[1] 1 5 7
dupdiff(x, c(5, 7))
#[1] 1 3 3 8
dupdiff(x, c(5, 7, 9))
#[1] 1 3 3 8

【讨论】:

    【解决方案3】:

    match 带有一点 for 循环确实有效:

    > f(x, y)
    [1] 1 3 8
    > f(x, z)
    [1] 1 5 7
    

    代码

    f <- function(s, r) {
        for(i in 1:length(s)){
            j <- match(s[i], r)
            if(!is.na(j)) {
                s[i] <- NA
                r[j] <- NA
            } 
        }
        print(s[complete.cases(s)])
    }
    

    【讨论】:

      【解决方案4】:

      有新的 Hadley-verse 包waldo

      对对象的差异进行真正简洁明了的概述,而不仅仅是向量

      library(waldo)
      
      compare(x, y)
      #> `old`: 1 3 5 7 3 8
      #> `new`:   3 5 7
      compare(x, z)
      #> `old`: 1 3 5 7 3 8
      #> `new`:   3     3 8
      

      【讨论】:

      • 这个比较只是为了显示目的吗?我们不能以某种方式使用这些值吗?
      • @RonakShah 好问题。我认为它的主要目的确实是展示。我认为仍然值得指出这个包,特别是因为 OP 在要求“找出差异”时没有特别说明他们的意图。另一方面,(现在不在控制台上),我确信 waldo::compare 返回一个可以探索值的对象。回到 R 后会更新。
      • @RonakShah 查看讨论here
      • @user63230 谢谢,这很有趣
      猜你喜欢
      • 2018-07-03
      • 1970-01-01
      • 1970-01-01
      • 2015-10-12
      • 2014-10-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多