как преобразовать несколько двоичных файлов в категориальные - PullRequest
1 голос
/ 03 апреля 2020

Я хотел бы преобразовать несколько двоичных столбцов в один столбец с категориальным содержимым на основе имен строк двоичных столбцов. Я пытался использовать код на этом форуме в других вопросах , но так как мой случай отличается тем, что в некоторых строках нет записей, мне не удалось найти эффективное решение. Предложенное dplyr решение медленно работает с моим набором данных. В моем наборе данных более 2 миллионов строк.

Вот данные

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 ]

5 голосов
/ 03 апреля 2020

Другим способом использования max.col может быть получение индекса максимального элемента в каждой строке с указанием ties.method = "first" и получение имен соответствующих столбцов. Затем мы можем заменить имена столбцов пустыми, которые возвращают значение max.col как 1 (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" ""  ""  ""  "" 
5 голосов
/ 03 апреля 2020

Это должно быть быстро (заимствуя подсказку от 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: у моего ноутбука меньше 5 секунд на матрицу 2M 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 

Решения max.col на 1018 * намного быстрее, чем apply, а оптимизация Ronak делает его довольно хорошо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...