从 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 question 的 data.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
需要更大。)
- nc。
table
也随列线性扩展,而其他两个更好。
再次,融化
# 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 的 melt
和 which.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)
对的数量不太大。
我有一个 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 question 的 data.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
需要更大。) - nc。
table
也随列线性扩展,而其他两个更好。
再次,融化
# 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 的 melt
和 which.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)
对的数量不太大。