【发布时间】:2011-04-22 05:26:10
【问题描述】:
假设你有一个值列表
x <- list(a=c(1,2,3), b = c(2,3,4), c=c(4,5,6))
我想从所有组合的列表元素中找到唯一值。到目前为止,下面的代码就成功了
unique(unlist(x))
有人知道更有效的方法吗?我有一个包含很多价值的大量清单,如果能加快速度,我将不胜感激。
【问题讨论】:
假设你有一个值列表
x <- list(a=c(1,2,3), b = c(2,3,4), c=c(4,5,6))
我想从所有组合的列表元素中找到唯一值。到目前为止,下面的代码就成功了
unique(unlist(x))
有人知道更有效的方法吗?我有一个包含很多价值的大量清单,如果能加快速度,我将不胜感激。
【问题讨论】:
Marek 建议的这个解决方案是对原始 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,因为unique 有一个matrix 方法可以保持一个边距固定;这很好,因为矩阵可以被视为向量。
Marek 在此答案的 cmets 中指出,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() 到单个组件然后 unique() 那些较小的唯一值集要快得多,但这种加速纯粹是由于 names on列表DF。如果我们告诉unlist 不使用names,则对于这个问题,Marek 的解决方案比双倍unique 略快。由于 Marek 的解决方案正确使用了正确的工具,并且比变通方案更快,因此它是首选解决方案。
双重unique 方法的最大问题是它只会工作如果,如这里的两个示例,输入列表的每个组件(DF 或x)具有相同数量的唯一值。在这种情况下,sapply 将结果简化为允许我们应用unique.default 的矩阵。如果输入列表的组件具有不同数量的唯一值,则双重唯一解决方案将失败。
【讨论】:
system.time(replicate(10, unique(unlist(DF,FALSE,FALSE))))。它更快。
unique(unlist(DF, use.names = TRUE)) 即可获得大幅提速。我知道数据帧上的名称会导致速度变慢,但我没有想到这会成为问题。据我所知,没有任何递归发生,因为DF 和x 只有一个级别的组件。您应该将其发布为答案,因为它直接使用正确的工具。
unique(unlist(DF, use.names = FALSE))?如果您喜欢,请将其包含在您的答案中;)
unique(unlist(DF, use.names = FALSE))。将以适当的归属将您的改进添加到我的答案中。