3

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?

Remi.b
  • 17,389
  • 28
  • 87
  • 168
  • This may illustrate the subject: https://stackoverflow.com/questions/69084753/selecting-a-single-column-from-a-tibble-still-returns-a-tibble-instead-of-a-vect/69087492#69087492 – GuedesBF Sep 09 '21 at 10:05

4 Answers4

3

Just subset with the drop = FALSE option:

extractRow = function(d, index) {
    return(d[index, , drop=FALSE])
}
Tim Biegeleisen
  • 502,043
  • 27
  • 286
  • 360
2

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
Robin Gertenbach
  • 10,316
  • 3
  • 25
  • 37
1

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
user438383
  • 5,716
  • 8
  • 28
  • 43
0

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"
GuedesBF
  • 8,409
  • 5
  • 19
  • 37