2014-10-27 82 views
1

鉴于data.table,我如何找到它包含的唯一键的数量?我的data.table有多少个唯一键?

library(data.table) 
z <- data.table(id=c(1,2,1,3),key="id") 
length(unique(z$id)) 
==> 3 

的问题是,unique是一般二次,但是,由于在data.table键进行排序,应该可以找到线性时间唯一键在data.table数量。

+0

@Arun:哈希表是'O(N)'_worst case_(恒定期望),所以我们得到'O(N^2)'最坏的情况。 – sds 2014-10-27 17:53:10

+0

@sds,如果将所有值都转储到同一个桶中,就会发生这种情况 - 这必定是一个可怕的散列函数! – Arun 2014-10-27 18:04:40

回答

2

也许这样的:

sum(Negate(duplicated)(z$id)) 

Z $ ID仍排序,所以复制可以在它的工作速度快:

bigVec <- sample(1:100000, 30000000, replace=TRUE) 
system.time(sum(Negate(duplicated)(bigVec))) 
    user system elapsed 
    8.161 0.475 8.690 

bigVec <- sort(bigVec) 
system.time(sum(Negate(duplicated)(bigVec))) 
    user system elapsed 
    0.00 2.09 2.10 

但我只是检查和长度(独特的())的作品更快的分类向量以及...

所以也许有某种检查,如果向量进行排序(可以在线性时间完成)。对我来说,这看起来不是二次的:

system.time(length(unique(bigVec))) 
    user system elapsed 
    0.000 0.583 0.664 

bigVec <- sort(sample(1:100000, 20000000, replace=TRUE)) 
system.time(length(unique(bigVec))) 
    user system elapsed 
    0.000 1.290 1.242 

bigVec <- sort(sample(1:100000, 30000000, replace=TRUE)) 
system.time(length(unique(bigVec))) 
    user system elapsed 
    0.000 1.655 1.715 
+0

当'duplicateated'获得'z $ id'时,它已经是一个纯粹的向量,'R'不再知道它是排序的。 – sds 2014-10-27 17:36:20

+1

我跑了一些代码行。对于我来说,长度(unique())在向量排序时似乎并不占用二次方时间。我怀疑在基函数内部会有像is.sorted()这样的检查。 – 2014-10-27 17:54:26

6

我会扩大我的评论作为答案。

base::uniqueunique.default)在矢量上使用散列表,效率很高,平均复杂度为O(1) - 这很可能是一般情况。最坏情况的复杂度是O(n)。但是在每次插入/搜索时发生这种情况的机会应该非常少见 - 如果确实如此,它必定是一个可怕的哈希函数。

在你的问题中,你只有一个关键列,因此基地的独特应该是相当有效的。但是,在多个列中,unique.data.frame效率非常低 - 因为它将所有列都强制转换为字符,然后将它们粘贴在一起,然后调用unique.default

您可以使用:

nrow(unique(z)) 

data.table的unique方法,默认情况下,提供键列其by说法。而且由于我们知道数据已经被排序,我们使用data.table:::uniqlist来取代与O(n)中的唯一行相对应的索引。因此,它在任何关键列上都是有效的。

但是,我们可以在设置密钥时将此信息添加为属性,因为它非常简单。

+0

很好的解释。我不知道'unique.data.frame'将所有列粘贴在一起。但是现在我发现''duplicate''就是它发生的地方 – 2014-10-27 18:13:53

+1

所以,'length(data.table :::uniqlist(z))'是当前最快的方法,对不对?如果您决定实施[FR900](https://github.com/Rdatatable/data)。table/issues/900),这将提供更好的方式来访问隐藏在命名空间的功能。 – 2014-10-27 18:43:52

+0

@ JoshO'Brien,最快的方法是在设置键时检索属性(可以设置)(因为'forderv'已经收集到这个信息)。但之后,是的,这是最快的。 – Arun 2014-10-27 18:57:33