Data

This is an analysis of Let’s Go To Court episodes based on this spreadsheet.

This information is incomplete; this file will be periodically updated as more information is added.

The spreadsheet was started by stephhayes and bizzybee429 on the Let’s Go To Court Patreon discord server and has been contributed to by many other members.

Setup

Load Packages

library(googlesheets4)
library(skimr)
library(tidyverse)
library(knitr)
library(textTinyR)
library(textstem)
library(tidytext)
library(tm)
library(wordcloud)
library(stringr)
library(patchwork)

Load data

The googlesheets4 package is used to load the data via the Sheet API V4.

sheet_key <- "1fjcQMWOd-nlz3OUZ3f3MdCYAkJXJWN-2fsVSDu0bB_U" 
# sheet_key is a static reference to the sheet

sheet <- gs4_get(sheet_key)

# Get Sheet 1 - regular episodes
datareg <- read_sheet(sheet, sheet = 1) %>%
  mutate(type = 'Regular') 

# Get Sheet 2 - bonus episodes
databonus <- read_sheet(sheet, sheet = 2) %>%
  mutate(type = 'Bonus') %>%
  rename(`...1` = `Episode Number`,
         `...5` = `Brandi's Case`) # renaming for consistency to allow merge of datasets

# Combine into one dataset - 'stacks' both on top of each other
data <- bind_rows(datareg, databonus) 

Clean Data

During cleaning I have

  • removed columns that I’m not using

  • renamed the columns for easier reference

  • made the episode number numeric

  • removed episodes with empty titles - the spreadsheet is pre-numbered for future episodes so these extra rows need to be removed.

data_clean <- data %>%
  select(-`Inside Joke Origin`, 
         -`Discord Questions Answered`, 
         -`Interesting Facts/Anecdotes`, 
         -`Release Date`) %>%
  rename(episode_num = `...1`,
         title = `Episode Title`,
         summary = `Episode summary/Show notes`,
         b_case = `...5`,
         b_disc = `Brandi's Disclaimers`,
         k_case = `Kristin's Case`,
         k_disc = `Kristin's Disclaimers`,
         after_dark = `After Dark?`,
         fun_facts = `Tim Pound's Fun Facts`,
         not_fun_facts = `Kristin's Not-So-Fun Fun Facts`,
         guests = Guests,
         guest_case = `Guest's Case`,
         songs = `Songs Sung`,
         k_source = `Kristin's Sources`,
         b_source = `Brandi's Sources`,
         g_source = `Guest's Sources`) %>%
  mutate(episode_num = as.numeric(sub("#", "", episode_num))) %>%
  filter(!is.na(title))

Quick Look at Cleaned Data

skim(data_clean)
Data summary
Name data_clean
Number of rows 282
Number of columns 17
_______________________
Column type frequency:
character 16
numeric 1
________________________
Group variables None

Variable type: character

skim_variable n_missing complete_rate min max empty n_unique whitespace
title 0 1.00 5 83 0 281 0
summary 172 0.39 525 1467 0 110 0
b_case 163 0.42 3 52 0 118 0
b_disc 278 0.01 20 24 0 3 0
k_case 170 0.40 4 75 0 112 0
k_disc 270 0.04 20 49 0 7 0
after_dark 274 0.03 1 3 0 3 0
fun_facts 277 0.02 26 96 0 5 0
not_fun_facts 278 0.01 56 94 0 4 0
guests 271 0.04 2 45 0 8 0
guest_case 275 0.02 4 45 0 6 0
songs 269 0.05 15 189 0 13 0
k_source 200 0.29 34 1644 0 82 0
b_source 202 0.28 8 1125 0 80 0
g_source 278 0.01 8 276 0 4 0
type 0 1.00 5 7 0 2 0

Variable type: numeric

skim_variable n_missing complete_rate mean sd p0 p25 p50 p75 p100 hist
episode_num 0 1 105.45 73.35 1 36 98.5 169.75 240 ▇▅▅▅▅

Disclaimers

Filter Disclaimers

Here I’m filtering for just the two disclaimer columns then pivoting them into a tidy data format and removing blanks. There is some inconsistency in capitalisation in the ‘disclaimer’ column so I’ve also standardised this.

b_disclaimers <- data_clean %>%
  select(episode_num, title, b_case, b_disc, type) %>%
  rename(disclaimer = b_disc,
         case = b_case) %>%
  mutate(name = 'Brandi') %>%
  filter(!is.na(disclaimer))

