> For the complete documentation index, see [llms.txt](https://wordlens.datalit.de/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wordlens.datalit.de/part-1-transform-and-visualize-data/data-transformation/add-or-change-columns/joining-data-sets.md).

# Joining Data Sets

A special case of adding a new column is when the column already exists in a different data set. Then we can apply the join-operator.

Data analysis often involves working with multiple data sets. In many cases, we need to combine or merge data sets to gain insights or answer questions. This process is known as joining data sets. In this lesson, we will discuss why we need to join data sets, the different types of joins that exist, and how to implement joins using R and the Tidyverse.

There are four types of joins that we can use to combine data sets: inner join, left join, right join, and full join. In this lesson, we will illustrate them using the example of our politician's tweets. We want to enrich our data with some meta information about each politician, such as their political party, resort, age, or gender. For this, we first load the metadata from Excel into a tibble `meta`:

```r
library(tidyverse)
library(readxl)
library(janitor)

# Load the meta data from Excel
meta <- 
  read_excel("data/tweets_metadata.xlsx") |> 
  clean_names() # make column names nicer
```

Note that the function `clean_names` automatically fixes column names for us. In Excel, people tend to use speaking names with spaces in them. The function `clean_names` replaces those with underscores and resolves capital letters and more.

## Inner Join

An <mark style="background-color:yellow;">**inner join**</mark> returns only the rows that have matching values in both data sets. In other words, it only includes the observations that are common to both data sets. This type of join is useful when we want to exclude observations that do not have a match in the other data set. For example, if we take the data set with metadata about our Twitter users, we would effectively filter our tweets if we joined both using an inner join:

```r
tweets |> 
  inner_join(meta, by = join_by(screen_name == user_screenname), keep = TRUE) |>
  distinct(screen_name, user_screenname, party)
```

<img src="https://3926876715-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5u6uPm9RedbBzxioX29S%2Fuploads%2Fy5010BlM4ecpQc2tSKHx%2Ffile.excalidraw.svg?alt=media&amp;token=50279996-3686-4231-97d1-e0049704b672" alt="The INNER JOIN removes all rows that do not have matches in both tables." class="gitbook-drawing">

## Left and Right Join

A <mark style="background-color:yellow;">**left join**</mark> returns all the rows from the left data set and the matching rows from the right data set. If there is no match in the right data set, it will return NA values for the columns from that data set. This type of join is useful when we want to include all the observations from one data set and match them with the relevant observations from the other data set.

```r
# Keep all tweets, regardless of whether we have metadata for the user
tweets |> 
  left_join(meta, by = join_by(screen_name == user_screenname)) |> 
  distinct(screen_name, party)
```

<img src="https://3926876715-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5u6uPm9RedbBzxioX29S%2Fuploads%2FgFyrIam75h0V8TzouCF1%2Ffile.excalidraw.svg?alt=media&amp;token=3e4c0211-e8a4-4c3e-9fe8-50c79bb2089b" alt="The LEFT JOIN keeps all rows from the left table and fills missing matches with &#x22;NA&#x22;." class="gitbook-drawing">

A <mark style="background-color:yellow;">**right join**</mark> returns all the rows from the right data set and the matching rows from the left data set. If there is no match in the left data set, it will return NA values for the columns from that data set. This type of join is similar to the left join, but with the roles of the data sets reversed.

```r
# Keep all users from the meta data set, even if there are no tweets
tweets |> 
  right_join(meta, by = join_by(screen_name == user_screenname)) |> 
  distinct(screen_name, party)
```

<img src="https://3926876715-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5u6uPm9RedbBzxioX29S%2Fuploads%2FvY8D91eVQJ9QHVUcPdPX%2Ffile.excalidraw.svg?alt=media&amp;token=fe543242-78ac-47c3-afe0-9f09a0c9ad12" alt="The RIGHT JOIN keeps all rows from the right table and fills missing matches with &#x22;NA&#x22;." class="gitbook-drawing">

## Full Join

A full join returns all the rows from both data sets. If there is no match in one data set, it will return NA values for the columns from that data set. This type of join is useful when we want to combine all the observations from both data sets. However, it can also result in numerous missing values if there are many observations without a match.

```r
# Keep all rows from both data sets
tweets |> 
  full_join(meta, by = join_by(screen_name == user_screenname)) |> 
  distinct(screen_name, party)
```

<img src="https://3926876715-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F5u6uPm9RedbBzxioX29S%2Fuploads%2FqyNjVy8NR7LgVtcVZZw7%2Ffile.excalidraw.svg?alt=media&amp;token=8c1bb929-c94d-4740-b5cf-006ce09bdd5d" alt="The FULL JOIN keeps all rows from both tables and fills missing matches with &#x22;NA&#x22; on both sides." class="gitbook-drawing">
