【问题标题】:Count variable on a Variable R [duplicate]在变量 R 上计数变量 [重复]
【发布时间】:2015-09-08 12:15:37
【问题描述】:
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,但在不止一个变量上使用它时遇到了一些问题。

【问题讨论】:

  • 下面的答案很棒。特别注意如何处理 NA 值。例如。如果你有类似Tid &lt;- c(1,1,2,2,2,3,4,4); Uid &lt;- c(10,10,11,NA,12,13,10,14); Data &lt;- data.frame(Tid,Uid)

标签: r count


【解决方案1】:

带基数 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

【讨论】:

  • 或者tapply(Data$Uid,Data$Tid,function(x) length(unique(x))),只是为了在base R中添加另一个选项。
  • @nicola 谢谢 :) 它与table(unique(Data)$Tid) 相同。我不确定 OP 是否会对该输出感到满意
  • 是的,您可以应用as.data.frametable 方法:as.data.frame.table(tapply(Data$Uid,Data$Tid,function(x) length(unique(x)))),我们就在那里。该评论只是为了让读者了解tapply函数。
  • 好的,谢谢,我加一下。
【解决方案2】:

我们可以从dplyr 使用n_distinct。我们按“Tid”分组,并在summarise 中获取“Uid”的n_distinct

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

或者我们可以使用来自data.tableuniqueN。我们将“data.frame”转换为“data.table”(setDT(Data)),按“Tid”分组,得到“Uid”的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 

如果我们删除f1f2中的as.data.frame(输出格式会有所不同),然后再次运行基准测试。

  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   

【讨论】:

  • data.table 在哪里? :( 另外,可能从f2 中取出as.data.frame 或添加到f1,不确定是哪个。
  • 我知道,这就是为什么如果我们想与 tapply 进行比较或相应地调整 tapply 时,我建议不使用它运行它
  • @DavidArenburg 您的意思是要将as.data.frame 添加到f1 吗?
  • 或将其从f2 中删除,无论如何。
  • @DavidArenburg 更新了基准。
【解决方案3】:

另一种可能性:

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

R@David Arenburg 下划线:

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

【讨论】:

  • 或者只是 by(Uid, Tid, FUN=function(x) length(unique(x))) :P,但是 +1 以获得最原始的答案
  • Compose 的充分理由是我尝试制作简洁和“会说话”的代码(不一定是资产,因为它是主观的并且我使用包..)
  • 也许然后解释一下Compose 做了什么,因为我不知道。我也想知道这是否应该包装成do.call(rbind...
  • 它只是将几个函数链接成一个函数,就像一个数学运算符!
【解决方案4】:

只是为了引入另一种 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 对象)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-09-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-10
    相关资源
    最近更新 更多