We need to make sure functions are vectorized, not using loops if at all possible. Loops are 10x slower.
For example, compare the readability and speed of clean date functions implemented like this:
date.words <-
c( "JANUARY","JAN","FEBRUARY","FEB",
"MARCH","MAR","APRIL","APR","MAY",
"JUNE","JUN","JULY","JUL","AUGUST","AUG",
"SEPTEMBER","SEPT","SEP","OCTOBER","OCT",
"NOVEMBER","NOV","DECEMBER","DEC", "PARTIAL YEAR", "PARTIAL YR",
"PART YEAR", "PART-YEAR", "YR", "YEAR",
"PART YR","MO", "MOS", "MONTH", "MONTHS" )
identify_date <- function(TitleTxt)
{
#mm/dd/yyyy format
format1 <- grepl( "\\d+/\\d+(/\\d+)*\\b", TitleTxt )
#mm-dd-yyyy format
format2 <- grepl( "\\d+-\\d+(-\\d+)*\\b", TitleTxt )
#date strings
date <- paste0( "\\b", date.words, "\\b", collapse="|" )
format3 <- grepl( date, TitleTxt )
has.date <- format1 | format2 | format3
return( has.date )
}
remove_date <- function( TitleTxt )
{
#mm/dd/yyyy format
TitleTxt <- gsub( "\\d+/\\d+(/\\d+)*\\b", "", TitleTxt )
#mm-dd-yyyy format
TitleTxt <- gsub( "\\d+-\\d+(-\\d+)*\\b", "", TitleTxt )
#date strings
date <- paste0( "\\b", date.words, "\\b", collapse="|" )
TitleTxt <- gsub( date, "", TitleTxt )
#remove miscellaneous digits still lying around
TitleTxt <- gsub("\\d[A-Z]*\\s", " ", TitleTxt)
TitleTxt <- gsub("\\d", " ", TitleTxt)
#remove starting and leading spaces and excess spacing
TitleTxt <- gsub("^\\s* | \\s*$", "", TitleTxt)
TitleTxt <- gsub( "\\s{2,}", " ", TitleTxt)
return(TitleTxt)
}
clean_dates <- function( comp.data )
{
title <- convert_ordinal( comp.data$TitleTxt )
has.date <- identify_date( title )
title <- remove_date( title )
# 1 if date was removed from title, 0 otherwise
comp.data$Date.Code <- ifelse( has.date, 1, 0 )
comp.data$TitleTxt <- title
return( comp.data )
}
Versus the current versions:
identify_date <- function(TitleTxt){
#mm/dd/yyyy format
k <- stringr::str_extract_all(TitleTxt,"\\d+/\\d+(/\\d+)*\\b")[[1]][1]
if(!is.na(k)) {
# print(k)
return(TRUE)
}
#mm-dd-yyyy format
k <- stringr::str_extract_all(TitleTxt,"\\d+-\\d+(-\\d+)*\\b")[[1]][1]
if(!is.na(k)) {
# print(k)
return(TRUE)
}
#months
month.words <- c("JANUARY","JAN","FEBRUARY","FEB",
"MARCH","MAR","APRIL","APR","MAY",
"JUNE","JUN","JULY","JUL","AUGUST","AUG",
"SEPTEMBER","SEPT","SEP","OCTOBER","OCT",
"NOVEMBER","NOV","DECEMBER","DEC", "PARTIAL YEAR", "PARTIAL YR",
"PART YEAR", "PART-YEAR", "YR", "YEAR",
"PART YR","MO", "MOS", "MONTH", "MONTHS")
for(word in month.words){
month <- paste0("\\b",word,"\\b")
if(grepl(month, TitleTxt)) {
# print(month)
return(TRUE)
}
}
return(FALSE)
}
remove_date <- function(TitleTxt){
#mm/dd/yyyy format
k <- stringr::str_extract_all(TitleTxt,"\\d+/\\d+(/\\d+)*\\b")[[1]][1]
if(!is.na(k)) {
TitleTxt <- gsub(k,"",TitleTxt)
}
#mm-dd-yyyy format
k <- stringr::str_extract_all(TitleTxt,"\\d+-\\d+(-\\d+)*\\b")[[1]][1]
if(!is.na(k)) {
TitleTxt <- gsub(k,"",TitleTxt)
}
#month words
month.words <- c("JANUARY","JAN","FEBRUARY","FEB",
"MARCH","MAR","APRIL","APR","MAY",
"JUNE","JUN","JULY","JUL","AUGUST","AUG",
"SEPTEMBER","SEPT","SEP","OCTOBER","OCT",
"NOVEMBER","NOV","DECEMBER","DEC", "PARTIAL YEAR", "PARTIAL YR",
"PART YEAR", "PART YR","MO", "MOS", "MONTH", "MONTHS")
for(word in month.words){
month <- paste0("\\b",word,"\\b")
TitleTxt <- gsub(month,"",TitleTxt)
}
#remove miscellaneous digits still lying around
TitleTxt <- gsub("\\d[A-Z]*\\s", " ", TitleTxt)
TitleTxt <- gsub("\\d", " ", TitleTxt)
#remove starting and leading spaces and excess spacing
TitleTxt <- gsub("^\\s* | \\s*$", "", TitleTxt)
TitleTxt <- gsub( "\\s{2,}", " ", TitleTxt)
return(TitleTxt)
}
clean_dates <- function(comp.data){
comp.table <- comp.data
comp.table$Date.Code <- 0
for(i in 1:length(comp.table$TitleTxt)) {
#asssume the table already formatted correctly
title <- convert_ordinal(comp.table$TitleTxt[i])
if(identify_date(title)){
comp.table$Date.Code[i] <- 1
comp.table$TitleTxt2[i] <- remove_date(title)
}
else{
comp.table$TitleTxt2[i] <- title
}
}
return(comp.table)
}
We need to make sure functions are vectorized, not using loops if at all possible. Loops are 10x slower.
For example, compare the readability and speed of clean date functions implemented like this:
Versus the current versions: