機械学習 業務

#データの保存

from sklearn import datasets, svm
import pickle

#アヤメのサンプルデータ読み込む
iris = datasets.load_iris()

#データを学習
clf = svm.SVC()
clf.fit(iris.data, iris.target)

#学習済みデータを保存
with open('iris.pkl', 'wb') as fp:
    pickle.dump(clf, fp)

# データの読み込み

from sklearn import datasets, svm
from sklearn.metrics import accuracy_score
import pickle

#保存した学習済みデータと分類器を読み込み
with open('iris.pkl', 'rb') as fp:
    clf = pickle.load(fp)  
    
#アヤメのサンプルデータ読み込む
iris = datasets.load_iris()

#予測する
pre = clf.predict(iris.data)

#正解率を表示
print(accuracy_score(iris.target, pre))

TensorFlowと Kerasの場合

# keras保存

from sklearn import datasets
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.utils import to_categorical

# アヤメのサンプルデータを読み込む
iris = datasets.load_iris()
in_size = 4
nb_classes = 3

# ラベルデータをone-hotベクトルに変換
x = iris.data
y = to_categorical(iris.target, nb_classes)

# モデルを定義
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(nb_classes, activation='softmax'))

# モデルを構築
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])

# 学習を実行
model.fit(x, y, batch_size=20, epochs=50)

# モデル全体を保存(新しいフォーマットを使用)
model.save('iris-model.keras')

# 学習済み重みデータを保存
model.save_weights('iris-weights.weights.h5')
from sklearn import datasets
import keras
from keras.models import load_model
from keras.utils import to_categorical

# アヤメのサンプルデータを読み込む
iris = datasets.load_iris()
nb_classes = 3

# ラベルデータをone-hotベクトルに変換
x = iris.data
y = to_categorical(iris.target, nb_classes)

# モデル全体を読み込む
model = load_model('iris-model.keras')

#積みデータを読み込み
model.load_weights('iris-weights.weights.h5')

# モデルを評価
score = model.evaluate(x, y, verbose=1)
print('正解率=', score[1])
#TF-IDFでテキストをベクトル化するモジュール

import MeCab
import pickle
import numpy as np

#MeCabの初期化
# tagger = MeCab.Tagger("-r /etc/mecabrc -d /home/linuxbrew/.linuxbrew/lib/mecab/dic/mecab-ipadic")
tagger = MeCab.Tagger("-r /etc/mecabrc -d /home/linuxbrew/.linuxbrew/lib/mecab/dic/ipadic")

#グローバル変数
word_dic = {'_id': 0}
dt_dic = {}
files = []

def tokenize(text):
    # MeCabで形態素解析を行う
    result = []
    word_s = tagger.parse(text)
    for n in word_s.split("\n"):
        if n == 'EOS' or n == '': continue
        p = n.split('\t')[1].split(',')
        hinsi = p[0]
        if hinsi not in ['名詞', '形容詞', '動詞']: continue
        w = p[6] if p[6] != '*' else n.split('\t')[0]
        if w == '' or w == '\n': continue
        result.append(w)  # 'org' の代わりに 'w' を使用
    return result


def words_to_ids(words, auto_add = True):
    #単語一覧をIDのリストに変換する
    result = []
    for word in words:
        if word in word_dic:
            result.append(word_dic[word])
            continue
        elif auto_add:
            id = word_dic[word] = word_dic['_id']
            word_dic['_id'] += 1
            result.append(id)
    return result

def add_text(text):
    #テキストをIDリストに変換して追加する
    ids = words_to_ids(tokenize(text))
    files.append(ids)
    
def add_file(path):
    #テキストファイルを学習用に追加する
    with open(path, "r", encoding="utf-8") as f:
        s = f.read()
        add_text(s)
        
def calc_files():
    #追加したファイルを計算する
    global dt_dicf
    result = []
    doc_count = len(files)
    dt_dic = {}
    #単語の出現頻度を数える
    for words in files:
        usred_word = {}
        data = np.zeros(word_dic['_id'])
        for id in words:
            data[id] += 1
            usred_word[id] = 1
        #単語tが使われていればdt_dicのカウントを増やす
        for id in usred_word:
            if not id in dt_dic: dt_dic[id] = 0
            dt_dic[id] += 1
        # 出現回数を割合に直す
        data = data / len(words)
        result.append(data)
    # TF-IDFを計算する
    for i, doc in enumerate(result):
        for id, v in enumerate(doc):
            idf = np.log(doc_count / dt_dic[id]) + 1
            doc[id] = min([doc[id] * idf, 1.0])
        result[i] = doc
    return result

