从 R table 的多列中选择频繁值

Selecting frequent values from multiple columns from R table

我有一个 data.table res 有如下数据:

            V1 V2 V3 V4
  1:     Day_1  4  4  4
  2:     Day_2  1  1  2
  3:     Day_3  4  5  4
  4:     Day_4  3  4  4
  5:     Day_5  3  2  3

我需要 select 组合列 V2、V3 和 V4 中出现频率最高的值。也就是说,我需要select结果如下:

Day_1 4
Day_2 1
Day_3 4
Day_4 4
Day_5 3

我不希望有任何关系,因为列数总是奇数。是否可以操纵 data.table 来做到这一点?或者我应该将其修改为其他数据类型?

谢谢-V

我将此作为 this old questiondata.table 版本发布,直到提供更好的东西为止

Mode <- function(x) {
  ux <- unique(x)  
  ux[which.max(tabulate(match(x, ux)))]
}

DT[, .(res = Mode(unlist(.SD))), by = V1]

#       V1 res
# 1: Day_1   4
# 2: Day_2   1
# 3: Day_3   4
# 4: Day_4   4
# 5: Day_5   3

以下是 David 回答的两个变体:

# table
DT[,ans:={
    tab <- table( r = rep(.I,length(.SD)), unlist(.SD) )
    as( colnames(tab)[ max.col(tab) ], class(.SD[[1]]) )
},.SDcols=-1]

# apply Mode
DT[,ans:=apply(.SD,1,Mode),.SDcols=-1]

我想看看这些,因为按行拆分 DT 可能很慢。

速度

逐行比较。从很少的唯一值和行开始...

n  <- 1e4
nv <- 5
nc <- 3

DT <- do.call(data.table,c(
  list(id=1:n),
  replicate(nc,sample(nv,n,replace=TRUE),simplify=FALSE)
))

require(rbenchmark)

benchmark(
  table     = DT[,.({
    tab <- table( r = rep(.I,length(.SD)), unlist(.SD) )
    as( colnames(tab)[ max.col(tab) ], class(.SD[[1]]) )
  }),.SDcols=-1],
  byMode    = DT[,.(Mode(unlist(.SD))), by = id],
  applyMode = DT[,.(apply(.SD,1,Mode)),.SDcols=-1],
  replications=10
)[1:5]
#        test replications elapsed relative user.self
# 3 applyMode           10    1.66    4.611      1.65
# 2    byMode           10    2.03    5.639      2.02
# 1     table           10    0.36    1.000      0.36

分别增加三个参数中的每一个...

nv <- 1e3 # up from 5

#        test replications elapsed relative user.self
# 3 applyMode           10    1.67    1.000      1.67
# 2    byMode           10    2.05    1.228      2.02
# 1     table           10    4.27    2.557      4.15

n  <- 5e4 # up from 1e4

#        test replications elapsed relative user.self
# 3 applyMode           10    8.67    4.492      8.65
# 2    byMode           10   10.21    5.290     10.22
# 1     table           10    1.93    1.000      1.92

nc <- 100 # up from 3

#        test replications elapsed relative user.self
# 3 applyMode           10    2.59    1.000      2.59
# 2    byMode           10    6.71    2.591      6.69
# 1     table           10   11.69    4.514     11.68

讨论。 (我正在比较基准中的 elapsed 列。)

  • nv. 虽然 table 在小情况下胜出,但由于其 tab 对象变得非常大,所以它在唯一值数量方面的扩展性很差.其他两种方式不受影响
  • n。一切都与行数成线性比例。 (我预计 table 在这个维度上也会更糟,但也许 n 需要更大。)
  • nctable 也随列线性扩展,而其他两个更好。

再次,融化

# back to original values for n, nv, nc
benchmark(
  table     = DT[,.({
    tab <- table( r = rep(.I,length(.SD)), unlist(.SD) )
    as( colnames(tab)[ max.col(tab) ], class(.SD[[1]]) )
  }),.SDcols=-1],
  byMode    = DT[,.(Mode(unlist(.SD))), by = id],
  applyMode = DT[,.(apply(.SD,1,Mode)),.SDcols=-1],
  melt      = melt(DT, id.vars = 'id')[, .N, by = .(id, value)][, 
                value[which.max(N)], by = id],
  melto     = melt(DT, id.vars = 'id')[, .N, by = .(id, value)][
                order(N)][,last(value),by=id],
  meltMode  = melt(DT, id.vars = 'id')[,Mode(value),by=id],
  replications=10
)[1:5]
#        test replications elapsed relative user.self
# 3 applyMode           10    2.42    8.643      2.36
# 2    byMode           10    2.84   10.143      2.81
# 4      melt           10    0.28    1.000      0.28
# 6  meltMode           10    1.92    6.857      1.81
# 5     melto           10    0.44    1.571      0.44
# 1     table           10    0.83    2.964      0.81

看起来@eddi 的 meltwhich.max 赢了。

数据.

DT <- 
  data.table(V1=paste("Day",1:5,sep="_"),V2=c(4,1,4,3,3),V3=c(4,1,5,4,2),V4=c(4,2,4,4,3))

转换为长格式,然后就很简单了:

dt <- data.table(id=paste("Day",1:5,sep="_"),V2=c(4,1,4,3,3),V3=c(4,1,5,4,2),V4=c(4,2,4,4,3))

melt(dt, id.vars = 'id')[, .N, by = .(id, value)][, value[which.max(N)], by = id]
#      id V1
#1: Day_1  4
#2: Day_2  1
#3: Day_3  4
#4: Day_4  4
#5: Day_5  3

到目前为止,这比其他选项快得多,只要唯一 (id,value) 对的数量不太大。