Rarely do we work on only one data.frame, particularly when we start working with complex data and data contained within relational databases. In these cases, data are factored into several tables (akin to data.frame objects) with entries that connect the information from one table to another. Consider the following example tables

Example data table structure

Each has a column I named Key and another with some data in it. In R they could be defined as:

df.X <- data.frame( Key = c("A","B","C"),
                    X = c(1,2,3) )
df.X

and

df.Y <- data.frame( Key = c("B","C","D"),
                    Y = c(10,11,12) )
df.Y

Keys

An important component of relational data are the keys. These are unique identifiers for a particular datum from a table. In each of these examples the varible (obviously named) Key is what is called a Primary Key because it uniquely identifies each row. You can verify this by counting the number of entries then filtering only for ones with 2 or more instances.

df.X %>%
  count( Key ) %>%
  filter( n > 1 )

Notice there is nothing here as each is unique.

The column Key is a Primary Key for the df.X data because it identifies a unique row in that table.

In addition to a Primary Key we can have a Foreign Key when it is used to indicate data within a separate table. For example, if I am interested to see if the smallest value in df.X$X corresponds with the smallest value in df.Y$Y, then I will be using the Key form df.X representing max(X) to find the value of Y in df.Y and evaluate if it is max(Y). This means that df.X$Key is a Foreign Key as it points to a row in the df.Y data frame.

The keys are used to link together different tables.

Joins

A join is where we combine information contained within two data frames.

Joins are ways to merge together data and come in four flavors.

Left Join

A left join is one where all the data from the left data frame is in the result and the data whose keys in the right data frame are present in the left one are also included. Graphically, this leads to:

left join

Where in R we do this using the left_join() function.

df.X %>%
  left_join( df.Y, by="Key")

Right Join

The right join does the same thing but keeps all the keys in the right data table and has missing data where the key in the left one is not in the right one.

Right Join

This is accomplished using the right_join() function.

df.X %>%
  right_join( df.Y, by="Key")

Full (or Outer) Join

This join is one where all the keys are retained adding missing data as necessary.

Outer Join

df.X %>%
  full_join( df.Y, by="Key")

Inner Join

The last one retains only those keys that are common in both.

Inner Join

df.X %>%
  inner_join( df.Y, by="Key")

Filtering Joins

We can also use joins to filter values within one data.frame. Here the semi_join() keeps everything in the left data that has a key in the right one, but importantly it does not import the right data columns into the result.

df.X %>%
  semi_join( df.Y )

The opposite of this is the anti_join() which drops everything in the left table that has a key in the right one, leaving only the ones that are unique.

df.X %>%
  anti_join( df.Y )
