潜在的ディリクレ分配法


AIって結局何なのかよく分からないので、とりあえず100日間勉強してみた Day47


経緯についてはこちらをご参照ください。



■本日の進捗

  • LDAを理解


■はじめに

引き続き「Pythonではじめる機械学習(オライリー・ジャパン)」で学んでいきます。

今回はテキストデータに対する(主に)教師なし学習として用いられるトピックモデリング手法からLDAをIMDbデータセットに適用してみます。

■LDA

LDA(latent dirichlet allocation)とは、コーパスの各ドキュメントに対して1つ以上のトピックを含むと仮定してこれを割り当てるトピックモデリング(topic modeling)手法のひとつで、教師なし学習における成分分析手法にあたります。

各ドキュメントはいくつかのトピック(ここでいうトピックは「話題」というよりも「特徴量」と考えた方が理解しやすいかもしれません。つまり人間に解釈可能なトピックもあればそうではない可能性もあります。)の「混合物」であり、そのトピックは(同じトピックであれば)複数の単語から成り立っていると考えます。トピックの混合分布や単語の出現確率からドキュメントを分析し潜在変数を教えてくれます。

ストップワードなどにも表現される頻出単語のトピックへの影響を減らすためにも一般的な単語は予め除いておくことが推奨されます。

トピックの生成に乱数性があること、単語の順序や文脈を考慮されない可能性があること、スケーラビリティが得られ難いことなどにも注意が必要です。

これまでお世話になってきたIMDbデータセットをLDAで分析してみます。

import numpy as np
from sklearn.datasets import load_files
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation

reviews_train = load_files("C:/Users/****/Documents/Python/aclImdb/train")
text_train, y_train = reviews_train.data, reviews_train.target

vectorizer = CountVectorizer(max_features=10000, max_df=0.15)
X = vectorizer.fit_transform(text_train)

lda = LatentDirichletAllocation(n_components=100, learning_method="batch", max_iter=25, random_state=8, n_jobs=-1)

document_topics = lda.fit_transform(X)

sorting = np.argsort(lda.components_, axis=1)[:, ::-1]
feature_names = np.array(vectorizer.get_feature_names_out())

for topic_idx in range(10):
    top_words = feature_names[sorting[topic_idx, :10]]
    print(f"topic {topic_idx + 1}: {', '.join(top_words)}")

トピックを100個抽出し、最初(もちろん順番に意味はない)の10トピックを表示させてみました。前述の通りこの「トピック」はあくまで機械学習モデルにとって類似性が確認できるだけで、僕ら人間にとって理解できる範疇にない可能性もありますが、topic 1は明らかに殺人事件が関連するミステリー作品だったり、topic 7は動物や虫が出てくるアニメーションで、topic 9はテレビシリーズなのでしょう。

この直観が実際に正しいかどうかを確認してみます。個人的にはtopic 7が本当にディズニーアニメーション(使っていい単語?お金請求されたりしますか?)と関連があるのかが気になるので、topic 7が含まれているドキュメントをいくつか見てみます。

import numpy as np
from sklearn.datasets import load_files
from sklearn.feature_extraction.text import CountVectorizer
from sklearn.decomposition import LatentDirichletAllocation

reviews_train = load_files("C:/Users/****/Documents/Python/aclImdb/train")
text_train, y_train = reviews_train.data, reviews_train.target

reviews_test = load_files("C:/Users/hamni/Documents/Python/aclImdb/test")
text_test, y_test = reviews_test.data, reviews_test.target

vectorizer = CountVectorizer(max_features=10000, max_df=0.15)
X = vectorizer.fit_transform(text_train)

lda = LatentDirichletAllocation(n_components=100, learning_method="batch", max_iter=25, random_state=8, n_jobs=-1)

document_topics = lda.fit_transform(X)

sorting = np.argsort(lda.components_, axis=1)[:, ::-1]
feature_names = np.array(vectorizer.get_feature_names_out())

animation = np.argsort(document_topics[:, 6])[::-1]
for i in animation[:10]:
    print(b".".join(text_train[i].split(b".")[:2]) + b".\n")

実際にtopic 7(インデックスは6)は、「ライオンキング1 1/2」(ディズニーの知見がなくて申し訳ないのですが、調べたらこういう作品があるみたいです)や、「ライオンキング3」、「バッグスバニー」、「ポケモン」のアニメーション作品に関連するトピックであったみたいです。”bug” が虫ではなかったことを除いては、当初の直観通りにLDAも分析していたということになります。「バグズライフ」かな、とか思ってました…。

■おわりに

LDAでトピックを生成した後は、このトピックをこれまでも構築してきた教師あり学習に組み込んでもいいですが、もう既に実際に誰もが触れているサービスに組み込まれているモデルでもあるのです。

例えば先ほど挙げたようなレビューを書いているユーザーにはディズニーやポケモン、あるいはその他のアニメーション映画をレコメンドしてみるのはどうでしょう。

論文やコミュニティの投稿をタグ付けのように分類したり、その内容を要約することも出来そうです。

SNSの投稿から(いわゆる普段僕ら人間が使う意味での)トピックを抽出して、「映画のトレンド」、「音楽のトレンド」、「社会問題のトレンド」と提案してみるのもいいかもしれません。特に「タイヤ」や「空力」といった単語から「スポーツのトレンド」ではなく「モータースポーツのトレンド」というところまで分析できるでしょう。

製品レビューなどから顧客が良く話題にあげるトピックを分析し、どんなことが購買に影響するかを抽出できればビジネスにも利用できそうです。

機械学習モデルの勉強として簡単なクラス分類や回帰タスクを予測してきましたが、ようやく一般人が想像するいわゆる “AI” っぽくなってきたのではないでしょうか。

■参考文献

  1. Andreas C. Muller, Sarah Guido. Pythonではじめる機械学習. 中田 秀基 訳. オライリー・ジャパン. 2017. 392p.
  2. ChatGPT. 4o mini. OpenAI. 2024. https://chatgpt.com/
  3. API Reference. scikit-learn.org. https://scikit-learn.org/stable/api/index.html
  4. Maas, Andrew L. and Daly, Raymond E. and Pham, Peter T. and Huang, Dan and Ng, Andrew Y. and Potts, Christopher, Learning Word Vectors for Sentiment Analysis, Proceedings of the 49th Annual Meeting of the Association for Computational Linguistics: Human Language Technologies, June, 2011, Portland, Oregon, USA, Association for Computational Linguistics, 142–150, http://www.aclweb.org/anthology/P11-1015
  5. Potts, Christopher. 2011. On the negativity of negation. In Nan Li and David Lutz, eds., Proceedings of Semantics and Linguistic Theory 20, 636-659.


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です