diff --git a/R/fmelt.R b/R/fmelt.R index ba61e2b04..4c034641d 100644 --- a/R/fmelt.R +++ b/R/fmelt.R @@ -1,13 +1,15 @@ -melt.data.table <- function(data, id.vars = NULL, measure.vars = NULL, variable.name = "variable", +melt.data.table <- function(data, id.vars, measure.vars, variable.name = "variable", value.name = "value", ..., na.rm = FALSE, variable.factor = TRUE, value.factor = FALSE, verbose = getOption("datatable.verbose")) { drop.levels <- FALSE # maybe a future FR if (!inherits(data, "data.table")) stop("'data' must be a data.table") - ans <- .Call("Cfmelt", data, id.vars, measure.vars, - as.logical(variable.factor), as.logical(value.factor), - variable.name, value.name, - as.logical(na.rm), as.logical(drop.levels), - as.logical(verbose)); + if (missing(id.vars)) id.vars=NULL + if (missing(measure.vars)) measure.vars = NULL + ans <- .Call("Cfmelt", data, id.vars, measure.vars, + as.logical(variable.factor), as.logical(value.factor), + variable.name, value.name, + as.logical(na.rm), as.logical(drop.levels), + as.logical(verbose)); setattr(ans, "row.names", .set_row_names(length(ans[[1L]]))) setattr(ans, "class", c("data.table", "data.frame")) alloc.col(ans) diff --git a/README.md b/README.md index aefd89703..62e9ae571 100644 --- a/README.md +++ b/README.md @@ -276,6 +276,8 @@ We moved from R-Forge to GitHub on 9 June 2014, including history. 44. Subset on data.table using `lapply` of the form `lapply(L, "[", Time == 3L)` works now without error due to "[.data.frame" redirection. Closes [#500](https://github.com/Rdatatable/data.table/issues/500). Thanks to Garrett See for reporting. + 45. `id.vars` and `measure.vars` default value of `NULL` was removed to be consistent in behaviour with `reshape2:::melt.data.frame`. Closes [#780](https://github.com/Rdatatable/data.table/issues/500). Thanks to @dardesta for reporting. + #### NOTES 1. Reminder: using `rolltolast` still works but since v1.9.2 now issues the following warning: diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index b0f90c10b..f65309c4e 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -5110,6 +5110,17 @@ for (i in seq_along(dt)) { }) } +# fix for #780. +if ("package:reshape2" %in% search()) { + try(detach(package:reshape),silent=TRUE) + DT = data.table(x=rep(c("a","b","c"),each=3), y=c(1,3,6), v=1:9) + foo = function(input, by, var) { + melt(input, id.vars = by, measure.vars=var) + } + test(1371.1, foo(DT, by="x"), data.table(x=rep(DT$x, 2L), variable=factor(rep(c("y", "v"), each=9L), levels=c("y", "v")), value=c(DT$y, DT$v)), warning="All 'measure.vars are NOT of the SAME type.") + test(1371.2, foo(DT), data.table(x=rep(DT$x, 2L), variable=factor(rep(c("y", "v"), each=9L), levels=c("y", "v")), value=c(DT$y, DT$v)), warning="To be consistent with reshape2's melt, id.vars and") +} + ########################## diff --git a/man/melt.data.table.Rd b/man/melt.data.table.Rd index ce4141eed..9c54e94da 100644 --- a/man/melt.data.table.Rd +++ b/man/melt.data.table.Rd @@ -7,7 +7,7 @@ } \usage{ ## fast melt a data.table -\method{melt}{data.table}(data, id.vars = NULL, measure.vars = NULL, +\method{melt}{data.table}(data, id.vars, measure.vars, variable.name = "variable", value.name = "value", ..., na.rm = FALSE, variable.factor = TRUE, value.factor = FALSE, @@ -15,8 +15,8 @@ } \arguments{ \item{data}{ A \code{data.table} object to melt.} - \item{id.vars}{vector of id variables. Can be integer (corresponding id column numbers) or character (id column names) vector. If \code{NULL}, all non-measure columns will be assigned to it.} - \item{measure.vars}{vector of measure variables. Can be integer (corresponding measue column numbers) or character (measure column names) vector. If \code{NULL}, all non-id columns will be assigned to it.} + \item{id.vars}{vector of id variables. Can be integer (corresponding id column numbers) or character (id column names) vector. If missing, all non-measure columns will be assigned to it.} + \item{measure.vars}{vector of measure variables. Can be integer (corresponding measue column numbers) or character (measure column names) vector. If missing, all non-id columns will be assigned to it.} \item{variable.name}{name for the measured variable names column. The default name is 'variable'.} \item{value.name}{name for the molten data values column. The default name is 'value'.} \item{na.rm}{If \code{TRUE}, \code{NA} values will be removed from the molten data.} @@ -26,7 +26,7 @@ \item{...}{any other arguments to be passed to/from other methods} } \details{ -If \code{id.vars} and \code{measure.vars} are both \code{NULL}, all non-\code{numeric/integer/logical} columns are assigned as id variables and the rest of the columns are assigned as measure variables. If only one of \code{id.vars} or \code{measure.vars} is supplied, the rest of the columns will be assigned to the other. Both \code{id.vars} and \code{measure.vars} can have the same column more than once and same column can be as id and measure variables. +If \code{id.vars} and \code{measure.vars} are both missing, all non-\code{numeric/integer/logical} columns are assigned as id variables and the rest of the columns are assigned as measure variables. If only one of \code{id.vars} or \code{measure.vars} is supplied, the rest of the columns will be assigned to the other. Both \code{id.vars} and \code{measure.vars} can have the same column more than once and same column can be as id and measure variables. \code{melt.data.table} also accepts \code{list} columns for both id and measure variables. When all \code{measure.vars} are not of the same type, they'll be coerced according to the hierarchy \code{list} > \code{character} > \code{numeric > integer > logical}. For example, any of the measure variables is a \code{list}, then entire value column will be coerced to a list. Note that, if the type of \code{value} column is a list, \code{na.rm = TRUE} will have no effect.