Python Machine Learning - Code Examples

Chapter 9 - Embedding a Machine Learning Model into a Web Application

Note that the optional watermark extension is a small IPython notebook plugin that I developed to make the code reproducible. You can just skip the following line(s).

In [1]:
%load_ext watermark
%watermark -a 'Sebastian Raschka' -u -d -v -p numpy,pandas,matplotlib,nltk
Sebastian Raschka 
Last updated: 08/20/2015 

CPython 3.4.3
IPython 3.2.1

numpy 1.9.2
pandas 0.16.2
matplotlib 1.4.3
nltk 3.0.4
In [ ]:
# to install watermark just uncomment the following line:


The code for the Flask web applications can be found in the following directories:

  • 1st_flask_app_1/: A simple Flask web app
  • 1st_flask_app_2/: 1st_flask_app_1 extended with flexible form validation and rendering
  • movieclassifier/: The movie classifier embedded in a web application
  • movieclassifier_with_update/: same as movieclassifier but with update from sqlite database upon start

To run the web applications locally, cd into the respective directory (as listed above) and execute the main-application script, for example,

cd ./1st_flask_app_1

Now, you should see something like

 * Running on
 * Restarting with reloader

in your terminal. Next, open a web browsert and enter the address displayed in your terminal (typically to view the web application.

Link to a live example application built with this tutorial:

In [1]:
from IPython.display import Image

Chapter 8 recap - Training a model for movie review classification

This section is a recap of the logistic regression model that was trained in the last section of Chapter 6. Execute the folling code blocks to train a model that we will serialize in the next section.

In [2]:
import numpy as np
import re
from nltk.corpus import stopwords

stop = stopwords.words('english')
porter = PorterStemmer()

def tokenizer(text):
    text = re.sub('<[^>]*>', '', text)
    emoticons = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)', text.lower())
    text = re.sub('[\W]+', ' ', text.lower()) + ' '.join(emoticons).replace('-', '')
    tokenized = [w for w in text.split() if w not in stop]
    return tokenized

def stream_docs(path):
    with open(path, 'r') as csv:
        next(csv) # skip header
        for line in csv:
            text, label = line[:-3], int(line[-2])
            yield text, label
