<jupyter_start><jupyter_text>Model Deployment with CivisMLIf you are familiar with scikit-learn and/or CivisML, deploying machine learning models in Python can now be done in Civis Platform with just a couple of API calls. This notebook will walk you through the following steps:1. Training a model on some toy data in CivisML,2. Deploying that model as a web service on Civis Platform,3. Getting the URL and an access token for your deployed model, and4. Making requests of your now-deployed model. By executing the code in the cells below, you will be able to get predictions from a deployed model in about 5 minutes.<jupyter_code># NOTE: you should be using version 1.8.X or 1.9.X of the Civis API client
import civis<jupyter_output><empty_output><jupyter_text>First, make some toy dataLet's suppose we want to make a model to determine whether an individual will likely be persuaded a particluar message. For each person in our (artificial) training data set, we have `age`, `gender`, and political `party` as features. We also have binary labels `msg` for whether or not the individual said they liked a message we showed them.<jupyter_code>from io import StringIO
import pandas as pd
data = 'age,gender,party,msg\n20,M,other,1\n25,M,D,0\n30,F,D,0\n40,M,R,1\n50,F,D,0\n60,M,other,1\n65,F,R,0\n70,F,D,1\n80,M,R,1\n'

df = pd.read_csv(StringIO(data))<jupyter_output><empty_output><jupyter_text>The first five rows in our training data look like:<jupyter_code>df.head()<jupyter_output><empty_output><jupyter_text>Next, let's build a model with CivisMLUsing CivisML, we can train a random forest classifier to predict the probability that future individuals will also respond positively to the message.<jupyter_code>mp = civis.ml.ModelPipeline(model='random_forest_classifier', dependent_variable='msg')
_ = mp.train(df)
mp.train_result_.train_job_id<jupyter_output><empty_output><jupyter_text>You can monitor the status of your training job on Platform:https://platform.civisanalytics.com//Your model must finish training before you can deploy it.    We can deploy this model with two API callsWhen the model has finished training, we can create a service for deployment by passing the training job ID (`mp.train_result_.train_job_id`) as an environment variable to our CivisML model deployment Docker image. You can optionally pass in the training run ID as well (`mp.train_result_.train_run_id`); if no such run ID is provided, the most recent run is used by default.<jupyter_code>client = civis.APIClient(resources='all')

# The version of the Civis API client with which we trained our model determines which
# Docker image we should use. 
civ_minor_version = '.'.join(civis.__version__.split('.')[:2])
if civ_minor_version == '1.9':
    image_tag = '1.1'
elif civ_minor_version == '1.8':
    image_tag = '1.0'
else:
    print("WARNING: Your model may not properly deploy. Your version of the Civis "
          "API client is {}, but it should be either v1.8 or 1.9!".format(civis.__version__))
    image_tag = '1.0'

resp = client.services.post(
    name='my_deployed_model',
    docker_image_name="civisanalytics/model-deployment",
    docker_image_tag=image_tag,
    cpu=1000,
    memory=8000, 
    environment_variables={'MODEL_JOB_ID': mp.train_result_.train_job_id, 
                           'DEBUG': 1}   # The optional "DEBUG" environment variable turns on verbose logging
)<jupyter_output><empty_output><jupyter_text>The `DEBUG` environment variable ensures that our logs are verbose. You may want this turned off for models in production.Once we have created our service, we can start the deployment with the following API call:<jupyter_code>_ = client.services.post_deployments(resp['id'])<jupyter_output><empty_output><jupyter_text>It may take a minute or two for the deployment to start up, but once it does we can make requests from our model. You can monitor the logs of your deployment on Platform.<jupyter_code>print("Platform page for your deployment: ")
print("https://platform.civisanalytics.com/#/services/{}".format(resp['id']))<jupyter_output><empty_output><jupyter_text>You can find the logs under the "Deployment History" link towards the upper right-hand side of the screen. When the logs say "_Application successfully changed to ready state_" you're ready to make calls.  Let's get some predictions from our model!First, we'll need to get the model's URL and an access token. Once we have those, we can use python's `requests` library to make some simple RESTful calls.<jupyter_code>url = client.services.get(resp['id'])['current_url']
print(url)
token_resp = client.services.post_tokens(resp['id'], 'keiths_token')<jupyter_output><empty_output><jupyter_text>We can get predictions from our model by passing covariates as query parameters to the `/predict` endpoint and making a GET call:<jupyter_code>import requests

# Put the token in the header of the HTTP call
headers = {"Authorization": "Bearer {}".format(token_resp['token'])}
# Pass your model covariates as query parameters
pred_url = url + '/predict?age=30&gender=F&party=D'

# Make the GET call
getresp = requests.get(pred_url, headers=headers)
print(getresp.text)<jupyter_output><empty_output><jupyter_text>Look: a prediction! Predictions are returned as JSON dictionaries. Instead of passing our access token through the HTTP header, we can optionally pass it as a query parameter using the `civis_service_token` keyword:<jupyter_code>pred_url = url + '/predict?age=30&gender=F&party=D&civis_service_token=' + token_resp['token']

# Make the GET call, no headers necessary
getresp = requests.get(pred_url)
print(getresp.text)<jupyter_output><empty_output><jupyter_text>Model GUIGo to your model's deployment page:<jupyter_code>print("https://platform.civisanalytics.com/#/services/{}".format(resp['id']))<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.0908467603702434, 'fraction_numerical': 0.010970174837161468, 'mean_word_length': 5.638225255972697, 'pattern_counts': {'":': 1, '<': 45, '<?xml version=': 0, '>': 45, 'https://': 3, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, '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': '11', 'dir': 'jupyter-structured-clean-dedup', 'id': '157011', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 1804, 'n_tokens_neox': 1733, 'n_words': 642, 'path': 'examples/civisml_deployment.ipynb', 'repo_name': 'civisanalytics/model-deployment', 'size': '5834'}