機械学習実装のWeb サイト作り【Flask使用】

#目的

入力したワインの特徴から、ワインの品質（quality）Bランク〜Sランクを予測するWebサイトを作成する
機械学習を使った、webサイト作成を体験してみる

![4285898_s.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/9d5c95f3-0610-9fc9-2121-de808d0e8f98.jpeg)


![スクリーンショット 2021-04-02 18.08.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/6ffed1e6-5201-daa5-3d7e-678ca0268c83.png)
#データ
使用出来るデータ
https://archive.ics.uci.edu/ml/datasets/Wine+Quality

複数の成分からワインの品質の予測を行う

固定酸性度	fixed_acidity
揮発性酸性度	volatile_acidity
クエン酸	citric_acid
残留糖	residual_sugar
塩化物	chlorides
遊離亜硫酸濃度	free_sulfur_dioxide
総亜硫酸濃度	total_sulfur_dioxide
密度	density	
pH	ph
硫酸塩	sulphates
アルコール　alcohol
品質	quality



#環境
Colaboratory使用(学習モデル作成時)
Atom1.55.0(Web page作成)


#学習のモデル作り
googleのColaboratoryでまずは、機械学習のモデル作りを行う

ワインのデータセットをダウンロード

```python:
import pandas as pd
wine = pd.read_csv("https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv", sep=";", encoding="utf-8")
wine
```
1599index(行)×12 columns（列）のデータセット確認

![スクリーンショット 2021-03-30 14.55.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/b5ff7e2a-1e69-1ebf-6261-3169354d6386.png)



corr()でqualityとの相関係数を確認をする
残念ながら。。。
0.6や-0.6を超えるような、qualityに大きな影響を当たる特徴がない



```python:
wine.corr()
```

![スクリーンショット 2021-03-31 15.53.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/e3f60427-389a-2426-2e71-ae33fdb34fb3.png)



正解の品質ラベルのデータをY
個人的に予測に使用するデータは、シンプルにアルコールとよく成分で見かけるtotal_sulfur_dioxide（総亜硫酸濃度）としたいが


２つの特徴だけでは、いい精度を出すのは不可能に近いので

今回は、相関係数が高いvolatile_acidity（揮発性酸性度）,sulphates（硫酸塩）も使用する



```python:
Y = wine["quality"]
using_coulumns=["total sulfur dioxide","alcohol","volatile acidity","sulphates"]

X =wine[using_coulumns]
```

この4つの特徴から、ワインの品質を予測する

![スクリーンショット 2021-04-02 17.32.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/3e5438ab-9688-307f-0d13-c477e2160792.png)


ヒストグラムでワインの品質を確認

```python:
from matplotlib import pyplot as plt
plt.hist(Y,bins=10)
```

![スクリーンショット 2021-04-02 17.35.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/26ae8574-e65d-6499-9356-f26b36a862c6.png)


３と８が少しだけあるが、これを含めて予測するのは難しいので
正解ラベルを３等分にする、
3,4→0
5,6→1
7,8→２

```python:
Y.replace({3:0,4:0},inplace=True)
Y.replace({5:1,6:1},inplace=True)
Y.replace({7:2,8:2},inplace=True)
```

正解ラベルYと特徴Xから、学習するためのtrainデータと
精度確認のためtestデータを作成
testデータは3割りで残りは学習データとする

```python:
from sklearn.model_selection import train_test_split
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.3)
```

今回はrandom_forestで学習を行う、

```python:
from sklearn.ensemble import RandomForestClassifier
model = RandomForestClassifier()
model.fit(x_train, y_train)
```

先ほど学習を行ったモデルでtestデータの予測を行う
testデータのラベル（正解）と、予測したデータをaccuracy_scoreで比較する
結果は正答率85%前後

```python:
from sklearn.metrics import accuracy_score
y_pred = model.predict(x_test)

print("正解率 = ", accuracy_score(y_test, y_pred))
```
先ほどの学習のモデルをpickleで保存
左のファイルから右クリックでダウンロード出来る
このwinemodel.pklをweb pageで使用する


