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

S F*_*ont 1 r vector dplyr

我想根据二进制列的行名将多个二进制列转换为具有分类内容的一列。我曾尝试在其他问题中使用此论坛中的代码,但由于我的情况不同,有些行没有条目,我没有设法找到有效的解决方案。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
Run Code Online (Sandbox Code Playgroud)

看起来像这样

      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
Run Code Online (Sandbox Code Playgroud)

我想得到

      colname 
 [1,] "" 
 [2,] "" 
 [3,] "b"
 [4,] "h" 
 [5,] "h" 
 [6,] "a" 
 [7,] "d" 
 [8,] "" 
 [9,] "" 
[10,] "" 
Run Code Online (Sandbox Code Playgroud)

Gre*_*gor 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" ""  ""  ""  "" 
Run Code Online (Sandbox Code Playgroud)

通常,基质是比数据帧更快。dplyr与全矩阵操作相比,将矩阵转换为要使用的数据帧会很慢。

这是另一种可能性:

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

max.col解决方案是非常快的,尤其是Ronak的,以我的笔记本电脑不到一个2M5秒X 325矩阵:

## 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 
Run Code Online (Sandbox Code Playgroud)

max.col解决方案是的速度比apply,和Ronak的优化使其相当不错。


Ron*_*hah 5

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

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