Search on the blog

2015年12月28日月曜日

LDAで日経225企業をクラスタリングする

 最近LDAという言葉をよく聞くので、LDAを使って何かをやってみることにした。
とりあえず使ってみることを重視するため、深い/細かい話には立ち入らない。

LDAとは?
  • Latent Dirichlet Allocationの略。
  • トピックモデルの一種。
  • ドキュメントは複数のトピックから成り立っていると仮定。
  • 入力=ドキュメント集合、出力=各ドキュメントのトピック分布、各トピックの語句分布
やること
日経225の企業をwikipediaの文章を元にクラスタリングする。
事前準備として、225銘柄一覧に記載されている企業のwikiページのHTMLを取得しておく。HTMLはhtml/配下に企業名.htmlというファイル名で格納しておく。
$ ls html | head -n 10
ANAホールディングス.html
DOWAホールディングス.html
IHI.html
J.フロント リテイリング.html
JFEホールディングス.html
JXホールディングス.html
KDDI.html
MS&ADインシュアランスグループホールディングス.html
NTN.html
NTTデータ.html

前処理
html/配下に格納されたHTMLを前処理して、text/配下に格納する。
行った前処理は以下のとおり。
  • Javascript/CSSの記述削除
  • HTMLタグの除去
  • MeCabで分かち書き
# -*- coding: utf-8 -*-

import os
from bs4 import BeautifulSoup
import MeCab

for f_name in os.listdir('html'):
    f_path = 'html/' + f_name
    with open(f_path, 'r') as f:
        data = f.read()
        soup = BeautifulSoup(data, 'lxml')
        for script in soup.find_all('script'): script.decompose()
        for script in soup.find_all('style'): script.decompose()
        text = soup.getText()
        text = [line for line in text.splitlines() if line]
        text = '\n'.join(text)

        tagger = MeCab.Tagger('-Owakati')
        wakati_text = tagger.parse(text.encode('utf-8'))    

        t_path = 'text/{name}.txt'.format(name = os.path.splitext(f_name)[0])
        open(t_path, 'w').write(wakati_text)

LDAモデルの学習
前処理したテキストを使ってLDAモデルを学習する。
  • Dictionaryの作成(tokenのid化、document ごとのtokenの頻度計算など)
  • 汎用的な語句(60%以上のドキュメントで使われる語句)の除去
  • bag of words形式の行列作成
  • LDAモデルの構築
  • ドキュメント-トピック配分の行列を作成し保存
import logging
import os
import pickle
import gensim

logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
TOPIC_NUM = 30

texts = [file('text/' + f_name, 'r').read().split() for f_name in os.listdir('text')]
dictionary = gensim.corpora.Dictionary(texts)
dictionary.filter_extremes(no_below=1, no_above=0.6, keep_n=None)
corpus = [dictionary.doc2bow(text) for text in texts]
lda = gensim.models.ldamodel.LdaModel(corpus, num_topics=TOPIC_NUM, id2word = dictionary, passes=20)

topics = []
for c in corpus:
    topic = [0] * TOPIC_NUM
    for (tpc, prob) in lda.get_document_topics(c):
        topic[tpc] = prob
    topics.append(topic)

pickle.dump(topics, open("topics.p", "w"))

クラスタリング
トピック配分を特徴量としてK−meansでクラスタリング。
  • 特徴量のL2ノルム正規化
  • K-meansの学習
  • ドキュメントのクラスタリング
# -*- coding: utf-8 -*-

import pickle
import os
from sklearn.preprocessing import Normalizer
from sklearn.cluster import KMeans

N_CLUSTER = 20

xs = pickle.load(open('topics.p', 'r'))
ys = [os.path.splitext(f_name)[0] for f_name in os.listdir('text')]

xs = Normalizer().fit_transform(xs)
kmeans = KMeans(n_clusters=N_CLUSTER, init='k-means++', max_iter=100, n_init=1)
kmeans.fit(xs)
clusters = kmeans.predict(xs)

for i in range(N_CLUSTER):
    text = 'cluster {clr}:'.format(clr = i)
    companies = [y for k, y in enumerate(ys) if clusters[k] == i]
    print text + " ".join(companies)

結果
それっぽく分かれているところを色つけしてみた。