k_disclaimers <- data_clean %>%
  select(episode_num, title, k_case, k_disc, type) %>%
  rename(disclaimer = k_disc,
         case = k_case) %>%
  mutate(name = "Kristin") %>%
  filter(!is.na(disclaimer))

disclaimers <- bind_rows(b_disclaimers, k_disclaimers) %>%
  separate_rows(disclaimer, sep = " and ") %>%
  arrange(episode_num) %>%
  mutate(disclaimer = case_when(
    disclaimer == 'old Timey Disclaimer' ~ 'Old Timey Disclaimer',
    disclaimer == 'Old timey case, but no proper disclaimer' ~ 'Old Timey Disclaimer',
    disclaimer == 'International Case Disclaimer' ~ 'International Disclaimer',
    TRUE ~ disclaimer
  ))

View Disclaimers

kable(disclaimers, col.names = c("Ep Number", "Title", "Case", "Disclaimers", "Episode Type", "Name"))
Ep Number Title Case Disclaimers Episode Type Name
3 Unsolved Cases Mysterious Death of Roland T. Owen Old Timey Disclaimer Bonus Kristin
6 A Murder on a Greyhound Bus & the First Time “The Scream” Was Stolen “The Scream” is stolen International Disclaimer Bonus Kristin
7 Heidi Fleiss & Dr. Hawley Harvey Crippen The Murder of Cora Crippen Old Timey Disclaimer Bonus Kristin
9 The Disappearance of Lori Hacking & a Woman Who Wrote Bad Checks A Woman Who Wrote Back Checks Old Timey Disclaimer Bonus Kristin
17 Martha Moxley & Blanche Monnier Blanche Monnier Old Timey Disclaimer Bonus Kristin
24 The Charming Kidnappers & the Swope Family Murders (?) The Charming Kidnappers Old Timey Disclaimer Regular Brandi
24 The Charming Kidnappers & the Swope Family Murders (?) The Swope Family Murders (?) Old Timey Disclaimer Regular Kristin
56 Fugitive Slave Anthony Burns & the Power of Suggestion (Part 2) Anthony Burns Old Timey Disclaimer Regular Kristin
91 Fatty Arbuckle & Strangers with Candy NA Old Timey Disclaimer Regular Brandi
91 Fatty Arbuckle & Strangers with Candy NA Old Timey Disclaimer Regular Kristin
95 Mob Bosses! (a.k.a. Bob Mosses) Al Capone Old Timey Disclaimer Regular Brandi
95 Mob Bosses! (a.k.a. Bob Mosses) Dutch Schultz Old Timey Disclaimer Regular Kristin
110 The Murder of Emmett Till & Justice for Cyntoia Brown Emmett Till Old Timey Disclaimer Regular Kristin
110 The Murder of Emmett Till & Justice for Cyntoia Brown Emmett Till Racism Disclaimer Regular Kristin
114 The Biggest Idiot Ever & a Woman Who Refused to Marry a Rapist NA Old Timey Disclaimer Regular Kristin
114 The Biggest Idiot Ever & a Woman Who Refused to Marry a Rapist NA International Disclaimer Regular Kristin
115 Pepsi’s Big Mistake & the Murder of Skylar Neese NA International Disclaimer Regular Brandi
212 An Australian Catfish & Domestic Violence An Australian Catfish International Disclaimer Regular Kristin

Summarise

Summarising the data for plotting.

summary_disc <- disclaimers %>%
  count(name, disclaimer) %>%
  rename(count = n) 

Plot

# Set custom colours
colours <- RColorBrewer::brewer.pal(5, "Accent")
disc_colours <- c(colours[1], colours[5])


# Plot
ggplot(summary_disc, aes(x = disclaimer, y = count, fill = name)) +
  geom_bar(stat = "identity") +
  scale_fill_manual(values = disc_colours) +
  labs(title = "Disclaimer Counts by Host",
       y = "Count",
       fill = "Name") +
  theme_minimal() + 
  theme(legend.position = "right", 
        legend.title = element_blank(), 
        axis.text.x = element_text(angle = 45, hjust = 1), 
        axis.title.x = element_blank(),
        axis.title.y = element_blank())


Kristin uses a lot more disclaimers than Brandi, especially the Old Timey Disclaimer.

