Подтвердить что ты не робот

Поиск уникальных значений из списка

Предположим, что у вас есть список значений

x <- list(a=c(1,2,3), b = c(2,3,4), c=c(4,5,6))

Я хотел бы найти уникальные значения из всех элементов списка, объединенных. До сих пор следующий код сделал трюк

unique(unlist(x))

Кто-нибудь знает более эффективный способ? У меня есть огромный список с большим количеством ценностей и буду признателен за любое ускорение.

4b9b3361

Ответ 1

Это решение, предложенное Мареком, является лучшим ответом на исходный Q. См. ниже обсуждение других подходов и почему Marek является наиболее полезным.

> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6

Обсуждение

Более быстрое решение состоит в том, чтобы сначала вычислить unique() на компонентах вашего x, а затем сделать окончательный unique() по этим результатам. Это будет работать, только если компоненты списка имеют одинаковое количество уникальных значений, как в обоих примерах ниже. Например:.

Сначала ваша версия, затем мой двойной уникальный подход:

> unique(unlist(x))
[1] 1 2 3 4 5 6
> unique.default(sapply(x, unique))
[1] 1 2 3 4 5 6

Нам нужно вызвать unique.default, поскольку существует метод matrix для unique, который фиксирует один край фиксированного; это прекрасно, так как матрица может рассматриваться как вектор.

Марек в комментариях к этому ответу отмечает, что медленная скорость подхода unlist потенциально связана с names в списке. Решение Marek должно использовать аргумент use.names для unlist, который, если используется, приводит к более быстрому решению, чем двойная уникальная версия выше. Для простого x римского поста получаем

> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6

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

Вот пример с несколькими таймингами всех трех методов:

## Create a large list (1000 components of length 100 each)
DF <- as.list(data.frame(matrix(sample(1:10, 1000*1000, replace = TRUE), 
                                ncol = 1000)))

Ниже приведены результаты для двух подходов с использованием DF:

> ## Do the three approaches give the same result:
> all.equal(unique.default(sapply(DF, unique)), unique(unlist(DF)))
[1] TRUE
> all.equal(unique(unlist(DF, use.names = FALSE)), unique(unlist(DF)))
[1] TRUE
> ## Timing Roman original:
> system.time(replicate(10, unique(unlist(DF))))
   user  system elapsed 
  12.884   0.077  12.966
> ## Timing double unique version:
> system.time(replicate(10, unique.default(sapply(DF, unique))))
   user  system elapsed 
  0.648   0.000   0.653
> ## timing of Marek solution:
> system.time(replicate(10, unique(unlist(DF, use.names = FALSE))))
   user  system elapsed 
  0.510   0.000   0.512

Что показывает, что двойной unique намного быстрее применяет unique() к отдельным компонентам, а затем unique() эти меньшие множества уникальных значений, но это ускорение происходит исключительно из-за names on список DF. Если мы скажем unlist не использовать names, решение Марека будет немного быстрее, чем двойное unique для этой проблемы. Поскольку решение Marek правильно использует правильный инструмент, и оно быстрее, чем обход, это предпочтительное решение.

Большая getcha с двойным подходом unique заключается в том, что она будет работать только , если, как в двух примерах здесь, каждый компонент списка ввода (DF или x) имеет такое же количество уникальных значений. В таких случаях sapply упрощает результат до матрицы, которая позволяет применить unique.default. Если компоненты входного списка имеют разные числа уникальных значений, двойное уникальное решение не будет выполнено.