Функция для нахождения симметричной разности (противоположной пересечению) в R?

Эта проблема

У меня есть два строковых вектора разной длины. Каждый вектор имеет свой набор строк. Я хочу найти строки, которые находятся в одном векторе, но не в обоих; то есть симметричная разница.

Анализ

Я посмотрел на функцию setdiff, но ее вывод зависит от порядка, в котором рассматриваются векторы. Я нашел пользовательскую функцию externalsect, но эта функция требует, чтобы два вектора были одинаковой длины.

Какие-либо предложения?

коррекция

Эта проблема, кажется, специфична для данных, с которыми я работаю. В противном случае ответ ниже решает проблему, о которой я упоминаю в этом посте. Я посмотрю, что уникального в моих данных, и отправлю ответ, если узнаю что-нибудь полезное для других пользователей.

4 ответа

Решение

Почему бы и нет:

sym_diff <- function(a,b) setdiff(union(a,b), intersect(a,b))

Еще один вариант, который немного быстрее:

sym_diff2 <- function(a,b) unique(c(setdiff(a,b), setdiff(b,a)))

Если мы сравним это с ответом Blue Magister:

sym_diff <- function(a,b) setdiff(union(a,b), intersect(a,b))

library(microbenchmark)
library(MASS)

set.seed(1)
cars1 <- sample(Cars93$Make, 70)
cars2 <- sample(Cars93$Make, 70)

microbenchmark(sym_diff(cars1, cars2), sym_diff2(cars1, cars2), times = 10000L)

>Unit: microseconds
>                  expr     min       lq     mean   median      uq      max neval
>sym_diff(cars1, cars2) 114.719 119.7785 150.7510 125.0410 131.177 12382.02 10000
>sym_diff2(cars1, cars2) 94.369 100.0205 121.6051 103.8285 109.239 12013.69 10000

identical(sym_diff(cars1, cars2), sym_diff2(cars1, cars2))
>[1] TRUE

Разница в скорости между этими двумя методами увеличивается, когда сравниваемые выборки больше (тысячи или больше), но я не смог найти пример набора данных для использования с таким количеством переменных.

Вот еще одна симметричная функция разности, эта из определения (которую можно увидеть, например, на странице Википедии, на которую есть ссылка в вопросе).

sym_diff3 <- function(a, b) union(setdiff(a, b), setdiff(b, a))

Включение функции в тестовый прогон в этом другом ответе пользователя sebpardo дает примерно те же сроки, но немного медленнее. Вывод опущен.

identical(sym_diff(cars1, cars2), sym_diff3(cars1, cars2))
#[1] TRUE

microbenchmark(sym_diff(cars1, cars2),
               sym_diff2(cars1, cars2), 
               sym_diff3(cars1, cars2),
               times = 10000L)

Вы можете использоватьsymdiffвdplyrс1.1.0:

      library(dplyr)
symdiff(1:3, 3:5)
#[1] 1 2 4 5

Обратите внимание, что эта функция пока доступна только в разрабатываемой версии (по состоянию на 23 октября 2022 г.).

Другие вопросы по тегам