Recommendation Systemを考える その3の続き。
1.やりたいこと
その3でやりたかったことの続き。回帰ではなく分類で予測してみる。
2.分類
データを読み込む
前回作成したDoc2Vecデータを読み込み、配列に変換する。
from gensim.models.doc2vec import Doc2Vec
from pathlib import Path
MODEL_DATA_PATH = str(Path.home()) + '/vscode/syosetu/data/search_novel_doc2vec_100.model'
m = Doc2Vec.load(MODEL_DATA_PATH)
vectors_list = [m.dv[n] for n in range(len(m.dv))]
データ処理しやすいように、必要な情報をPandasにまとめる。
import pandas as pd
import numpy as np
MODEL_TITLES_CSV_PATH = str(Path.home()) + '/vscode/syosetu/data/search_novel_titles.csv'
df = pd.read_csv(MODEL_TITLES_CSV_PATH, thousands=',')
df = df.drop(columns=['URL'])
df['VECTORS'] = vectors_list
データを加工する
評価ポイントから 不要な文字を取り除き、数値に変換する。
df['EVALUATION'] = df['EVALUATION'].str.replace(',', '')
df['EVALUATION'] = df['EVALUATION'].str.replace('評価受付停止中', '').astype(float)
df['EVALUATION'].describe()
count 2000.000000
mean 32735.061500
std 33540.729876
min 4019.000000
25% 14118.000000
50% 21271.000000
75% 38219.250000
max 323929.000000
Name: EVALUATION, dtype: float64
評価ポイントの値によって5つくらいに分類する。
df['EVALUATION_BAND'] = pd.cut(df['EVALUATION'], 5)
df[['EVALUATION_BAND', 'EVALUATION']].groupby(['EVALUATION_BAND'], as_index=False).count().sort_values(by='EVALUATION_BAND', ascending=True)
EVALUATION_BAND EVALUATION
0 (3699.09, 68001.0] 1801
1 (68001.0, 131983.0] 149
2 (131983.0, 195965.0] 38
3 (195965.0, 259947.0] 6
4 (259947.0, 323929.0] 6
3699.09から68001.0が最も多く1801件も存在する。逆に予測したい評価の高い小説は6件しか存在しない。今回予測したいのは数の少ない小説の方なので、このままでは正しく予測することが出来ない。そこで区分2、3、4を一つのグループ、区分1のグループ、区分0のグループに分けることにする。
df.loc[ df['EVALUATION'] <= 68001, 'EVALUATION'] = 0
df.loc[(df['EVALUATION'] > 68001) & (df['EVALUATION'] <= 131983), 'EVALUATION'] = 1
df.loc[ df['EVALUATION'] > 131983, 'EVALUATION'] = 2
df = df.drop(['EVALUATION_BAND'], axis=1)
df['EVALUATION'].value_counts()
0.0 1801
1.0 149
2.0 50
Name: EVALUATION, dtype: int64
区分2の50本に合わせて他の区分からランダムに50本の小説を抽出することにする。
df_0 = df[df['EVALUATION'] == 0].sample(n=50, random_state=0)
df_1 = df[df['EVALUATION'] == 1].sample(n=50, random_state=0)
df_2 = df[df['EVALUATION'] == 2]
df = pd.concat([df_0, df_1, df_2])
作成したデータを元に予測する
先程作成したデータをトレーニングデータとテストデータに分ける。
from sklearn.model_selection import train_test_split
X = pd.DataFrame(df['VECTORS'].tolist(), index=df.index)
X.columns = [f'No{i+1}' for i in range(len(X.columns))]
y = df['EVALUATION']
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state=0)
試しにランダムフォレストにかけてみる。
from sklearn.ensemble import RandomForestClassifier
random_forest = RandomForestClassifier(random_state=0)
random_forest.fit(X_train, y_train)
random_forest.score(X_test, y_test)
0.5263157894736842
random_forest.predict(X_test)
array([2., 1., 2., 2., 2., 1., 0., 1., 1., 0., 2., 1., 2., 2., 1., 0., 1.,
1., 2., 1., 0., 2., 2., 0., 0., 1., 2., 1., 1., 0., 2., 2., 1., 2.,
2., 2., 2., 1.])
5割を少しだけ超えるほどの精度での予測になった。このままチューニングしても良い結果は得られそうにない。トレーニングデータの作成からやり直す必要がありそう。
3.まとめ
評価ポイントを文章のみから予測するのは難しそう。