Stay Hungry,Stay Foolish!

一则Iris分类器系统介绍(DecisionTree + Flask + React)

简介

https://github.com/fanqingsong/Building-Recommendation-Systems-with-Python/tree/master/Section%205/Video%205.4

系统包括三个部分:

1) 模型产生模块

  实现主体 model_generator.py

  使用iris.data数据, 训练模型,保存模型为 classifier.joblib

2) 分类API服务模块

  使用Flask框架和API库, 暴露出API库, 调用分类器模型 classifier.joblib ,将输入(iris的四个特征值)feed到模型中,模型给出输出(iris分类)

3) 前端界面模块

  基于React实现前端界面,提供用户输出界面,包括iris四个特征值, 并调用分类器服务API,得到iris分类。

 

安装运行

https://github.com/fanqingsong/Building-Recommendation-Systems-with-Python/tree/master/Section%205/Video%205.4

到 video 5.4 目录下,执行以下命令:

service

 

install && run

  • cd service
  • pip3 install -r requirement.txt
  • export FLASK_APP=app.py
  • flask run

 

ui

 

install && run

  • cd ui
  • npm install
  • npm start

 

运行界面

service

访问

http://localhost:5000/

提供了 API的测试界面。

 

 ui

访问

http://127.0.0.1:3000/

提供了用户操作界面。

 

 

 Code Analysis

 模型产生

 

# Import libraries
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.metrics import confusion_matrix
from sklearn.tree import DecisionTreeClassifier
from sklearn.externals import joblib
from sklearn import datasets

# Get the dataset
dataset = datasets.load_iris()

# Split the dataset into features and labels
X = dataset.data
y = dataset.target

# Split the dataset into training (80%) and testing (20%) data
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2, random_state = 0, shuffle = True)

# Build the classifier and make prediction
classifier = DecisionTreeClassifier()
classifier.fit(X_train, y_train)
prediction = classifier.predict(X_test)

# Print the confusion matrix
print("Confusion Matrix:")
print(confusion_matrix(y_test, prediction))

# Save the model to disk
joblib.dump(classifier, 'classifier.joblib')

 

分类服务API

from flask import Flask, request, jsonify, make_response
from flask_restplus import Api, Resource, fields
from sklearn.externals import joblib
import numpy as np
import sys

flask_app = Flask(__name__)
app = Api(app=flask_app,
          version="1.0",
          title="Iris Plant identifier",
          description="Predict the type of iris plant")

name_space = app.namespace('prediction', description='Prediction APIs')

model = app.model('Prediction params',
                  {'sepalLength': fields.Float(required=True,
                                               description="Sepal Length",
                                               help="Sepal Length cannot be blank"),
                   'sepalWidth': fields.Float(required=True,
                                              description="Sepal Width",
                                              help="Sepal Width cannot be blank"),
                   'petalLength': fields.Float(required=True,
                                               description="Petal Length",
                                               help="Petal Length cannot be blank"),
                   'petalWidth': fields.Float(required=True,
                                              description="Petal Width",
                                              help="Petal Width cannot be blank")})

classifier = joblib.load('classifier.joblib')


@name_space.route("/")
class MainClass(Resource):

    def options(self):
        response = make_response()
        response.headers.add("Access-Control-Allow-Origin", "*")
        response.headers.add('Access-Control-Allow-Headers', "*")
        response.headers.add('Access-Control-Allow-Methods', "*")
        return response

    @app.expect(model)
    def post(self):
        try:
            formData = request.json
            data = [val for val in formData.values()]
            prediction = classifier.predict(np.array(data).reshape(1, -1))
            types = {0: "Iris Setosa", 1: "Iris Versicolour ", 2: "Iris Virginica"}
            response = jsonify({
                "statusCode": 200,
                "status": "Prediction made",
                "result": "The type of iris plant is: " + types[prediction[0]]
            })
            response.headers.add('Access-Control-Allow-Origin', '*')
            return response
        except Exception as error:
            return jsonify({
                "statusCode": 500,
                "status": "Could not make prediction",
                "error": str(error)
            })

 

前端界面

import React, { Component } from 'react';
import './App.css';
import Form from 'react-bootstrap/Form';
import Col from 'react-bootstrap/Col';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Button from 'react-bootstrap/Button';
import 'bootstrap/dist/css/bootstrap.css';

