感情分析のためのモデルを作成していきます。
まずはベンチマークとして、単純なモデルと、単純な特徴量の組み合わせのモデルを作成します。
具体的には、分類器にはロジスティック回帰を、特徴量は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という単純な手法を使って、ベンチマークの予測精度を出すことができました。
次回以降は、更に発展的な手法を使用して、予測精度が上がるかを試して見ようと思います。