python3.doc_71
最終投稿日:2022年6月18日
アヤメと言う花のデータをダウンロードします。
が、ライブラリ Pandas の中にアヤメの CSV データがあるのでそれを使います。
データの抜粋が以下です。
抜粋)
SepalLength,SepalWidth,PetalLength,PetalWidth,Name
5.1,3.5,1.4,0.2,Iris-setosa
ヘッダー行とデータ行(150行)のファイルです。
データの内容は以下となります。
SepalLength がく片の長さ
SepalWidth がく片の幅
PetalLength 花びらの長さ
PetalWidth 花びらの幅
Name 花の名前
例)
from sklearn import svm, metrics
import random, re, os
csv = []
dir = os.path.dirname(__file__)
fname = os.path.join(dir, 'iris.csv')
#CSV ファイルを開く
with open(fname, 'r', encoding='utf-8') as fp:
for line in fp:
#改行文字を削除
line = line.strip()
#カンマで区切り配列にする
cols = line.split(',')
#ラムダ関数定義
fn = lambda n: float(n) if re.match(r'^[0-9\.]+$', n) else n
#map メソッドにより再帰的に配列を処理する
cols = list(map(fn, cols))
#配列を作り直す(数字は数値に変換しただけ)
csv.append(cols)
#1行目を削除(タイトル行なので)
del csv[0]
#配列をシャッフルする
random.shuffle(csv)
#ここからトレーニングデータとテストデータを作成している
total_len = len(csv)
train_len = int(total_len * 2 / 3)
train_data = []
train_label = []
test_data = []
test_label = []
for i in range(total_len):
data = csv[i][0:4]
label = csv[i][4]
if i < train_len:
train_data.append(data)
train_label.append(label)
else:
test_data.append(data)
test_label.append(label)
#学習器を初期化
clf = svm.SVC()
#学習させる
clf.fit(train_data, train_label)
#テストデータを実行
pre = clf.predict(test_data)
#結果を取得
ac_score = metrics.accuracy_score(test_label, pre)
print(ac_score)
内容としては、任意の外国語からなるHTML文章が何語なのかを判定する学習器を作成します。
● サンプルデータ(HTML)を収集し、トレーニングデータを作成する
wiki をスクレイピングし、
国別のアルファベットの出現率データを作成し、CSVデータとして保存します。
en 英語
fr フランス語
es スペイン語
id インドネシア語
例)
import urllib.request as urlreq
import urllib.parse as urlps
from bs4 import BeautifulSoup
import re, random, os, csv, time
def analize_start(url):
target_url = []
res = urlreq.urlopen(url[2])
soup = BeautifulSoup(res, 'html.parser')
soup.prettify()
links = soup.find_all('a')
for a in links:
for key, val in a.attrs.items():
if key == 'href':
# 有効なURLを抽出(/wikiから始まり「:」「()」がないURL)
if re.search(r'^(?=/wiki)(?!.*(:|\()).*$', val) != None:
if val not in target_url: target_url.append(val)
continue
if len(target_url) < MAX_URL:
print('収集するURLが足りません。。')
exit()
# 配列をシャッフル
random.shuffle(target_url)
# 任意の個数にする
target_url = target_url[:MAX_URL]
return getHtml2Text(url[0], url[1], target_url)
def getHtml2Text(label, base, target_url):
data = []
for val in target_url:
url = urlps.urljoin(base, val)
res = urlreq.urlopen(url)
time.sleep(1)
soup = BeautifulSoup(res, 'html.parser')
soup.prettify()
# BODYタグ内のみ取得
body = soup.find('body')
# タグを全て除去
text = re.sub(r'<[^>]*?>','',body.text)
d = create_data(label, text)
data.append(d)
return data
def create_data(label, text):
# データ用配列定義(A~Z)
cnt = [0 for n in range(0, 26)]
code_a = ord('a')
code_z = ord('z')
text = text.lower()
for ch in text:
n = ord(ch)
if code_a <= n <= code_z:
#該当のアルファベットの次元を +1 する
cnt[n - code_a] += 1
total = sum(cnt)
#全体の文字数で割り、率にする
cnt = list(map(lambda n: n / total, cnt))
cnt.insert(0, label)
return cnt
if __name__ != '__main__':
exit()
# グローバル変数
MAX_URL = 50
#検索する言語の最初のページ
start_url = [
('en','https://en.wikipedia.org','https://en.wikipedia.org/wiki/Internet')
,('fr','https://fr.wikipedia.org','https://fr.wikipedia.org/wiki/Internet')
,('es','https://es.wikipedia.org','https://es.wikipedia.org/wiki/Internet')
,('id','https://id.wikipedia.org','https://id.wikipedia.org/wiki/Internet')
]
traning_data = [] # トレーニングデータ取得配列(2次元)
for url in start_url:
# スクレイピング開始
d = analize_start(url)
traning_data.append(d)
dir = os.path.dirname(__file__)
sava_name = os.path.join( dir, 'language_data.csv' )
f = open(sava_name, 'w')
writer = csv.writer(f, lineterminator='\n')
# CSVファイル作成
for arr_text in traning_data:
for arr_t in arr_text:
writer.writerow(arr_t)
print('完了~')
● 学習し、言語を予測する
上述の CSV を利用し、学習させます。
例)
from sklearn import svm, metrics
import random, re, os
csv = []
dir = os.path.dirname(__file__)
fname = os.path.join(dir, 'language_data.csv')
#CSV ファイルを開く
with open(fname, 'r', encoding='utf-8') as fp:
for line in fp:
line = line.strip()
cols = line.split(',')
# 精度の調節として 50 倍する
#CSV データは全て文字列なので
fn = lambda n: float(n) * 50 if re.match(r'^[0-9\.]+$', str(n)) else n
#数値に変換し配列に格納する。
csv.append(list(map(fn, cols)))
random.shuffle(csv)
total_len = len(csv)
train_len = int(total_len * 3 / 4)
train_data = []
train_label = []
test_data = []
test_label = []
for i in range(total_len):
data = csv[i][1:]
label = csv[i][0]
if i < train_len:
train_data.append(data)
train_label.append(label)
else:
test_data.append(data)
test_label.append(label)
#学習器を初期化
clf = svm.SVC()
#学習
clf.fit(train_data, train_label)
#テストデータ予測
pre = clf.predict(test_data)
ac_score = metrics.accuracy_score(test_label, pre)
cl_report = metrics.classification_report(test_label, pre)
print(ac_score)
print(cl_report)
● 学習した内容を保存する
上述でした言語学習を記憶させます。
例)
※clf.fit(train_data, train_label) までの内容は同じ
from sklearn.externals import joblib
dir = os.path.dirname(__file__)
pkl_name = os.path.join(dir, 'pkl_files', 'language', 'language.pkl.cmp')
#学習内容を保存
joblib.dump(clf, pkl_name, compress=True)
print('保存完了~')
#学習内容を読込む
clf = joblib.load(pkl_name)
#同様にテストできる
pre = clf.predict(test_data)
ac_score = metrics.accuracy_score(test_label, pre)
print(ac_score)
【メモ】
joblib.dump メソッドを使う際に第3引数に名前付き引数 compress=True を設定しています。
これは、学習内容を保存する際に圧縮する設定をしています。
この設定をしない場合は、ファイル名を XXXX.pkl とする必要があります。
因みに解凍する際のメソッド joblib.load の振る舞いは同じなので圧縮した方が良いかも。。
● Django で言語判別インターフェースを作成する
※View のみ記載します。
例)
from django.shortcuts import render
from django.http.response import HttpResponse
from django.views.generic import View
import os
from sklearn import svm, metrics
from sklearn.externals import joblib
class IndexView(View):
def get(self, request):
d = {}
#GET 遷移時の HTML を表示する
return render(request, 'mysite/index.html', d)
#POST 遷移時の処理
def post(self, request):
d = {}
#何も書かれていない場合は終わり
if request.POST['bunsyo'].strip() == '':
d['msg'] = '何か書け!'
else:
#POST 値をデータ作成メソッドに送る
data = self.create_data(request.POST['bunsyo'])
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
fname = os.path.join(BASE_DIR, 'pkl_files', 'language.pkl.cmp')
#学習ファイルを読込む
clf = joblib.load(fname)
#予測させる
pre = clf.predict([data])
ans = {'en':'英語','fr':'フランス語','es':'スペイン語','id':'インドネシア語'}
d['msg'] = ans[pre[0]]
return render(request, 'mysite/index.html', d)
#データ作成メソッド
def create_data(self, text):
cnt = [0 for n in range(0, 26)]
code_a = ord('a')
code_z = ord('z')
text = text.lower()
for ch in text:
n = ord(ch)
if code_a <= n <= code_z:
cnt[n - code_a] += 1
total = sum(cnt)
#記録している学習ファイルが 50 倍しているので。
cnt = list(map(lambda n: (n / total) * 50, cnt))
return cnt