为每一行返回最大值的列名称
我有一个员工名册,我需要知道他们最常在哪个部门工作。 将员工ID与部门名称进行制表是微不足道的,但是从频率表中返回部门名称而不是名册数量更为棘手。 下面是一个简单的例子(列名=部门,行名=员工ID)。
DF <- matrix(sample(1:9,9),ncol=3,nrow=3) DF <- as.data.frame.matrix(DF) > DF V1 V2 V3 1 2 7 9 2 8 3 6 3 1 5 4
现在我怎么得到
> DF2 RE 1 V3 2 V1 3 V2
一个select使用您的数据(以备将来参考,使用set.seed()
来举例使用sample
重现):
DF <- data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(9,6,4)) colnames(DF)[apply(DF,1,which.max)] [1] "V3" "V1" "V2"
比使用apply
更快的解决scheme可能是max.col
:
colnames(DF)[max.col(DF,ties.method="first")] #[1] "V3" "V1" "V2"
… ties.method
可以是任何"random"
"first"
或"last"
这当然会导致问题,如果你碰巧有两个列等于最大值。 我不确定你想在这个例子中做什么,因为你将有一个以上的结果一些行。 例如:
DF <- data.frame(V1=c(2,8,1),V2=c(7,3,5),V3=c(7,6,4)) apply(DF,1,function(x) which(x==max(x))) [[1]] V2 V3 2 3 [[2]] V1 1 [[3]] V2 2
如果您对data.table
解决scheme感兴趣,请点击这里。 这是有点棘手,因为你喜欢得到第一个最大的ID。 如果你想要最后的最大值,这会容易得多。 不过,这并不复杂,而且速度很快!
在这里我已经生成了你的尺寸(26746 * 18)的数据。
数据
set.seed(45) DF <- data.frame(matrix(sample(10, 26746*18, TRUE), ncol=18))
data.table
答案:
require(data.table) DT <- data.table(value=unlist(DF, use.names=FALSE), colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF))) setkey(DT, colid, value) t1 <- DT[J(unique(colid), DT[J(unique(colid)), value, mult="last"]), rowid, mult="first"]
标杆:
# data.table solution system.time({ DT <- data.table(value=unlist(DF, use.names=FALSE), colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF))) setkey(DT, colid, value) t1 <- DT[J(unique(colid), DT[J(unique(colid)), value, mult="last"]), rowid, mult="first"] }) # user system elapsed # 0.174 0.029 0.227 # apply solution from @thelatemail system.time(t2 <- colnames(DF)[apply(DF,1,which.max)]) # user system elapsed # 2.322 0.036 2.602 identical(t1, t2) # [1] TRUE
这些维度的数据速度快了11倍,而data.table
相当好。
编辑:如果任何最大ID都可以,那么:
DT <- data.table(value=unlist(DF, use.names=FALSE), colid = 1:nrow(DF), rowid = rep(names(DF), each=nrow(DF))) setkey(DT, colid, value) t1 <- DT[J(unique(colid)), rowid, mult="last"]
基于以上build议,以下data.table
解决scheme对我来说工作得非常快:
set.seed(45) DT <- data.table(matrix(sample(10, 10^7, TRUE), ncol=10)) system.time( DT[, MAX := colnames(.SD)[max.col(.SD, ties.method="first")]] ) user system elapsed 0.10 0.02 0.21 DT V1 V2 V3 V4 V5 V6 V7 V8 V9 V10 MAX 1: 7 4 1 2 3 7 6 6 6 1 V1 2: 4 6 9 10 6 2 7 7 1 3 V4 3: 3 4 9 8 9 9 8 8 6 7 V3 4: 4 8 8 9 7 5 9 2 7 1 V4 5: 4 3 9 10 2 7 9 6 6 9 V4 --- 999996: 4 6 10 5 4 7 3 8 2 8 V3 999997: 8 7 6 6 3 10 2 3 10 1 V6 999998: 2 3 2 7 4 7 5 2 7 3 V4 999999: 8 10 3 2 3 4 5 1 1 4 V2 1000000: 10 4 2 6 6 2 8 4 7 4 V1
而且还带有这样的优点,即通过在.SDcols
提及它们,可以始终指定哪些列.SD
应考虑。
DT[, MAX2 := colnames(.SD)[max.col(.SD, ties.method="first")], .SDcols = c("V9", "V10")]