У меня есть список 50000 строковых векторов, состоящий из различных комбинаций из 6000 уникальных строк.
Цель: я хочу преобразовать их в "относительные частоты" (table(x)/length(x)
) и сохранить их в разреженной матрице. Низкое потребление памяти более важно, чем скорость. В настоящее время память является узким местом. (Хотя исходные данные имеют около ~ 50 мб, а данные в целевом формате ~ 10mb → Transformation кажутся неэффективными...)
Создание данных образца
dims <- c(50000, 6000)
nms <- paste0("A", 1:dims[2])
lengths <- sample(5:30, dims[1], replace = T)
data <- lapply(lengths, sample, x = nms, replace = T)
Возможные попытки:
1) sapply() с упрощением к разреженной матрице?
library(Matrix)
sparseRow <- function(stringVec){
relFreq <- c(table(factor(stringVec, levels = nms)) / length(stringVec))
Matrix(relFreq, 1, dims[2], sparse = TRUE)
}
sparseRows <- sapply(data[1:5], sparseRow)
sparseMat <- do.call(rbind, sparseRows)
Проблема. Мое узкое место, похоже, является sparseRows
рядами, поскольку строки не объединены напрямую с разреженной матрицей. (Если я запускаю код выше по полному образцу, я получаю сообщение об Error: cannot allocate vector of size 194 Kb Error during wrapup: memory exhausted (limit reached?)
- мое оборудование имеет 8 ГБ ОЗУ.)
Очевидно, что для создания списка строк больше потребления памяти, прежде чем объединять их, а не заполнять разреженную матрицу напрямую. → поэтому использование (s/l) применимо не к памяти, дружественной в моем случае?
object.size(sparseRows)
object.size(sparseMat)
2) Грязное обходное решение (?)
Моя цель, похоже, состоит в том, чтобы создать пустую разреженную матрицу и заполнить ее по-разному. Ниже приведен грязный способ сделать это (что работает на моем оборудовании).
indxs <- lapply(data, function(data) sapply(data, function(x) which(x == nms),
USE.NAMES = FALSE))
relFreq <- lapply(indxs, function(idx) table(idx)/length(idx))
mm <- Matrix(0, nrow = dims[1], ncol = dims[2])
for(idx in 1:dims[1]){
mm[idx, as.numeric(names(relFreq[[idx]]))] <- as.numeric(relFreq[[idx]])
}
#sapply(1:dims[1], function(idx) mm[idx,
# as.numeric(names(relFreq[[idx]]))] <<- as.numeric(relFreq[[idx]]))
Я хотел бы спросить, есть ли более элегантный/эффективный способ достичь этого с минимальным объемом оперативной памяти.