<jupyter_start><jupyter_text>A fast and dirty intro to running a model via web serviceHave you ever needed to score data with a predictive model in (near) real time, using a remote server/machine? While not a statistical or machine learning topic, it's one that I struggled with for a while, and haven't found many resources for.In this post, we're going to assume an understanding of predictive modeling and python, to focus on a simple way to set up a web service that can recieve data and return model predictions over the internet.This way is by no means definitive, but is straightforward and effective.  [Part 3: Sender](http://spencercarter.info/docs/model_web_service_flask_3.ipynb) Home stretch! Now we just need a way to send data to our web service.<jupyter_code># Repeat the setup block for the listener and sender
import sklearn as sk
import numpy as np
from sklearn.datasets import load_boston
from sklearn.linear_model import LassoCV
import pandas as pd
from flask import Flask
from flask import request
import requests
import pickle
from time import time

def unpickle_me(infile):
    with open(infile, 'rb') as f:
        unpickled = pickle.load(f)
    return unpickled

# Read in our pickled dictionary
stored = unpickle_me('model_web_service.pickle')

# Save the data types we  expect, to ensure typing works
df_types = stored['dtypes']
predictors = stored['predictors']
X = stored['X']
lasso = stored['lasso']<jupyter_output><empty_output><jupyter_text>We need to generate some test cases from our data. As you saw when creating the scoring function, we're going to turn our data into a JSON. To make things a little simpler here, we're going to make a sender that takes a row number, and sends a JSON of the data to our webservice (which you should run in a separate notebook).Status code 200 indicates success, and all others indicate something failed. As a simple failsafe, we'll return 0.0 to signal a failure.<jupyter_code>def make_a_post(indx):
    url = "http://127.0.0.1:1234/mass"
    data = X.iloc[indx].to_json()
    req = requests.post(url, json=data)
    if req.status_code != 200:
        return .0
    return float(req.content.decode("utf-8")) # The prediction will come in as a byte. Decode, then make float<jupyter_output><empty_output><jupyter_text>Finally, let's toss obervation 0 to the webservice. We know from earlier, that it should return 30.505530469875787, rounded to 2 decimal-places.<jupyter_code>make_a_post(0)<jupyter_output><empty_output><jupyter_text>And a few more for show. Let's sample over the observations:<jupyter_code>for i in np.random.choice(range(X.shape[0]), 10):
    print("Obs {0:03d}: {1}".format(i, make_a_post(i)))<jupyter_output>Obs 257: 41.79
Obs 195: 37.82
Obs 166: 37.75
Obs 168: 26.51
Obs 027: 16.4
Obs 289: 26.16
Obs 107: 20.25
Obs 225: 38.77
Obs 322: 23.24
Obs 504: 26.59<jupyter_text>And let's see how long these take to run. Take the average of 100 runs:<jupyter_code>lag = []
rep = 100
for _ in range(100):
    t0 = time()
    make_a_post(0)
    lag.append(time()-t0)
print("Over {0} runs, the web service averaged {1:0.4f} seconds to score".format(rep,np.mean(lag)))<jupyter_output>Over 100 runs, the web service averaged 0.0133 seconds to score
{'fraction_non_alphanumeric': 0.08498759305210918, 'fraction_numerical': 0.04404466501240695, 'mean_word_length': 4.707964601769912, 'pattern_counts': {'":': 0, '<': 19, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '616856', 'license': 'MIT', 'n_tokens_mistral': 1135, 'n_tokens_neox': 998, 'n_words': 420, 'path': 'model_web_service_flask_post_3.ipynb', 'repo_name': 'spencercarter/blog_content', 'size': '3224'}