LoginSignup
5
5

More than 5 years have passed since last update.

Qiita「非エンジニア」記事をトピック分類(scikit-learnのLDAが重くldaで比較編)

Posted at

※記事内で動かない・間違い箇所などありましたら是非教えて下さい!

こちらは前回の記事の続きです。
下準備まではコチラをご覧ください。
Qiita「非エンジニア」記事をトピック分類(スクレイピング・単語分解・正規化編)

記事の概要

前回は、169ページ分、1682個の「非エンジニア」記事を取ってきて、タイトル・本文・その他のデータフレームを作りました。
また単語に分解し、数字など不要なものを綺麗にしました。

この記事では、記事本文データを使ってLDAでいくつかのトピックに分けていこうと思います。
先に書いておくと、最初scikit-learnのLDAを使ったのですが、100記事以上が重くて動かず・・・コチラのldaを使いました。
https://pypi.org/project/lda/

まずはscikit-learnのLDAを動かしてみる

まずは途中で動かなくなったscikit-learnから。

#必要なライブラリをimport
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import joblib
#文章×単語行列に変換
vectorizer = CountVectorizer(token_pattern=r"(?u)\b\w+\b") 
#訓練データ用にBow表現に。
X = vectorizer.fit_transform(df["Content_normalization"]) 

↑ここでdf["Content_normalization"]とありますが、僕のPCだとdfは100記事までしか動きませんでした!なので、ここのdfは縮小版です。

#単語番号と単語を紐づけ
index2word = {}
for word, word_id in tqdm(vectorizer.vocabulary_.items()):
    index2word[word_id] = word
#3分類でインスタンス作成。モデルの作成
lda = LatentDirichletAllocation(n_components=3, n_jobs=-1, verbose=1)
X_transformed = lda.fit_transform(X)
#各トピックの特徴単語を抽出
for t in range(lda.n_components):
    # トピック t における、単語の出現確率を lda.components_[t] で取得
    # np.argsort で昇順に並び替えた順の index を取得、[::-1] で降順に並び替え
    indices = np.argsort(lda.components_[t])[::-1]
    print("Topic #{} ----------------------------------------".format(t+1))
    for word_id in indices[:10]:
        print(index2word[word_id])
    print()

▼JupyterNotebook
スクリーンショット 2018-08-19 19.34.26.png

うーん。という感じですね。
考えるに、下記の順でパッとしない原因と対策があると思っています。
「ため」などの無駄なものが多い。ストップワードで単語データを綺麗にする
データ数が100記事しか食わせてないので少ない
カテゴリ数が微妙。変えてみる
そもそも綺麗に分かれるはずがない?
そもそもなにか手順が変?

とりあえずこのまま、タイトル分類も見てみます。

for t in range(lda.n_components):
    # トピック t を軸に切り出す
    # np.argsort で昇順に並び替えた順の index を取得、[::-1] で降順に並び替え
    indices = np.argsort(X_transformed[:,t])[::-1]

    print("Topic #{} ----------------------------------------".format(t))
    for document_id in indices[:10]:
        print(df.iloc[document_id]["Title"])
    print()

▼JupyterNotebook
スクリーンショット 2018-08-19 19.40.27.png

なんとなく、トピック0:教育、トピック1:実用、トピック2:その他、という感じで分かれている、と言われればそう見えなくもないような、どうなんだろう・・・。

次はldaを使ってみる

#ライブラリのimport
import lda
import lda.datasets
#インスタンスなど
X = lda.datasets.load_reuters()
vocab = lda.datasets.load_reuters_vocab()
titles = lda.datasets.load_reuters_titles()
#上のscikit-learnで作った単語行列から、欲しいモノを取ってくる。
vect = vectorizer.get_feature_names()
#3分類でモデルの生成
model = lda.LDA(n_topics=3, n_iter=1500, random_state=1, alpha = 10)
model.fit(X)  # model.fit_transform(X) is also available
#単語抽出
for t in range(model.n_topics):
    indices = np.argsort(model.topic_word_[t])[::-1]
    print("Topic #{} ----------------------------------------".format(t+1))
    for word_id in indices[:10]:
        print(index2word[word_id])
    print()

スクリーンショット 2018-08-19 22.04.17.png
あれ、、、アルファベット順?笑
ちょっと並べ替えが上手くいっていないですが、タイトル分類にいきます。

doc_topic = model.doc_topic_
for t in range(model.n_topics):
    indices = np.argsort(doc_topic[:,t])[::-1]

    print("Topic #{} ----------------------------------------".format(t))
    for document_id in indices[:10]:
        print(df.iloc[document_id]["Title"])
    print()

スクリーンショット 2018-08-19 19.40.27.png

これはなかなかいい感じ・・・ですね!?笑

トピック0は考え方や言葉でのまとめ系、トピック1は挑戦してみた系の技術記事、トピック2は解説系(教える感じ)の技術記事、と分かれているように、僕は見えます!!笑

このニュアンス感がLDAっぽい...?

改善策

今回はとりあえずアウトプットを出してみましたが、前述した通り、下記の方法でもうちょっと改善しそうです。

  • ストップワードなど、もっと単語データを綺麗にする
  • カテゴリ数やその他オプション値を変えてみる

この記事は単純にLDAを使ってみたかった。という気持ちが先行しましたが、「非エンジニア」記事と他記事と比較・クラスタリングなどするともうちょっと何か見えそうです。記事自体はけっこうあったので、また手が空いた時に、単語ベースでの特徴抽出や、時系列で記事遷移やいいね数などを追ってみようかと思います。

※コードはサポートページや本などから持ってきている部分が多く、完全に理解できていない部分もあります。「もっとこうしたら良い」「ここいらない」など是非教えて下さい!

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5