开发一个NLP垃圾邮件侦测系统并有FLASK实现部署

来自:大邓和他的Python(微信号:DaDengAndHisPython),作者:Susan Li
原文标题:Develop a NLP Model in Python & Deploy It with Flask, Step by Step

到现在我已分享过好多篇使用机器学习做NLP的文章,但是训练好的模型如何去使用,似乎没有讲过。今天我想这两方面一起组合起来,看看训练好的模型如何通过flask实现部署。

机器学习模型构建

我们使用经典的垃圾短信数据集(SMS spam/ham)。首先我们使用这个数据集来构建一个垃圾短信侦测模型。

朴素贝叶斯分类器是一种常用的用于过滤垃圾邮件的方法。该分类器使用的词袋法来构建数据的特征。因此,我们使用朴素贝叶斯构建一个简单的短信分类器。

import pandas as pd

#数据是latin-1编码的csv文件
df = pd.read_csv('spam.csv', encoding='latin-1')
df.head()
#对数据进行原地操作,删除'Unnamed:2', 'Unnamed:3', 'Unnamed:4'这三个列。
#axis=1表示按照水平方向,跨列方向
df.drop(['Unnamed: 2''Unnamed: 3''Unnamed: 4'], axis=1, inplace=True)
#更改列名
df.columns = ['label''message']
#将ham替换为0, spam替换为1
df['label'] = df['label'].map({'ham':0'spam':1})
df.head()

现在我们开始对数据进行特征工程,并进行训练

import numpy as np
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.model_selection import train_test_split
from sklearn.naive_bayes import MultinomialNB
from sklearn.metrics import classification_report

X = df['message']
y = df['label']

#使用词袋法进行特征工程
cv = CountVectorizer()
X = cv.fit_transform(X)
#将数据集分为训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.30, random_state=42)
#训练模型
clf = MultinomialNB()
clf.fit(X_train, y_train)
#评价训练好的模型
print('模型得分:',clf.score(X_test, y_test))

y_pred = clf.predict(X_test)
#打印分类报告
print(classification_report(y_test, y_pred))
模型得分: 0.9784688995215312
             precision    recall  f1-score   support

          0       0.99      0.99      0.99      1453
          1       0.92      0.92      0.92       219

avg / total       0.98      0.98      0.98      1672

朴素贝叶斯不仅简单易用,而且表现相当出色。为了让我们训练的得到的模型能够持久的使用,我们需要将训练好的模型保存下来方便后续调用。这里我们将模型和特征空间cv均保存为pkl文件。

from sklearn.externals import joblib

joblib.dump(clf, 'NB_spam_model.pkl')
joblib.dump(cv, 'cv_engineering.pkl')

我们想通过网络请求将待预测的文本数据传送给后台,让后台的模型预测出结果。并将结果传给web前端。现在我们开始设计flask客户端,下面是项目文件关系:

spam.csv
app.py
templates/
         home.html
         result.html
static/
      style.css
  • templaces存放的是flask的静态html文件模板的文件夹

  • static存放的是样式表

app.py

app.py 文件是项目的主文件,包括机器学习和web(flask)两部分。

from flask import Flask, render_template, url_for, request
import pandas as pd
import pickle
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.naive_bayes import MultinomialNB
from sklearn.externals import joblib

app = Flask(__name__)

@app.route('/')
def home():
    return render_template('home.html')

@app.route('/predict', methods=['POST'])
def predict():
    #读取训练好的分类器模型和特征空间cv
    NB_spam_model = open('NB_spam_model.pkl','rb')
    clf = joblib.load(NB_spam_model)
    cv_engineering_model = open('cv_engineering.pkl','rb')
    cv = joblib.load(cv_engineering_model)
    if request.method=='POST':
        message = request.form['message']
        data = [message]
        vect = cv.transform(data).toarray()
        my_prediction = clf.predict(vect)
    return render_template('result.html', prediction = my_prediction)

if __name__ == '__main__':
    app.run(debug=True)

home.html

<!DOCTYPE html>
<html>
<head>
    <title>Home</title>
    <!-- <link rel="stylesheet" type="text/css" href="../static/css/styles.css"> -->
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>

    <header>
        <div class="container">
        <div id="brandname">
            Machine Learning App with Flask
        </div>
        <h2>Spam Detector For SMS Messages</h2>

    </div>
    </header>

    <div class="ml-container">

        <form action="{{ url_for('predict')}}" method="POST">
        <p>Enter Your Message Here</p>
        <!-- <input type="text" name="comment"/> -->
        <textarea name="message" rows="4" cols="50"></textarea>
        <br/>

        <input type="submit" class="btn-info" value="predict">

    </form>
    </div>
</body>
</html>

style.css

body{
    font:15px/1.5 Arial, Helvetica,sans-serif;
    padding0px;
    background-color:#f4f3f3;
}

.container{
    width:100%;
    margin: auto;
    overflow: hidden;
}

header{
    background:#03A9F4;#35434a;
    border-bottom:#448AFF 3px solid;
    height:120px;
    width:100%;
    padding-top:30px;

}

.main-header{
            text-align:center;
            background-color: blue;
            height:100px;
            width:100%;
            margin:0px;
        }
#brandname{
    float:left;
    font-size:30px;
    color#fff;
    margin10px;
}

header h2{
    text-align:center;
    color:#fff;

}


.btn-info {background-color#2196F3;
    height:40px;
    width:100px;} /* Blue */
.btn-info:hover {background#0b7dda;}


.resultss{
    border-radius15px 50px;
    background#345fe4;
    padding20px
    width200px;
    height150px;
}

result.html

<!DOCTYPE html>
<html>
<head>
    <title></title>
    <link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>

    <header>
        <div class="container">
        <div id="brandname">
            ML App
        </div>
        <h2>Spam Detector For SMS Messages</h2>

    </div>
    </header>
    <p style="color:blue;font-size:20;text-align: center;"><b>Results for Comment</b></p>
    <div class="results">



    {% if prediction == 1%}
    <h2 style="color:red;">Spam</h2>
    {% elif prediction == 0%}
    <h2 style="color:blue;">Not a Spam (It is a Ham)</h2>
    {% endif %}

    </div>

</body>
</html>

待预测文本

Wow. I never realized that you were so embarassed by your accomodations. I thought you liked it, since i was doing the best i could and you always seemed so happy about \the cave\". I'm sorry I didn't and don't have more to give. I'm sorry i offered. I'm sorry your room was so embarassing."

主页效果


预测结果效果

推荐↓↓↓
程序猿
上一篇:程序猿的年终总结,各种版本各种残 下一篇:小白科普:Java EE vs J2EE vs Jakarta EE