子集表通过替换一些行值

时间:2019-06-28 14:43:35

标签: r data.table

我有一个只有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))

任何线索如何解决? 谢谢

3 个答案:

答案 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"))]