2021年7月夏研修


2021年夏研修

今回研修で作成するシステム(AI家賃予測システム)



今回は前回構築してherokuに配備したモデルを家賃予想モデルに入れ替えます。それにあわせてクライアントも入れ替えます

PythonAPIサンプルの説明

前回構築したPythonAPIですが、修正点は学習済のモデルを入れ替えるだけです。

app.py

from joblib import dump, load
import flask
import numpy as np
from flask_cors import CORS 

# initialize our Flask application and pre-trained model
app = flask.Flask(__name__)
CORS(app)
model = None

# 学習済モデルの読み込み
def load_model():
    global model
    print(" * Loading pre-trained model ...")
    model = load("sample-model.pkl")
    print(' * Loading end')

# 接続確認テスト用 getでrootにアクセスしたときに、Hello Worldを表示させる
@app.route('/')
def index():
    return 'Hello World!'

# 機械学習結果返却処理
@app.route("/predict", methods=["POST"])
def predict():
    model = load("sample-model.pkl")  #このファイルを入れ替えます
    response = {
        "success": False,
        "Content-Type": "application/json"
    }
    # ensure an feature was properly uploaded to our endpoint
    if flask.request.method == "POST":
        if flask.request.get_json().get("feature"):
            # read feature from json
            feature = flask.request.get_json().get("feature")

            # preprocess for classification
            # list  -> np.ndarray
            feature = np.array(feature).reshape((1, -1))

            # classify the input feature
            response["prediction"] = model.predict(feature).tolist()

            # indicate that the request was a success
            response["success"] = True
    # return the data dictionary as a JSON response
    return flask.jsonify(response)


if __name__ == "__main__":
    load_model()
    print(" * Flask starting server...")
    app.run(host='0.0.0.0', port='8000')

家賃予測モデルの作成1

サンプルを以下の機械学習モデルに入れ替えてみましょう(家賃を予測するモデル)

#家賃を予測する
import numpy as np
from sklearn import linear_model
#1次元目は面積 2次元目は階
X = np.array([
    [7, 7.12, 7.2, 7.69, 7.79, 8, 8.28, 8.37, 8.7, 9.93, 10.5, 10.53, 11, 12.19, 12.4],
    [2, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 1, 3, 3, 1]
]).T
#家賃(千円単位)
Y = np.array([
    [45, 51, 52, 53, 52.6, 52, 54, 54.2, 56, 64, 65, 72, 75, 78.3, 80]
]).T

model = linear_model.LinearRegression(fit_intercept=False)
model.fit(X, Y)

#面積8m² で3階にある部屋の家賃は?=>[[51.32707814]]
print(model.predict([[8, 3]]))

学習済モデルのdump方法例

学習したモデルを保存するには、学習したモデルをdumpします

from sklearn import svm
from sklearn import datasets
from joblib import dump, load

# classifier
clf = svm.SVC()

iris = datasets.load_iris()

X, y = iris.data, iris.target
clf.fit(X, y)

dump(clf, 'sample-model.pkl')

クライアントの説明(前回の復習)

下記のサンプルは4つの変数をAPIに渡す形なので、家賃について、予測する変数の数を渡すように修正します

注意)Herokuの無料枠はしばらく使っていないとスリープするので、クライアントの初回実行はちょっと時間がかかります

Railsクライアントサンプルの説明(前回の例)

Controller

require 'json'
require 'net/https'
require "uri"

class ApiTestController < ApplicationController
  def index
    data={feature: [10, 20, 5, 1]}    #このパラメタの数は変更になります
    uri = URI.parse("http://syslink-ai-api.herokuapp.com/predict")
    http = Net::HTTP.new(uri.host, uri.port)
    req = Net::HTTP::Post.new(uri.path)
    req.set_content_type("application/json")
    req.body = data.to_json

    res = http.request(req)

    p res.code
    #if res.code == Net::HTTPSuccess
    if res.code == "200"
      res_data = JSON.parse(res.body)
      @prediction = res_data["prediction"]
    end
  end
end

View

<div class="container">
    <!-- 表題 -->
    <div class="content-title">
        <h3><span class="title-style"><label>AI分析結果</label></span></h3>
    </div>
    <div class="well">
        <h2>AI分析結果</h2>
        <h1>あなたの評価は<%= @prediction %>です</h1>
    </div>
</div>

JQueryクライアントサンプルの説明(前回の例)

main.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>
<p><input type="text" id="input1" value="0.74"></p>
<p><input type="text" id="input2" value="1.22"></p>
<p><input type="text" id="input3" value="1.22"></p>
<p><input type="text" id="input4" value="1.22"></p>
<button id="button">ボタン</button>
<p>結果:<span id="answer"></span></p>

<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="main.js"></script>
</body>
</html>

main.js

$(function(){
var url = 'http://syslink-ai-api.herokuapp.com/predict';
    $('#button').on('click', function() {
        var arays = []
        arays.push(parseFloat($('#input1').val()));
        arays.push(parseFloat($('#input2').val()));
        arays.push(parseFloat($('#input3').val()));
        arays.push(parseFloat($('#input4').val()));
        console.log(arays);

        // API連携
        $.ajax({
          type: 'POST',               // 使用するHTTPメソッド
          url : url,                  // 通信先URL
          dataType: 'json',           // レスポンスのデータタイプ
          contentType: "application/json",
          data: JSON.stringify({feature: arays}),
          traditional: true
        })
        .done(function(data, textStatus, jqXHR) {
          console.log(data.prediction[0]);
          $('#answer').text(data.prediction[0]);
        })
        .fail(function(jqXHR, textStatus, errorThrown) {
          console.log('通信が失敗しました');
        });
    
    });
});