LS0tCnRpdGxlOiAiUmVsYXRpb25hbCBEYXRhIgpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sKLS0tCgoKYGBge3Igc2V0dXAsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoIGtuaXRyICkKbGlicmFyeSggdGlkeXZlcnNlICkKb3B0c19jaHVuayRzZXQoIG1lc3NhZ2UgPSBGQUxTRSwKICAgICAgICAgICAgICAgIHdhcm5pbmcgPSBGQUxTRSwKICAgICAgICAgICAgICAgIGZpZy5yZXRpbmEgPSAzLAogICAgICAgICAgICAgICAgZWNobz1UUlVFKQpgYGAKCgpSYXJlbHkgZG8gd2Ugd29yayBvbiBvbmx5IG9uZSBgZGF0YS5mcmFtZWAsIHBhcnRpY3VsYXJseSB3aGVuIHdlIHN0YXJ0IHdvcmtpbmcgd2l0aCBjb21wbGV4IGRhdGEgYW5kIGRhdGEgY29udGFpbmVkIHdpdGhpbiByZWxhdGlvbmFsIGRhdGFiYXNlcy4gIEluIHRoZXNlIGNhc2VzLCBkYXRhIGFyZSBmYWN0b3JlZCBpbnRvIHNldmVyYWwgdGFibGVzIChha2luIHRvIGBkYXRhLmZyYW1lYCBvYmplY3RzKSB3aXRoIGVudHJpZXMgdGhhdCBjb25uZWN0IHRoZSBpbmZvcm1hdGlvbiBmcm9tIG9uZSB0YWJsZSB0byBhbm90aGVyLiAgIENvbnNpZGVyIHRoZSBmb2xsb3dpbmcgZXhhbXBsZSB0YWJsZXMKCjxjZW50ZXI+CiFbRXhhbXBsZSBkYXRhIHRhYmxlIHN0cnVjdHVyZV0oaHR0cHM6Ly9saXZlLnN0YXRpY2ZsaWNrci5jb20vNjU1MzUvNTA0Mjc2NzI2MzJfMjRlNDUxMzlhOF9jX2QuanBnKQo8L2NlbnRlcj4KCkVhY2ggaGFzIGEgY29sdW1uIEkgbmFtZWQgKktleSogYW5kIGFub3RoZXIgd2l0aCBzb21lIGRhdGEgaW4gaXQuICBJbiBgUmAgdGhleSBjb3VsZCBiZSBkZWZpbmVkIGFzOgoKYGBge3IgZWNobz1UUlVFfQpkZi5YIDwtIGRhdGEuZnJhbWUoIEtleSA9IGMoIkEiLCJCIiwiQyIpLAogICAgICAgICAgICAgICAgICAgIFggPSBjKDEsMiwzKSApCmRmLlgKYGBgCmFuZCAKCmBgYHtyIGVjaG89VFJVRX0KZGYuWSA8LSBkYXRhLmZyYW1lKCBLZXkgPSBjKCJCIiwiQyIsIkQiKSwKICAgICAgICAgICAgICAgICAgICBZID0gYygxMCwxMSwxMikgKQpkZi5ZCmBgYAoKCiMjIEtleXMKCkFuIGltcG9ydGFudCBjb21wb25lbnQgb2YgcmVsYXRpb25hbCBkYXRhIGFyZSB0aGUgKmtleXMqLiAgVGhlc2UgYXJlIHVuaXF1ZSBpZGVudGlmaWVycyBmb3IgYSBwYXJ0aWN1bGFyIGRhdHVtIGZyb20gYSB0YWJsZS4gIEluIGVhY2ggb2YgdGhlc2UgZXhhbXBsZXMgdGhlIHZhcmlibGUgKG9idmlvdXNseSBuYW1lZCkgYEtleWAgaXMgd2hhdCBpcyBjYWxsZWQgYSAqUHJpbWFyeSBLZXkqIGJlY2F1c2UgaXQgdW5pcXVlbHkgaWRlbnRpZmllcyBlYWNoIHJvdy4gIFlvdSBjYW4gdmVyaWZ5IHRoaXMgYnkgY291bnRpbmcgdGhlIG51bWJlciBvZiBlbnRyaWVzIHRoZW4gZmlsdGVyaW5nIG9ubHkgZm9yIG9uZXMgd2l0aCAyIG9yIG1vcmUgaW5zdGFuY2VzLgoKYGBge3J9CmRmLlggJT4lCiAgY291bnQoIEtleSApICU+JQogIGZpbHRlciggbiA+IDEgKQpgYGAKCk5vdGljZSB0aGVyZSBpcyBub3RoaW5nIGhlcmUgYXMgZWFjaCBpcyB1bmlxdWUuCgo+IFRoZSBjb2x1bW4gYEtleWAgaXMgYSBQcmltYXJ5IEtleSBmb3IgdGhlIGBkZi5YYCBkYXRhIGJlY2F1c2UgaXQgaWRlbnRpZmllcyBhIHVuaXF1ZSByb3cgKmluIHRoYXQgdGFibGUqLgoKSW4gYWRkaXRpb24gdG8gYSAqUHJpbWFyeSBLZXkqIHdlIGNhbiBoYXZlIGEgKkZvcmVpZ24gS2V5KiB3aGVuIGl0IGlzIHVzZWQgdG8gaW5kaWNhdGUgZGF0YSB3aXRoaW4gYSBzZXBhcmF0ZSB0YWJsZS4gIEZvciBleGFtcGxlLCBpZiBJIGFtIGludGVyZXN0ZWQgdG8gc2VlIGlmIHRoZSBzbWFsbGVzdCB2YWx1ZSBpbiBgZGYuWCRYYCBjb3JyZXNwb25kcyB3aXRoIHRoZSBzbWFsbGVzdCB2YWx1ZSBpbiBgZGYuWSRZYCwgdGhlbiBJIHdpbGwgYmUgdXNpbmcgdGhlIGBLZXlgIGZvcm0gYGRmLlhgIHJlcHJlc2VudGluZyBgbWF4KFgpYCB0byBmaW5kIHRoZSB2YWx1ZSBvZiBgWWAgaW4gYGRmLllgIGFuZCBldmFsdWF0ZSBpZiBpdCBpcyBgbWF4KFkpYC4gIFRoaXMgbWVhbnMgdGhhdCBgZGYuWCRLZXlgIGlzIGEgKkZvcmVpZ24gS2V5KiBhcyBpdCBwb2ludHMgdG8gYSByb3cgaW4gdGhlIGBkZi5ZYCBkYXRhIGZyYW1lLgoKVGhlIGtleXMgYXJlIHVzZWQgdG8gbGluayB0b2dldGhlciBkaWZmZXJlbnQgdGFibGVzLgoKCgojIEpvaW5zCgo+IEEgKmpvaW4qIGlzIHdoZXJlIHdlIGNvbWJpbmUgaW5mb3JtYXRpb24gY29udGFpbmVkIHdpdGhpbiB0d28gZGF0YSBmcmFtZXMuICAKCkpvaW5zIGFyZSB3YXlzIHRvIG1lcmdlIHRvZ2V0aGVyIGRhdGEgYW5kIGNvbWUgaW4gZm91ciBmbGF2b3JzLiAgCgojIyBMZWZ0IEpvaW4KCkEgKmxlZnQgam9pbiogaXMgb25lIHdoZXJlIGFsbCB0aGUgZGF0YSBmcm9tIHRoZSBsZWZ0IGRhdGEgZnJhbWUgaXMgaW4gdGhlIHJlc3VsdCBhbmQgdGhlIGRhdGEgd2hvc2Uga2V5cyBpbiB0aGUgcmlnaHQgZGF0YSBmcmFtZSBhcmUgcHJlc2VudCBpbiB0aGUgbGVmdCBvbmUgYXJlIGFsc28gaW5jbHVkZWQuICBHcmFwaGljYWxseSwgdGhpcyBsZWFkcyB0bzoKCgohW2xlZnQgam9pbl0oaHR0cHM6Ly9saXZlLnN0YXRpY2ZsaWNrci5jb20vNjU1MzUvNTA0Mjc4MTczNzFfNjc4ZjBmNjRjN19jX2QuanBnKQoKV2hlcmUgaW4gYFJgIHdlIGRvIHRoaXMgdXNpbmcgdGhlIGBsZWZ0X2pvaW4oKWAgZnVuY3Rpb24uIAoKYGBge3J9CmRmLlggJT4lCiAgbGVmdF9qb2luKCBkZi5ZLCBieT0iS2V5IikKYGBgCgoKCiMjIFJpZ2h0IEpvaW4KClRoZSByaWdodCBqb2luIGRvZXMgdGhlIHNhbWUgdGhpbmcgYnV0IGtlZXBzIGFsbCB0aGUga2V5cyBpbiB0aGUgcmlnaHQgZGF0YSB0YWJsZSBhbmQgaGFzIG1pc3NpbmcgZGF0YSB3aGVyZSB0aGUga2V5IGluIHRoZSBsZWZ0IG9uZSBpcyBub3QgaW4gdGhlIHJpZ2h0IG9uZS4KCiFbUmlnaHQgSm9pbl0oaHR0cHM6Ly9saXZlLnN0YXRpY2ZsaWNrci5jb20vNjU1MzUvNTA0MjcxMjU1MjhfMGRlNjI4MTQ3NV9jX2QuanBnKQoKVGhpcyBpcyBhY2NvbXBsaXNoZWQgdXNpbmcgdGhlIGByaWdodF9qb2luKClgIGZ1bmN0aW9uLgoKYGBge3IgZWNobz1UUlVFfQpkZi5YICU+JQogIHJpZ2h0X2pvaW4oIGRmLlksIGJ5PSJLZXkiKQpgYGAKCgoKIyMgRnVsbCAob3IgT3V0ZXIpIEpvaW4KClRoaXMgam9pbiBpcyBvbmUgd2hlcmUgYWxsIHRoZSBrZXlzIGFyZSByZXRhaW5lZCBhZGRpbmcgbWlzc2luZyBkYXRhIGFzIG5lY2Vzc2FyeS4KCgohW091dGVyIEpvaW5dKGh0dHBzOi8vbGl2ZS5zdGF0aWNmbGlja3IuY29tLzY1NTM1LzUwNDI3OTkzOTkyXzRjY2VkZTE1NzRfY19kLmpwZykKCmBgYHtyfQpkZi5YICU+JQogIGZ1bGxfam9pbiggZGYuWSwgYnk9IktleSIpCmBgYAoKCiMjIElubmVyIEpvaW4KClRoZSBsYXN0IG9uZSByZXRhaW5zICpvbmx5KiB0aG9zZSBrZXlzIHRoYXQgYXJlIGNvbW1vbiBpbiBib3RoLgoKIVtJbm5lciBKb2luXShodHRwczovL2xpdmUuc3RhdGljZmxpY2tyLmNvbS82NTUzNS81MDQyNzEyNTY4M19hYzQ0ZWIxNTAwX2NfZC5qcGcpCgpgYGB7cn0KZGYuWCAlPiUKICBpbm5lcl9qb2luKCBkZi5ZLCBieT0iS2V5IikKYGBgCgoKCgoKCiMgRmlsdGVyaW5nIEpvaW5zCgpXZSBjYW4gYWxzbyB1c2Ugam9pbnMgdG8gZmlsdGVyIHZhbHVlcyB3aXRoaW4gb25lIGBkYXRhLmZyYW1lYC4gIEhlcmUgdGhlIGBzZW1pX2pvaW4oKWAga2VlcHMgZXZlcnl0aGluZyBpbiB0aGUgbGVmdCBkYXRhIHRoYXQgaGFzIGEga2V5IGluIHRoZSByaWdodCBvbmUsIGJ1dCAqKmltcG9ydGFudGx5KiogaXQgZG9lcyBub3QgaW1wb3J0IHRoZSByaWdodCBkYXRhIGNvbHVtbnMgaW50byB0aGUgcmVzdWx0LgoKCmBgYHtyfQpkZi5YICU+JQogIHNlbWlfam9pbiggZGYuWSApCmBgYAoKVGhlIG9wcG9zaXRlIG9mIHRoaXMgaXMgdGhlIGBhbnRpX2pvaW4oKWAgd2hpY2ggZHJvcHMgZXZlcnl0aGluZyBpbiB0aGUgbGVmdCB0YWJsZSB0aGF0IGhhcyBhIGtleSBpbiB0aGUgcmlnaHQgb25lLCBsZWF2aW5nIG9ubHkgdGhlIG9uZXMgdGhhdCBhcmUgdW5pcXVlLgoKYGBge3J9CmRmLlggJT4lCiAgYW50aV9qb2luKCBkZi5ZICkKYGBgCgoK