Как превратить список списков в разреженную матрицу в R, не используя lapply? - PullRequest
2 голосов
/ 09 февраля 2011

У меня есть список списков, полученных в результате операции bigsplit () (из пакета biganalytics, части пакетов bigmemory).

Каждый список представляет столбец в матрице, а каждый элемент списка - индексзначение 1 в двоичной матрице.

Каков наилучший способ превратить этот список в разреженную двоичную (0/1) матрицу?Является ли использование lapply () внутри lapply () единственным решением?Как мне сохранить факторы именования списков в качестве имен для столбцов?

Ответы [ 5 ]

5 голосов
/ 09 февраля 2011

Вы можете сделать это без лишних слов, если вам нужна матрица.

Допустим, у вас есть список, построенный следующим образом:

Test <- list(
    col1=list(2,4,7),
    col2=list(3,2,6,8),
    col3=list(1,4,5,3,7)
)

Сначала вы строите матрицу с нулями правильных размеров.Если вы знаете их заранее, это легко.В противном случае вы можете легко получить:

n.cols <- length(Test)
n.ids <- sapply(Test,length)
n.rows <- max(unlist(Test))
out <- matrix(0,nrow=n.rows,ncol=n.cols)

Затем вы используете тот факт, что матрицы заполняются по столбцам, чтобы вычислить индекс каждой ячейки, которая должна стать единым:

> out
     col1 col2 col3
[1,]    0    0    1
[2,]    1    1    0
[3,]    0    1    1
[4,]    1    0    1
[5,]    0    0    1
[6,]    0    1    0
[7,]    1    0    1
[8,]    0    1    0
2 голосов
/ 09 февраля 2011

Вы можете также рассмотреть возможность использования пакета Matrix, который обрабатывает большие разреженные матрицы более эффективным способом, чем базовый R. Вы можете построить разреженную матрицу из 0 и 1, описав, какие строки и столбцы должны быть равны 1.

library(Matrix)
Test <- list(
    col1=list(2,4,7),
    col2=list(3,2,6,8),
    col3=list(1,4,5,3,7)
)
n.ids <- sapply(Test,length)
vals <- unlist(Test)
out <- sparseMatrix(vals, rep(seq_along(n.ids), n.ids))

Результат

> out
8 x 3 sparse Matrix of class "ngCMatrix"

[1,] . . |
[2,] | | .
[3,] . | |
[4,] | . |
[5,] . . |
[6,] . | .
[7,] | . |
[8,] . | .
2 голосов
/ 09 февраля 2011

Используя пример Joris, вот синтаксически простой способ использования sapply/replace. Я подозреваю, что подход Joris быстрее, потому что он заполняет предварительно выделенную матрицу, тогда как мой подход подразумевает cbind связку столбцов и поэтому потребует повторного выделения памяти для столбцов (это правда?).

Test <- list( 
col1=list(2,4,7), 
col2=list(3,2,6,8), 
col3=list(1,4,5,3,7) 
) 

> z <- rep(0, max(unlist(Test)))
> sapply( Test, function(x) replace(z,unlist(x),1))
     col1 col2 col3
[1,]    0    0    1
[2,]    1    1    0
[3,]    0    1    1
[4,]    1    0    1
[5,]    0    0    1
[6,]    0    1    0
[7,]    1    0    1
[8,]    0    1    0
0 голосов
/ 09 февраля 2011

Чтобы построить ответ Джориса, который использовал вектор скалярного индекса для заполнения выходной матрицы, вы также можете использовать вектор индекса матрицы для заполнения выходной матрицы; иногда это может быть немного понятнее, чтобы написать или понять позже.

Test <- list(
    col1=list(2,4,7),
    col2=list(3,2,6,8),
    col3=list(1,4,5,3,7)
)

n.cols <- length(Test)
n.ids <- sapply(Test,length)
vals <- unlist(Test)
n.rows <- max(vals)
idx <- cbind(vals, rep(seq_along(n.ids), n.ids))
out <- matrix(0,nrow=n.rows,ncol=n.cols)
out[idx] <- 1
colnames(out) <- names(Test)

Результат тот же.

0 голосов
/ 09 февраля 2011

Вот некоторые примеры данных, которые, кажется, соответствуют вашему описанию.

a <- as.list(sample(20, 5))
b <- as.list(sample(20, 5))
c <- as.list(sample(20, 5))
abc <- list(a = a, b = b, c = c)

Я не вижу способа сделать это с помощью вложенного lapply(), но есть другой способ.Было бы неплохо устранить unlist(), но, может быть, кто-то еще сможет улучшить это.

sp_to_bin <- function(splist) {
  binlist <- numeric(100)
  binlist[unlist(splist)] <- 1
  return(binlist)
}
bindf <- data.frame(lapply(abc, sp_to_bin))
...