Vue.jsクライアントサンプルの説明(前回の例)

main.html

<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <title></title>
</head>
<body>
<div id="app">
    <p><input type="text" id="input1" value="10"></p>
    <p><input type="text" id="input2" value="20"></p>
    <p><input type="text" id="input3" value="5"></p>
    <p><input type="text" id="input4" value="1"></p>
    <button v-on:click="showData">ボタン</button>
    <p>結果:<span id="answer"></span></p>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script src="https://jp.vuejs.org/js/vue.js"></script>
<script src="main.js"></script>
</body>
</html>

main.js

var app = new Vue({
    el: '#app',
    data: {
      message: ''
    },
    methods: {
        showData: function() {
            var url = 'http://syslink-ai-api.herokuapp.com/predict';
            var arays = []
            arays.push(parseFloat($('#input1').val()));
            arays.push(parseFloat($('#input2').val()));
            arays.push(parseFloat($('#input3').val()));
            arays.push(parseFloat($('#input4').val()));
            console.log(arays);

            // API連携
            $.ajax({
                type: 'POST',               // 使用するHTTPメソッド
                url : url,                  // 通信先URL
                dataType: 'json',           // レスポンスのデータタイプ
                contentType: "application/json",
                data: JSON.stringify({feature: arays}),
                traditional: true
            })
            .done(function(data, textStatus, jqXHR) {
                console.log(data.prediction[0]);
                $('#answer').text(data.prediction[0]);
            })
            .fail(function(jqXHR, textStatus, errorThrown) {
                console.log('通信が失敗しました');
            })
        }
    }
});

Railsクライアントサンプルの説明(修正版の例)

Controller

require 'json'
require 'net/https'
require "uri"

class ApiTestController < ApplicationController
  def index
    if params[:input_form].present?
      params[:input_form] = find_params.to_h
      @input_form = InputForm.new(params)

      data={feature: [params[:input_form][:area], params[:input_form][:floor]]}
      uri = URI.parse("http://(your url)/predict")
      http = Net::HTTP.new(uri.host, uri.port)
      req = Net::HTTP::Post.new(uri.path)
      req.set_content_type("application/json")
      req.body = data.to_json
  
      res = http.request(req)
  
      p res.code
      #if res.code == Net::HTTPSuccess
      if res.code == "200"
        res_data = JSON.parse(res.body)
        @prediction = res_data["prediction"]
      end
    else
      @input_form = InputForm.new(nil)
      @prediction = ""
    end
  end
  private
    def find_params
      params.require(:input_form).permit(:area, :floor)
    end
end

view(index.html.erb)

<div class="container">
	<!-- 表題 -->
	<div class="content-title">
		<h3><span class="title-style"><label>AI家賃予測</label></span></h3>
	</div>
	<%= form_for @input_form,url:{action: :index},html:{method: :get, class:'form-search'} do |f| %>
		<div class="table-responsive">
			<table class="table table-bordered">
				<colgroup>
					<col width="150px">
					<col width="180px">
					<col width="150px">
					<col width="180px">
				</colgroup>
				<tr>
					<td class="label-success" colspan="4">条件</td>
				</tr>
				<tr>
					<td class="success middle">面積</td>
					<td><%= f.text_field :area, class:"form-control" %></td>
					<td class="success middle">階</td>
					<td><%= f.text_field :floor, class:"form-control" %></td>
				</tr>
			</table>
		</div>
		<%= button_tag(type: 'submit', class: "btn btn-primary") do %>
			<span>検索</span>
		<% end %>
	<% end %>

	<div class="well">
		<h2>予測結果</h2>
<% if @prediction.present? %>
		<h1>家賃は<%= @prediction[0][0].to_i * 1000 %>円です</h1>
<% end %>
	</div>
</div>

model(input_form.rb)

class InputForm
  include ActiveModel::Model

  attr_accessor :area
  attr_accessor :floor

  def initialize(params)
    if params.present?
        if params.is_a?(Hash)
          @area   = params["area"]
          @floor  = params["floor"]
        else
          @area   = params[:input_form][:area]
          @floor  = params[:input_form][:floor]
      end
    end
  end
end

実行した画面

家賃予測モデルの作成2

上記の家賃を予測するシステムが作成したら、今度は松江家賃.csvを学習したモデルに書き換えて、松江の家賃を予測するシステムにしましょう 上記のモデルはプログラムの中に配列のデータを持っていますが、そこをpandasでcsvをデータフレームに読み込んで、学習させます

下記のサンプルは広さと何階かを入力としていますが、色々変えてみてください

#家賃を予測する
import pandas as pd
from sklearn import linear_model
df = pd.read_csv("松江家賃.csv", encoding="cp932")
X = df[["広さ", "階"]] 
Y = df["家賃"]

model = linear_model.LinearRegression(fit_intercept=False)
model.fit(X, Y)

#面積47.7m² で1階にある部屋の家賃は?=>[1.70486347]
print(model.predict([[47.7, 1]]))

参考資料 https://www.dandan-net.com/info/pandas/