感情分析のためのモデルを作成していきます。
まずはベンチマークとして、単純なモデルと、単純な特徴量の組み合わせのモデルを作成します。
具体的には、分類器にはロジスティック回帰を、特徴量はBag of Wordsによって作成します。
Bag of Wordsは、テキストデータを数値的に表現するためのシンプルな技術の一つです。文書内の単語の出現回数に基づいて文書を表現します。
目次
準備
ここではデータを読み込んで、特徴量の作成の準備と、モデルの評価の準備をします。
具体的には、以下の処理を実行します。
- 文章の分かち書き
- クロスバリデーションのための分割
データの読み込み
■python
import pandas as pd
import spacy
from sklearn.model_selection import StratifiedKFold
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.linear_model import LogisticRegression
from sklearn.metrics import accuracy_score
# データの読み込み
df = pd.read_csv('../data/interim/chabsa-sentiment-analysis.csv')
df.head()

文章の分かち書き
■python
# sentence列を分かち書きする
nlp = spacy.load('ja_core_news_md')
def apply_nlp(text):
doc = nlp(text)
return [token.text for token in doc]
# tokensに分かち書きされた単語が入る
df['tokens'] = df['sentence'].apply(apply_nlp)
# 分かち書きのリストが作成できているかを確認する
df.head(5)

クロスバリデーションのための分割
■python
# クロスバリデーションのために、kfoldの列を追加する
# k-fold
df['kfold'] = -1
# データをシャッフルする
df = df.sample(frac=1, random_state=0).reset_index(drop=True)
# StratifiedKFoldを使う
skf = StratifiedKFold(
n_splits=5,
shuffle=False
)
# データを分割する
for fold, (train_idx, val_idx) in enumerate(skf.split(X=df, y=df.rating.values)):
# foldの列にkfoldの分割番号を入れる
df.loc[val_idx, 'kfold'] = fold
# kfoldの分割番号が正しく振られていることを確認する
df.kfold.value_counts()
モデルの作成と評価
分割したデータセットごとに、以下の処理を実行します。
- 学習用データと検証用データに分割する
- Bag of Words特徴量を作成する
- モデルを学習する
- 正解率を計算する
評価指標としては、正解率(Accuracy)を使用します。クラスラベルの比率は、0が40%、1が60%であり、そこまで不均衡ではないため、正解率を使用することにします。
■python
# foldごとに以下の処理を行う
# 1. 学習用データと検証用データに分割する
# 2. BoW特徴量を作成する
# 3. モデルを学習する
# 4. 正解率を計算する
for fold_ in range(5):
# 学習用データと検証用データに分割する
df_train = df[df.kfold != fold_].reset_index(drop=True)
df_valid = df[df.kfold == fold_].reset_index(drop=True)
# CountVectorizerインスタンスを作成する
count_vec = CountVectorizer(
tokenizer=lambda x: x,
token_pattern=None,
lowercase=False
)
# 学習用データのtokens列を使ってBoW特徴量を作成する
count_vec.fit(df_train.tokens)
# 正解ラベルと特徴量を作成する
# 特徴量は、学習用データ文章にfitしたCountVectorizerを使って、学習用データと検証用データのBoW特徴量を作成する
y_train = df_train.rating
y_valid = df_valid.rating
X_train = count_vec.transform(df_train.tokens)
X_valid = count_vec.transform(df_valid.tokens)
# ロジスティック回帰のインスタンスを作成する
# BoWは疎な特徴量なので、L1正則化を使うことにする
lr = LogisticRegression(penalty='l1', solver='liblinear')
# ロジスティック回帰のモデルを学習する
lr.fit(X_train, y_train)
# 検証用データに対する予測を行う
preds = lr.predict(X_valid)
# 正解率(Accuracy)を計算する
accuracy = accuracy_score(
y_valid,
preds
)
# 予測結果をdfに追加する
df.loc[df.kfold == fold_, 'preds'] = preds
# 正解率を出力する
print(f'Fold={fold_} 検証用データに対する正解率: {accuracy:.4f}')
# トータルの正解率を出力する
accuracy = accuracy_score(
df.rating,
df.preds
)
print(f'トータルの正解率: {accuracy:.4f}')
Fold=0 検証用データに対する正解率: 0.8845 Fold=1 検証用データに対する正解率: 0.8845 Fold=2 検証用データに対する正解率: 0.9094 Fold=3 検証用データに対する正解率: 0.8843 Fold=4 検証用データに対する正解率: 0.9004 トータルの正解率: 0.8926
検証データに対する正解率は89.2%という結果が得られました。
まとめ
ロジスティック回帰とBag of Wordsという単純な手法を使って、ベンチマークの予測精度を出すことができました。
次回以降は、更に発展的な手法を使用して、予測精度が上がるかを試して見ようと思います。
