はじめに
最近の仕事で「文章を機械学習させる」という案件があり、これまでPythonでは経験があったから、せっかくRubyの街に住んでいるのでRubyでやってみよう...と思いましたが、意外と障壁が高かったのでPyCallを使うことにしました。
「Pythonでやるのと同じじゃないか!」と思われるかもしれませんが、細かなTipsがあるので参考までにまとめておきます。
ニュース記事の収集
ここでは、"AI"、"IoT"および"Robot"というキーワードで記事データを収集し、それぞれを以下のようにCSV形式で保存したファイルを作ります。
ファイル名は「news.csv」とします。
分類 | 記事 |
---|---|
ai | ビッグデータを分析して... |
iot | センサーを設置し、温度を... |
robot | モーターの制御を行う... |
ai | ... |
記事のソースは以下のサイトを参照。
PyCallのインストール
詳細は以下をご参照下さい。
僕は以下のコマンドでインストールしました。
sudo gem install pycall
sudo gem install pandas
Janomeのインストール
Janomeは形態素解析をするPython用のライブラリです。
僕は以下のコマンドでインストールしました。
pip install janome
記事データの読込
記事データを以下のスクリプトにて読み込みます。
require 'pycall'
require 'pandas'
pd = Pandas
file = "news.csv"
df = pd.read_csv(file)
形態素解析
以下のスクリプトにて文章を形態素解析により分かち書き文章へ変換します。
tokenizer = PyCall.import_module('janome.tokenizer')
t = tokenizer.Tokenizer.new()
notes = []
df.shape[0].times do |i|
note = df["記事"].iloc[i]
tokens = t.tokenize(note.gsub(' ',' '))
words = ""
(0..tokens.length - 1).each do |i|
words += " " + tokens[i].surface
end
notes << words
end
数値化
分かち書き文章を数値化します。
vectorizer = PyCall.import_module('sklearn.feature_extraction.text')
vect = vectorizer.TfidfVectorizer.new()
vect.fit(notes)
x = vect.transform(notes)
分類を数値化します。
labels = ["ai", "iot", "robot"]
y_dic = {}
i = 0
labels.each do |label|
y_dic[label] = i
i += 1
end
y = []
df.shape[0].times do |i|
y << y_dic[df.iloc[i]["分類"]]
end
機械学習
学習データと検証データの切り分け、学習、テストデータでの精度確認。
model_selection = PyCall.import_module('sklearn.model_selection')
x_train, x_test, y_train, y_test =
model_selection.train_test_split(x, y, test_size: 0.1, random_state: 42)
linear_model = PyCall.import_module('sklearn.linear_model')
model = linear_model.LogisticRegression.new()
model.fit(x_train, y_train)
puts model.score(x_test, y_test)
僕が集めた記事は、AIが137記事、IoTが134記事、Robotが129記事で、学習精度は0.775でした。
精度が良いのかどうかよくわからない...(-_-;)
分類
また、別のサイトから新しい記事を見つけて以下のようにデータ形式をあわせて分類を予測してみる。
text = <<EOF
AI活用の検証から導入、活用までを...
(中略)
...した。
EOF
text.gsub!("\n", "")
texts = [
text
]
notes = []
texts.each do |note|
tokens = t.tokenize(note)
words = ""
tokens.each do |token|
words += " " + token.surface
end
notes << words
end
x = vect.transform(notes)
result = model.predict(x)
puts labels[result[0].to_i]
結果は「ai」でした。
...ということで、できた!