ナード戦隊データマン

データサイエンスを用いて悪と戦うぞ

ツイートをCNNで感情分析 (失敗)

sentiment140データ・セットでは、distant supervisionを使ってアノテーションしたツイートデータを提供しています。今回は、このデータセットを文字ベースCNNで分類します。

(結論から言うと、失敗です。)

Kaggleで実行

GPUが無いのでKaggleで実行しました。 https://www.kaggle.com/sugiyamath/character-based-cnn-for-tweets-classification

説明

まず、実行フローは以下です。

  1. sentiment140データの読み込み。
  2. データが多いので、シャッフルして7000件だけ取得。
  3. ツイートを、文字ベースの行列に変換。
  4. 文字ベースの行列をサンプル、ポジ・ネガをラベルとして定義。
  5. KerasでテキトーにCNNモデル作成。
  6. モデルを訓練。
  7. 評価データで評価。

重要部分だけ説明します。

ツイートの行列化

CNNなので、行列化します。

def to_matrix(text, dim1=max_len, dim2=256):
    targets = list(map(ord, list(text)))
    targets += [0 for i in range(dim1 - len(targets))]
    mat = []
    for target in targets:
        vector = np.zeros(dim2)
        vector[target] = 1.
        mat.append(vector)
    return np.array(mat).reshape(max_len,256, 1)

これは、ASCII文字コードを列、ツイート内のそれぞれの文字を行とした行列です。対応文字の要素に1.0を代入します。

KerasのCNNモデル

これはコード以外、説明しません。詳細が知りたければ、CNNとKerasでググってください。

from keras import layers
from keras import models
from keras import optimizers

model = models.Sequential()
model.add(layers.Conv2D(32, (3,3), activation="relu", input_shape=(max_len, 256, 1)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(64, (3,3), activation="relu", input_shape=(max_len, 256, 1)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128, (3,3), activation="relu", input_shape=(max_len, 256, 1)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Conv2D(128, (3,3), activation="relu", input_shape=(max_len, 256, 1)))
model.add(layers.MaxPooling2D((2,2)))
model.add(layers.Flatten())
model.add(layers.Dense(512, activation="relu"))
model.add(layers.Dense(1, activation='sigmoid'))

model.compile(
    loss='binary_crossentropy',
    optimizer="rmsprop",
    metrics=['acc']
)

評価

test_loss, test_acc = model.evaluate(X_spl[2], y_spl[2])
test_loss, test_acc

損失, 精度: (0.8585477075576782, 0.613)

なぜツイートで画像分類の手法を使うか

ツイートをMeCabトークナイズしてBoWやWord2Vec等で特徴量設計したくなりますが、あまり精度は出ませんでした。精度は、0.78ぐらいです。(コードは省略)

そこで、「ツイッターは文字数制限がある」ということを利用してCNNを使えそうだと考え、実行しました。

しかし、結果は見ての通りダメダメです。行と列の定義方法がそもそもおかしいのかもしれません。例えば、行と列をsqrt(ツイートの文字数上限)にして、値はasciiの正規化した値にしたらまた変わるかもしれません。

ノイズありのデータで0.78の精度が出たtfidf + nnlm + logregのモデルはそこそこ優れていたようです。以下はそのモデルです。 https://www.kaggle.com/sugiyamath/tfidf-nnlm-logreg-twitter-sentiment-analysis

ディープラーニングを使うなら、もっとネットワークを工夫したほうが良いのかもしれません。

あるいはデータが少なすぎるのかもしれません。リソースが少ないので、データをすべて読み込んで訓練したとしたらかなり時間がかかりそうだったのでやめました。もっと多くのデータを使えば精度は上がる気がします。

参考

[0] PythonとKerasによるディープラーニング | Francois Chollet, 巣籠 悠輔, 株式会社クイープ