web-dev-qa-db-fra.com

meilleure façon de transposer data.table

J'ai souvent besoin de transposer un data.table, Chaque fois qu'il faut plusieurs lignes de code et je me demande s'il y a une meilleure solution que la mienne.

si nous prenons un échantillon de table

library(data.table)
mydata <- data.table(col0=c("row1","row2","row3"),
                     col1=c(11,21,31),
                     col2=c(12,22,32),
                     col3=c(13,23,33))

mydata
# col0 col1 col2 col3
# row1   11   12   13
# row2   21   22   23
# row3   31   32   33

et juste le transposer avec t(), il sera transposé à la matrice avec conversion en type character, tandis que l'application de data.table à une telle matrice perdra row.names :

t(mydata)
# [,1]   [,2]   [,3]  
# col0 "row1" "row2" "row3"
# col1 "11"   "21"   "31"  
# col2 "12"   "22"   "32"  
# col3 "13"   "23"   "33"  

data.table(t(mydata))
#   V1   V2   V3
# row1 row2 row3
#   11   21   31
#   12   22   32
#   13   23   33

j'ai donc dû écrire une fonction pour cela:

tdt <- function(inpdt){
  transposed <- t(inpdt[,-1,with=F]);
  colnames(transposed) <- inpdt[[1]];
  transposed <- data.table(transposed, keep.rownames=T);
  setnames(transposed, 1, names(inpdt)[1]);
  return(transposed);
}

 tdt(mydata)
# col0 row1 row2 row3
# col1   11   21   31
# col2   12   22   32
# col3   13   23   33

y a-t-il quelque chose que je pourrais optimiser ici ou le faire de manière "plus agréable"?

32
Vasily A

Pourquoi pas simplement melt et dcast le data.table?

require(data.table)

dcast(melt(mydata, id.vars = "col0"), variable ~ col0)
#    variable row1 row2 row3
# 1:     col1   11   21   31
# 2:     col2   12   22   32
# 3:     col3   13   23   33
37
A5C1D2H2I1M1N2O1R2T1

Voici une solution alternative qui utilise uniquement data.table et c'est plus proche de l'idée originale d'utiliser t pour transposer.

mydata[, data.table(t(.SD), keep.rownames=TRUE), .SDcols=-"col0"]
##      rn V1 V2 V3
## 1: col1 11 21 31
## 2: col2 12 22 32
## 3: col3 13 23 33

Si la conservation des noms de domaine est importante, setnames peut être utilisé. Certes, cela devient un peu maladroit et la solution de refonte est probablement préférable.

setnames(mydata[, data.table(t(.SD), keep.rownames=TRUE), .SDcols=-"col0"], 
         mydata[, c('rn', col0)])[]
##      rn row1 row2 row3
## 1: col1   11   21   31
## 2: col2   12   22   32
## 3: col3   13   23   33
18
shadow

Les documents actuels montrent une méthode transpose intégrée. Je ne sais pas quand il a été ajouté, mais apparemment c'était nécessaire!

13
abalter
df <- as.data.frame(t(mydata))

est ce que j'ai essayé et df est un data.frame et les noms de colonne sur mydata sont maintenant des noms de ligne sur df

1
Japa19

Voici une solution qui utilise un wrapper pour ranger la sortie de la fonction data.table transpose.

Avec des ensembles de données vraiment volumineux, cela semble être plus efficace que l'approche dcast/melt (je l'ai testé sur un ensemble de données de 8000 lignes x 29000 colonnes, la fonction ci-dessous fonctionne en environ 3 minutes mais dcast/melt s'est écrasé R):

# Function to clean up output of data.table transpose:

transposedt <- function(dt, varlabel) {
  require(data.table)
  dtrows = names(dt)
  dtcols = as.list(c(dt[,1]))
  dtt = transpose(dt)
  dtt[, eval(varlabel) := dtrows]
  setnames(dtt, old = names(dtt), new = c(dtcols[[1]], eval(varlabel)))
  dtt = dtt[-1,]
  setcolorder(dtt, c(eval(varlabel), names(dtt)[1:(ncol(dtt) - 1)]))
  return(dtt)
}

# Some dummy data 
mydt <- data.table(col0 = c(paste0("row", seq_along(1:100))), 
                   col01 = c(sample(seq_along(1:100), 100)),
                   col02 = c(sample(seq_along(1:100), 100)),
                   col03 = c(sample(seq_along(1:100), 100)),
                   col04 = c(sample(seq_along(1:100), 100)),
                   col05 = c(sample(seq_along(1:100), 100)),
                   col06 = c(sample(seq_along(1:100), 100)),
                   col07 = c(sample(seq_along(1:100), 100)),
                   col08 = c(sample(seq_along(1:100), 100)),
                   col09 = c(sample(seq_along(1:100), 100)),
                   col10 = c(sample(seq_along(1:100), 100)))


# Apply the function:
mydtt <- transposedt(mydt, "myvariables")

# View the results:
> mydtt[,1:10]
    myvariables row1 row2 row3 row4 row5 row6 row7 row8 row9
 1:       col01   58   53   14   96   51   30   26   15   68
 2:       col02    6   72   46   62   69    9   63   32   78
 3:       col03   21   36   94   41   54   74   82   64   15
 4:       col04   68   41   66   30   31   78   51   67   26
 5:       col05   49   30   52   78   73   71    5   66   44
 6:       col06   89   35   79   67    6   88   62   97   73
 7:       col07   66   15   27   29   58   40   35   82   57
 8:       col08   55   47   83   30   23   65   48   56   87
 9:       col09   41   10   21   33   55   81   94   25   34
10:       col10   35   17   41   44   21   66   69   61   46

Ce qui est également utile, c'est que les colonnes (ex lignes) apparaissent dans leur ordre d'origine et vous pouvez nommer la colonne des variables quelque chose de significatif.

1
Amy M