The hot dogs and buns contest is an international competition where competitors try to eat the most hot dogs in 12 minutes (formerly 10 minutes). I am going to scrape data on the contest from Wikipedia for visualization purposes.
The goal is to visualize the winners of the contest each year and to highlight each new record established. To do so, I am going to need the name of the winner, the year, and new record info.
N.B: The original idea of the graph comes from the awesome book “Visualize This” by Nathan Yau. Nevertheless, I am going to do it my way by scraping and organizing data instead of downloading the clean CSV file from http://datasets.flowingdata.com/hot-dog-contest-winners.csv.
# install.packages("tidyverse")
library(rvest)
URL = "https://en.wikipedia.org/wiki/Nathan%27s_Hot_Dog_Eating_Contest"
webpage = read_html(URL)
# get all tables on the wikipedia pages
tables <- webpage %>% html_elements("table")
# the second table is the one that contains our data
# R indices start with 1 :)
hdb_winners <- tables[2]
hdb_winners
## {xml_nodeset (1)}
## [1] <table class="wikitable plainrowheaders sortable"><tbody>\n<tr>\n<th>Year ...
hdb_winners_rows <- hdb_winners %>%
html_elements("tr") %>%
html_text2()
print(hdb_winners_rows[1:5])
## [1] "Year\tWinner\n(and date, if prior to permanently moving all contests to Independence Day in 1997)\tHot dogs and buns\n(HDB)\tContest duration\tNote(s)"
## [2] "2022\tMEN'S\nJoey Chestnut\t63a\t10 min.\tMiki Sudo returns from her pregnancy to reclaim her title. After being shoved from the table, Joey Chestnut puts a protester who ran onto the stage during the event in a chokehold. Geoffrey Esper (47 HDB) finished second. James Webb (41 HDB) finished third."
## [3] "WOMEN'S\nMiki Sudo\t40"
## [4] "2021\tMEN'S\nJoey Chestnut\t76\t10 min.\tThe event is held at Maimonides Park due to capacity restrictions and other health and safety requirements. Joey Chestnut breaks the world record with 76 HDB. Defending champion Miki Sudo was out due to her pregnancy."
## [5] "WOMEN'S\nMichelle Lesco\t30¾"
hdb_winners_rows <- hdb_winners_rows[-1]
print(hdb_winners_rows[1:5])
## [1] "2022\tMEN'S\nJoey Chestnut\t63a\t10 min.\tMiki Sudo returns from her pregnancy to reclaim her title. After being shoved from the table, Joey Chestnut puts a protester who ran onto the stage during the event in a chokehold. Geoffrey Esper (47 HDB) finished second. James Webb (41 HDB) finished third."
## [2] "WOMEN'S\nMiki Sudo\t40"
## [3] "2021\tMEN'S\nJoey Chestnut\t76\t10 min.\tThe event is held at Maimonides Park due to capacity restrictions and other health and safety requirements. Joey Chestnut breaks the world record with 76 HDB. Defending champion Miki Sudo was out due to her pregnancy."
## [4] "WOMEN'S\nMichelle Lesco\t30¾"
## [5] "2020\tMEN'S\nJoey Chestnut\t75\t10 min.\tFirst time event is being held indoors without fans caused by the COVID-19 pandemic. Joey Chestnut breaks the world record with 75 HDB. Darron Breeden (42 HDB) finished second. Nick Wehry (39.5 HDB) finished third. Miki Sudo breaks the women's world record with 48.5 HDB."
We take data from 1997 till 2022 since data is inconsistent before and then split each row to extract the columns.
winners <- c()
last_year <- 38
for ( i in 1:last_year ) {
tmp <- strsplit(hdb_winners_rows[i], split = '\t')
winners <- c(winners, tmp)
}
print(hdb_winners_rows[1:4])
## [1] "2022\tMEN'S\nJoey Chestnut\t63a\t10 min.\tMiki Sudo returns from her pregnancy to reclaim her title. After being shoved from the table, Joey Chestnut puts a protester who ran onto the stage during the event in a chokehold. Geoffrey Esper (47 HDB) finished second. James Webb (41 HDB) finished third."
## [2] "WOMEN'S\nMiki Sudo\t40"
## [3] "2021\tMEN'S\nJoey Chestnut\t76\t10 min.\tThe event is held at Maimonides Park due to capacity restrictions and other health and safety requirements. Joey Chestnut breaks the world record with 76 HDB. Defending champion Miki Sudo was out due to her pregnancy."
## [4] "WOMEN'S\nMichelle Lesco\t30¾"
winners <- rev(winners)
print(winners[35:38])
## [[1]]
## [1] "WOMEN'S\nMichelle Lesco" "30¾"
##
## [[2]]
## [1] "2021"
## [2] "MEN'S\nJoey Chestnut"
## [3] "76"
## [4] "10 min."
## [5] "The event is held at Maimonides Park due to capacity restrictions and other health and safety requirements. Joey Chestnut breaks the world record with 76 HDB. Defending champion Miki Sudo was out due to her pregnancy."
##
## [[3]]
## [1] "WOMEN'S\nMiki Sudo" "40"
##
## [[4]]
## [1] "2022"
## [2] "MEN'S\nJoey Chestnut"
## [3] "63a"
## [4] "10 min."
## [5] "Miki Sudo returns from her pregnancy to reclaim her title. After being shoved from the table, Joey Chestnut puts a protester who ran onto the stage during the event in a chokehold. Geoffrey Esper (47 HDB) finished second. James Webb (41 HDB) finished third."
We notice that during the same year, the man and the woman share the year, the duration and the grades. This shared data is stored in the man’s row. The woman’s row contains only the name and the number of hot dogs and buns consumed.
With that said, let’s add the missing data to the woman’s row.
Between 2011 - 2022, there’s a text (“MEN’S” or “WOMEN’S”) before the
name to indicate the gender. To deal with these years, we check if the
name starts with “MEN’S” or “WOMEN’S”. If it does, we extract only the
name.
E.g.: “WOMEN’S\nMiki Sudo” will result in “Miki Sudo”.
women <- array(dim=c(12, 5))
men_nrows = length(winners)- nrow(women) # 38 - 12 = 26 rows
men <- array(dim = c( men_nrows, 5) )
j = 1
k = 1
for ( i in 1:length(winners) ) {
# For women, append year, duration, notes
if (startsWith(winners[[i]][1], "WOMEN'S")) {
# stealing info from the man's data
year <- winners[[i+1]][1]
duration <- winners[[i+1]][4]
notes <- winners[[i+1]][5]
# getting the woman info
# extract name (column 1 for women)
name = strsplit(winners[[i]][1], split = '\n')[[1]][2]
nb_hdogs = winners[[i]][2]
# filling in each row of the women array
women[j,] <- c( year, name, nb_hdogs, duration, notes)
j <- j+1
} else {
men[k,] <- winners[[i]]
# extract name (column 2 for men)
if (startsWith(winners[[i]][2], "MEN'S")) {
men[k,2] <- strsplit(winners[[i]][2], split = '\n')[[1]][2]
} else {
men[k,2] <- winners[[i]][2]
}
k <- k+1
}
}
print(women[1,])
## [1] "2011"
## [2] "Sonya Thomas"
## [3] "40"
## [4] "10 min."
## [5] "Separate competitions are held for women and men for the first time. Chestnut dominates on his way to his fifth straight title. Sonya Thomas (40 HDB) won the inaugural women's event. Patrick Bertoletti (53) and Tim \"Eater X\" Janus (45) finish 2nd and 3rd for the second year in a row."
print(men[1,])
## [1] "1997"
## [2] "Hirofumi Nakajima\n"
## [3] "24½"
## [4] "12 min."
## [5] "Although Nathan's attempted to expand its pool of American contestants by sponsoring \"a circuit of qualifying contests leading up to the grand finale on the Fourth,\"[36] Japanese contestants continued to increase their influence. The contest was won by the reigning champion, a 135-pound, 22 year old furniture delivery worker from Kōfu, Japan. The prizes were \"a large emerald and brass trophy, a Mustard-Yellow International Belt, and a 20-pack take-out order for Nathan's hot dogs.\" 100-pound, 30 year old future champion Kazutoyo Arai of Saitama, Japan was the runner-up and consumed 24 hot dogs. 330-pound, 34 year old former champion Ed Krachie was the third-place finisher and consumed 20 hot dogs. 23 contestants participated. A press account from the time describes this as an annual contest held regularly since 1916.[37]"
Now, I see another problem here. “Hot dogs and buns eaten” and “Duration” often contain characters.
The regex expression \\D*(\\d+).*", "\\1 extracts the
first number in a string. We use it to retrieve the first number in
“Hots dogs and buns eaten” and in “Duration”.
Also note that we use nrow() instead of
length() which returns rows X cols.
for ( i in 1:nrow(women) ) {
# HDB eaten
women[i,3] <- as.numeric(gsub("\\D*(\\d+).*", "\\1", women[i,3]))
# duration
women[i,4] <- as.numeric(gsub("\\D*(\\d+).*", "\\1", women[i,4]))
}
women[1,]
## [1] "2011"
## [2] "Sonya Thomas"
## [3] "40"
## [4] "10"
## [5] "Separate competitions are held for women and men for the first time. Chestnut dominates on his way to his fifth straight title. Sonya Thomas (40 HDB) won the inaugural women's event. Patrick Bertoletti (53) and Tim \"Eater X\" Janus (45) finish 2nd and 3rd for the second year in a row."
for ( i in 1:nrow(men) ) {
# HDB eaten
men[i,3] <- as.numeric(gsub("\\D*(\\d+).*", "\\1", men[i,3]))
# duration
men[i,4] <- as.numeric(gsub("\\D*(\\d+).*", "\\1", men[i,4]))
}
men[1,]
## [1] "1997"
## [2] "Hirofumi Nakajima\n"
## [3] "24"
## [4] "12"
## [5] "Although Nathan's attempted to expand its pool of American contestants by sponsoring \"a circuit of qualifying contests leading up to the grand finale on the Fourth,\"[36] Japanese contestants continued to increase their influence. The contest was won by the reigning champion, a 135-pound, 22 year old furniture delivery worker from Kōfu, Japan. The prizes were \"a large emerald and brass trophy, a Mustard-Yellow International Belt, and a 20-pack take-out order for Nathan's hot dogs.\" 100-pound, 30 year old future champion Kazutoyo Arai of Saitama, Japan was the runner-up and consumed 24 hot dogs. 330-pound, 34 year old former champion Ed Krachie was the third-place finisher and consumed 20 hot dogs. 23 contestants participated. A press account from the time describes this as an annual contest held regularly since 1916.[37]"
For visualization purpose, it might be interesting to have a record column to see if the number of hot dogs and buns eaten was a new record that year.
record <- 0
women_records <- c()
for ( i in 1:nrow(women) ) {
if (women[i,3] > record) {
record <- women[i,3]
women_records <- c(women_records, 1)
} else {
women_records <- c(women_records, 0)
}
}
women_records
## [1] 1 1 0 0 0 0 0 0 0 1 0 0
record <- 0
men_records <- c()
for ( i in 1:nrow(men) ) {
if (men[i,3] > record) {
record <- men[i,3]
men_records <- c(men_records, 1)
} else {
men_records <- c(men_records, 0)
}
}
men_records
## [1] 1 0 0 1 1 0 0 1 0 0 1 0 1 0 0 0 1 0 0 1 1 1 0 1 1 0
women <-cbind(women, women_records)
men <-cbind(men, men_records)
print(women[1,])
##
## "2011"
##
## "Sonya Thomas"
##
## "40"
##
## "10"
##
## "Separate competitions are held for women and men for the first time. Chestnut dominates on his way to his fifth straight title. Sonya Thomas (40 HDB) won the inaugural women's event. Patrick Bertoletti (53) and Tim \"Eater X\" Janus (45) finish 2nd and 3rd for the second year in a row."
## women_records
## "1"
print(men[1,])
##
## "1997"
##
## "Hirofumi Nakajima\n"
##
## "24"
##
## "12"
##
## "Although Nathan's attempted to expand its pool of American contestants by sponsoring \"a circuit of qualifying contests leading up to the grand finale on the Fourth,\"[36] Japanese contestants continued to increase their influence. The contest was won by the reigning champion, a 135-pound, 22 year old furniture delivery worker from Kōfu, Japan. The prizes were \"a large emerald and brass trophy, a Mustard-Yellow International Belt, and a 20-pack take-out order for Nathan's hot dogs.\" 100-pound, 30 year old future champion Kazutoyo Arai of Saitama, Japan was the runner-up and consumed 24 hot dogs. 330-pound, 34 year old former champion Ed Krachie was the third-place finisher and consumed 20 hot dogs. 23 contestants participated. A press account from the time describes this as an annual contest held regularly since 1916.[37]"
## men_records
## "1"
Women first, as always :)
colnames(women) <- c("Year", "Name", "Hot dogs and buns eaten", "Duration (min)", "Notes", "isRecord")
df_women = data.frame(women)
print(df_women[1:2,])
## Year Name Hot.dogs.and.buns.eaten Duration..min.
## 1 2011 Sonya Thomas 40 10
## 2 2012 Sonya Thomas 45 10
## Notes
## 1 Separate competitions are held for women and men for the first time. Chestnut dominates on his way to his fifth straight title. Sonya Thomas (40 HDB) won the inaugural women's event. Patrick Bertoletti (53) and Tim "Eater X" Janus (45) finish 2nd and 3rd for the second year in a row.
## 2 Chestnut tied his previous record, previously set in 2009. He also became the second person to win six consecutive titles. Thomas set a new women's record. Tim Janus (52.25) and Patrick Bertoletti (51) finish second and third once again, this time with Janus edging out for second place. Matt Stonie, who would go on to claim victory in 2015 finished fourth with 46 HDB. Thomas (45 HDB) broke the female record, beating Juliet Lee (33 HDB).
## isRecord
## 1 1
## 2 1
colnames(men) <- c("Year", "Name", "Hot dogs and buns eaten", "Duration (min)", "Notes", "isRecord")
df_men = data.frame(men)
print(df_men[1:2,])
## Year Name Hot.dogs.and.buns.eaten Duration..min.
## 1 1997 Hirofumi Nakajima\n 24 12
## 2 1998 Hirofumi Nakajima 19 12
## Notes
## 1 Although Nathan's attempted to expand its pool of American contestants by sponsoring "a circuit of qualifying contests leading up to the grand finale on the Fourth,"[36] Japanese contestants continued to increase their influence. The contest was won by the reigning champion, a 135-pound, 22 year old furniture delivery worker from Kōfu, Japan. The prizes were "a large emerald and brass trophy, a Mustard-Yellow International Belt, and a 20-pack take-out order for Nathan's hot dogs." 100-pound, 30 year old future champion Kazutoyo Arai of Saitama, Japan was the runner-up and consumed 24 hot dogs. 330-pound, 34 year old former champion Ed Krachie was the third-place finisher and consumed 20 hot dogs. 23 contestants participated. A press account from the time describes this as an annual contest held regularly since 1916.[37]
## 2 The contest was won by the reigning champion, a 135-pound, 23 year old furniture delivery worker from Kōfu, Japan. The prizes were "the coveted mustard-yellow International Belt, a huge red trophy, and 20 pounds of Nathan's hot dogs."[33] A 387-pound, 29 year old corrections officer from Brooklyn, Charles "Hungry" Hardy, was the runner-up and consumed 17½ hot dogs.[34] 381-pound, 35 year old mechanical engineer and former champion Ed Krachie came out of retirement in a vain attempt to break Japan's win streak but was the third-place finisher and consumed 14 hot dogs. A 53 year old haggis-eating champion from the United Kingdom, Barry Noble, also participated. In all, 16 contestants participated.[35]
## isRecord
## 1 1
## 2 0
Finally, oh yeah… I said FINALLY! we convert “Year”, “Hot dogs and buns eaten”, and”Duration” to numeric.
df_women$Year = as.numeric(df_women$Year)
df_women$Hot.dogs.and.buns.eaten = as.numeric(df_women$Hot.dogs.and.buns.eaten)
df_women$Duration..min. = as.numeric(df_women$Duration..min.)
print(paste("Year: ", class(df_women$Year)))
## [1] "Year: numeric"
print(paste("Hot.dogs.and.buns.eaten: ", class(df_women$Hot.dogs.and.buns.eaten)))
## [1] "Hot.dogs.and.buns.eaten: numeric"
print(paste("Duration: ", class(df_women$Duration..min.)))
## [1] "Duration: numeric"
df_men$Year = as.numeric(df_men$Year)
df_men$Hot.dogs.and.buns.eaten = as.numeric(df_men$Hot.dogs.and.buns.eaten)
df_men$Duration..min. = as.numeric(df_men$Duration..min.)
print(paste("Year: ", class(df_men$Year)))
## [1] "Year: numeric"
print(paste("Hot.dogs.and.buns.eaten: ", class(df_men$Hot.dogs.and.buns.eaten)))
## [1] "Hot.dogs.and.buns.eaten: numeric"
print(paste("Duration: ", class(df_men$Duration..min.)))
## [1] "Duration: numeric"
Whew! It was hell of an adventure. Now it’s time to have fun! Let’s make some nice plots to visualize our clean data.
# Highlighting records
fill_colors <- c()
for ( i in 1:nrow(df_men) ) {
if (df_men$isRecord[i] == 1)
fill_colors <- c(fill_colors, "#29966c")
else
fill_colors <- c(fill_colors, "#cccccc")
}
barplot(df_men$Hot.dogs.and.buns.eaten, names.arg=df_men$Year, col=fill_colors,
border=NA, space=0.3, xlab='Year', ylab="Hot dogs and buns (HDB) eaten",
main = "Nathan's Hot Dog Eating Contest Results, 1997 - 2022")
The previous bar graph is good for analysis, but not it is
publication-ready.
Let’s edit it and tell the story behind the data.
Let’s compare women and men. The goal is to introduce a new category to the plot: the gender.
# HDBs eaten (2011-2022)
women_nb_HDB_eaten <- df_women$Hot.dogs.and.buns.eaten
men_nb_HDB_eaten <- df_men[df_men$Year >= 2011, ]$Hot.dogs.and.buns.eaten
# years as column names
years <- df_women$Year
women_men <- array(dim=c(2, length(years)))
women_men[1,] <- men_nb_HDB_eaten
women_men[2,] <- women_nb_HDB_eaten
colnames(women_men) <- c(years)
Who eats the most hot dogs and buns?
barplot(women_men, border=NA, space=0.25, ylim=c(0, 160),
col = c("#023e8a", "#ff4d6d"),
xlab="Year", ylab="Hot dogs and buns (HDBs) eaten",
main="Hot Dog Eating Contest Results, 2011-2022")
I find it more intuitive to compare the values with horizontal stacked bars.
barplot(women_men, border=NA, space=0.5, horiz=TRUE, las=1,
col = c("#023e8a", "#ff4d6d"), xlim=c(0,140),
xlab="Hot dogs and buns (HDBs) eaten", ylab="Year",
main="Hot Dog Eating Contest Results, 2011-2022")
When I started this project, I didn’t know much about R syntax, which explains why I spent a lot of time trying to understand how vectors, matrix, 2D array work. I have encountered many challenges, but hey, it didn’t stop me. I know it might seem like it is nothing for more experienced Data scientist, but for me it’s a big and motivating step towards my future bigger projects!
I stopped here, but I could have also extracted data from previous years and years when there were multiple competitions.
MISSING_INFO = c(“1973”, “1968-1971”, “1976-1977”)
MULTIPLE_CONTEST_IN_A_YEAR = c(1972, 1974, 1986, 1993, 1996)
Blooper 1: The 2008 year seemed completely off because I extracted number 595 from “59 Eat-off: 5”. I fixed my regex pattern to extract only the first number.
Blooper 2: The plot heights were all the same because I inadvertently
put the year inside the number of hot dogs eaten and buns.
df_men$Hot.dogs.and.buns.eaten = as.numeric(df_men$Year)
Blooper 3: I was looping through length() of a 2D array instead of the number of rows. So I was getting an “out of bound” error.
Blooper 4: Before 2011, there was no “MEN’S” before the row, but I was trying to split the strings to remove a “MEN’S” that did not exist. Which explains why I got a data frame full of “NA”.
Blooper 5: At first I didn’t sort the data in ascending year, so I had to loop through the arrays from the end to create new records, which gave me 2 reversed vectors of records which did not match with the men and women arrays. Sorting by year before merging fixed it though.
Blooper 6: When I sorted the table though, it created an issue I only noticed later. At first, I was retrieving data from the previous row (the man i-1) to store it in the current row (the woman). After sorting I had to replace it by the next row (e.g.: year <- winners[[i+1]][1]).
Blooper 7: All the challenges I bumped on and forgot about :)