Angenommen, Sie möchten eine Matrix in eine Liste konvertieren, in der jedes Element der Liste eine Spalte enthält. list()
oder as.list()
offensichtlich nicht funktionieren, und bis jetzt benutze ich einen Hack mit dem Verhalten von tapply
:
x <- matrix(1:10,ncol=2)
tapply(x,rep(1:ncol(x),each=nrow(x)),function(i)i)
Ich bin damit nicht ganz zufrieden. Kennt jemand eine sauberere Methode, die ich übersehen habe?
(Um eine Liste mit den Zeilen zu erstellen, kann der Code natürlich geändert werden in:
tapply(x,rep(1:nrow(x),ncol(x)),function(i)i)
)
Antworten:
Behandeln Sie das Array im Interesse des Enthäutens der Katze als Vektor, als hätte es kein dim-Attribut:
split(x, rep(1:ncol(x), each = nrow(x)))
quelle
tapply
tun ist. Aber es ist einfacher :). Wahrscheinlich wird eine langsamere, aber gut aussehende Lösung seinsplit(x, col(x))
(split(x, row(x))
bzw.).split(x, c(col(x)))
. Aber es sieht schlimmer aus.x
Spaltennamen die Namensplit(x, col(x, as.factor = TRUE))
beibehalten werden.Gavins Antwort ist einfach und elegant. Wenn es jedoch viele Spalten gibt, wäre eine viel schnellere Lösung:
lapply(seq_len(ncol(x)), function(i) x[,i])
Der Geschwindigkeitsunterschied beträgt im folgenden Beispiel 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
quelle
Ich glaube, data.frames werden als Listen gespeichert. Daher scheint Zwang am besten:
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
Benchmarking-Ergebnisse sind interessant. as.data.frame ist schneller als data.frame, entweder weil data.frame ein ganz neues Objekt erstellen muss oder weil das Verfolgen der Spaltennamen irgendwie kostspielig ist (Zeuge des Vergleichs von c (unname ()) gegen c () )? Die von @Tommy bereitgestellte Lösung ist um eine Größenordnung schneller. Die Ergebnisse von as.data.frame () können durch manuelles Erzwingen etwas verbessert werden.
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
quelle
as.data.frame()
verliert er die Namen des Datenrahmens ,data.frame()
ist also etwas schöner.manual.coerce(x)
könnte seinunclass(as.data.frame(x))
.Das Konvertieren in einen Datenrahmen von dort in eine Liste scheint zu funktionieren:
> 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
quelle
Die Verwendung
plyr
kann für solche Dinge sehr nützlich sein:library("plyr") alply(x,2) $`1` [1] 1 2 3 4 5 $`2` [1] 6 7 8 9 10 attr(,"class") [1] "split" "list"
quelle
Ich weiß, dass dies ein Anathema in R ist, und ich habe nicht wirklich den Ruf, dies zu belegen, aber ich finde, dass eine for-Schleife effizienter ist. Ich verwende die folgende Funktion, um die Matrixmatte in eine Liste ihrer Spalten zu konvertieren:
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 }
Schneller Benchmark im Vergleich zu mdsummer's und der ursprünglichen Lösung:
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
quelle
system.time( lapply(seq_len(ncol(x)), function(i) x[,i]) ) user: 1.668 system: 0.016 elapsed: 1.693
vec2 = castMatrixToSequenceOfLists(vecs);
Die neue Funktion
asplit()
wird in Version 3.6 auf Basis R kommen. Bis dahin und in ähnlicher Weise wie die Antwort von @mdsumner können wir dies auch tungemäß den Dokumenten von
asplit()
. Wie bereits gezeigt, sind allesplit()
basierten Lösungen viel langsamer als die von @ Tommylapply/`[`
. Dies gilt auch für das Neueasplit()
, zumindest in seiner jetzigen Form.split_1 <- function(x) asplit(x, 2L) split_2 <- function(x) split(x, rep(seq_len(ncol(x)), each = nrow(x))) split_3 <- function(x) split(x, col(x)) split_4 <- function(x) split(x, slice.index(x, 2L)) split_5 <- function(x) lapply(seq_len(ncol(x)), function(i) x[, i]) dat <- matrix(rnorm(n = 1e6), ncol = 100) #> Unit: milliseconds #> expr min lq mean median uq max neval #> split_1(dat) 16.250842 17.271092 20.26428 18.18286 20.185513 55.851237 100 #> split_2(dat) 52.975819 54.600901 60.94911 56.05520 60.249629 105.791117 100 #> split_3(dat) 32.793112 33.665121 40.98491 34.97580 39.409883 74.406772 100 #> split_4(dat) 37.998140 39.669480 46.85295 40.82559 45.342010 80.830705 100 #> split_5(dat) 2.622944 2.841834 3.47998 2.88914 4.422262 8.286883 100 dat <- matrix(rnorm(n = 1e6), ncol = 1e5) #> Unit: milliseconds #> expr min lq mean median uq max neval #> split_1(dat) 204.69803 231.3023 261.6907 246.4927 289.5218 413.5386 100 #> split_2(dat) 229.38132 235.3153 253.3027 242.0433 259.2280 339.0016 100 #> split_3(dat) 208.29162 216.5506 234.2354 221.7152 235.3539 342.5918 100 #> split_4(dat) 214.43064 221.9247 240.7921 231.0895 246.2457 323.3709 100 #> split_5(dat) 89.83764 105.8272 127.1187 114.3563 143.8771 209.0670 100
quelle
Verwenden Sie
asplit
diese Option , um eine Matrix in eine Liste von Vektoren zu konvertierenasplit(x, 1) # split into list of row vectors asplit(x, 2) # split into list of column vectors
quelle
array_tree()
Daspurrr
Paket von tidyverse enthält eine Funktion , die dies mit minimalem Aufwand erledigt:x <- matrix(1:10,ncol=2) xlist <- purrr::array_tree(x, margin=2) xlist #> [[1]] #> [1] 1 2 3 4 5 #> #> [[2]] #> [1] 6 7 8 9 10
Verwenden Sie
margin=1
diese Option, um stattdessen nach Zeilen aufzulisten. Funktioniert für n-dimensionale Arrays. Standardmäßig werden Namen beibehalten:x <- matrix(1:10,ncol=2) colnames(x) <- letters[1:2] xlist <- purrr::array_tree(x, margin=2) xlist #> $a #> [1] 1 2 3 4 5 #> #> $b #> [1] 6 7 8 9 10
(Dies ist eine fast wörtliche Kopie meiner Antwort auf eine ähnliche Frage hier )
quelle
Unter Some R Help Site, auf die über nabble.com zugegriffen werden kann, finde ich:
c(unname(as.data.frame(x)))
Als gültige Lösung und in meiner R v2.13.0-Installation sieht dies in Ordnung aus:
> y <- c(unname(as.data.frame(x))) > y [[1]] [1] 1 2 3 4 5 [[2]] [1] 6 7 8 9 10
Ich kann nichts über Leistungsvergleiche sagen oder wie sauber es ist ;-)
quelle
c(as.data.frame(x))
erzeugt identisches Verhalten wieas.list(as.data.frame(x)
Sie könnten verwenden
apply
und dannc
mitdo.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
Und es sieht so aus, als würden die Spaltennamen beibehalten, wenn sie der Matrix hinzugefügt werden.
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
quelle
unlist(apply(x, 2, list), recursive = FALSE)
y <- vector("list", ncol(x))
und dann etwas in der Art vony[1:2] <- x[,1:2]
, obwohl es nicht genau so funktioniert.convertRowsToList {BBmisc}
Konvertieren Sie Zeilen (Spalten) von data.frame oder Matrix in Listen.
ref: http://berndbischl.github.io/BBmisc/man/convertRowsToList.html
quelle
In dem trivialen Fall, in dem die Anzahl der Spalten klein und konstant ist, habe ich festgestellt, dass die schnellste Option darin besteht, die Konvertierung einfach hart zu codieren:
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
quelle