class App extends Component {

  constructor(props) {
    super(props);

    this.state = {
      isLoading: false,
      formData: {
        sepalLength: 4,
        sepalWidth: 2,
        petalLength: 1,
        petalWidth: 0
      },
      result: ""
    };
  }

  handleChange = (event) => {
    const value = event.target.value;
    const name = event.target.name;
    var formData = this.state.formData;
    formData[name] = value;
    this.setState({
      formData
    });
  };

  handlePredictClick = (event) => {
    const formData = this.state.formData;
    this.setState({ isLoading: true });
    fetch('http://127.0.0.1:5000/prediction/', 
      {
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        method: 'POST',
        body: JSON.stringify(formData)
      })
      .then(response => response.json())
      .then(response => {
        this.setState({
          result: response.result,
          isLoading: false
        });
      });
  };

  handleCancelClick = (event) => {
    this.setState({ result: "" });
  };

  render() {
    const isLoading = this.state.isLoading;
    const formData = this.state.formData;
    const result = this.state.result;

    var sepalLengths = [];
    for (var i = 4; i <= 7; i = +(i + 0.1).toFixed(1)) {
      sepalLengths.push(<option key = {i} value = {i}>{i}</option>);
    }
    var sepalWidths = [];
    for (var i = 2; i <= 4; i = +(i + 0.1).toFixed(1)) {
      sepalWidths.push(<option key = {i} value = {i}>{i}</option>);
    }
    var petalLengths = [];
    for (var i = 1; i <= 6; i = +(i + 0.1).toFixed(1)){
      petalLengths.push(<option key = {i} value = {i}>{i}</option>);
    }
    var petalWidths = [];
    for (var i = 0.1; i <= 3; i = +(i + 0.1).toFixed(1)) {
      petalWidths.push(<option key = {i} value = {i}>{i}</option>);
    }
    return (
      <Container>
        <div>
          <h1 className="title">Iris Plant Classifier</h1>
        </div>
        <div className="content">
          <Form>
            <Form.Row>
              <Form.Group as={Col}>
                <Form.Label>Sepal Length</Form.Label>
                <Form.Control 
                  as="select"
                  value={formData.sepalLength}
                  name="sepalLength"
                  onChange={this.handleChange}>
                  {sepalLengths}
                </Form.Control>
              </Form.Group>
              <Form.Group as={Col}>
                <Form.Label>Sepal Width</Form.Label>
                <Form.Control 
                  as="select"
                  value={formData.sepalWidth}
                  name="sepalWidth"
                  onChange={this.handleChange}>
                  {sepalWidths}
                </Form.Control>
              </Form.Group>
            </Form.Row>
            <Form.Row>
              <Form.Group as={Col}>
                <Form.Label>Petal Length</Form.Label>
                <Form.Control 
                  as="select"
                  value={formData.petalLength}
                  name="petalLength"
                  onChange={this.handleChange}>
                  {petalLengths}
                </Form.Control>
              </Form.Group>
              <Form.Group as={Col}>
                <Form.Label>Petal Width</Form.Label>
                <Form.Control 
                  as="select"
                  value={formData.petalWidth}
                  name="petalWidth"
                  onChange={this.handleChange}>
                  {petalWidths}
                </Form.Control>
              </Form.Group>
            </Form.Row>
            <Row>
              <Col>
                <Button
                  block
                  variant="success"
                  disabled={isLoading}
                  onClick={!isLoading ? this.handlePredictClick : null}>
                  { isLoading ? 'Making prediction' : 'Predict' }
                </Button>
              </Col>
              <Col>
                <Button
                  block
                  variant="danger"
                  disabled={isLoading}
                  onClick={this.handleCancelClick}>
                  Reset prediction
                </Button>
              </Col>
            </Row>
          </Form>
          {result === "" ? null :
            (<Row>
              <Col className="result-container">
                <h5 id="result">{result}</h5>
              </Col>
            </Row>)
          }
        </div>
      </Container>
    );
  }
}

export default App;

 

posted @ 2019-08-05 23:53  lightsong  阅读(348)  评论(0编辑  收藏  举报
Life Is Short, We Need Ship To Travel