def save_dirc(fname):
    #辞書をファイルに保存する
    pickle.dump([word_dic, dt_dic], open(fname, "wb"))
    
def load_dic(fname):
    #辞書ファイルを読み込む
    global word_dic, dt_dic, files
    n = pickle.load(open(fname, "rb"))
    word_dic, dt_dic, files = n 

def calc_text(text):
    #辞書を更新せずにベクトル変換する
    data = np.zeros(word_dic['_id'])
    words = words_to_ids(tokenize(text), False)
    for w in words:
        data[w] += 1
    data = data / len(words)
    for id, v in enumurate(data):
        idf = np.log(len(files) / dt_dic[id]) + 1
        data[id] = min([data[id] * idf, 1.0])
    return data

#モジュールのテスト
if __name__ == "__main__":
    add_text("雨")
    add_text("今日は、雨が降った")
    add_text("今日は暑い日だったけど雨が降った")
    add_text("今日も雨だ。でも日曜だ。")
    print(calc_files())
    print(word_dic)

ニュース記事分類

# 文章をTF-IDFのデータベースに変換

import os, glob, pickle
import tfidf

#変数の初期化
y = []
x = []

#ディレトリー内のファイル一覧を処理
def read_files(path, label):
    print("read_files=", path)
    files = glob.glob(path + "/*.txt")
    for f in files:
        tfidf.add_file(f)
        y.append(label)
        
#ファイル一覧を読む
read_files("text/sports-watch", 0)
read_files("text/it-life-hack", 1)
read_files("text/movie-enter", 2)
read_files("text/dokujo-tsushin", 3)

#TF-IDFベクトルに変換
x = tfidf.calc_files()

#保存
pickle.dump([y, x], open("text/genre.pickle", "wb"))
# tfidf.save_dic("text/genre-tdidf.dic")
tfidf.save_dic("text/genre-tdidf.dic")
print("ok")
# TF-IDFをNaiveBayesで学習

import pickle
from sklearn.naive_bayes import GaussianNB
from sklearn.model_selection import train_test_split
import sklearn.metrics as metrics
import numpy as np

# TF-IDF のデータベースを読み込む
data = pickle.load(open("text/genre.pickle", "rb"))
y = data[0]
x = data[1]

# 学習用とテスト用に分離
x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2)

# ナイーブベイズで学習
model = GaussianNB()
model.fit(x_train, y_train)

# 評価して結果を表示
y_pred = model.predict(x_test)
acc = metrics.accuracy_score(y_test, y_pred)
rep = metrics.classification_report(y_test, y_pred)

print("正解率=", acc)
print(rep)

ディープラーニングに置き換え

ラベルデータをOne-Hot形式に直し、入力と出力のベクトルサイズを調べ指定すること。

import pickle
from sklearn.model_selection import train_test_split
import sklearn.metrics as metrics
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
import matplotlib.pyplot as plt
import numpy as np
import h5py
from keras.utils import to_categorical  # to_categorical を直接インポート


# 分類するラベルの数 --- (*1)
nb_classes = 4

# データベースの読込 --- (*2)
data = pickle.load(open("text/genre.pickle", "rb"))
y = data[0] # ラベル
x = data[1] # TF-IDF
# ラベルデータをone-hotベクトルに直す --- (*3)
# ラベルデータを One-Hot ベクトルに変換
y = to_categorical(y, nb_classes)
# y = keras.utils.np_utils.to_categorical(y, nb_classes)
in_size = x[0].shape[0]

# 学習用とテスト用を分ける --- (*4)
x_train, x_test, y_train, y_test = train_test_split(
        np.array(x), np.array(y), test_size=0.2)

# MLPモデル構造を定義 --- (*5)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(in_size,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(nb_classes, activation='softmax'))

# モデルをコンパイル --- (*6)
model.compile(
    loss='categorical_crossentropy',
    optimizer=RMSprop(),
    metrics=['accuracy'])

# 学習を実行 --- (*7)
hist = model.fit(x_train, y_train,
          batch_size=128, 
          epochs=20,
          verbose=1,
          validation_data=(x_test, y_test))

# 評価する ---(*8)
score = model.evaluate(x_test, y_test, verbose=1)
print("正解率=", score[1], 'loss=', score[0])

# 重みデータを保存 --- (*9)
model.save_weights('./text/genre-model.weights.h5')  # 拡張子を .weights.h5 に変更