cluster 0: SUMCO りそなホールディングス オークマ クラレ コニカミノルタ サッポロホールディングス トクヤマ ユニチカ 三井化学 三井造船 三井金属鉱業 三菱マテリアル 双日 商船三井 大林組 宇部興産 帝人 日新製鋼 日本製紙 日本製鋼所 日東電工 日立造船 昭和電工 東レ 東宝 => 三井グループ
cluster 1: JXホールディングス MS&ADインシュアランスグループホールディングス アステラス製薬 アドバンテスト 三井住友トラスト・ホールディングス 信越化学工業 国際石油開発帝石 大和証券グループ本社 太平洋セメント 損保ジャパン日本興亜ホールディングス 日本水産 日産化学工業
cluster 2: KDDI NTTドコモ アマダホールディングス ディー・エヌ・エー デンソー ブリヂストン 京王電鉄 宝ホールディングス 富士通 東海カーボン => 携帯電話関連
cluster 3: オリンパス キッコーマン セブン&アイ・ホールディングス マルハニチロ 三井物産 明治ホールディングス 清水建設 王子ホールディングス
cluster 4: IHI J.フロント リテイリング ふくおかフィナンシャルグループ ニチレイ 三菱UFJフィナンシャル・グループ 三菱商事 三越伊勢丹ホールディングス 千代田化工建設 第一生命保険
cluster 5: NTTデータ TDK いすゞ自動車 アルプス電気 クレディセゾン コナミホールディングス ソフトバンク テルモ トヨタ自動車 トレンドマイクロ マツダ ヤマトホールディングス 三菱地所 大平洋金属 大成建設 太陽誘電 富士重工業 小田急電鉄 新日鐵住金 日本碍子 日本通運 日野自動車 昭和シェル石油 東武鉄道 東海旅客鉄道 松井証券 沖電気工業 積水ハウス 花王 長谷工コーポレーション => 自動車関連鉄道関連
cluster 6: ミネベア 中外製薬 味の素 大日本住友製薬 富士電機 日本曹達 日本精工 日清製粉グループ本社 横河電機 武田薬品工業
cluster 7: ジェイテクト スカパーJSATホールディングス 京成電鉄 古河機械金属 古河電気工業 日本軽金属ホールディングス 東日本旅客鉄道 東洋製罐グループホールディングス 西日本旅客鉄道
cluster 8: TOTO クボタ ヤマハ ユニーグループ・ホールディングス 中部電力 日清紡ホールディングス 東京電力 横浜ゴム 関西電力
cluster 9: カシオ計算機 キヤノン ミツミ電機 凸版印刷 富士フイルムホールディングス 川崎汽船 日本化薬
cluster 10: SCREENホールディングス みずほフィナンシャルグループ コムシスホールディングス ヤフー リコー 三井住友フィナンシャルグループ 住友大阪セメント 旭硝子 東京海上ホールディングス 野村ホールディングス 電通 => 金融関連
cluster 11: シチズンホールディングス シャープ パナソニック 北越紀州製紙 川崎重工業 日立建機 旭化成
cluster 12: 伊藤忠商事 大阪ガス 日本郵船 日本電気 東京ガス 東急不動産ホールディングス
cluster 13: ANAホールディングス DOWAホールディングス スズキ ファナック 三菱ケミカルホールディングス 住友金属鉱山 東京ドーム
cluster 14: イオン ジーエス・ユアサコーポレーション ソニー ソニーフィナンシャルホールディングス デンカ ニコン ファーストリテイリング 三井不動産 丸井グループ 東ソー 東京建物 東芝 高島屋
cluster 15: 三菱重工業 丸紅 安川電機 日本ハム 日立製作所 本田技研工業 東京エレクトロン 神戸製鋼所
cluster 16: JFEホールディングス アサヒグループホールディングス ダイキン工業 日本板硝子 日本電信電話 日産自動車 東邦亜鉛 豊田通商
cluster 17: T&Dホールディングス あおぞら銀行 セコム 千葉銀行 新生銀行 横浜銀行 第一三共 静岡銀行 => 銀行関連
cluster 18: エーザイ キリンホールディングス フジクラ 三菱倉庫 三菱自動車工業 住友不動産 住友化学 住友商事 住友重機械工業 住友電気工業 協和発酵キリン 大和ハウス工業 大日本印刷 小松製作所 日本たばこ産業 日本電気硝子 明電舎 東京急行電鉄 東洋紡 荏原製作所 鹿島建設 => 住友グループ
cluster 19: NTN パイオニア 三菱電機 京セラ 塩野義製薬 日揮 資生堂

改善点
  • 他の情報源からもドキュメントを集める
  • 汎用語句の閾値をチューニングする
  • トピックの数をチューニングする
  • クラスタの数をチューニングする

0 件のコメント:

コメントを投稿