While the OP's use case is probably better solved by switching to a long format, the problem of a missing prefix for named single column arguments to cbind.data.frame
persists and is perhaps highlighted better in the following example:
cbind(x=data.frame(a=1,b=2), y=data.frame(a=3, b=4))
#> x.a x.b y.a y.b
#> 1 1 2 3 4
cbind(x=data.frame(a=1,b=2), y=data.frame(a=3))
#> x.a x.b a
#> 1 1 2 3
Note, how the a
column in the second case lacks the y.
prefix. This odd behavior is documented in the value section of ?data.frame
(which is called by cbind
for data.frame
arguments):
How the names of the data frame are created is complex, and the rest of this paragraph is only the basic story. [...] For a named matrix/list/data frame argument with more than one named column, the names of the columns are the name of the argument followed by a dot and the column name inside the argument: if the argument is unnamed, the argument's column names are used. For a named or unnamed matrix/list/data frame argument that contains a single column, the column name in the result is the column name in the argument.
One possible workaround (with several positive side effects) is switching from base
data.frame
to data.table
. It handles the the column names more consistently:
library(data.table)
cbind(x=data.table(a=1,b=2), y=data.frame(a=3))
#> x.a x.b y.a
#> <num> <num> <num>
#> 1: 1 2 3