Tibbles, Data frames and Vectors

June 18, 2019    tibble

I learned something new today and the reason I write this is that I’m somewhat confused as to how I didn’t know it already.

Data Frames

Let us start by creating a data frame.

temp = data.frame(x = c(1:3), y = c(10:12))
temp
  x  y
1 1 10
2 2 11
3 3 12

We can select rows

temp[1,]
  x  y
1 1 10

and columns

temp$x
[1] 1 2 3
temp[,2]
[1] 10 11 12

What I hadn’t realised before is that there is another way to select columns, using [[ notation that I’m used to using with lists.

temp[[1]]
[1] 1 2 3

Let’s see if there is any difference in what is returned with these variations.

class(temp[1,])
[1] "data.frame"
class(temp[,1])
[1] "integer"
class(temp$x)
[1] "integer"
class(temp[[1]])
[1] "integer"

So selecting a row returns a data frame, whereas selecting a column in any way seems to return a vector.

Tibbles

Let’s do the same things with a tibble

library(tibble)
temp2 = tibble(x = c(1:3), y = c(10:12))
temp2
# A tibble: 3 x 2
      x     y
  <int> <int>
1     1    10
2     2    11
3     3    12

We can select rows

temp2[1,]
# A tibble: 1 x 2
      x     y
  <int> <int>
1     1    10

and columns

temp2$x
[1] 1 2 3
temp2[,2]
# A tibble: 3 x 1
      y
  <int>
1    10
2    11
3    12
temp2[[1]]
[1] 1 2 3

You’ve probably noticed a difference already but if we now look at what is returned we see some differences to the behaviour of data.frame().

class(temp2[1,])
[1] "tbl_df"     "tbl"        "data.frame"
class(temp2[,1])
[1] "tbl_df"     "tbl"        "data.frame"
class(temp2$x)
[1] "integer"
class(temp2[[1]])
[1] "integer"

There is now consistency using [,] notation - both temp2[1,] and temp2[,1] return a tibble. Using either $ or [[]] returns a vector as it did for a data.frame.

Why did this make a difference?

What happened in my case was that I’d written a function that had a data frame as one of the arguments. In this function I’d used the $ notation to select a column and then treated this as a vector. Not a problem.

I then wrote a similar function and used the [,] notation to select a column and then treated it as a vector. This wasn’t a problem when I gave it a data frame but then I gave it a tibble. This actually threw an error for me but this sort of thing could result in just the wrong value being returned. A quick demo of this could be using the length() function.

# data frame
length(temp[,1])
[1] 3
# tibble
length(temp2[,1])
[1] 1

You may be wondering what sort of error I got, well as an example lets do something slightly more meaningful.

temp = data.frame(x = rnorm(100))
temp2 = tibble(x = rnorm(100, 2, 0.5))

Then something like this will work fine

t.test(temp$x, temp2$x)

    Welch Two Sample t-test

data:  temp$x and temp2$x
t = -20.396, df = 153, p-value < 2.2e-16
alternative hypothesis: true difference in means is not equal to 0
95 percent confidence interval:
 -2.289389 -1.885050
sample estimates:
  mean of x   mean of y 
-0.06469698  2.02252275 

but this throws an error.

t.test(temp[,1], temp2[,1])
Must use a vector in `[`, not an object of class matrix.

Now I know about [[]] I will definitely being using it with tibbles.