I've encountered a strange behaviour in cast
/melt
from the reshape
package. If I cast a data.frame
, and then try to melt
it, the melt
comes out wrong. Manually unsetting the "df.melt" clas开发者_运维百科s from the cast data.frame
lets it be melted properly.
Does anyone know if this is intended behaviour, and if so, what is the use case when you'd want it?
A small code example which shows the behaviour:
> 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
I know this is an OLD question, and not likely to generate a lot of interest. I also can't quite figure out why you're doing what you demonstrate in your example. Nevertheless, to summarize the answer, either:
- Wrap your
df.cast
inas.data.frame
before "melting" again. - Ditch "reshape" and update to "reshape2". That wasn't applicable when you posted this question, since your question predates version 1 of "reshape2" by about half a year.
Here's a lengthier walktrhough:
First, we'll load "reshape" and "reshape2", perform your "casting", and rename your "n" variable. Obviously, objects appended with "R2" are those from "reshape2", and "R1", from "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"
Second, let's just have a quick look at what we've got now:
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
A few observations are obvious:
- By looking at the output of
class
, you can guess that you won't have any problems doing what you're trying to do if you're using "reshape2" - Whoa. That output of
str(df.cast.R1)
is the strangest lookingdata.frame
I've ever seen! It actually looks like there are two single variabledata.frame
s in there.
With this new knowledge, and with the prerequisite that we do not want to change the class
of your casted data.frame
, let's proceed:
# 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
If you're still working with cast
from "reshape", consider upgrading to "reshape2", or write a convenience wrapper function around melt
... perhaps melt2
?
melt2 <- function(data, ...) {
ifelse(isTRUE("cast_df" %in% class(data)),
data <- as.data.frame(data),
data <- data)
melt(data, ...)
}
Try it out on 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
You need to melt the data frame before you cast it. Casting without melting first will yield all kinds of unexpected behavior, because reshape has to guess the structure of your data.
精彩评论