我有一个只有0和1的表。第一列始终只有1。 一旦第一个1出现,行将被零填充。
dt <- data.table(ID = c( "ID1", "ID2", "ID3", "ID4", "ID5"), Q1 = c(1, 1, 1, 1, 1), Q2 = c(1, 1, 0, 1, 1), Q3 = c(0, 1, 0, 1, 1), Q4 = c(0, 0, 0, 1, 1), Q5 = c(0, 0, 0, 0, 0))
我需要对表进行子集化,以便在每行中搜索最后一个1。如果建立了行,请保留该表并将前一个1替换为0。
这是预期的输出:
dt2 <- data.table(ID = c( "ID1", "ID2", "ID3", "ID4", "ID5"), Q1 = c(0, 0, 1, 0, 0), Q2=c(1, 0, 0, 0, 0), Q3=c(0, 1, 0, 0, 0), Q4 = c(0, 0, 0, 1, 1), Q5 = c(0, 0, 0, 0, 0))
任何线索如何解决? 谢谢
答案 0 :(得分:2)
使用矩阵?
wr = which(rowSums(dt[, -1]) > 0)
wc = max.col(dt[wr, -1], ties = "last")
m = matrix(0L, nrow(dt), nc, dimnames = list(dt[[1]], names(dt)[-1]))
m[cbind(wr, wc)] = 1L
Q1 Q2 Q3 Q4 Q5
ID1 0 1 0 0 0
ID2 0 0 1 0 0
ID3 1 0 0 0 0
ID4 0 0 0 1 0
ID5 0 0 0 1 0
这仍然可以强制返回到data.table,例如data.table(m, keep.rownames = "ID")
。
或者,以更紧凑的形式保存数据吗?
DT = copy(dt)
DT[wr, Qmax := names(dt)[-1][max.col(dt[wr, -1], ties = "last")]]
DT[, paste0("Q", 1:5) := NULL]
ID Qmax
1: ID1 Q2
2: ID2 Q3
3: ID3 Q1
4: ID4 Q4
5: ID5 Q4
答案 1 :(得分:1)
我有一个使用tidyverse的解决方案,不确定这是最短的还是最快的。
首先使用rowSums计算行数,然后在前面加上“ Q”以获得正确的名称,Q列将为您提供放置该列的位置。 factor
在这里是为了确保所有Q1至Q5都将出现在结果中(如果您不考虑因素,则Q5将不会出现)。然后传播以转换为宽格式。 ones
列位于value
spread
自变量中
library(tidyverse)
dt2<- dt %>%
mutate(ones=1,
Q = factor(paste0("Q",rowSums(dt[,paste0("Q",1:5)])),levels=paste0("Q",1:5))) %>%
select(ID,Q,ones) %>%
spread(Q,ones,fill=0,drop=FALSE)
# ID Q1 Q2 Q3 Q4 Q5
#1 ID1 0 1 0 0 0
#2 ID2 0 0 1 0 0
#3 ID3 1 0 0 0 0
#4 ID4 0 0 0 1 0
#5 ID5 0 0 0 1 0
答案 2 :(得分:1)
另一种选择,但不会比Frank的矩阵方法快
dt2 <- copy(dt)[, paste0("Q", 1:5) := 0L]
dt[, set(dt2, .I, .BY$col + 1L, 1L), .(col=max.col(dt[, -1L], ties="last"))]