Cleaning dates
clean-dates.RmdBelow we’ll fetch the live USADA sanctions data and process the text:
usada_raw <- get_sanctions_data()
usada <- process_text(raw_data = usada_raw)Dates
sanction_announced contains the date the sanction was
announced, and some of these contain two values (original
and updated). Wrangling these values pose some challenges
because they aren’t consistently messy:
bad_dates <- subset(usada,
grepl("^original", usada[['sanction_announced']]),
c(athlete, sanction_announced))
bad_dates
#> athlete sanction_announced
#> 4 boyle, evan original: 04/24/2026; updated: 09/09/2026
#> 30 mitchell, manteo original: 09/26/2025; updated: 02/25/2026
#> 54 qualls, robert jerry original: 06/26/2024; updated: 08/13/2025
#> 126 jha, kanak original: 3/20/2023; updated: 12/01/2023
#> 210 prempeh, ernest original: 05/07/2019; updated: 02/04/2022
#> 213 ngetich, eliud original: 09/03/21; updated: 01/25/22
#> 243 gehm, zach original: 11/04/2019;updated: 05/17/2021
#> 274 hudson, ryan original 12/20/2018; updated 11/04/2020
#> 278 paparella, flavia original: 10/19/2020updated: 01/05/2021
#> 289 murdock, vince original: 09/05/2019; updated: 08/26/2020
#> 293 rante, danielle original: 07/22/2020, updated: 11/03/2022
#> 322 werdum, fabricio original 09/11/2018; updated 01/16/2020
#> 334 jones, stirley original: 06/17/2019; updated: 12/16/2019
#> 335 hay, amy original: 10/31/2017; updated: 12/16/2019
#> 362 orbon, joane original: 08/12/2019; updated: 09/10/2019
#> 377 ribas, amanda original: 01/10/2018; updated 05/03/2019
#> 410 saccente, nicholas original: 02/14/2017; updated: 12/11/2018
#> 411 miyao, paulo original: 05/10/2017;updated: 11/27/2018
#> 415 garcia del moral, luis original: 07/10/2012;updated: 10/26/2018
#> 416 bruyneel, johan original: 04/22/2014;updated: 10/24/2018
#> 417 celaya lazama, pedro original: 04/22/2014;updated: 10/24/2018
#> 418 marti, jose original: 04/22/2014;updated: 10/24/2018
#> 419 moffett, shaun original: 04/24/2018updated: 10/19/2018
#> 427 hunter, adam original: 10/28/2016; updated: 09/26/2018
#> 506 bailey, ryan original: 08/03/2017; updated: 12/01/2017
#> 572 thomas, tammy original: 08/30/2002; updated: 02/13/2017
#> 600 tovar, oscar original: 10/28/2015; updated: 10/04/2016
#> 640 fischbach, dylan original: 12/18/2015; updated: 04/11/2016
#> 661 trafeh, mohamed original: 12/18/2014; updated: 08/25/2015
#> 864 young, jerome original: 11/10/2004; updated: 06/17/2008clean_dates()
I’ve written a clean_dates() function that takes
date_col, split and pattern
arguments:
df= processed USADA dataset with messy datesdate_col= sanction date column (usuallysanction_announced)split= regex to pass to split argument ofstrsplit()(defaults to"updated")pattern= regex for other non-date pattern (defaults to"original")
Below, clean_dates() is demonstrated on a couple of the
messy rows found above:
clean_dates(
df = head(bad_dates, 2),
date_col = "sanction_announced",
split = "updated",
pattern = "original")
#> athlete sanction_announced pattern_date
#> 4 boyle, evan original: 04/24/2026; updated: 09/09/2026 2026-04-24
#> 30 mitchell, manteo original: 09/26/2025; updated: 02/25/2026 2025-09-26
#> split_date
#> 4 2026-09-09
#> 30 2026-02-25For usada, split the data into three
data.frames (bad_dates,
good_dates, and no_dates).
bad_dates <- subset(usada,
grepl("^original", usada[['sanction_announced']]))
good_dates <- subset(usada,
!grepl("^original", usada[['sanction_announced']]) & sanction_announced != "")
no_dates <- subset(usada,
athlete == "*name removed" & sanction_announced == "")Clean dates in bad_dates by splitting the bad dates on
"updated" and provided "original" as the
pattern (the opposite will also work). The sanction_date
column will contain the correctly formatted updated
sanction_date.
After formatting good_dates and removing
original_date column we can combine the two with
rbind().
cleaned_dates <- clean_dates(
df = bad_dates,
date_col = "sanction_announced",
split = "updated",
pattern = "original")
# address names
names(cleaned_dates)[names(cleaned_dates) == 'split_date'] <- 'sanction_date'
names(cleaned_dates)[names(cleaned_dates) == 'pattern_date'] <- 'original_date'
# format good_dates
good_dates$sanction_date <- as.Date(x = good_dates[['sanction_announced']],
format = "%m/%d/%Y")
# get intersecting names
nms <- intersect(names(cleaned_dates), names(good_dates))
# bind the two datasets
usada_dates <- rbind(good_dates, cleaned_dates[nms])
str(usada_dates)
#> 'data.frame': 704 obs. of 6 variables:
#> $ athlete : chr "lingafeldt, seth" "samelo do amaral, rider" "oprea, erin" "meador, laura" ...
#> $ sport : chr "weightlifting" "brazilian jiu-jitsu" "triathlon" "weightlifting" ...
#> $ substance_reason : chr "testosterone" "drostanolone; nandrolone; 19-norsteroids" "ostarine; lgd-4033; testosterone" "testosterone" ...
#> $ sanction_terms : chr "1-year suspension; loss of results" "3-year suspension; loss of results" "5-year suspension; loss of results" "4-year suspension; loss of results" ...
#> $ sanction_announced: chr "09/24/2026" "09/21/2026" "09/11/2026" "09/03/2026" ...
#> $ sanction_date : Date, format: "2026-09-24" "2026-09-21" ...