x <- list(a=c(1,2,3), b = c(2,3,4), c=c(4,5,6))
我想从所有列表元素中找到唯一的值。目前为止,以下代码已经解决了这个问题。
unique(unlist(x))
有人知道更有效的方法吗?我有一个巨大的列表,有很多值,希望能够加速处理。
Marek建议的这个解决方案是原始问题的最佳答案。请参阅下面的讨论以了解其他方法以及为什么Marek的方法最有用。
> unique(unlist(x, use.names = FALSE))
[1] 1 2 3 4 5 6
更快的解决方案是首先在您的x
组件上计算unique()
,然后对这些结果进行最终的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
,因为存在一个针对 unique
的 matrix
方法,它保持一个边缘固定;这是可以的,因为矩阵可以被视为向量。
Marek在对这个答案的评论中指出,unlist
方法速度慢的原因可能是列表中的 names
。Marek的解决方案是利用 unlist
的 use.names
参数,如果使用该参数,则得到的解决方案比上面的双重去重版本更快。 对于Roman帖子中的简单 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's 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's solution:
> system.time(replicate(10, unique(unlist(DF, use.names = FALSE))))
user system elapsed
0.510 0.000 0.512
这表明,将双重unique
应用于各个组件,然后对这些较小的唯一值集合应用unique()
,要比直接对整个列表DF
使用unique()
更快;但是,这种加速纯粹是由于列表DF
上的names
。如果我们告诉unlist
不要使用names
,那么Marek的解决方案比双重unique
稍微快一点。因为Marek的解决方案正确地使用了正确的工具,而且比变通方法更快,所以它是首选解决方案。
使用双重unique
的一个大问题是,它只在每个输入列表(DF
或x
)的每个组件具有相同数量的唯一值时才有效,就像这里的两个示例一样。在这种情况下,sapply
将结果简化为矩阵,从而允许我们应用unique.default
。如果输入列表的组件具有不同数量的唯一值,则双重unique解决方案将失败。
system.time(replicate(10, unique(unlist(DF,FALSE,FALSE))))
。它更快。 - Marekunique(unlist(DF, use.names = TRUE))
即可获得实质性的加速。我知道数据框中的名称是减速的源头,但我没有想到这会成为这里的问题。就我所见,由于“DF”和“x”仅具有单个级别的组件,因此没有任何递归发生。你应该将它作为答案发布,因为它直接使用了正确的工具。 - Gavin Simpsonunique(unlist(DF, use.names = FALSE))
吗?如果你喜欢的话,请在你的回答中包含它 ;) - Marek