Extracting single row from data.frame without loss of names

Viewed 125

I am simply extracting a single row from a data.frame. Consider for example

d=data.frame(a=1:3,b=1:3)
d[1,]    # returns a data.frame
#   a b
# 1 1 1

The output matched my expectation. The result was not as I expected though when dealing with a data.frame that contains a single column.

d=data.frame(a=1:3)
d[1,]   # returns an integer
# [1] 1

Indeed, here, the extracted data is not a data.frame anymore but an integer! To me, it seems a little strange that the same function on the same data type wants to return different data types. One of the issue with this conversion is the loss of the column name.

To solve the issue, I did

extractRow = function(d,index)
{
    if (ncol(d) > 1)
    {
        return(d[index,])
    } else
    {
        d2 = as.data.frame(d[index,])
        names(d2) = names(d)
        return(d2)
    }
}

d=data.frame(a=1:3,b=1:3)
extractRow(d,1)
#   a b    
# 1 1 1

d=data.frame(a=1:3)
extractRow(d,1)
#   a
# 1 1

But it seems unnecessarily cumbersome. Is there a better solution?

4 Answers

Just subset with the drop = FALSE option:

extractRow = function(d, index) {
    return(d[index, , drop=FALSE])
}

R tries to simplify data.frame cuts by default, the same thing happens with columns:

d[, "a"]

# [1] 1 2 3

Alternatives are:

  • d[1, , drop = FALSE]
  • tibble::tibble which has drop = FALSE by default

I can't tell you why that happens - it seems weird. One workaround would be to use slice from dplyr (although using a library seems unecessary for such a simple task).

library(dplyr)
slice(d, 1)
  a
1 1

data.frames will simplify to vectors or scallars whith base subsetting [,].

If you want to avoid that, you can use tibbles instead:

> tibble(a=1:2)[1,]

# A tibble: 1 x 1
      a
  <int>
1     1

tibble(a=1:2)[1,] %>% class
[1] "tbl_df"     "tbl"        "data.frame"
Related