«Задать разницу» между двумя векторами с повторяющимися значениями - PullRequest
0 голосов
/ 23 октября 2018

У меня есть 3 вектора

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

Я хочу найти элементы x, которые не находятся в y и не в z.Есть ли функция f, которая выдала бы мне следующий вывод:

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

Другими словами, я хочу найти «разность наборов» между 2 векторами, каждый из которых может иметь повторяющиеся значения.Функции %in%, match и setdiff в этом случае не работают по понятным причинам.

Ответы [ 3 ]

0 голосов
/ 23 октября 2018

Вот попытка использования 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
0 голосов
/ 23 октября 2018

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)])
}
0 голосов
/ 23 октября 2018

Должны быть лучшие способы сделать это, но вот один из вариантов

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

Мы считаем частоты x и y, используя table, match числа, которые встречаютсяв обоих и вычтите количество y из x.Наконец, воссоздайте оставшийся вектор, используя 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...