162

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
M--
  • 25,431
  • 8
  • 61
  • 93
DQdlM
  • 9,814
  • 13
  • 37
  • 34

5 Answers5

173

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> 
Dirk Eddelbuettel
  • 360,940
  • 56
  • 644
  • 725
  • 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 Jun 18 '17 at 02:54
  • 3
    @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 Sep 30 '22 at 11:28
88

As of 2016 you can also use the tidyverse.

library(tidyverse)
samp %>% remove_rownames %>% column_to_rownames(var="names")
Joe
  • 8,073
  • 1
  • 52
  • 58
28

in one line

> samp.with.rownames <- data.frame(samp[,-1], row.names=samp[,1])
nigelhenry
  • 479
  • 5
  • 6
21

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])
stragu
  • 1,051
  • 9
  • 15
  • 2
    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. – Andrew Brēza May 13 '21 at 18:29
13

You can execute this in 2 simple statements:

row.names(samp) <- samp$names
samp[1] <- NULL
victor8910
  • 193
  • 1
  • 8