# 学習の様子をグラフへ描画 --- (*10)
plt.plot(hist.history['accuracy'])
plt.plot(hist.history['val_accuracy'])
plt.title('Accuracy')
plt.legend(['train', 'test'], loc='upper left')
plt.show()
#テキストを判別

import pickle, tfidf
import numpy as np
import keras
from keras.models import Sequential
from keras.layers import Dense, Dropout
from keras.optimizers import RMSprop
from keras.models import model_from_json

# 独自のテキストを指定 --- (*1)
text1 = """
野球を観るのは楽しいものです。
試合だけでなくインタビューも楽しみです。
"""
text2 = """
常にiPhoneとiPadを持っているので、
二口あるモバイルバッテリがあると便利。
"""
text3 = """
幸せな結婚の秘訣は何でしょうか。
夫には敬意を、妻には愛情を示すことが大切。
"""

# TF-IDFの辞書を読み込む --- (*2)
tfidf.load_dic("text/genre-tdidf.dic")

# Kerasのモデルを定義して重みデータを読み込む --- (*3)
nb_classes = 4
dt_count = len(tfidf.dt_dic)
model = Sequential()
model.add(Dense(512, activation='relu', input_shape=(dt_count,)))
model.add(Dropout(0.2))
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.2))
model.add(Dense(nb_classes, activation='softmax'))
model.compile(
    loss='categorical_crossentropy',
    optimizer=RMSprop(),
    metrics=['accuracy'])
model.load_weights('./text/genre-model.weights.h5')

# テキストを指定して判定 --- (*4)
def check_genre(text):
    # ラベルの定義
    LABELS = ["スポーツ", "IT", "映画", "ライフ"]
    # TF-IDFのベクトルに変換 -- (*5)
    data = tfidf.calc_text(text)
    # MLPで予測 --- (*6)
    pre = model.predict(np.array([data]))[0]
    n = pre.argmax()
    print(LABELS[n], "(", pre[n], ")")
    return LABELS[n], float(pre[n]), int(n) 

if __name__ == '__main__':
    check_genre(text1)
    check_genre(text2)
    check_genre(text3)

テキスト分類にディープラーニングは使える。

未知の単語は飛ばす仕組みなので、正確性をあげるにはさらに勉強させる必要がある。

# APIを呼び出すWebアプリを作ろう

import json
import flask
from flask import request
import my_text

# ポート番号
TM_PORT_NO = 8888

# HTTPサーバーを起動
app = flask.Flask(__name__)
print("https://localhost:" + str(TM_PORT_NO))

# ルートへアクセスした場合
@app.route('/', methods=['GET'])
def index():
    try:
        with open("index.html", "rb") as f:
            return f.read()
    except FileNotFoundError:
        return "Index page not found", 404


# /api へアクセスした場合
@app.route('/api', methods=['GET'])  # 修正
def api():
    # URLパラメータを取得
    q = request.args.get('q', '')
    if q == '':
        return '{"label": "からです", "per":0}'
    print("q=", q)
    
    # テキストジャンル判定を行う
    label, per, no = my_text.check_genre(q)
    
    # 結果をJSONで出力
    return json.dumps({
        "label": label,
        "per": per,
        "genre_no": no
    })
    
if __name__ == '__main__':
    app.run(debug=True, host='0.0.0.0', port=TM_PORT_NO)

index.html

<DOCTYPE html>
<html><meta charset="utf-8"><body>
<h1>テキストのジャンル判定</h1>
<div>
  <textarea id="q" rows="10" cols="60"></textarea>
  <br><button id="qButton">判定</button>
  <div id="result"></div>
</div>
<script>
const qs = (q) => document.querySelector(q)
window.onload = () => {
  const q = qs('#q')
  const qButton = qs('#qButton')
  const result = qs('#result')
  // 判定ボタンを押した時 --- (*1)
  qButton.onclick = () => {
    result.innerHTML = "..."
    // APIサーバに送信するURLを構築 --- (*2)
    const api = "/api?q=" + 
      encodeURIComponent(q.value)
    // APIにアクセス --- (*3)
    fetch(api).then((res) => {
      return res.json() // JSONで返す
    }).then((data) => {
      // 結果を画面に表示 --- (*4)
      result.innerHTML =
        data["label"] + 
        "<span style='font-size:0.5em'>(" + 
        data["per"] + ")</span>"
    })
  }
}
</script>
<style>
#result { padding: 10px; font-size: 2em; color: red; }
#q { background-color: #fffff0; }
</style>
</body></html>
タイトルとURLをコピーしました