File Icons
BLOG
(ch-5) ロジスティック回帰 + BoWによる感情分析

感情分析のためのモデルを作成していきます。
まずはベンチマークとして、単純なモデルと、単純な特徴量の組み合わせのモデルを作成します。
具体的には、分類器にはロジスティック回帰を、特徴量はBag of Wordsによって作成します。

Bag of Wordsは、テキストデータを数値的に表現するためのシンプルな技術の一つです。文書内の単語の出現回数に基づいて文書を表現します。

目次

  1. 準備
    1. データの読み込み
    2. 文章の分かち書き
    3. クロスバリデーションのための分割
  2. モデルの作成と評価
  3. まとめ

準備

ここではデータを読み込んで、特徴量の作成の準備と、モデルの評価の準備をします。

具体的には、以下の処理を実行します。

  • 文章の分かち書き
  • クロスバリデーションのための分割

データの読み込み

■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()
スクリーンショット 2023-09-13 18.46.24.png (87.6 kB)

文章の分かち書き

■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)
スクリーンショット 2023-09-13 18.47.46.png (138.3 kB)

クロスバリデーションのための分割

■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()

モデルの作成と評価

分割したデータセットごとに、以下の処理を実行します。

  1. 学習用データと検証用データに分割する
  2. Bag of Words特徴量を作成する
  3. モデルを学習する
  4. 正解率を計算する

評価指標としては、正解率(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という単純な手法を使って、ベンチマークの予測精度を出すことができました。

次回以降は、更に発展的な手法を使用して、予測精度が上がるかを試して見ようと思います。

CONTACT
ご依頼やご相談、サービスについてのご質問やご要望がございましたら、お気軽にお問い合わせください。
送付いただいた内容を確認の上、担当者からご連絡させていただきます。
お問い合わせ