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

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

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

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

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

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

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

```python
#必要なライブラリをimport
from sklearn.feature_extraction.text import CountVectorizer, TfidfVectorizer
from sklearn.decomposition import LatentDirichletAllocation
import joblib
```

```python
#文章×単語行列に変換
vectorizer = CountVectorizer(token_pattern=r"(?u)\b\w+\b") 
#訓練データ用にBow表現に。
X = vectorizer.fit_transform(df["Content_normalization"]) 
```
<font color="Red">**↑ここでdf["Content_normalization"]とありますが、僕のPCだとdfは100記事までしか動きませんでした！なので、ここのdfは縮小版です。**</font>

```python
#単語番号と単語を紐づけ
index2word = {}
for word, word_id in tqdm(vectorizer.vocabulary_.items()):
    index2word[word_id] = word
```

```python
#3分類でインスタンス作成。モデルの作成
lda = LatentDirichletAllocation(n_components=3, n_jobs=-1, verbose=1)
X_transformed = lda.fit_transform(X)
```

```python
#各トピックの特徴単語を抽出
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
<img width="237" alt="スクリーンショット 2018-08-19 19.34.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/244525/65fd49aa-8d5a-e8c5-7da9-8cb924090c32.png">

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


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

```python
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
<img width="743" alt="スクリーンショット 2018-08-19 19.40.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/244525/b4735e88-9f95-0a00-c135-506d700e979c.png">

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

#次はldaを使ってみる
```python
#ライブラリのimport
import lda
import lda.datasets
```

```python
#インスタンスなど
X = lda.datasets.load_reuters()
vocab = lda.datasets.load_reuters_vocab()
titles = lda.datasets.load_reuters_titles()
```

```python
#上のscikit-learnで作った単語行列から、欲しいモノを取ってくる。
vect = vectorizer.get_feature_names()
```
```python
#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
```
```python
#単語抽出
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()
```
<img width="444" alt="スクリーンショット 2018-08-19 22.04.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/244525/39121264-2a72-2444-6c14-2c5a6abd4f6b.png">
あれ、、、アルファベット順？笑
ちょっと並べ替えが上手くいっていないですが、タイトル分類にいきます。

```python
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()
```
<img width="743" alt="スクリーンショット 2018-08-19 19.40.27.png" src="https://qiita-image-store.s3.amazonaws.com/0/244525/35ec36f2-40f4-03fd-ca6b-7aa6654c102f.png">

###これはなかなかいい感じ・・・ですね！？笑
トピック0は<font color = "green">**考え方や言葉でのまとめ系**</font>、トピック1は<font color = "DarkOrange">**挑戦してみた系の技術記事**</font>、トピック2は<font color = "MediumBlue">**解説系（教える感じ）の技術記事**</font>、と分かれているように、僕は見えます！！笑

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

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

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


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


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