Lesson 2 of 4

dplyr vs data.table

In Lesson 1 Maya learned data.table on her bakery chain's sales: the DT[i, j, by] bracket and keys. But she already knew dplyr, and a fair question nags. If both tools can filter, group and summarise the same sales, why keep two? Do they even give the same answer, and when does the choice actually matter?

This lesson puts them side by side on Maya's till data. You will write the same task in both dialects, confirm they return the identical result, then measure exactly where data.table pulls ahead on speed and memory, and learn when each is the right call.

By the end of this lesson you will be able to:

  • Write the same filter, mutate and grouped summary in both dplyr and data.table, and get the identical result
  • Explain why data.table is faster and leaner: an optimized C engine and modify-by-reference (no copy)
  • Choose dplyr, data.table, or the dtplyr bridge for a given job

Prerequisites: you can run R, and you know the dplyr verbs and the pipe and the [data.table DT[i, j, by] bracket](data-table-Syntax-and-Keys.html) from Lesson 1.

The bars below are the payoff in one picture: the same grouped sum on a million rows, timed both ways. You will run the real benchmark yourself in a moment.

The premise

Two dialects, one result

Here is the idea that makes this whole lesson safe to learn: for everyday wrangling, dplyr and data.table do the same job and return the same data. They are two dialects for one language. dplyr spells the steps out as verbs joined by a pipe; data.table packs them into the DT[i, j, by] bracket. Pick the spelling you like; the answer is identical.

Each lesson runs in a fresh R session, so we build Maya's sales right here, once, in two shapes: a sales table for dplyr and the same data as a salesDT for data.table.

RInteractive R
library(dplyr) library(tibble) library(data.table) setDTthreads(1) # the in-browser R runs on one core # Maya's bakery chain: a week of sales across three shops, one row per sale sales <- tibble( shop = c("Austin","Austin","Austin","Denver","Denver","Denver", "Seattle","Seattle","Seattle","Austin","Denver","Seattle"), item = c("Sourdough","Bagel","Croissant","Sourdough","Bagel","Croissant", "Sourdough","Bagel","Croissant","Sourdough","Sourdough","Bagel"), units = c(18, 40, 27, 22, 30, 15, 12, 33, 19, 20, 24, 28), revenue = c(81, 60, 108, 99, 45, 60, 54, 49, 76, 90, 108, 42) ) salesDT <- as.data.table(sales) # the same data, as a data.table

  

Now the simplest task: keep just the Austin sales. Write it both ways and compare.

RInteractive R
filter(sales, shop == "Austin") # dplyr: the filter() verb salesDT[shop == "Austin"] # data.table: a condition in the i slot #> shop item units revenue #> 1: Austin Sourdough 18 81 #> 2: Austin Bagel 40 60 #> 3: Austin Croissant 27 108 #> 4: Austin Sourdough 20 90

  

Same four Austin rows, same columns, same order. The widget shows that shared result: eight rows fall away, the four Austin sales remain, whichever dialect you used.