2010-03-03 5 views
1

J'ai rencontré un comportement étrange dans cast/melt du paquet reshape. Si je lance un data.frame, puis essaie de le melt, le melt sort erroné. Désactiver manuellement la classe "df.melt" de la distribution data.frame permet de la faire fondre correctement.La fusion d'une trame de données cast donne une sortie incorrecte

Est-ce que quelqu'un sait si c'est un comportement prévu, et si oui, quel est le cas d'utilisation quand vous le voudriez?

Un petit exemple de code qui montre le comportement:

> df <- data.frame(type=c(1, 1, 2, 2, 3, 3), variable="n", value=c(71, 72, 68, 80, 21, 20)) 

> df 
    type variable value 
1 1  n 71 
2 1  n 72 
3 2  n 68 
4 2  n 80 
5 3  n 21 
6 3  n 20 

> df.cast <- cast(df, type~., sum) 
> names(df.cast)[2] <- "n" 

> df.cast 
    type n 
1 1 143 
2 2 148 
3 3 41 

> class(df.cast) 
[1] "cast_df" "data.frame" 

> melt(df.cast, id="type", measure="n") 
     type value value 
X.all.  1 143 (all) 
X.all..1 2 148 (all) 
X.all..2 3 41 (all) 

> class(df.cast) <- "data.frame" 
> class(df.cast) 
[1] "data.frame" 

> melt(df.cast, id="type", measure="n") 
    type variable value 
1 1  n 143 
2 2  n 148 
3 3  n 41 
+2

Je suis confus. Pourquoi voudriez-vous «fondre» un df qui est déjà en format long? Et votre utilisation de 'cast' n'a pas beaucoup de sens non plus. Habituellement, vous l'utilisez * après * vous utilisez 'fondre'. – Harlan

+1

S'il vous plaît expliquer un peu plus sur ce que vous essayiez de faire et le résultat que vous attendiez. –

Répondre

2

Je sais que c'est une question ANCIENNE, et peu susceptible de susciter beaucoup d'intérêt. Je ne peux pas vraiment comprendre pourquoi vous faites ce que vous démontrez dans votre exemple. Néanmoins, pour résumer la réponse, soit:

  1. Enveloppez votre df.cast dans as.data.frame avant « fondre » à nouveau.
  2. Ditch "remodeler" et mettre à jour à "reshape2". Cela ne s'appliquait pas lorsque vous posiez cette question, car votre question est antérieure d'environ six mois à la version 1 de "reshape2".

est ici une plus longue walktrhough:

D'abord, nous allons charger "remodeler" et "reshape2", effectuez votre "coulée" et Renommez votre variable "n". Évidemment, les objets ajoutés avec "R2" sont ceux de "reshape2", et "R1", de "reshape".

library(reshape) 
library(reshape2) 
df.cast.R2 <- dcast(df, type~., sum) 
df.cast.R1 <- cast(df, type~., sum) 
names(df.cast.R1)[2] <- "n" 
names(df.cast.R2)[2] <- "n" 

Deuxièmement, nous allons avoir juste un coup d'œil à ce que nous avons maintenant:

class(df.cast.R1) 
# [1] "cast_df" "data.frame" 
class(df.cast.R2) 
[1] "data.frame" 
str(df.cast.R1) 
# List of 2 
# $ type: num [1:3] 1 2 3 
# $ n : num [1:3] 143 148 41 
# - attr(*, "row.names")= int [1:3] 1 2 3 
# - attr(*, "idvars")= chr "type" 
# - attr(*, "rdimnames")=List of 2 
# ..$ :'data.frame': 3 obs. of 1 variable: 
# .. ..$ type: num [1:3] 1 2 3 
# ..$ :'data.frame': 1 obs. of 1 variable: 
# .. ..$ value: Factor w/ 1 level "(all)": 1 
str(df.cast.R2) 
# 'data.frame': 3 obs. of 2 variables: 
# $ type: num 1 2 3 
# $ n : num 143 148 41 

Quelques observations sont évidentes:

  • En regardant la sortie de class, vous pouvez deviner que vous n'aurez aucun problème à faire ce que vous essayez de faire si vous utilisez "reshape2"
  • Whoa. Cette sortie de str(df.cast.R1) est la plus étrange data.frame que j'ai jamais vu! En fait, il semble y avoir deux variables uniques data.frame s là-dedans.

Avec ces nouvelles connaissances, et la condition sine qua non que nous ne voulons pas changer le class de votre casted data.frame, nous allons procéder:

# You don't want this 
melt(df.cast.R1, id="type", measure="n") 
#   type value value 
# X.all.  1 143 (all) 
# X.all..1 2 148 (all) 
# X.all..2 3 41 (all) 

# You *do* want this 
melt(as.data.frame(df.cast.R1), id="type", measure="n") 
# type variable value 
# 1 1  n 143 
# 2 2  n 148 
# 3 3  n 41 

# And the class has not bee altered 
class(df.cast.R1) 
# [1] "cast_df" "data.frame" 

# As predicted, this works too. 
melt(df.cast.R2, id="type", measure="n") 
# type variable value 
# 1 1  n 143 
# 2 2  n 148 
# 3 3  n 41 

Si vous travaillez toujours avec cast à partir de "reshape", envisager de mise à niveau vers "reshape2", ou écrire une fonction wrapper commodité autour de melt ... peut-être melt2?

melt2 <- function(data, ...) { 
    ifelse(isTRUE("cast_df" %in% class(data)), 
     data <- as.data.frame(data), 
     data <- data) 
    melt(data, ...) 
} 

Essayez sur df.cast.R1:

melt2(df.cast.R, id="type", measure="n") 
# ype variable value 
# 1 1  n 143 
# 2 2  n 148 
# 3 3  n 41 
+0

+1 pour une réponse bien forgé! Je dois encore passer à reshape2 si ... –

+0

@PaulHiemstra, une raison pour laquelle vous n'avez pas changé? (Demande à un gars qui colle généralement à la base R pour tous ses besoins de remodelage.) – A5C1D2H2I1M1N2O1R2T1

+0

Je n'ai tout simplement pas ressenti le besoin, j'ai principalement utilisé 'fondu 'pour préparer les données pour ggplot2 ou plyr, pas beaucoup plus. –

1

Vous devez faire fondre la trame de données avant vous lancer. Lancer sans fondre en premier donnera lieu à toutes sortes de comportements inattendus, parce que le remodelage doit deviner la structure de vos données.