Intro

The AutoRecommenderUpdate function is presented in this webpage. The reader will first see sample data in a format that is typically outputed from a product recommender algorithm. The data contains two distinct customers with ten different SKUs that they are most likely to purchase in ascending order, as well as the most recent timestamp in which the product recommender was ran. The source code of the AutoRecommenderFunction was then saved in order for it to be used to run tests that showed all three possible scenrios that the user will encounter as well as the different function paramaters that can be manipulated.

Hardcoded Data

ProductRecommenderData = data.table :: data.table(CustomerID = rep(c(12346L,12347L),each = 10), 
StockCode = c("23167","23165","22969","22501","22720","23154","22722", 
"23298", "22961", "23293", "23245", "22961", "21977", "22952",
"22730","23240","22624","22950","47566","85123A"),
ProductRank = c(1:10), ModelTimeStamp = "2019-06-23 12:14:10")

View Data

ProductRecommenderData
##     CustomerID StockCode ProductRank      ModelTimeStamp
##  1:      12346     23167           1 2019-06-23 12:14:10
##  2:      12346     23165           2 2019-06-23 12:14:10
##  3:      12346     22969           3 2019-06-23 12:14:10
##  4:      12346     22501           4 2019-06-23 12:14:10
##  5:      12346     22720           5 2019-06-23 12:14:10
##  6:      12346     23154           6 2019-06-23 12:14:10
##  7:      12346     22722           7 2019-06-23 12:14:10
##  8:      12346     23298           8 2019-06-23 12:14:10
##  9:      12346     22961           9 2019-06-23 12:14:10
## 10:      12346     23293          10 2019-06-23 12:14:10
## 11:      12347     23245           1 2019-06-23 12:14:10
## 12:      12347     22961           2 2019-06-23 12:14:10
## 13:      12347     21977           3 2019-06-23 12:14:10
## 14:      12347     22952           4 2019-06-23 12:14:10
## 15:      12347     22730           5 2019-06-23 12:14:10
## 16:      12347     23240           6 2019-06-23 12:14:10
## 17:      12347     22624           7 2019-06-23 12:14:10
## 18:      12347     22950           8 2019-06-23 12:14:10
## 19:      12347     47566           9 2019-06-23 12:14:10
## 20:      12347    85123A          10 2019-06-23 12:14:10

Save Function

AutoRecommenderUpdate <- function (
  data,
  FeaturedProduct,
  ReplaceProduct = FALSE,
  N = 10,
  EntityColName  = "CustomerID",
  ProductColName = "StockCode",
  Rank = "ProductRank",
  TimeStamp = "ModelTimeStamp") {
  
  # Ensure data is data.table----
  if (!data.table::is.data.table(data)) {
    data <- data.table::as.data.table(data)
  }
  
  # Gather Data to Determine Correct Scenerio----
  CustomersWithFeaturedItem <- data[get(ProductColName) == FeaturedProduct, get(EntityColName)]
  CustomersWithFeaturedItemTable <- data[get(EntityColName) %in% CustomersWithFeaturedItem]
  CustomersWithoutFeaturedItemTable <- data[!(get(EntityColName) %in% CustomersWithFeaturedItem )]
  
  # The Three Possible Scenerios are Listed Below----
  # No Customer Has the Fetured Product Recommended to Them
  # Every Customer Already Has the Fetured Product Recommended to Them
  # Some Customers Have the Fetured Product Recommended to Them
  if (nrow(CustomersWithFeaturedItemTable) == 0) {
    A <- CustomersWithoutFeaturedItemTable
    B <- NULL
  } else if(nrow(CustomersWithoutFeaturedItemTable) == 0) {
    return ("Every Customer has the featured product")
  } else {
    A <- CustomersWithoutFeaturedItemTable
    B <- CustomersWithFeaturedItemTable
  }
  
  # Choose to replace the least likey product with the featured Product----
  if(ReplaceProduct == TRUE) { 
    if(!N %in% unique(A[,get(Rank)])) {
      stop("Rank does not exist in model")
    }
    data.table::set(
      A, 
      i = A[get(Rank) == N, which = TRUE],
      j = eval(ProductColName), 
      value = FeaturedProduct) 
    data <- data.table::rbindlist(
      list(A,B), 
      fill = TRUE)
    data.table::setorderv(
      data, 
      cols = c(eval(EntityColName),
               eval(Rank)))
    return(data)
    
    # Add the featured product to current recommendations----
  } else {
    
    # Test if timestamp should be added----
    if(is.null(TimeStamp)){
      DT <- data.table::data.table(
        V1 = unique(A[,get(EntityColName)]), 
        V2 = FeaturedProduct,
        V3 = 0)
      data.table::setnames(
        x = DT, 
        old = c("V1",
                "V2",
                "V3"),
        new = c(eval(EntityColName),
                eval(ProductColName),
                eval(Rank)))
    } else {
      DT <- data.table::data.table(
        V1 = unique(A[,get(EntityColName)]), 
        V2 = FeaturedProduct,
        V3 = 0, 
        V4 = unique(A[,get(TimeStamp)]))
      data.table::setnames(
        x = DT, 
        old = c("V1",
                "V2",
                "V3",
                "V4"),
        new = c(eval(EntityColName),
                eval(ProductColName),
                eval(Rank),
                eval(TimeStamp)))
    }
    
    # Finalize data prep and return----
    data <- data.table::rbindlist(
      list(DT,A,B), 
      fill = TRUE)
    data.table::setorderv(
      data, 
      cols = c(eval(EntityColName),
               eval(Rank)))
    return(data)
  }
}

