如何将多个二进制转换为分类

时间:2020-04-03 00:45:44

标签: r vector dplyr

我想根据二进制列的行名将多个二进制列转换为具有分类内容的一列。我试图在其他questions的论坛中使用该代码,但是由于我的情况有所不同,因为有些行没有条目,所以我没有设法找到有效的解决方案。提出的dplyr解决方案在我的数据集上很慢。我的数据集有2多个Mio行。

这里是数据

m <- matrix(0,10,10)
colnames(m) <- c("a","b","c","d","e","f","g","h","i","j")
m[3,2] <- 1
m[4,8] <- 1
m[5,8] <- 1
m[6,1] <- 1

看起来像这样

      a b c d e f g h i j
 [1,] 0 0 0 0 0 0 0 0 0 0
 [2,] 0 0 0 0 0 0 0 0 0 0
 [3,] 0 1 0 0 0 0 0 0 0 0
 [4,] 0 0 0 0 0 0 0 1 0 0
 [5,] 0 0 0 0 0 0 0 1 0 0
 [6,] 1 0 0 0 0 0 0 0 0 0
 [7,] 0 0 0 1 0 0 0 0 0 0
 [8,] 0 0 0 0 0 0 0 0 0 0
 [9,] 0 0 0 0 0 0 0 0 0 0
[10,] 0 0 0 0 0 0 0 0 0 0

我想得到

      colname 
 [1,] "" 
 [2,] "" 
 [3,] "b"
 [4,] "h" 
 [5,] "h" 
 [6,] "a" 
 [7,] "d" 
 [8,] "" 
 [9,] "" 
[10,] "" 

2 个答案:

答案 0 :(得分:5)

这应该很快(从Ronak借用提示并使用ties.method = "first"

mc = max.col(m, ties.method = "first")
result = ifelse(m[cbind(1:nrow(m), mc)] == 0, "", colnames(m)[mc])
result
# [1] ""  ""  "b" "h" "h" "a" ""  ""  ""  "" 

通常,矩阵比数据帧快很多。与所有矩阵操作相比,将矩阵转换为数据帧以使用dplyr的速度会很慢。

这是另一种可能性:

nm = colnames(m)
apply(m, 1, function(x) if (any(x == 1)) nm[which.max(x)] else "")

max.col解决方案非常快,尤其是Ronak的解决方案,它使我的笔记本电脑在2M x 325矩阵上的耗时不到5秒:

## Generate data
nm = combn(letters, 2, FUN = paste, collapse = "")
nr = 2e6
nc = length(nm)

m = matrix(0, nrow = nr, ncol = nc)
n_ones = 1.5e6
ones = cbind(sample(1:nr, size = n_ones), sample(1:nc, size = n_ones, replace = TRUE))
m[ones] = 1

system.time(
  {r1 = apply(m, 1, function(x) if (any(x == 1)) nm[which.max(x)] else "")}
)
#  user  system elapsed 
# 13.94    3.87   19.50 

system.time({
  mc = max.col(m, ties.method = "first")
  r2 = ifelse(m[cbind(1:nrow(m), mc)] == 0, "", nm[mc])
})
# user  system elapsed 
# 3.56    0.01    3.72 

# Ronak's solution
system.time({
  cols <- max.col(m, ties.method = "first")
  vec <- colnames(m)[cols]
  vec[cols == 1 & m[, 1] != 1] <- ''
})
# user  system elapsed 
# 3.16    0.00    3.31 

max.col解决方案比apply快很多,而Ronak的优化使其变得非常好。

答案 1 :(得分:5)

使用max.col的另一种方法可能是获取指定ties.method = "first"的每一行中max元素的索引并获取相应的列名。然后,我们可以将列名称替换为空白,以将max.col的值返回为1(第一列),但在m的第一列中没有1。

cols <- max.col(m, ties.method = "first")
vec <- colnames(m)[cols]
vec[cols == 1 & m[, 1] != 1] <- ''
#[1] ""  ""  "b" "h" "h" "a" ""  ""  ""  ""