In [5]:
('"In 1974, the teenager Martha Moxley (Maggie Grace) moves to the high-class area of Belle Haven, Greenwich, Connecticut. On the Mischief Night, eve of Halloween, she was murdered in the backyard of her house and her murder remained unsolved. Twenty-two years later, the writer Mark Fuhrman (Christopher Meloni), who is a former LA detective that has fallen in disgrace for perjury in O.J. Simpson trial and moved to Idaho, decides to investigate the case with his partner Stephen Weeks (Andrew Mitchell) with the purpose of writing a book. The locals squirm and do not welcome them, but with the support of the retired detective Steve Carroll (Robert Forster) that was in charge of the investigation in the 70\'s, they discover the criminal and a net of power and money to cover the murder.<br /><br />""Murder in Greenwich"" is a good TV movie, with the true story of a murder of a fifteen years old girl that was committed by a wealthy teenager whose mother was a Kennedy. The powerful and rich family used their influence to cover the murder for more than twenty years. However, a snoopy detective and convicted perjurer in disgrace was able to disclose how the hideous crime was committed. The screenplay shows the investigation of Mark and the last days of Martha in parallel, but there is a lack of the emotion in the dramatization. My vote is seven.<br /><br />Title (Brazil): Not Available"',


If you haven't created the movie_data.csv file in the previous chapter, you can find a download a zip archive at

In [6]:
def get_minibatch(doc_stream, size):
    docs, y = [], []
        for _ in range(size):
            text, label = next(doc_stream)
    except StopIteration:
        return None, None
    return docs, y
In [7]:
from sklearn.feature_extraction.text import HashingVectorizer
from sklearn.linear_model import SGDClassifier

vect = HashingVectorizer(decode_error='ignore', 

clf = SGDClassifier(loss='log', random_state=1, n_iter=1)
doc_stream = stream_docs(path='./movie_data.csv')
In [8]:
import pyprind
pbar = pyprind.ProgBar(45)

classes = np.array([0, 1])
for _ in range(45):
    X_train, y_train = get_minibatch(doc_stream, size=1000)
    if not X_train:
    X_train = vect.transform(X_train)
    clf.partial_fit(X_train, y_train, classes=classes)
0%                          100%
[##############################] | ETA[sec]: 0.000 
Total time elapsed: 59.019 sec
In [9]:
X_test, y_test = get_minibatch(doc_stream, size=5000)
X_test = vect.transform(X_test)
print('Accuracy: %.3f' % clf.score(X_test, y_test))
Accuracy: 0.868
In [10]:
clf = clf.partial_fit(X_test, y_test)

Serializing fitted scikit-learn estimators

After we trained the logistic regression model as shown above, we know save the classifier along woth the stop words, Porter Stemmer, and HashingVectorizer as serialized objects to our local disk so that we can use the fitted classifier in our web application later.

In [12]:
import pickle
import os

dest = os.path.join('movieclassifier', 'pkl_objects')
if not os.path.exists(dest):

pickle.dump(stop, open(os.path.join(dest, 'stopwords.pkl'), 'wb'), protocol=4)   
pickle.dump(clf, open(os.path.join(dest, 'classifier.pkl'), 'wb'), protocol=4)

Next, we save the HashingVectorizer as in a separate file so that we can import it later.

In [1]:
%%writefile movieclassifier/
from sklearn.feature_extraction.text import HashingVectorizer
import re
import os
import pickle

cur_dir = os.path.dirname(__file__)
stop = pickle.load(open(
                'stopwords.pkl'), 'rb'))

def tokenizer(text):
    text = re.sub('<[^>]*>', '', text)
    emoticons = re.findall('(?::|;|=)(?:-)?(?:\)|\(|D|P)',
    text = re.sub('[\W]+', ' ', text.lower()) \
                   + ' '.join(emoticons).replace('-', '')
    tokenized = [w for w in text.split() if w not in stop]
    return tokenized

vect = HashingVectorizer(decode_error='ignore',
Overwriting movieclassifier/

After executing the preceeding code cells, we can now restart the IPython notebook kernel to check if the objects were serialized correctly.

First, change the current Python directory to movieclassifer:

In [1]:
import os
In [2]:
import pickle
import re
import os
from vectorizer import vect

clf = pickle.load(open(os.path.join('pkl_objects', 'classifier.pkl'), 'rb'))
In [3]:
import numpy as np
label = {0:'negative', 1:'positive'}

example = ['I love this movie']
X = vect.transform(example)
print('Prediction: %s\nProbability: %.2f%%' %\
      (label[clf.predict(X)[0]], clf.predict_proba(X).max()*100))
Prediction: positive
Probability: 91.56%

Setting up a SQLite database for data storage

Before you execute this code, please make sure that you are currently in the movieclassifier directory.

In [5]:
import sqlite3

conn = sqlite3.connect('reviews.sqlite')
c = conn.cursor()
c.execute('CREATE TABLE review_db (review TEXT, sentiment INTEGER, date TEXT)')

example1 = 'I love this movie'
c.execute("INSERT INTO review_db (review, sentiment, date) VALUES (?, ?, DATETIME('now'))", (example1, 1))

example2 = 'I disliked this movie'
c.execute("INSERT INTO review_db (review, sentiment, date) VALUES (?, ?, DATETIME('now'))", (example2, 0))

In [7]:
conn = sqlite3.connect('reviews.sqlite')
c = conn.cursor()

c.execute("SELECT * FROM review_db WHERE date BETWEEN '2015-01-01 10:10:10' AND DATETIME('now')")
results = c.fetchall()

In [8]:
[('I love this movie', 1, '2015-07-15 01:25:15'), ('I disliked this movie', 0, '2015-07-15 01:25:15')]
In [3]:
Image(filename='./images/09_01.png', width=700) 

Developing a web application with Flask


Our first Flask web application


Form validation and rendering

In [6]:
Image(filename='./images/09_02.png', width=400) 
In [7]:
Image(filename='./images/09_03.png', width=400) 

Turning the movie classifier into a web application

In [8]:
Image(filename='./images/09_04.png', width=400) 
In [9]:
Image(filename='./images/09_05.png', width=400) 
In [10]:
Image(filename='./images/09_06.png', width=400) 
In [12]:
Image(filename='./images/09_07.png', width=200) 

Deploying the web application to a public server

In [14]:
Image(filename='./images/09_08.png', width=600)