Run Function Tests

Test1 = AutoRecommenderUpdate(data = ProductRecommenderData , FeaturedProduct = "00")
Test1
##     CustomerID StockCode ProductRank      ModelTimeStamp
##  1:      12346        00           0 2019-06-23 12:14:10
##  2:      12346     23167           1 2019-06-23 12:14:10
##  3:      12346     23165           2 2019-06-23 12:14:10
##  4:      12346     22969           3 2019-06-23 12:14:10
##  5:      12346     22501           4 2019-06-23 12:14:10
##  6:      12346     22720           5 2019-06-23 12:14:10
##  7:      12346     23154           6 2019-06-23 12:14:10
##  8:      12346     22722           7 2019-06-23 12:14:10
##  9:      12346     23298           8 2019-06-23 12:14:10
## 10:      12346     22961           9 2019-06-23 12:14:10
## 11:      12346     23293          10 2019-06-23 12:14:10
## 12:      12347        00           0 2019-06-23 12:14:10
## 13:      12347     23245           1 2019-06-23 12:14:10
## 14:      12347     22961           2 2019-06-23 12:14:10
## 15:      12347     21977           3 2019-06-23 12:14:10
## 16:      12347     22952           4 2019-06-23 12:14:10
## 17:      12347     22730           5 2019-06-23 12:14:10
## 18:      12347     23240           6 2019-06-23 12:14:10
## 19:      12347     22624           7 2019-06-23 12:14:10
## 20:      12347     22950           8 2019-06-23 12:14:10
## 21:      12347     47566           9 2019-06-23 12:14:10
## 22:      12347    85123A          10 2019-06-23 12:14:10
##     CustomerID StockCode ProductRank      ModelTimeStamp

The featured item was successfully added to both customers.

Test2 = AutoRecommenderUpdate(data = Test1,FeaturedProduct = "00")
Test2
## [1] "Every Customer has the featured product"

We do not want to run this function if every customer already has the product recommended to them.

Test3 = AutoRecommenderUpdate(data = ProductRecommenderData ,FeaturedProduct = "23167")
Test3
##     CustomerID StockCode ProductRank      ModelTimeStamp
##  1:      12346     23167           1 2019-06-23 12:14:10
##  2:      12346     23165           2 2019-06-23 12:14:10
##  3:      12346     22969           3 2019-06-23 12:14:10
##  4:      12346     22501           4 2019-06-23 12:14:10
##  5:      12346     22720           5 2019-06-23 12:14:10
##  6:      12346     23154           6 2019-06-23 12:14:10
##  7:      12346     22722           7 2019-06-23 12:14:10
##  8:      12346     23298           8 2019-06-23 12:14:10
##  9:      12346     22961           9 2019-06-23 12:14:10
## 10:      12346     23293          10 2019-06-23 12:14:10
## 11:      12347     23167           0 2019-06-23 12:14:10
## 12:      12347     23245           1 2019-06-23 12:14:10
## 13:      12347     22961           2 2019-06-23 12:14:10
## 14:      12347     21977           3 2019-06-23 12:14:10
## 15:      12347     22952           4 2019-06-23 12:14:10
## 16:      12347     22730           5 2019-06-23 12:14:10
## 17:      12347     23240           6 2019-06-23 12:14:10
## 18:      12347     22624           7 2019-06-23 12:14:10
## 19:      12347     22950           8 2019-06-23 12:14:10
## 20:      12347     47566           9 2019-06-23 12:14:10
## 21:      12347    85123A          10 2019-06-23 12:14:10
##     CustomerID StockCode ProductRank      ModelTimeStamp

Notice that only the customer without the featured product got a new record. This avoids duplicate products being recommended to the same customer.

Test4 = AutoRecommenderUpdate(data = ProductRecommenderData,FeaturedProduct = "23167",ReplaceProduct = TRUE)
Test4
##     CustomerID StockCode ProductRank      ModelTimeStamp
##  1:      12346     23167           1 2019-06-23 12:14:10
##  2:      12346     23165           2 2019-06-23 12:14:10
##  3:      12346     22969           3 2019-06-23 12:14:10
##  4:      12346     22501           4 2019-06-23 12:14:10
##  5:      12346     22720           5 2019-06-23 12:14:10
##  6:      12346     23154           6 2019-06-23 12:14:10
##  7:      12346     22722           7 2019-06-23 12:14:10
##  8:      12346     23298           8 2019-06-23 12:14:10
##  9:      12346     22961           9 2019-06-23 12:14:10
## 10:      12346     23293          10 2019-06-23 12:14:10
## 11:      12347     23245           1 2019-06-23 12:14:10
## 12:      12347     22961           2 2019-06-23 12:14:10
## 13:      12347     21977           3 2019-06-23 12:14:10
## 14:      12347     22952           4 2019-06-23 12:14:10
## 15:      12347     22730           5 2019-06-23 12:14:10
## 16:      12347     23240           6 2019-06-23 12:14:10
## 17:      12347     22624           7 2019-06-23 12:14:10
## 18:      12347     22950           8 2019-06-23 12:14:10
## 19:      12347     47566           9 2019-06-23 12:14:10
## 20:      12347     23167          10 2019-06-23 12:14:10

You have the option to replace products of a perticular rank by sepcifying the N argument (I left it blank so N equals 10 by default). This can be useful if you are worried about overloading your servers with too many products or you want to control the amount of products you want to recommend to your customers.

Conclusion

Notice that the featured products will have a default product rank of 0 when you are not replacing an existing SKU. Hence, this will be the first product customer’s see and it facilitates deletion if needed.