Как преобразовать матрицу в список столбцов-векторов в 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)
)
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.callx <- 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