Deploying Energy Theft Models With R’s RESTful API
While scrolling through my Linkedin page on a sultry Saturday afternoon, I read through a post where some folks argued about the limitations of Machine Learning and why they think it is overhyped. Their underlying argument was that ML is only useful for predictions and really not worth the stress of having to go through all the rigour just to build a model. This came to me, not as a surprise because there has been this silent consensus amongst data science enthusiasts who doubt the value of ML.
To safeguard against this notion and to contribute the to rising call to democratize knowledge around machine learning, I have decided to continue with my series of energy theft detection, but this time, I will use an API to demonstrate how this technology fits properly into the ML bundle.
Why APIs?
In one of my articles, I did a walkthrough on ML models for energy theft detection https://georgegoddy-t.medium.com/machine-learning-for-energy-theft-detection-f37ff42e2719 In the article, we built a model that predicted likely bypass cases based on an analysis drawn from the customer’s data and customers actually caught on bypass. Now, we are going to show the results of each customer bypass probability by serving API calls.
Since we made our model in R, the challenge here is that other tools or systems may not be able to use it in production. Hence, how do we put the model in production so that other tools or systems that will leverage our model will know R or be able to call it directly? That’s why we need an API!
What did you hear about APIs?
Technically, API stands for Application Program Interface — a name that’s both exactly what an API is and too vague to actually convey any meaning. But what is API really? They’re a simple way to set up a computer to pass information to other computers through the internet. 95% of the time, when people say API they mean a RESTful API, which is an API that uses HTTP to interact with other computers — all software languages speak HTTP!
HTTP is the same protocol your browser is using for you to read this article right now, as websites just APIs! When you type in a URL to a website, a computer receives your request and sends back HTML. RESTful API’s are the same thing, but instead of HTML, they send back text or data.
How do I make API in R?
The easiest way to create an API in R is using the library plumber — a package that can convert existing R code into an API with just a few extra lines. Plumber turns R functions into API endpoints. Without an understanding of functions, we are not going to be able to put our code into production and create these APIs. So, what are functions? Functions are code shortcuts that help us do things faster essentially.
Let’s get to work
So, let’s start by building a simple predictive model and then use the generalised linear model (GLM) to predict the probability likelihood of meter bypass for each customer.
#Building our modelLogModel <- glm(Status ~ Estimated.Connected.Load + Availability,data = ml)
print(summary(LogModel))## Predict the outcomes against our test datato_predict <- data.frame( availability =630, Estimated.Connected.Load = 10)
glimpse(to_predict)
predict(LogModel, data = to_predict)# Add meter number column from the original dataset(ml)to the predicted modelfinal_df <- cbind(ml[, c(5)],"Pred_values"=LogModel)
Remember, we talked about creating functions as an essential part of putting our code into production and creating our own API. Let's see how that works.
#Creating a useful function from our model
pred_theft <- function(Supply_Hrs, Customer_load){
to_predict <- data.frame( availability =Supply_Hrs , Estimated.Connected.Load = Customer_load)
logit.pred.prob <- predict(LogModel, data = to_predict, type = ‘response’)
final_df <- cbind(ml[, c(5)],”Pred_values”=logit.pred.prob)
}
We just created a function object called pred_theft. The arguments — usually as placeholder values returns a predicted value each time an input value is given.
Let’s talk a bit about the anatomy of the Plumber package
- Uses roxygen-like commenting #* documentation
- #* is followed by tags
- Tags look like @tagname
- Endpoints are defined by the appropriate method tag
- Followed by endpoint name E.g @get/predict
Now that we’ve built our model, saved it and created a function, let’s create our API with the plumber.
plumber.Rlibrary(plumber)theft.model <- readr::read_rds(“theft_model.rds”)#* @apiTitle Energy Theft Prediction App#* @apiDescription This API serves up prediction of energy theft based on customers monthly hours of availability and connected load.#* @param Supply_Hrs The average availability in a given area per month.#* @param Customer_load The load of the customer.#* @get /Theft_APIfunction(Supply_Hrs, Customer_load){
to_predict <- data.frame( availability = as.numeric(Supply_Hrs), Estimated.Connected.Load = as.numeric(Customer_load))
logit.pred.prob <- predict(theft.model, data = to_predict, type = ‘response’)
#final_df <- cbind(ml[, c(5)],”Pred_values”=logit.pred.prob)
}
Cool! When we use the plumber, we create what is called a Swagger interface for interacting with RESTful API.
Let’ see what the results look like
It works!
Calling our API from R
Since we’ve already created an API, what we want is to actually use the API that we’ve created. And to do that, we are going to utilise the httr package (you can know more about the httr package by reading the documentation). Simply put, the moment we add our endpoint (theft_API) to a URL and send a request to a server, this is what counts as making an API call.
Still not getting the concept? Imagine you have just downloaded an app linked to our API. You will be required to fill in the customer average hours of supply and connected load. The moment you hit the “enter button” to submit your details, you have made an API call and the result will be displayed for you to see.
Often, a lot of data engineers only talk about making APIs. There are series of steps to follow when trying to call API’s — it’s pretty much the same for any language you need to work with.
The first step is to generate the query URL, the second step is to make the request and the final step is to parse the response. The codes below pretty much does all of those.
library(plumber)
pr <- plumber::plumb(“plumber.R”)#setwd(“C:/Users/KEYACCTS/Documents/ML_PROJECTS/APIs”)
pr$run(host = “127.0.0.1”, port = 5022)library(httr)
b_url <- “http://127.0.0.1:5022/Theft_API"
b_url
params <- list(Supply_Hrs = 630, Customer_load= 10)
query_url <- modify_url(url = b_url, query = params)
resp <- GET(query_url)
resp_raw <- content(resp, as= “text”, encoding = “utf-8”)
jsonlite::fromJSON(resp_raw)get_theft_pred <- function(availability = 0, Estimated_Load = 0){
b_url <- “http://127.0.0.1:5022/Theft_API"
params <- list(Supply_Hrs = availability, Customer_load= Estimated_Load)
query_url <- modify_url(url = b_url, query = params)
resp <- GET(query_url)
resp_raw <- content(resp, as = “text”, encoding = “utf-8”)
jsonlite::fromJSON(resp_raw)
}get_theft_pred(630,10)
Thank you for reading my post, please like and share. Bye for now.