开发者

Melting a cast data frame gives incorrect output

开发者 https://www.devze.com 2022-12-21 15:40 出处:网络
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开发者_运

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:

  1. Wrap your df.cast in as.data.frame before "melting" again.
  2. 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 looking data.frame I've ever seen! It actually looks like there are two single variable data.frames 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.

0

精彩评论

暂无评论...
验证码 换一张
取 消