web-dev-qa-db-fra.com

le value.var dans dcast peut-il être une liste ou avoir plusieurs variables de valeur?

Dans les fichiers d'aide pour dcast.data.table, une note indique qu'une nouvelle fonctionnalité a été implémentée: "dcast.data.table permet à la colonne value.var d'être de type liste"

Je suppose que cela signifie que l'on peut avoir plusieurs variables de valeur dans une liste, c'est-à-dire dans ce format:

dcast.data.table(dt, x1~x2, value.var=list('var1','var2','var3'))

Mais nous obtenons une erreur: 'value.var' must be a character vector of length 1.

Existe-t-il une telle fonctionnalité, et sinon, quelles seraient les autres alternatives à une ligne?

EDIT: En réponse aux commentaires ci-dessous

Il existe des situations où vous avez plusieurs variables que vous souhaitez traiter comme value.var. Imaginons par exemple que x2 se compose de 3 semaines différentes, et que vous ayez 2 variables de valeur telles que la consommation de sel et de sucre et que vous souhaitiez répartir ces variables sur les différentes semaines. Bien sûr, vous pouvez "fondre" les 2 variables de valeur dans une seule colonne, mais pourquoi faire quelque chose en utilisant deux fonctions, alors que vous pouvez le faire dans une seule fonction comme reshape?

(Remarque: j'ai également remarqué que reshape ne peut pas traiter plusieurs variables comme la variable de temps comme le fait dcast.)

Donc, mon point est que je ne comprends pas pourquoi ces fonctions ne permettent pas la flexibilité d'inclure plusieurs variables dans le value.var ou la time.var tout comme nous autorisons plusieurs variables pour le id.var.

30
AlexR

À partir de la version 1.9.6 de data.table, nous pouvons convertir plusieurs value.var colonnes simultanément (et utilisent également plusieurs fonctions d'agrégation dans fun.aggregate). S'il te plait regarde ?dcast et la vignette Remodelage efficace à l'aide de data.tables pour en savoir plus.

Voici comment nous pourrions utiliser dcast:

dcast(setDT(mydf), x1 ~ x2, value.var=c("salt", "sugar"))
#    x1 salt_1 salt_2 salt_3 sugar_1 sugar_2 sugar_3
# 1:  1      3      4      6       1       2       2
# 2:  2     10      3      9       5       3       6
# 3:  3     10      7      7       4       6       7
37
Arun

Mise à jour

Apparemment, le correctif était beaucoup plus facile ...


Techniquement, votre affirmation selon laquelle "apparemment il n'y a pas une telle fonctionnalité" n'est pas tout à fait correcte. Il existe une telle fonctionnalité dans la fonction recast (qui masque en quelque sorte le processus de fusion et de coulée), mais il semble que Hadley ait oublié de terminer la fonction ou quelque chose: la fonction renvoie un list de les parties pertinentes de votre opération.

Voici un exemple minimal ...

Quelques exemples de données:

set.seed(1)
mydf <- data.frame(x1 = rep(1:3, each = 3),
                   x2 = rep(1:3, 3),
                   salt = sample(10, 9, TRUE),
                   sugar = sample(7, 9, TRUE))

mydf
#   x1 x2 salt sugar
# 1  1  1    3     1
# 2  1  2    4     2
# 3  1  3    6     2
# 4  2  1   10     5
# 5  2  2    3     3
# 6  2  3    9     6
# 7  3  1   10     4
# 8  3  2    7     6
# 9  3  3    7     7

L'effet que vous semblez essayer d'obtenir:

reshape(mydf, idvar='x1', timevar='x2', direction='wide')
#   x1 salt.1 sugar.1 salt.2 sugar.2 salt.3 sugar.3
# 1  1      3       1      4       2      6       2
# 4  2     10       5      3       3      9       6
# 7  3     10       4      7       6      7       7

recast en action. (Notez que les valeurs sont toutes ce que nous attendons dans les dimensions que nous attendons.)

library(reshape2)
out <- recast(mydf, x1 ~ x2 + variable, measure.var = c("salt", "sugar"))
### recast(mydf, x1 ~ x2 + variable, id.var = c("x1", "x2"))
out
# $data
#      [,1] [,2] [,3] [,4] [,5] [,6]
# [1,]    3    1    4    2    6    2
# [2,]   10    5    3    3    9    6
# [3,]   10    4    7    6    7    7
# 
# $labels
# $labels[[1]]
#   x1
# 1  1
# 2  2
# 3  3
# 
# $labels[[2]]
#   x2 variable
# 1  1     salt
# 2  1    sugar
# 3  2     salt
# 4  2    sugar
# 5  3     salt
# 6  3    sugar

Honnêtement, je ne sais pas si c'était une fonction incomplète, ou si c'est une fonction d'aide à une autre fonction.

Toutes les informations sont là pour pouvoir recomposer les données, ce qui facilite l'écriture d'une fonction comme celle-ci:

recast2 <- function(...) {
  inList <- recast(...)
  setNames(cbind(inList[[2]][[1]], inList[[1]]),
           c(names(inList[[2]][[1]]), 
             do.call(paste, c(rev(inList[[2]][[2]]), sep = "_"))))
}
recast2(mydf, x1 ~ x2 + variable, measure.var = c("salt", "sugar"))
#   x1 salt_1 sugar_1 salt_2 sugar_2 salt_3 sugar_3
# 1  1      3       1      4       2      6       2
# 2  2     10       5      3       3      9       6
# 3  3     10       4      7       6      7       7

Encore une fois, un avantage possible avec le recast2 L'approche est la capacité d'agréger et de remodeler dans la même étape.

10

Utilisation d'un exemple de trame de données mydf de réponse d'A5C1D2H2I1M1N2O1R2T1 .

Modifier décembre 2016 à l'aide de tidyr

Reshape2 a été remplacé par le paquet tidyr .

library(tidyr)
mydf  %>% 
    gather(variable, value, -x1, -x2)  %>% 
    unite(x2_variable, x2, variable)  %>% 
    spread(x2_variable, value)

#   x1 1_salt 1_sugar 2_salt 2_sugar 3_salt 3_sugar
# 1  1      3       1      4       2      6       2
# 2  2     10       5      3       3      9       6
# 3  3     10       4      7       6      7       7

Réponse originale basée sur reshape2

@AlexR a ajouté à sa question:

Bien sûr, vous pouvez "fondre" les 2 variables de valeur dans une seule colonne,

Pour ceux qui viennent ici à la recherche d'une réponse basée sur reshape2 , voici comment faire fondre les données et ensuite utiliser dcast basé sur la "variable". .

dt2 <- melt(mydf, id = c("x1", "x2")) 

La colonne variable contiendra désormais "var1", "var2", "var3". Vous pouvez obtenir l'effet souhaité avec

dt3 <- dcast(dt2, x1 ~ x2 + variable, value.var="value")
dt3
#   x1 1_salt 1_sugar 2_salt 2_sugar 3_salt 3_sugar
# 1  1      3       1      4       2      6       2
# 2  2     10       5      3       3      9       6
# 3  3     10       4      7       6      7       7

value.var est facultatif dans cet appel de fonction car dcast le devinera automatiquement.

8
Paul Rougieux