Top Words in Summary

These are the words that are most used in the ‘summary’ column.

Process data

remove <- "WARNING: The audio in this episode is rough\\. What can we say\\? We were young\\(ish\\), dumb, and thought we’d save a little money by sharing one microphone\\. Yeah\\. The audio quality improves drastically after episode 9\\."

word_df <- data_clean %>%
  mutate(
    summary = str_replace_all(summary, remove, ""),
    summary = str_replace_all(summary, "(?<!\\d)-(?!\\d)", " ") %>%
    str_replace_all("[^A-Za-z\\s]", "")
  ) %>%
  unnest_tokens(word, summary) %>%
  mutate(word = lemmatize_words(word)) %>%
  anti_join(stop_words) %>%
  filter(!is.na(word)) %>%
  filter(!word %in% c("kristin", "brandi"))

word_counts <- word_df %>%
  group_by(word) %>%
  summarise(count = n()) %>%
  arrange(desc(count))

top_words <- word_counts %>%
  top_n(n=20, wt=count)

Plot

ggplot(top_words, aes(x = count, y = fct_reorder(word, count))) +
  geom_bar(stat = "identity", fill = disc_colours[1], alpha = 0.8) +
  labs(title = "Top Words Used in Episode Summary", x = "Count", y = "") +
  theme_minimal() +
  theme(axis.title.y = element_blank())

Word Cloud

wordcloud(
  words = word_df$word,
  scale = c(3, 0.5),
  min.freq = 15, 
  random.order = FALSE, 
  colors = brewer.pal(8, "Dark2")
)

Guests

Prepare Data

Here I’m selecting for episodes with a value for ‘guests’ then standardising the value for each person’s name. Non-name information from the ‘guests’ column is moved into the ‘Notes’ column.

guests <- data_clean %>%
  select(type, episode_num, title, guests, guest_case) %>%
  filter(!is.na(guests)) %>%
  mutate(guest = case_when(
    grepl("norm|norman", guests, ignore.case = TRUE) ~ "Norman",
    grepl("dp|daryl", guests, ignore.case = TRUE) ~ "DP",
    TRUE ~ guests
  )) %>%
  mutate(Notes = str_replace_all(guests, c("Norman" = "", "Norm" = "", "Caruso" = "", "DP" = "", "Daryl" = ""))) %>%
  select(-guests) %>%
  mutate(Notes = str_trim(str_replace(Notes, "^[[:punct:][:space:]]+", "")),
         guest_case = coalesce(guest_case, "None")) %>%
  select(type, episode_num, title, guest, guest_case, Notes) %>%
  arrange(type, episode_num) 

View Guest Table

kable(guests, col.names = c("Episode Type", "Episode Num", "Title", "Guest", "Case", "Notes"))
Episode Type Episode Num Title Guest Case Notes
Bonus 3 Unsolved Cases Norman None doesn’t present a case
Bonus 12 The Excedrin Murders Norman None
Bonus 41 We dug up Norm! Norman Murder of Milton Sawyer (Elizabeth City case)
Regular 12 Video Game Lawsuits with the Gaming Historian Norman Atari Games vs Nintendo
Regular 22 Food Lawsuits with the Gaming Historian Norman Hit by a flying hot dog
Regular 49 Cheaters… with Daryl Pitts! DP Murder of Emmet Corrigan The one and only
Regular 52 A Celebrity Stalker & the Blended Family DP None calls and wants to be put on speaker phone
Regular 75 The Jenny Jones Show & Brandi’s Most Horrifying Case Norman None moderates the Q&A
Regular 83 Bad Dads! (Featuring DP) DP None
Regular 91 Fatty Arbuckle & Strangers with Candy Norman None
Regular 235 Prepare to be DP’d! DP Ira Bernstein

Summarise for Plot

guest_summary <- guests %>%
  group_by(guest) %>%
  summarise(count = n())

Plot

ggplot(guest_summary, aes(x = guest, y = count, fill = guest)) +
  geom_bar(stat = "identity") +
  labs(title="Visitor Counts",
       y="Count") +
  theme_minimal() + 
  theme(axis.title.x = element_blank(),
        legend.position = "none")


DP needs to make a few more appearances to catch up!

Songs

Data Preparation

I’ve filtered the data for episodes where there is a value for ‘songs’ and summarised it by episode type (regular or bonus).

