毎日テキストマイニング

180日間、毎日テキストマイニングをするブログです

2018/7/19【27日目】ランダムフォレストを調べて、分析用の正解データを作ってみる

やりたいことをまとめますと、1日の呟きの中で福岡聖菜の呟きかどうかを判定したのです。イメージとしましては福岡聖菜だったら1、福岡聖菜でなければ0、どっちかわからないようでしたら0.5を返すようにしたいと思います。

おそらくこれは分類というやつですね。分類といえば聞き覚えがあるランダムフォレストという機械学習が思い浮かびますが、いったいどうなんでしょう? 今日はランダムフォレストについて調べていきたいと思います。

ランダムフォレストとは

ランダムフォレストはアンサンブル学習の一種で、決して精度が高いとはいえない複数の結果を組み合わせて精度のを向上させる方法、だそうです。要は一つひとつは精度が低いけど、いっぱい集めれば精度が高くなる、というアリゴリズムのようです。

文章だけ読んでもあまりイメージが湧きませんので、ひとまず、Scikit-learn内のランダムフォレストのサンプルをみていきます。

ランダムフォレストの実装

とりあえず、scikit-learnからランダムフォレストをimportします。2番目のmake_classificationというのは、指定した数値でサンプルデータを作れる関数だそうです。

from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification

サンプルのままですが、こんな感じのようです。

X, y = make_classification(n_samples=1000, n_features=4,
                           n_informative=2, n_redundant=0,
                           random_state=0, shuffle=False)
print(X)

実行結果

array([[-1.66853167, -1.29901346,  0.2746472 , -0.60362044],
       [-2.9728827 , -1.08878294,  0.70885958,  0.42281857],
       [-0.59614125, -1.37007001, -3.11685659,  0.64445203],
(以下、省略)
  • n_samples=1000がサンプルを1000個作成
  • n_features=4,が特徴量を4個作成
  • n_informative=2は不明です。
  • n_redundant=0,がランダムな線形を作った時のインフォメイティブな特徴。何を言っているのかよくわかりませんね。
  • random_state=0は0を指定すると、毎回同じ数のランダムを生成するぽいです。
  • shuffle=Falseはtrueにすると行列をシャッフルするそうです。

printしたものを見ると、特徴データが1行に4個あるようですね。一応shapeで確認してみます。

print(X.shape)
(1000, 4)

間違いなく1000行4列ですね。yの方も見ていきます。

print(y)
[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 (以下、省略)

0がハズレで1が正解、、、のデータだと思います。 こっちもshapeをprintしてみると、1000行あることがわかります。

print(y.shape)
(1000,)

Xとyを学習させてみます。

clf = RandomForestClassifier(max_depth=2, random_state=0)
clf.fit(X, y)
print(clf.feature_importances_)

実行結果。

[ 0.17287856  0.80608704  0.01884792  0.00218648]

feature_importances_は特徴量の重要度だそうです。 2番目の要素が重要だそうです。と、いいますより、この数値をみると、ほぼ2番目で正解かどうかを判断しているような気がしますね。

学習したモデルに新たなデータを入れます。

print(clf.predict([[-1.66853167, -1.29901346, -1.66853167, -1.66853167]]))
[0]

正解でないと返ってきました。 違う要素にしてみます。

print(clf.predict([[0.91711204,  1.10596645,  0.86766522, -2.25625012]]))
[1]

こっちは1が返ってきました。どうやら正解のようです。

とりあえず、著者推定をするには、正解データが必要そうですね。

正解データの用意

上で見たyのように正解データを作っていきたいと思います。 まずは、Mysqlから名前だけを取得したcsvを読み込みます。

import pandas as pd
names = pd.read_csv('name_20180720.csv',
                   sep=':', 
                   encoding='utf-8')
names.head()

実行結果はこんな感じです。

 name
0   48_asainanami
1   48_asainanami
2   48_asainanami
3   48_asainanami
4   48_asainanami

これで、"seina_fuku48”を1に、それ以外のメンバーを0に置換すれば良さそうです。 pandasはわからないので、ネットから情報を拾ってきます。

names[names.name == "48_asainanam"].name = 1
names[names.name != "seina_fuku48"].name = 0
/anaconda/lib/python3.6/site-packages/pandas/core/generic.py:3110: SettingWithCopyWarning: 
A value is trying to be set on a copy of a slice from a DataFrame.
Try using .loc[row_indexer,col_indexer] = value instead

See the caveats in the documentation: http://pandas.pydata.org/pandas-docs/stable/indexing.html#indexing-view-versus-copy
  self[name] = value
In [54]:

エラーが出ました。loc[row_indexer,col_indexer] = valueを使えとのこと。エラーの表示通りに修正してみます。

names.loc[names['name'] == "48_asainanam", 'name'] = 1
names.loc[names['name'] != "48_asainanam", 'name'] = 0

何も起こらないということは、置換できたようですね。 表示してみます。

names.head()
 name
0   0
1   0
2   0
3   0
4   0

お、無事にできたみたいです。 正解データはできましたので、あしたは学習データを作っていきたいとおもいます。

今日の結果

今日のAKBメンバーの呟きは39件でした。 なかなか少ないですね。

f:id:rimt:20180720235418p:plain

'ない': 2, '早い': 2, 'すごい': 2, '暑い': 2, 'いい': 2, 'くさい': 1, 'うまい': 1, '気まずい': 1, '見苦しい': 1, '良い': 1, '優しい': 1, '嬉しい': 1, '有難い': 1, '新しい': 1, '美しい': 1, '凄い': 1, '面白い': 1, '上手い': 1, 'おもしろい': 1})

'さん': 10, 'ちゃん': 8, '笑': 7, 'ん': 6, '日': 6, '歳': 6, '祭': 5,

'する': 31, 'さん': 10, 'なる': 9, 'ちゃん': 8, '笑': 7, '見る': 7, 'ん': 6, '日': 6, '歳': 6, '祭': 5, 'くださる': 5, 'てる': 5, 'せる': 5, 'れる': 5, 'くる': 5, '思う': 5, 'いる': 5, '一緒'