我有一个{0,1}的数据框,表明产品是小型,中型还是大型。
dat <- data.frame(Sm = c(1,0,0), Med = c(0,1,0), Lg = c(0,0,1))
Sm Med Lg
1 1 0 0
2 0 1 0
3 0 0 1
我希望将1分配给0到达给定行中的1。例如,在第2行中,产品是&#34; Med&#34;,因此我希望在&#34; Sm&#34;中分配1到0。列。
分配大小是一个考虑因素,所以我正在寻找一种不使用for循环的矢量化方法。最终解决方案应输出以下内容:
Sm Med Lg
1 1 0 0
2 1 1 0
3 1 1 1
我已经尝试了下面代码的几种变体,但我能得到的最接近的是一个参差不齐的数组,它在丢弃具有合法0的元素时正确地分配了所有的1。
apply(dat, 1, function(x) {
x[1:which.max(x)] <- 1
})
[1] 1 1 1
在下面,它接近但没有所需的尾随0
apply(dat, 1, function(x) {
temp <- x[1:which.max(x)]
unlist(lapply(temp, function(y) {
y <- 1
}))
})
[[1]]
Sm
1
[[2]]
Sm Med
1 1
[[3]]
Sm Med Lg
1 1 1
答案 0 :(得分:4)
首先,转换为矩阵并使用max.col
获取每行1
的索引:
mat <- as.matrix(dat)
mc <- max.col(mat)
逻辑构造覆盖矩阵:
mat = +(col(mat) <= mc)
或构建矩阵位置索引以更改和更改&#39; em:
逻辑索引
mat[col(mat) < mc] <- 1L
# or
mat[which(col(mat) < mc)] <- 1L
矩阵索引
idx <- do.call( rbind, lapply( seq_along(mc), function(i)
if (i==1L) NULL
else cbind(i,seq_len(mc[i]-1))
))
mat[idx] <- 1L
矢量索引
nr <- nrow(mat)
idx <- unlist( lapply( seq_along(mc), function(i)
if (mc[i]==1L) NULL
else seq(from = i, by = nr, length.out = mc[i]-1L)
))
mat[idx] <- 1L
可以在help("[<-")
找到所有三种索引方法的帮助。
答案 1 :(得分:1)
这将做你想要的。
dat[which(dat$Med==1),]$Sm = 1
dat[which(dat$Lg==1),]$Med = 1
dat[which(dat$Lg==1),]$Sm = 1