Questa si è rivelata più veloce di quanto mi aspettassi (anche se stil Non sono veloce come l'approccio ovvio che ha preso @akrun), quindi pubblicherò questo (come David) "solo per conoscenza generale". (. Inoltre, "data.table" tutte le cose) :-)
Crea una data.table
con tre colonne:
- I valori non quotati del vostro singola riga.
- Una variabile di raggruppamento per indicare a quale riga deve essere assegnato il valore nell'output finale.
- Una variabile di raggruppamento per indicare a quale colonna deve essere assegnato il valore nell'output finale.
Una volta che hai, puoi usare dcast.data.table
per ottenere l'output che hai menzionato (più una colonna bonus).
Per il punto numero 2 di cui sopra, si può facilmente definire una funzione come la seguente per rendere il processo di creazione di gruppi facile:
groupMaker <- function(vecLen, perGroup) {
(0:(vecLen-1) %/% perGroup) + 1
}
Quindi possiamo usare come segue:
dcast.data.table(
data.table(value = unlist(df, use.names = FALSE),
row = groupMaker(ncol(df), 3),
col = 1:3),
row ~ col)
# row 1 2 3
# 1: 1 1 2 3
# 2: 2 4 5 6
# 3: 3 7 8 9
# 4: 4 10 11 12
Ora, lei dice che si sta effettivamente occupando di una colonna a riga singola ~ 40K data.frame
(presumo che sia 39.999 colonne poiché è ben divisibile per 3 e non voglio ak le altre risposte).
Tenendo questo a mente, ecco alcuni (inutili) benchmark (inutile perché stiamo parlando di millisecondi qui, davvero).
set.seed(1)
S <- sample(20, 39999, TRUE)
S <- data.frame(t(S))
funAM <- function(indf) {
dcast.data.table(
data.table(value = unlist(indf, use.names = FALSE),
row = groupMaker(ncol(indf), 3),
col = 1:3),
row ~ col)
}
funDA <- function(indf) {
as.data.frame(t(`dim<-`(unlist(indf), c(3, ncol(indf)/3))))
}
funAK <- function(indf) as.data.frame(matrix(indf, ncol=3, byrow=TRUE))
library(microbenchmark)
microbenchmark(funAM(S), funDA(S), funAK(S))
# Unit: milliseconds
# expr min lq mean median uq max neval
# funAM(S) 18.487001 18.813297 22.105766 18.999891 19.455812 50.25876 100
# funDA(S) 37.187177 37.450893 40.393893 37.870683 38.869726 94.20128 100
# funAK(S) 5.018571 5.149758 5.929944 5.271679 5.536449 26.93281 100
Dove questo potrebbe essere utile sarebbe nel caso in cui il numero di colonne desiderate e il numero di colonne di input non sono ben divisibile per l'altro.
Ad esempio, provare i seguenti dati di esempio:
set.seed(1)
S2 <- sample(20, 40000, TRUE)
S2 <- data.frame(t(S))
Con questi dati di esempio:
funAM
darebbe una warning
, ma sarebbe corretto dare le ultime due colonne della ultima riga come NA
.
funAK
fornirebbe un warning
ma (presumibilmente) ricicla correttamente i valori nell'ultima riga.
funDA
darebbe solo un error
.
penso ancora che si dovrebbe solo risolvere il problema alla fonte se :-)
Sembra a me come si dovrebbe risolvere il comando che ha creato il problema! Puoi spiegare come hai finito con un frame di dati super-wide per cominciare? – A5C1D2H2I1M1N2O1R2T1