```python:
import pickle
with open('winemodel.pkl', mode='wb') as fp:
  pickle.dump(model,fp)
```


![スクリーンショット 2021-03-30 15.55.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/eb5b17f6-1d17-0ee4-1c28-c5aa225f15aa.png)

#Web作成

表示するHTMLのindex.htmlはtemplatesへ

├main.py
├winemodel.pkl
├templates/index.html

main.py file

```python:main.py


from flask import Flask, render_template, redirect
from flask import request, jsonify
import pandas as pd
import pickle
from sklearn.ensemble import RandomForestRegressor

app = Flask(__name__)

#先ほどの機械学習のモデル読み込み
model_file_name='winemodel.pkl'
model = pickle.load(open(model_file_name, 'rb'))

#実行を開始すべきURLを指定
@app.route('/')
def index():
   return render_template('index.html')

#HTMLのformから受け取った時の処理
@app.route('/hinshitsu', methods=['POST'])
def lower_conversion():
   total = request.form["total sulfur dioxide"]
   alcohol=request.form["alcohol"]
   volatile = request.form["volatile acidity"]
   sulphates = request.form["sulphates"]
　　#受け取ったデータをデータフレームに変更
   df = pd.DataFrame({'total sulfur dioxide': [total],
                   'alcohol': [alcohol],
                   'volatile acidity': [volatile],
                   'sulphates': [sulphates],
                   })
　　#予測
   result = model.predict(df)
　　#予測結果をpythonのint型に変更
   result = result.item()
   rank=""
   if result==0:
       rank="Bランク"
   elif result==1:
       rank="Aランク"
   else:
       rank="Sランク"

   #HTMLに変更内容を送る
   return render_template('index.html',rank = rank)


if __name__ == '__main__':
   app.run(host="0.0.0.0", port=8080)

```


入力フォームは step=で入力出来る小数点の単位を指定

```HTML:index.html

<!DOCTYPE html>
<html lang="ja">
 <head>
   <meta charset="utf-8"></meta>
   <title>ワイン品質予測</title>
 </head>
 <body>
         <h1>ワインの品質予想</h1>
             <hr>
             ここに結果が表示される:<h1>{{rank}}</h1>
             <hr>
             <p>ワインの成分を入力して下さい</p>
         <form method='POST' action='/hinshitsu'>

             <div>
                 <p>総亜硫酸濃度(total sulfur dioxide):</p>
                 <p><input type="number" step="0.01"  name="total sulfur dioxide"required></p>
             </tr>
             </div>

             <div>
                 <p>アルコール(alcohol):</p>
                 <p> <input type="number" step="0.01"  name="alcohol"required></p>
             </div>

             <div>
                 <p>揮発性酸性度(volatile acidity):</p>
                 <p>  <input type="number" step="0.001" name="volatile acidity"required></p>
             </div>
             <div>
                 <p>硫酸塩(sulphates):</p>
                 <p> <input type="number" step="0.01"  name="sulphates"required></p>
             </div>


          <input type="submit" value="予測">
          </form>
</body>
</html>
```

python main.pyでmain.py fileを実行する
下記、WARNINGが表示されたら成功、Running onに表示されているURLにアクセスしたら完了

   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://0.0.0.0:8080/ (Press CTRL+C to quit)

#実験
モデルを作成する時に使った、最初の0番目のデータで確認



![スクリーンショット 2021-03-31 16.54.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/5a157473-1d60-a6ac-2231-780cd4472cc7.png)

![スクリーンショット 2021-04-02 18.08.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/6ffed1e6-5201-daa5-3d7e-678ca0268c83.png)



予測すると・・・




品質5なので無事Aランクで表示

![スクリーンショット 2021-03-31 17.00.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1186069/55721cf5-8960-2214-521c-4c03300e2301.png)

#終わりに
ターゲットをソムリエなどのプロ集団なら、データの特徴を増やして、精度をかなり上げないといけないが
軽く参考程度に確認を行う場合は、複雑な成分がありすぎると利用面では不便
どれだけ精度を出せるか、また使いやすさも大切でトレードオフな部分がある
まずは、ターゲットを絞ることが大切かもしれない