Repository navigation
melt with measure.vars=list of length=1 should return integer in variable column #5209
Description
Activity
+1 I have been surprised by this behaviour too
I've seen the docs for that but had not recognized the real meaning of it until looking at your example
measure.vars = list(Length="Petal.Length"). Is there an example of where changing thevariable's values to integer indices is meaningful? I've internally assumed that if I needed an index instead of a string, I'd set it withmatchorfactor/levels.Is there an example of where changing the variable's values to integer indices is meaningful?
not sure how to interpret "meaningful" in this context, could you please clarify?
my goal was to increase consistency.
Sure, I apologize for lack of clarity. What is the justification for having this seemingly inconsistent difference? ("Inconsistent" between 1 and 2+ args, not commenting on documentation-vs-execution, that's different.)
To me, having (starkly) different behavior between 1 arg and 2+ args is counter-intuitive and requires caller's use of
data.table::meltto guard against it with extra code. Granted, that code is not cosmic.To me it seems more intuitive and consistent to always behave the same, whether always-strings or always-integers or always-factors, with arguments (e.g.,
variable.factor=) that support differing paths.I'm late to the discussion, in a sense, and I'm not arguing change for change's sake, so I'm "curious" in case you know the history of why this explicit behavior was chosen (or did it just fall into place this way).
ok, so I understand that you are curious about the inconsistency in the output type, between two uses.
First usage below is whenmeasure.varsis a character vector, in which outputvariableis character (name of melted column)> melt(iris.row, measure.vars = c("Petal.Length","Sepal.Length")) Sepal.Width Petal.Width Species variable value <num> <num> <fctr> <fctr> <num> 1: 3.5 0.2 setosa Petal.Length 1.4 2: 3.5 0.2 setosa Sepal.Length 5.1
Second usage below is when
measure.varsis a list, in which outputvariableis "integer indicating an index/position in each of those vectors." (quote from ?melt)> melt(iris.row, measure.vars = list(Length=c("Petal.Length","Sepal.Length"),Width=c("Petal.Width","Sepal.Width"))) Species variable Length Width <fctr> <fctr> <num> <num> 1: setosa 1 1.4 0.2 2: setosa 2 5.1 3.5
you would have to ask @arunsrinivasan about the history about why he made this choice, but I think it makes sense. (integer index is necessary to identify which column was melted)
Rather than using
measure.vars=list(...)(above), more recently I implemented support formeasure.vars=measure(...)(see below) which is almost always preferable, because we get more informative "variable" columns (part below).> melt(iris.row, measure.vars = measure(part, value.name, sep=".")) Species part Length Width <fctr> <char> <num> <num> 1: setosa Sepal 5.1 3.5 2: setosa Petal 1.4 0.2
I understand that that's what the docs say, and I see how
measure(.)adds a lot of value here. My question is why it's useful to have different behaviors? From a "simple/consistent" approach mindset, I don't think it's wrong to hope thatmelt(iris.row, measure.vars = list(Length=c("Petal.Length","Sepal.Length"))) # ignoring the warning melt(iris.row, measure.vars = list(Length=c("Petal.Length","Sepal.Length"), Width=c("Petal.Width","Sepal.Width")))
would both produce a column named
variablethat contains a factor with levels derived from the column names. In my use-cases, I can't think of a time when I don't care which column name is paired with each row; I recognize my use-cases are just mine.I think the point of my question is the history of it (as you suggested, from arunsrinivasan) to know if it "just happened this way" or if there is a specific mindset/use-case where having diverging behavior makes sense. (Backwards compatibility is always valuable, of course.)
Thanks tdhock!
- added a commit that references this issue
on May 22, 2026
melt() docs say that variable column should be an integer when measure.vars is a list,
In most cases that is true, for example
However if measure.vars is a list of length=1 then we get variable= character column name instead,
This is not a big deal (probably not a lot of users which melt only one column), but it is inconsistent with the documentation, so I will work on a fix.