计算变量R上的变量

时间:2015-09-08 12:15:37

标签: r count

Tid <- c(1,1,2,2,2,3,4,4)
Uid <- c(10,10,11,11,12,13,10,14)

Data <- data.frame(Tid,Uid)

我想知道每个Tid上出现了多少不同的Uid。 我的结果看起来应该是这样的。

Tid, freqUid 
1, 1
2, 2
3, 1
4, 2

我试图在它上面使用count但是在一个变量上使用它有一些问题。

4 个答案:

答案 0 :(得分:9)

基础R

as.data.frame(table(unique(Data)$Tid))
#   Var1 Freq
# 1    1    1
# 2    2    2
# 3    3    1
# 4    4    2

或(尽管列名信息量较少)

aggregate(Uid ~ Tid, unique(Data), length)
#   Tid Uid
# 1   1   1
# 2   2   2
# 3   3   1
# 4   4   2

此处的基本想法是仅对Tid/Uid的唯一组合进行操作,然后计算不同的Tid个实例

编辑: 根据@nicolas评论,我们也可以在此处添加tapply作为可能的解决方案

as.data.frame.table(tapply(Data$Uid, Data$Tid, function(x) length(unique(x))))
#   Var1 Freq
# 1    1    1
# 2    2    2
# 3    3    1
# 4    4    2

答案 1 :(得分:4)

我们可以使用n_distinct中的dplyr。我们按照Tid&#39;进行分组,然后获取n_distinct用于&#39; Uid&#39;在summarise内。

library(dplyr)
Data %>% 
   group_by(Tid) %>%
   summarise(freqUid=n_distinct(Uid))
#    Tid freqUid
#   (dbl)   (int)
#1     1       1
#2     2       2
#3     3       1
#4     4       2

或者我们可以使用uniqueN中的data.table。我们转换了&#39; data.frame&#39;到&#39; data.table&#39; (setDT(Data)),按照&t'tid&#39;分组,我们得到了&#39; Uid&#39;的uniqueN

library(data.table)#v1.9.5+
setDT(Data)[, list(freqUid=uniqueN(Uid)), by = Tid]
#  Tid freqUid
#1:   1       1
#2:   2       2
#3:   3       1
#4:   4       2

基准

以下是使用大数据集

的一些基准测试
set.seed(24)
Data <- data.frame(Tid=rep(1:1e4, each=100),
       Uid= sample(10:70, 1e4*100, replace=TRUE))
f1 <- function() as.data.frame.table(with(Data, 
          tapply(Uid, Tid, function(.) length(unique(.)))))
f2 <- function() as.data.frame(table(unique(Data)$Tid))
f3 <- function() aggregate(Uid ~ Tid, unique(Data), length)
f4 <- function() Data %>% 
                    group_by(Tid) %>% 
                    summarise(freqUid=n_distinct(Uid))
f5 <- function() as.data.table(Data)[, list(freqUid=uniqueN(Uid)), by = Tid]

library(microbenchmark)
microbenchmark(f1(), f2(), f3(), f4(), f5(), times=20L, unit='relative')
#Unit: relative
# expr       min        lq      mean    median        uq       max neval cld
#f1()  2.357808  2.506813  2.347543  2.401787  2.138740  2.706053    20 a 
#f2() 10.581284 11.798583 11.456316 11.975014 11.411718 10.664648    20 b
#f3() 28.243538 27.740333 25.630334 25.042240 25.590332 23.426749    20 c
#f4()  1.000000  1.000000  1.000000  1.000000  1.000000  1.000000    20 a
#f5()  1.385114  1.369170  1.396271  1.405275  1.354914  1.473114    20 a 

如果我们移除as.data.framef1中的f2(输出格式会有所不同),请再次运行基准测试。

  f1 <- function() with(Data, tapply(Uid, Tid, function(.) length(unique(.))))
  f2 <- function() table(unique(Data)$Tid)

正如@DavidArenburg所提到的,uniqueNlength(unique(.))相比较慢。所以,在f5

中替换它
 f5 <- function() as.data.table(Data)[, list(freqUid=length(unique(Uid))),
                                    by = Tid]

 microbenchmark(f1(), f2(), f3(), f4(), f5(), times=20L, unit='relative')
 #Unit: relative
 #expr       min        lq      mean    median        uq        max neval  cld
 #f1()  3.466328  3.052508  2.789366  2.968971  3.069631  1.7850643    20  b  
 #f2() 11.539920 13.372543 12.067983 13.266105 13.014644  7.6774925    20   c 
 #f3() 33.491446 30.839725 27.339148 30.888726 29.953344 17.3956850    20    d
 #f4()  1.254533  1.177933  1.083263  1.213019  1.162862  0.6981573    20 a   
 #f5()  1.000000  1.000000  1.000000  1.000000  1.000000  1.0000000    20 a   

答案 2 :(得分:2)

只是投入另一种dplyr风格的方法:

library(dplyr)
distinct(Data) %>% count(Tid)
#Source: local data frame [4 x 2]
#
#  Tid n
#1   1 1
#2   2 2
#3   3 1
#4   4 2

(并不是说这比其他dplyr / data.table解决方案更快。)

回复@David的评论,所有提议的解决方案都得到了基本相同的结果。但当然,我的建议 table(unique(Data)$Tid)完全相同。它更快并返回data.frame(不是table对象)。

答案 3 :(得分:2)

另一种可能性:

library(functional)
by(Uid, Tid, FUN=Compose(unique, length))

或基地R正如@David Arenburg所强调的那样:

by(Uid, Tid, FUN=function(x) length(unique(x)))