170

I would like to convert the values in a column of an existing data frame into row names. Is is possible to do this without exporting the data frame and then reimporting it with a row.names = call?

For example I would like to convert:

 > samp 
     names Var.1 Var.2 Var.3
 1     A     1     5     0
 2     B     2     4     1
 3     C     3     3     2
 4     D     4     2     3
 5     E     5     1     4

Into:

> samp.with.rownames 
     Var.1 Var.2 Var.3
A     1     5     0
B     2     4     1
C     3     3     2
D     4     2     3
E     5     1     4

5 Answers 5

181

This should do:

samp2 <- samp[,-1]
rownames(samp2) <- samp[,1]

So in short, no there is no alternative to reassigning.

Edit: Correcting myself, one can also do it in place: assign rowname attributes, then remove column:

R> df<-data.frame(a=letters[1:10], b=1:10, c=LETTERS[1:10])
R> rownames(df) <- df[,1]
R> df[,1] <- NULL
R> df
   b c
a  1 A
b  2 B
c  3 C
d  4 D
e  5 E
f  6 F
g  7 G
h  8 H
i  9 I
j 10 J
R> 
2
  • 10
    > rownames(df)<-df[,1] Error in row.names<-.data.frame(*tmp*, value = value) : invalid 'row.names' length In addition: Warning message: Setting row names on a tibble is deprecated.
    – user3673
    Commented Jun 18, 2017 at 2:54
  • 4
    @user3673 A likely suspect is that you are not working with a dataframe. Verify this via class(df). If this gives multiple classes, simply call df<- as.data.frame(df) that should resolve it.
    – R. Iersel
    Commented Sep 30, 2022 at 11:28
96

As of 2016 you can also use the tidyverse.

library(tidyverse)
samp %>% remove_rownames %>% column_to_rownames(var="names")
4
  • 11
    More specifically, it is tibble::column_to_rownames
    – Ott Toomet
    Commented Jan 16, 2018 at 22:09
  • 1
    I get a warning "Setting row names on a tibble is deprecated"
    – Quantum7
    Commented Jun 13, 2018 at 7:13
  • 1
    tibble visualization doesn't show rownames, though, to see it you need to pipe it to as.data.frame() samp %>% remove_rownames %>% column_to_rownames(var="names") %>% as.data.frame()
    – Matteo
    Commented Jan 16, 2019 at 9:11
  • It looks like the latest version of the package automatically handles the conversion from tibble to data.frame. Commented May 13, 2021 at 18:28
28

in one line

> samp.with.rownames <- data.frame(samp[,-1], row.names=samp[,1])
0
24

It looks like the one-liner got even simpler along the line (currently using R 3.5.3):

# generate original data.frame
df <- data.frame(a = letters[1:10], b = 1:10, c = LETTERS[1:10])
# use first column for row names
df <- data.frame(df, row.names = 1)

The column used for row names is removed automatically.

With a one-row dataframe

Beware that if the dataframe has a single row, the behaviour might be confusing. As the documentation mentions:

If row names are supplied of length one and the data frame has a single row, the row.names is taken to specify the row names and not a column (by name or number).

This mean that, if you use the same command as above, it might look like it did nothing (when it actually named the first row "1", which won't look any different in the viewer).

In that case, you will have to stick to the more verbose:

df <- data.frame(a = "a", b = 1)
df <- data.frame(df, row.names = df[,1])

... but the column won't be removed. Also remember that, if you remove a column to end up with a single-column dataframe, R will simplify it to an atomic vector. In that case, you will want to use the extra drop argument:

df <- data.frame(df[,-1, drop = FALSE], row.names = df[,1])
1
  • 3
    Neat! I went straight for the tidyverse solution without checking to see if base R had a handy way of dealing with the issue. I should start with base. Commented May 13, 2021 at 18:29
13

You can execute this in 2 simple statements:

row.names(samp) <- samp$names
samp[1] <- NULL
1
  • Works in R 3.5.3
    – TheSciGuy
    Commented Apr 8, 2019 at 15:34

Not the answer you're looking for? Browse other questions tagged or ask your own question.