<jupyter_start><jupyter_text>How do we deploy these ML Model now?Python has a solution to it: Serialization! In Python, pickling is a standard way to store objects and retrieve them as their original state. To give a simple example:<jupyter_code>list_to_pickle = [1, 'here', 123, 'walker']

#Pickling the list
import dill as pickle

with open('./list.pk', 'wb') as filename:
    pickle.dump(list_to_pickle, filename)
!ls *.pk<jupyter_output>list.pk<jupyter_text>Contents of the pickle file are nothing but all your data stored in bytes! When we load the pickle back:<jupyter_code>with open('./list.pk', 'rb') as filename:
    loaded_pickle = pickle.load(filename)
    
print("Content of the pickle: {}".format(loaded_pickle))<jupyter_output>Content of the pickle: [1, 'here', 123, 'walker']<jupyter_text>For folks who are more familiar with R$$.rda\;==\;.pk$$ For our hack session we already have a model, pickled and ready  How to load our pickled model<jupyter_code>import dill as pickle
clf = 'model_v1.pk'
loaded_model = None
with open('../working_api/working_api/models/'+clf, 'rb') as f:
    loaded_model = pickle.load(f)
loaded_model<jupyter_output><empty_output><jupyter_text>Test dataset:<jupyter_code>import pandas as pd

import warnings
warnings.filterwarnings('ignore')
df = pd.read_csv('../working_api/test_data/test1.csv', encoding="utf-8-sig")
df = df.head(10)
df
loaded_model.predict(df)
loaded_model.predict_proba(df)<jupyter_output><empty_output><jupyter_text>DEMO: HELLO-WORLD - Importing the __Flask__ class<jupyter_code>from flask import Flask<jupyter_output><empty_output><jupyter_text>- Creating an instance of the class:<jupyter_code>app = Flask(__name__)<jupyter_output><empty_output><jupyter_text>- Since we are dealing with Web APIs and endpoints, __Flask__ saves us the hassle by providing decorators, `route()` as a means to add new endpoints to the web application:<jupyter_code>@app.route('/')
def hello_world():
    return("Hello, world!")<jupyter_output><empty_output><jupyter_text>- __What is a decorator?__    * In layman's term, decorators are __Funceptions__. Functions within functions.    * Example:<jupyter_code>def decorate(func):
   def func_wrapper(name):
       return "Our result: {}".format(func(name))
   return func_wrapper
@decorate
def get_text(name):
   return "lorem ipsum, {} dolor sit amet".format(name)
get_text("John")<jupyter_output><empty_output><jupyter_text>- Content in `return()` in the above definition will be displayed in the browser. DEMO:WRAPPING ML MODELS  Client Side code:<jupyter_code>import json
import requests<jupyter_output><empty_output><jupyter_text>-  Setting the headers to send and accept json responses<jupyter_code>header = {'Content-Type': 'application/json', \
                  'Accept': 'application/json'}<jupyter_output><empty_output><jupyter_text>-  Reading test batch<jupyter_code>df = pd.read_csv('../working_api/test_data/test1.csv', encoding="utf-8-sig")
df = df.head(5)
print(df)<jupyter_output>Loan_ID Gender Married Dependents     Education Self_Employed  \
0  LP001015   Male     Yes          0      Graduate            No   
1  LP001022   Male     Yes          1      Graduate            No   
2  LP001031   Male     Yes          2      Graduate            No   
3  LP001035   Male     Yes          2      Graduate            No   
4  LP001051   Male      No          0  Not Graduate            No   

   ApplicantIncome  CoapplicantIncome  LoanAmount  Loan_Amount_Term  \
0             5720                  0       110.0             360.0   
1             3076               1500       126.0             360.0   
2             5000               1800       208.0             360.0   
3             2340               2546       100.0             360.0   
4             3276                  0        78.0             360.0   

   Credit_History Property_Area  