songs <- data_clean %>%
  select(type, episode_num, title, songs) %>%
  filter(!is.na(songs))

song_type <- songs %>%
  group_by(type) %>%
  summarise(count = n()) %>%
  mutate(percentage = count / sum(count) * 100)

Plot

g1 <- ggplot(song_type, aes(x = "", y = count, fill = type)) +
  geom_bar(width = 1, stat = "identity") +
  geom_text(aes(label = paste0(round(percentage), "%")), 
            position = position_stack(vjust = 0.5)) +
  coord_polar(theta = "y") +
  theme_minimal() +
  theme(axis.line = element_blank(),
        axis.text = element_blank(),
        axis.ticks = element_blank(),
        panel.grid = element_blank(),
        plot.margin = unit(rep(0, 4), "cm"),
        plot.background = element_blank()) +  # Remove plot background
  labs(title = "Episodes with Songs",
       fill = "Episode Type",
       y = "Count") +
  theme_void() +
  scale_fill_manual(values = disc_colours)

# Compare to overall episodes
overall_count <- data_clean %>%
  group_by(type) %>%
  summarise(count = n()) %>%
  mutate(percentage = count / sum(count) * 100)

g2 <- ggplot(overall_count, aes(x = "", y = count, fill = type)) +
  geom_bar(width = 1, stat = "identity") +
  geom_text(aes(label = paste0(round(percentage), "%")), 
            position = position_stack(vjust = 0.5)) +
  coord_polar(theta = "y") +
  theme_minimal() +
  theme(axis.line = element_blank(),    # Remove the axis line
        axis.text = element_blank(),    # Remove axis text
        axis.ticks = element_blank(),   # Remove axis ticks
        panel.grid = element_blank(),   # Remove grid lines
        plot.margin = unit(rep(0, 4), "cm"),
        plot.background = element_blank()) +  # Remove plot background
  labs(title = "Episodes Overall",
       fill = "Episode Type",
       y = "Count") +
  theme_void() +
  scale_fill_manual(values = disc_colours)

(g1 | g2) + plot_layout(guides = "collect")


Bonus episodes make up just 15% of all episodes but account for 31% of episodes with songs sung.

Tim Pound’s Fun Facts

Get out your Fun Fact Journal

Brandi sometimes shares fun facts about her dad. If you haven’t kept track of them in your own Fun Fact Journal, they’re summarised for you here.

tim_pound <- data_clean %>%
  select(episode_num, title, fun_facts) %>%
  filter(!is.na(fun_facts)) %>%
  arrange(episode_num)

kable(tim_pound, col.names = c("Episode Num", "Episde", "Tim Pound's Fun Facts"))
Episode Num Episde Tim Pound’s Fun Facts
52 A Celebrity Stalker & the Blended Family Lunch time Bold and the Beautiful routine
114 The Biggest Idiot Ever & a Woman Who Refused to Marry a Rapist Tim Pounds was born in 1963, graduated from highschool in 1981, and watched the Olympics in 1996
115 Pepsi’s Big Mistake & the Murder of Skylar Neese Tim Pounds got divorced in 1992.
124 The Chicago Tylenol Murders and Corruption in Kansas City October 3rd is Tim and Lisa Pound’s Wedding Anniversary
204 Wells Fargo Robbery & a Mysterious Illness Tim’s middle name is David

Kristin’s Not-So-Fun Fun Facts

Some of us have different definitions of ‘fun’

not_fun_facts <- data_clean %>%
  select(episode_num, title, not_fun_facts) %>%
  filter(!is.na(not_fun_facts)) %>%
  arrange(episode_num)

kable(not_fun_facts, col.names = c("Episode Num", "Episode", "Kristin's Not-So-Fun Fun Facts"))
Episode Num Episode Kristin’s Not-So-Fun Fun Facts
4 A Forbidden Love & Stupid Pranks Our fav dummies prepared the same case for this week, Kristin had to pull a case outta nowhere
52 A Celebrity Stalker & the Blended Family AKA Kristin Tits the pack a day smoker with a deep voice
64 Trapped in a Burger King & Eccentric Millionaire John du Pont The plaintiff in Kristins case is a registered sex offender :(
111 Chocolate Candy Murders & the Wrongful Conviction of Scott Hornoff Kristin accidentally posted the question to the Gaming Historian Discord