I just want to understand if there is a difference between names
and colnames
when working with data.frame
. Both seems to behave the same way. Can I subsitute one by the other?

- 2,289
- 2
- 14
- 22

- 523
- 1
- 5
- 17
-
3From `?colnames`: "For a data frame, `rownames` and `colnames` eventually call `row.names` and `names` respectively, but the latter are preferred." – Henrik Jul 17 '14 at 09:12
4 Answers
Are they the same for data.frames? YES
Are they the same in general? Not quite--the big difference is that colnames also works for matrices, whereas names does not (just dataframes).
In addition, you can use names to set/get the names of vectors (and, for obvious reasons, you can't do this with colnames--the result is NULL for getting and an error for setting).

- 1,023
- 7
- 19
-
`names` works on vectors too. And it actually does work on matrices... it just does not do what you expect it to do! – nico Jul 17 '14 at 09:15
-
2Re: "names" and matrices--that's kind of a loose notion of "working"... Nevertheless, point taken. – Steve S Jul 17 '14 at 09:34
-
1just kidding, was mostly to point out that it won't throw an error, and in some cases it may slip through :) – nico Jul 17 '14 at 11:01
-
1@SteveS Can you precise "for obvious reasons"? Doesn't seem so obvious to me ;) – Aurélien Gasser Feb 04 '17 at 17:31
-
3@AurélienGasser, you're right: I'm not even sure myself why I thought that was so obvious at the time... But to answer your question, **colnames** only works for matrix-like objects with at least two dimensions (since it must have rows *and* columns) and, as a result, it doesn't work for vectors (since they don't have columns (or even a 'dim' attribute)). – Steve S Feb 09 '17 at 18:06
-
`names()` does not work for just data.frames but also lists (no?). Example: `x <- list(); x[["a"]] <- 2; x[["b"]] <- "foo"; names(x) <- c("c", "d")` – s_baldur Mar 01 '18 at 10:27
-
A data.frame is a list, and that's likely why `names<-` works on data.frames – alan ocallaghan Dec 16 '19 at 14:53
If you look at the beginning of the colnames
and colnames<-
functions source code :
R> colnames
function (x, do.NULL = TRUE, prefix = "col")
{
if (is.data.frame(x) && do.NULL)
return(names(x))
(...)
R> `colnames<-`
function (x, value)
{
if (is.data.frame(x)) {
names(x) <- value
}
(...)
You can see that for data frames, colnames
just call the names
function. So yes, they are strictly equivalent.

- 47,631
- 14
- 113
- 118
names()
creates name attributes where as colnames()
simply names the columns.
i.e.
Create a temp variable.
> temp <- rbind(cbind(1,2,3,4,5),
+ cbind(6,7,8,9,10))
> temp
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 6 7 8 9 10
Create the names.temp
object.
> names.temp <- temp
Use names()
on names.temp
> names(names.temp) <- paste(c("First col", "Second col", "Third col",
"Fourth Col", "Fifth col"))
> names.temp
[,1] [,2] [,3] [,4] [,5]
[1,] 1 2 3 4 5
[2,] 6 7 8 9 10
attr(,"names")
[1] "First col" "Second col" "Third col" "Fourth Col" "Fifth col"
NA NA NA
[9] NA NA
We see here we can actually call the 5th name attribute in names.temp
.
> names(names.temp)[5]
[1] "Fifth col"
Repeat with a second object but this time create the colnames.temp
object.
> colnames.temp <- temp
Use colnames()
on colnames.temp
> colnames(colnames.temp) <- paste(c("First col", "Second col", "Third col",
"Fourth Col", "Fifth col"))
> colnames.temp
First col Second col Third col Fourth Col Fifth col
[1,] 1 2 3 4 5
[2,] 6 7 8 9 10
Now name attribute is NULL.
> names(colnames.temp)[5]
NULL
FINALLY. Let's look at our trusty str()
command. We can see there is a structural difference between names.temp
and colnames.temp
. Specifically, colnames.temp
has dimnames
attributes not names
attributes.
> str(names.temp)
num [1:2, 1:5] 1 6 2 7 3 8 4 9 5 10
- attr(*, "names")= chr [1:10] "First col" "Second col" "Thrid col" "Fourth
Col" ...
> str(colnames.temp)
num [1:2, 1:5] 1 6 2 7 3 8 4 9 5 10
- attr(*, "dimnames")=List of 2
..$ : NULL
..$ : chr [1:5] "First col" "Second col" "Thrid col" "Fourth Col" ...

- 21,571
- 9
- 87
- 105

- 81
- 2
- 5
-
2Nice first answer, but `names()` does not create names. `names<-` does. It is a different function. – Frank Feb 03 '17 at 18:20
-
1I stand corrected. The implication (read assumption) was to invoke `names()` implies the desire to name which is poor logic. Thanks Frank. – eyeknownothing Feb 03 '17 at 18:24
As far as I am concerned, the only difference between names()
and colnames()
with respect to a data.frame
input is that they allocated memory slightly differently. For instance, consider the code chunk below:
df <- data.frame(x=1:5, y=6:10, z=11:15)
tracemem(df)
names(df) <- c("A", "B", "C")
colnames(df) <- c('a','b','c')
If you run this code, you will see that the copying of df
only occurs once during the names()
call, whereas the copying of df
occurs twice during the colnames()
call.

- 11
- 4
-
3If you don't like copying, use `data.table::setnames` (which you can use on data.frames). – Frank Feb 03 '17 at 18:21