Как преобразовать матрицу в список столбцов-векторов в R?



Допустим, вы хотите преобразовать матрицу в список, где каждый элемент списка содержит один столбец. list() или as.list() очевидно, не будет работать, и до сих пор я использую Хак, используя поведение tapply:



x <- matrix(1:10,ncol=2)

tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i)


Я не совсем доволен этим. Кто-нибудь знает более чистый метод, который я пропускаю?



(для создания списка, заполненного строками, код, очевидно, может быть изменен на:



tapply(x,rep(1:nrow(x),ncol(x)),function(i)i)


)

675   10  

10 ответов:

в интересах снятия шкуры с кошки, рассматривайте массив как вектор, как если бы он не имел атрибута dim:

 split(x, rep(1:ncol(x), each = nrow(x)))

ответ Гэвина прост и элегантен. Но если есть много столбцов, гораздо более быстрое решение будет:

lapply(seq_len(ncol(x)), function(i) x[,i])

разница в скорости составляет 6x в примере ниже:

> x <- matrix(1:1e6, 10)
> system.time( as.list(data.frame(x)) )
   user  system elapsed 
   1.24    0.00    1.22 
> system.time( lapply(seq_len(ncol(x)), function(i) x[,i]) )
   user  system elapsed 
    0.2     0.0     0.2 

данные.кадры хранятся в виде списков, я считаю. Поэтому принуждение кажется лучшим:

as.list(as.data.frame(x))
> as.list(as.data.frame(x))
$V1
[1] 1 2 3 4 5

$V2
[1]  6  7  8  9 10

результаты бенчмаркинга интересны. как.данные.фрейм быстрее, чем данные.кадр, либо потому что данные.фрейм должен создать целый новый объект, или потому, что отслеживание имен столбцов является каким-то дорогостоящим (свидетель сравнения c(unname()) vs c ())? Решение lapply, предоставленное @Tommy, быстрее на порядок. То же самое.данные.результаты frame () могут быть несколько улучшены принуждение вручную.

manual.coerce <- function(x) {
  x <- as.data.frame(x)
  class(x) <- "list"
  x
}

library(microbenchmark)
x <- matrix(1:10,ncol=2)

microbenchmark(
  tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i) ,
  as.list(data.frame(x)),
  as.list(as.data.frame(x)),
  lapply(seq_len(ncol(x)), function(i) x[,i]),
  c(unname(as.data.frame(x))),
  c(data.frame(x)),
  manual.coerce(x),
  times=1000
  )

                                                      expr     min      lq
1                                as.list(as.data.frame(x))  176221  183064
2                                   as.list(data.frame(x))  444827  454237
3                                         c(data.frame(x))  434562  443117
4                              c(unname(as.data.frame(x)))  257487  266897
5             lapply(seq_len(ncol(x)), function(i) x[, i])   28231   35929
6                                         manual.coerce(x)  160823  167667
7 tapply(x, rep(1:ncol(x), each = nrow(x)), function(i) i) 1020536 1036790
   median      uq     max
1  186486  190763 2768193
2  460225  471346 2854592
3  449960  460226 2895653
4  271174  277162 2827218
5   36784   37640 1165105
6  171088  176221  457659
7 1052188 1080417 3939286

is.list(manual.coerce(x))
[1] TRUE

преобразование в фрейм данных оттуда в список, кажется, работает:

> as.list(data.frame(x))
$X1
[1] 1 2 3 4 5

$X2
[1]  6  7  8  9 10
> str(as.list(data.frame(x)))
List of 2
 $ X1: int [1:5] 1 2 3 4 5
 $ X2: int [1:5] 6 7 8 9 10

используя plyrможет быть очень полезно для вещей как этот:

library("plyr")

alply(x,2)

$`1`
[1] 1 2 3 4 5

$`2`
[1]  6  7  8  9 10

attr(,"class")
[1] "split" "list" 

Я знаю, что это анафема в R, и у меня действительно нет большой репутации, чтобы поддержать это, но я нахожу цикл for более эффективным. Я использую следующую функцию для преобразования матричного мата в список его столбцов:

mat2list <- function(mat)
{
    list_length <- ncol(mat)
    out_list <- vector("list", list_length)
    for(i in 1:list_length) out_list[[i]] <- mat[,i]
    out_list
}

быстрый тест по сравнению с mdsummer и оригинальным решением:

x <- matrix(1:1e7, ncol=1e6)

system.time(mat2list(x))
   user  system elapsed 
  2.728   0.023   2.720 

system.time(split(x, rep(1:ncol(x), each = nrow(x))))
   user  system elapsed 
  4.812   0.194   4.978 

system.time(tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i))
   user  system elapsed 
 11.471   0.413  11.817 

под некоторые R справочный сайт доступен через nabble.com я нахожу:

c(unname(as.data.frame(x))) 

как допустимое решение и в моем R v2.13.0 установить это выглядит нормально:

> y <- c(unname(as.data.frame(x)))
> y
[[1]]
[1] 1 2 3 4 5

[[2]]
[1]  6  7  8  9 10

ничего не могу сказать о сравнениях производительности или о том, насколько он чист; -)

convertRowsToList {BBmisc}

преобразование строк (столбцов) данных.рамка или матрица для списков.

BBmisc::convertColsToList(x)

ref:http://berndbischl.github.io/BBmisc/man/convertRowsToList.html

вы могли бы использовать apply а то c С do.call

x <- matrix(1:10,ncol=2)
do.call(c, apply(x, 2, list))
#[[1]]
#[1] 1 2 3 4 5
#
#[[2]]
#[1]  6  7  8  9 10

и похоже, что он сохранит имена столбцов при добавлении в матрицу.

colnames(x) <- c("a", "b")
do.call(c, apply(x, 2, list))
#$a
#[1] 1 2 3 4 5
#
#$b
#[1]  6  7  8  9 10

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

mat2list  <- function (mat) lapply(1:2, function (i) mat[, i])
mat2list2 <- function (mat) list(mat[, 1], mat[, 2])


## Microbenchmark results; unit: microseconds
#          expr   min    lq    mean median    uq    max neval
##  mat2list(x) 7.464 7.932 8.77091  8.398 8.864 29.390   100
## mat2list2(x) 1.400 1.867 2.48702  2.333 2.333 27.525   100

Comments

    Ничего не найдено.