#r #list #vector #unique #data-mining
#r #Список #вектор #уникальный #интеллектуальный анализ данных
Вопрос:
Например, у меня есть 5 векторов в списке:
A <- c(1,2,3,4,5)
B <- c(1,2,3,4,5,6)
C <- c(5,6,7,8,9)
D <- c(8,9)
На самом деле у меня есть 100 таких векторов, но я дал только 5 векторов для воспроизводимости.
Моя цель -:
- Определите уникальные элементы, исходящие из векторов. Например,
vector A
не должен ничего возвращать, потому что все его элементы являются частьюvector B
, однакоvector B
вносит дополнительный уникальный элемент, и это так6
.Vector C
должен дать мне7,8,9
, посколькуc(5,6)
они уже были включеныvector B
.Vector D
ничего не должно возвращать, потому что все его элементы являются частью C - распознать, какой элемент является уникальным из какого вектора
- Найдите, какие векторы являются подмножествами других больших векторов. Например,
vector D
является подмножествомC
иvector A
является подмножествомvector B
.
До сих пор единственным решением, которое я нашел, было:
Reduce(setdiff, list("my_vectors"))
Но это не позволяет мне распознать, какой элемент уникален из какого вектора. Например, Reduce(setdiff, list(A,B))
вернул 6
бы, но я бы понятия не имел, откуда 6
взялся ( A
или B
)?
Моя трудность заключается в том, что это крупномасштабная проблема, у меня нет только 5 векторов, у меня их 100, поэтому я не могу найти устойчивое решение. Любые советы приветствуются.
Редактировать: мои векторы находятся в списке
Комментарии:
1. Являются ли векторы в списке
.GlobalEnv
или в списке?2. Они находятся в списке. Итак, у меня есть список векторов.
3. В вашем примере нет эксклюзивных шифров.
4. Это не совсем точно определено: например, A не должен возвращать ничего, потому что B содержит все элементы в A, но B должен возвращать 6. Однако 6 также содержится в C. Итак, здесь единственным по-настоящему уникальным элементом, который у вас есть, является 7 в C, я прав?
5. Точно. Это довольно неоднозначно.
Ответ №1:
Предположим, что ваши данные хранятся следующим образом:
my_vectors <- list(
A = c(1,2,3,4,5),
B = c(1,2,3,4,5,6),
C = c(5,6,7,8,9),
D = c(8,9)
)
Если вы используете accumulate = TRUE
вызов Reduce
to , вы также получаете все промежуточные результаты. Мы можем использовать это вместе с union
для пошагового создания общего набора (обратите внимание, что я установил init = c()
, чтобы убедиться, что мы начинаем с пустого):
acc <- Reduce(union, my_vectors, init = c(), accumulate = T)
Затем мы можем взять значение setdiff
каждого элемента с помощью этого созданного списка.
lapply(1:length(my_vectors), function(i) setdiff(my_vectors[[i]], acc[[i]]))
Это дает
[[1]]
[1] 1 2 3 4 5
[[2]]
[1] 6
[[3]]
[1] 7 8 9
[[4]]
numeric(0)
Вы можете применить имена my_vectors
позже, если хотите.
Ответ №2:
Первым наивным подходом был бы цикл for, просто чтобы иметь рабочее решение. Функция возвращает список с ненужными элементами и фреймом данных, описывающим, из какого вектора в векторном списке исходят уникальные элементы (первое появление).
A <- c(1,2,3,4,5)
B <- c(1,2,3,4,5,6)
C <- c(5,6,7,8,9)
D <- c(8,9)
vectorList <- list(A,B,C,D)
ff <- function(vectorList) {
uniques <- unique(vectorList[[1]])
comingFromDf <- data.frame(values=uniques)
comingFromDf$source <- 1
for(k in 2:length(vectorList)) {
vec <- vectorList[[k]]
newUniques <- vec[!(vec %in% uniques)]
if(length(newUniques)) {
newUniques <- unique(newUniques)
toAdd <- data.frame(values=newUniques)
toAdd$source <- k
comingFromDf <- rbind(comingFromDf,toAdd)
uniques <- c(uniques,newUniques)
}
}
list(uniqueElements = uniques,
comingFromInfo = comingFromDf)
}
ff(vectorList)
Я не знаю, насколько эффективной вам нужна функция, но даже с 200 векторами длиной 1000 она, похоже, быстро завершается (я не знаю о ваших размерах):
bigVectorList <- lapply(1:200, function(k) {
sample(1:1e6,1000)
})
microbenchmark::microbenchmark(ff(bigVectorList),times=10)
#Unit: milliseconds
# expr min lq mean median uq max neval
#ff(bigVectorList) 619.5148 624.8351 639.7535 633.2326 647.118 685.0387 10
На моей машине это заняло чуть больше половины секунды, может быть, для вас этого достаточно. Поскольку функция включает только векторы и фрейм данных, было бы довольно легко повторно реализовать ее на C и с использованием Rcpp. Это должно быть намного быстрее, чем реализация цикла for в R. Кроме того, вы можете рассмотреть возможность использования accumulate
аргумента -в Reduce
-функции для сохранения промежуточных результатов вычисления.
Ответ №3:
Вот tidyverse
решение.
lag(accumulate(l, union))
отслеживает все элементы, которые были замечены до сих пор. Разница между этим и исходным списком приводит к появлению новых элементов.
library(tidyverse)
l <- lst(A, B, C, D)
map2(l, lag(accumulate(l, union)), setdiff)
#> $A
#> [1] 1 2 3 4 5
#>
#> $B
#> [1] 6
#>
#> $C
#> [1] 7 8 9
#>
#> $D
#> numeric(0)
Вот ответ на ваш другой вопрос о том, какие векторы являются подмножествами других больших векторов.
expand_grid
получит все комбинации векторов. Отфильтруйте это, чтобы найти, какой вектор является подмножеством любого другого вектора.
l %>%
enframe() %>%
expand_grid(a = ., b = .) %>%
filter(
a$name != b$name,
map2_lgl(a$value, b$value, ~all(.x %in% .y))
) %>%
transmute(this_vector = a$name, is_a_subset_of_this_vector = b$name)
#> # A tibble: 2 x 2
#> this_vector is_a_subset_of_this_vector
#> <chr> <chr>
#> 1 A B
#> 2 D C
Ответ №4:
Здесь у вас есть только один действительно уникальный элемент, который находится 7
внутри C
. Ниже будут возвращены уникальные элементы, а также их членство
mylist <- list("A"=A,"B"=B,"C"=C,"D"=D) #better for 100's of vectors
myres <- !unlist(lapply(1:length(mylist), function(x) unlist(mylist[x]) %in% unlist(mylist[-x])))
result <- as.numeric(unlist(mylist)[myres])
member <- sapply(mylist, function(x) result %in% x)
membername <- names(mylist[member])
result
membername
> result
7
> membername
[1] "C"