0             1.0         Urban  
1             1.0         Urban  
2             1.0         Urban  
3             NaN     [...]<jupyter_text>-  Converting Pandas Dataframe to json<jupyter_code>data = df.to_json(orient='records')
data
data = df.to_json(orient='split')
data
data = df.to_json(orient='columns')
data<jupyter_output><empty_output><jupyter_text>-  We'll be sending resources to the server-side, hence __POST__ ```pythonresp = requests.post("http:///predict", \                    data = json.dumps(data),\                    headers= header)```  Server Side code:<jupyter_code>import pandas as pd<jupyter_output><empty_output><jupyter_text>```pythontest_json = response.get_json() response object in Flask that contains our dataframe sent our via POSTtest = pd.read_json(test_json, orient='records')``` -  Converting the json back to pandas dataframe<jupyter_code>test = pd.read_json(data, orient='records')
test<jupyter_output><empty_output><jupyter_text>- Minor pre-processing steps before we proceed:<jupyter_code>#To resolve the issue of TypeError: Cannot compare types 'ndarray(dtype=int64)' and 'str'
test['Dependents'] = [str(x) for x in list(test['Dependents'])]

#Getting the Loan_IDs separated out
loan_ids = test['Loan_ID']<jupyter_output><empty_output><jupyter_text>- Loading our pickled estimator and do predictions:<jupyter_code>import dill as pickle
clf = 'model_v1.pk'
loaded_model = None
with open('../working_api/working_api/models/'+clf, 'rb') as f:
    loaded_model = pickle.load(f)
predictions = loaded_model.predict(test)
predictions<jupyter_output><empty_output><jupyter_text>- jsonify our predictions and send the response back with status code: 200<jupyter_code>prediction_series = list(pd.Series(predictions))
final_predictions = pd.DataFrame(list(zip(loan_ids, prediction_series)))
print(final_predictions)
from flask import jsonify<jupyter_output><empty_output><jupyter_text>```pythonresponses = jsonify(predictions=final_predictions.to_json(orient="records"))responses.status_code = 200``` Demo Run for API: Local<jupyter_code>import json
import requests
import pandas as pd

"""Setting the headers to send and accept json responses
"""
header = {'Content-Type': 'application/json', \
                  'Accept': 'application/json'}

"""Reading test batch
"""
df = pd.read_csv('../working_api/test_data/test1.csv', encoding="utf-8-sig")
df = df.head(10)

"""Converting Pandas Dataframe to json

MORE INFO:
==============
orient: string

    Series
    =====================
    default is 'index'
    allowed values are: {'split', 'records', 'index'}
    
    Dataframe
    =====================
    default is 'columns'
    allowed values are: {'split', 'records', 'columns', 'values'}
    
"""
data = df.to_json(orient='records')

"""POST <url>/predict, sending data to the Flask Server

NOTE: 
==================================
- <url> for local: localhost or 127.0.0.1 or 0.0.0.0
- <url> for cloud: DNS or ip of VM created
"""
resp = requests.post("http://192.168.127.12:5000/predict", \
                    data = json.dumps(data),\
                    headers= header)
resp.status_code
resp.json()<jupyter_output><empty_output><jupyter_text>Demo Run for API: Cloud<jupyter_code>import json
import requests
import pandas as pd

"""Setting the headers to send and accept json responses
"""
header = {'Content-Type': 'application/json', \
                  'Accept': 'application/json'}

"""Reading test batch
"""
df = pd.read_csv('../working_api/test_data/test1.csv', encoding="utf-8-sig")
df = df.head(10)

"""Converting Pandas Dataframe to json

MORE INFO:
==============
orient: string

    Series
    =====================
    default is 'index'
    allowed values are: {'split', 'records', 'index'}
    
    Dataframe
    =====================
    default is 'columns'
    allowed values are: {'split', 'records', 'columns', 'values'}
    
"""
data = df.to_json(orient='records')

"""POST <url>/predict, sending data to the Flask Server

NOTE: 
==================================
- <url> for local: localhost or 127.0.0.1
- <url> for cloud: DNS or ip of VM created
"""
resp = requests.post("http://45.55.83.36:5000/predict", \
                    data = json.dumps(data),\
                    headers= header)
resp.status_code
resp.json()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.13334148130041554, 'fraction_numerical': 0.024932779271571743, 'mean_word_length': 3.5562360801781736, 'pattern_counts': {'":': 0, '<': 80, '<?xml version=': 0, '>': 80, 'https://': 0, 'lorem ipsum': 1, 'www.': 0, 'xml': 0}, 'pii_count': 5, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '19', 'dir': 'jupyter-structured-clean-dedup', 'id': '541413', 'license': 'MIT', 'n_tokens_mistral': 2750, 'n_tokens_neox': 2553, 'n_words': 690, 'path': 'slides/datahack_code.ipynb', 'repo_name': 'pratos/datahack2017-workshop-av', 'size': '8183'}