Kesin's diary

プログラミングの記事がメインです

RSSで自然言語処理を体験する

自然言語処理って何?

大学の研究では自然言語処理というものを扱っています。
と言われても自然言語処理って何?という人がほとんど(自分も今年の4月まで知りませんでした)だと思いますので、自然言語処理について紹介していきたいと思います。

自然言語処理は一言で言えば「人間が使用している言語(日本語や英語)をコンピューターに処理させる技術」です。実際には、

  • 類似する文書を検索
  • キーワード抽出
  • 機械翻訳
  • 質問応答システム(最近話題になった人間のクイズ王に勝利したIBMのスーパーコンピューターなど)

などが自然言語処理の技術です。

ここでは最も基礎的な方法で「類似する文書検索」というプログラムを書いてみます

どうやって類似する文書を探す?

ではどうやって類似する文書を探すことができるでしょうか。人間なら何となく類推することができますが、コンピューターは内部的には数式の処理しかできないので、人間のようにはいきません。方法はいくつもありますが、おそらく最も単純な方法であるベクトルで文書がどれだけ似ているかを計算する方法を紹介します。

例を挙げましょう。以下の3つの文書を考えます

AppleはMacというOSを作った
MicrosoftはWindowsというOSを作った
Googleは優秀な検索エンジンを開発

この3つの文書から意味のある言葉を抜き出すと、

[Apple, Mac, OS, 作った]
[Microsoft, Windows, OS, 作った]
[Google, 優秀, 検索エンジン, 開発]

というように文書を単語で表すことができました。
同じ単語が何回も出ていますね?これを利用すれば何となく似た文書を検索することができそうです。
ではこの3つの文書をベクトル化します。まずは登場した全ての単語の集合を作ります

[Apple, Mac, OS, 作った, Microsoft, Windows, Google, 優秀, 検索エンジン, 開発]

そしてこの集合の左から、それぞれの文書の中にこの単語が登場したら1, 登場しなければ0と置いていくとベクトルを作ることができます。

{1, 1, 1, 1, 0, 0, 0, 0, 0, 0}
{0, 0, 1, 1, 1, 1, 0, 0, 0, 0}
{0, 0, 0, 0, 0, 0, 1, 1, 1, 1}

既にどの文書が似ているのか一目瞭然ですが、実際にどれだけ似ているかを計算しましょう。ここではとても単純に2つのベクトルがなす角度を比べることにします。つまり、2つのベクトルの余弦を計算します。計算式はcos=ベクトルA,Bの内積/(ベクトルAのノルム*ベクトルBのノルム) です。これをcos類似度と呼びます。
何をしているのかイメージがわからない方は高校でやった線形代数を思い出してください。ここでは10次元という大きな次元になっていますが、やっていることは同じです。
では実際に1番目の文書と2, 3番目の文書がどれだけ似ているかを計算しましょう。このベクトルは0,1しかないので内積とノルムの計算は非常に簡単です。この二つの求め方を忘れてしまった方は高校の教科書を引っ張り出してもらうか、この後のソースコードで思い出してください。

  • 文書1と文書2の類似度: 0.5
  • 文書1と文書3の類似度: 0

というような結果になりました。単語集合やベクトルのときから何となく分かっていた結果ですが、このように計算で数値的に文書がどれだけ似ているかを求めることができます。

コンピューターにどうやらせるか

さて、ではここまでの手順をどうやってコンピューターにやらせましょうか?
計算はコンピューターの十八番なので全く問題ないですが、文書の単語を判断させるのは難しいです。ここでは世の中で既に使われているツールの力を借りましょう。文書を分かち書きすることを形態素解析といい、例えばMeCabというツールが形態素解析を行うことができます。例として先ほどの「AppleはMacというOSを作った」をMeCab形態素解析させると、

Apple     名詞,固有名詞,組織,*,*,*,*
は     助詞,係助詞,*,*,*,*,は,ハ,ワ,,
Mac     名詞,固有名詞,組織,*,*,*,*
という     助詞,格助詞,連語,*,*,*,という,トイウ,トユウ,,
OS     名詞,一般,*,*,*,*,*
を     助詞,格助詞,一般,*,*,*,を,ヲ,ヲ,,
作っ     動詞,自立,*,*,五段・ラ行,連用タ接続,作る,ツクッ,ツクッ,つくっ/ツクっ/作っ,
た     助動詞,*,*,*,特殊・タ,基本形,た,タ,タ,,

この結果からちゃんとした単語を抜き出す作業はそれなりに大変なので、とりあえず助詞と助動詞あたりを除外して残りを単語とします。すると

[Apple, Mac, OS, 作っ]

という単語集合を得ることができます。単語さえ抜き出すことができれば後は簡単です。全ての文書の単語を抜き出してベクトルを作り、cos類似度を計算するだけです。
実際にpythonで作ったプログラムを載せておきます。ちょっとズルイですが簡単に似たような文書を見つけるためにiPhoneやMacに関するRSSの記事タイトルを使いました。

#coding: utf-8
import feedparser
import MeCab
import re
import math

def analysis_entrie(entrie_list, allnoun_set):  #エントリーの単語を解析
    t = MeCab.Tagger("")
    re_word = re.compile("助詞|接尾|BOS|EOS|記号|名詞,数|助動詞| ") #除外する品詞
    feed=[]
    for entrie in entrie_list['entries']:
        if not "PR:" in entrie.title and not "AD:" in entrie.title: #広告除外
            noun_set = set([])
            dict = {}
            m = t.parseToNode(entrie.title.encode('utf-8')) #MeCabはUnicodeに対応していないのでutf-8に変換
            while m:
                if not re_word.findall(m.feature) and not m.surface.isspace():  #品詞チェック
                    noun_set.add(m.surface.decode('utf-8')) #単語集合に追加
                    allnoun_set.add(m.surface.decode('utf-8')) #全体単語集合に追加
                m = m.next
            dict['title'] = entrie.title
            dict['noun'] = noun_set
            dict['date'] = entrie.updated
            dict['url'] = entrie.link
            feed.append(dict)
            print entrie.title
            print "["+",".join(noun_set)+"]"
    return feed
def get_vector(allnoun_set, noun_set): #記事ごとの単語と全単語からベクトル生成
    vector = []
    for noun in allnoun_set:
        if noun in noun_set:
            vector.append(1)
        else:
            vector.append(0)
    return vector
def cos_similar(vector_A, vector_B): #cos類似度計算
    inner=0.0
    for (a, b) in zip(vector_A, vector_B):
        inner += a*b                        #内積
    for i in range(len(vector_A)):
        vector_A[i] = vector_A[i]**2
    for i in range(len(vector_B)):
        vector_B[i] = vector_B[i]**2
    norm_A = math.sqrt(sum(vector_A))       #ノルムA
    norm_B = math.sqrt(sum(vector_B))       #ノルムB
    return inner / (norm_A * norm_B)
   
if __name__ == '__main__':
    hatena = feedparser.parse("http://b.hatena.ne.jp/hotentry/it.rss")
    mycom_apple = feedparser.parse("http://feeds.journal.mycom.co.jp/rss/mycom/pc/apple")
    ascii_apple = feedparser.parse("http://rss.rssad.jp/rss/ascii/mac/rss.xml")
    itmedia_iphone = feedparser.parse("http://rss.rssad.jp/rss/itm/1.0/kw_iphone.xml")
    site_list= []
    site_list.append(hatena)
    site_list.append(mycom_apple)
    site_list.append(ascii_apple)
    site_list.append(itmedia_iphone)
   
    allnoun_set = set([])
    feed_list = []
   
    for site in site_list:
        feed_list += analysis_entrie(site, allnoun_set)
    for entrie in feed_list:
        entrie['vector'] = get_vector(allnoun_set, entrie['noun'])
   
    while True:    #入力した記事番号と類似する記事を表示
        print "記事番号を入力:"
        num = input()
        find_entrie = feed_list[num]
       
        for entrie in feed_list: #選択した記事とのcos類似度を計算
            entrie['score'] = cos_similar(find_entrie['vector'], entrie['vector'])
        feed_list.sort(key=lambda x:x['score'], reverse=True)
       
        print '\n"'+find_entrie['title'] +"\t"+"["+",".join(find_entrie["noun"])+"]"
        print "に似た上位5記事は以下のものです:"
        for entrie in feed_list[:6]:
            if (entrie['score'] < 0.99 and entrie['score'] > 0): #score=1は元記事、=0は全く関係ないので除外
                print entrie['title'], "\t"+"score:"+str(entrie['score'])+" ["+",".join(entrie["noun"])+"]"

実行結果

スマフォとかミニマルデザインに特化した、これからお世話になりそうなWebデザインギャラリー - かちびと.net[Web,し,お世話,ギャラリー,デザイン,ちび,スマフォ,なり,特,net,ミニマルデザイン]
カレンダー・TODOリスト・ガントチャートなどのPDF・エクセルの無料テンプレート素材 | コリス
[素材,リス,コ,テンプレート,カレンダー,リスト・ガントチャート,エクセル,無料,PDF,TODO]
一夜漬けでCSS3をマスターするために見ておくべきコードのまとめ - jsdo.it - Share JavaScript, HTML5 and CSS
[HTML,and,する,コード,見,JavaScript,Share,jsdo,it,おく,まとめ,CSS,マスター,一夜漬け,ため]

・・・
中略
・・・
“お父さん”を使ったオリジナルカバーが作れる「カバコレ」用iPhoneアプリ
[作れる,カバコレ,使っ,カバー,お父さん,iPhone,アプリ,オリジナル]
ソフトバンクモバイル、iPhone 3G/3GSのバージョンアップを告知
[GS,iPhone,告知,バージョンアップ,モバイル,ソフトバンク]
iPhone・iPadアクセサリー専門店「Case Play」が秋葉原にオープン
[iPad,Case,Play,専門,アクセサリー,iPhone,オープン,秋葉原]

記事番号を入力:
0
"スマフォとかミニマルデザインに特化した、これからお世話になりそうなWebデザインギャラリー - かちびと.net     [Web,し,お世話,ギャラリー,デザイン,ちび,スマフォ,なり,特,net,ミニマルデザイン]
に似た上位5記事は以下のものです:
GoogleAnalyticsで+1やTwitter、Facebookのソーシャルトラッキングを行う方法|caraldo.net | WebとiPhoneとロードバイクが大好き!      score:0.167248402001 [GoogleAnalytics,行う,Web,Twitter,caraldo,バイク,Facebook,iPhone,大好き,net,ロード,方法,ソーシャルトラッキング]
驚異的なAppleの業績: その“季節性を無視した変動”      score:0.106600358178 [季,その,Apple,変動,し,無視,業績,驚異]
フォーカルポイント、4色のラバーバンドを同梱したiPad 2用PUレザーケース      score:0.100503781526 [iPad,バンド,フォーカルポイント,レザー,同,梱,し,ケース,ラバー]
楽譜を撮れば演奏してくれるiPhoneアプリ「楽譜カメラ」 河合楽器から      score:0.100503781526 [撮れ,河合楽器,楽譜,カメラ,くれる,演奏,iPhone,し,アプリ]
全世界のWebトラフィックにiPadの占める割合は1% - Net Applications調査      score:0.0953462589246 [iPad,Web,調査,全,占める,世界,Applications,トラフィック,Net,割合]

記事番号を入力:
2
"自転車、バイクのハンドルに装着っ――「iPhone4用 生活防水ケース」     [防水,っ,生活,装着,バイク,iPhone,ハンドル,ケース,自転車]
に似た上位5記事は以下のものです:
特集・「実質0円」から始めるiPhone生活      score:0.298142397 [始める,生活,実質,iPhone,特集]
サンワダイレクト、スタンドとしても使用できるハンドル付きiPad 2用ケース      score:0.251976315339 [スタンド,できる,iPad,ケース,サンワダイレクト,ハンドル,使用]
iPhone 3Gハイライト      score:0.235702260396 [ハイライト,iPhone]
軍事規格にも対応! 超頑丈なiPhoneケースが登場      score:0.235702260396 [超,登場,ケース,軍事,規格,iPhone,頑丈,対応]
GoogleAnalyticsで+1やTwitter、Facebookのソーシャルトラッキングを行う方法|caraldo.net | WebとiPhoneとロードバイクが大好き!      score:0.184900065408 [GoogleAnalytics,行う,Web,Twitter,caraldo,バイク,Facebook,iPhone,大好き,net,ロード,方法,ソーシャルトラッキング]

記事番号を入力:
50
"カレンダー・TODOリスト・ガントチャートなどのPDF・エクセルの無料テンプレート素材 | コリス     [素材,リス,コ,テンプレート,カレンダー,リスト・ガントチャート,エクセル,無料,PDF,TODO]
に似た上位5記事は以下のものです:
企業や会社ブログでより魅力的なコンテンツを提供するための42のアイデア | コリス      score:0.182574185835 [コンテンツ,する,アイデア,提供,企業,コ,より,会社,ため,魅力,ブログ,リス]
無料コラボツール「サイボウズLive」のiPhoneアプリが登場      score:0.119522860933 [登場,Live,iPhone,無料,コラボツール,アプリ,サイボウズ]
アップル、iOS 4.3.4アップデートを公開 -PDFのセキュリティを修正      score:0.119522860933 [セキュリティ,アップル,修正,iOS,公開,PDF,アップデート]
iPhone 4/iPad 2でガンガン撃ちまくる――「TIME CRISIS 2ND STRIKE」対応のアプリ「iGunCon」を無料配信開始      score:0.0877058019307 [iPad,iGunCon,対応,開始,ガンガン,配信,無料,iPhone,TIME,STRIKE,撃ちまくる,アプリ,CRISIS]

記事番号を入力:
51
"Androidの「警告」、チェックしてる?――モバイルマルウェアの増加にシマンテックが警鐘&amp;#8206;     [シマンテック,チェック,増加,警鐘,モバイルマルウェア,し,amp,Android,てる,警告]
に似た上位5記事は以下のものです:
すべて見せます!! 「iPad 2」を全力チェック!      score:0.141421356237 [見せ,iPad,すべて,チェック,全力]
驚異的なAppleの業績: その“季節性を無視した変動”      score:0.111803398875 [季,その,Apple,変動,し,無視,業績,驚異]
Androidマーケットが複数APKをサポート(見た目以上に重要)      score:0.111803398875 [サポート,重要,複数,以上,APK,マーケット,見た目,Android]
楽譜を撮れば演奏してくれるiPhoneアプリ「楽譜カメラ」 河合楽器から      score:0.105409255339 [撮れ,河合楽器,楽譜,カメラ,くれる,演奏,iPhone,し,アプリ]
KDDIがiPhoneアプリ開発、Androidとともに展開――若手社員ら推進      score:0.105409255339 [若手,推進,KDDI,iPhone,展開,社員,開発,アプリ,Android]

それなりに上手くできたケースと全く見当はずれなケースを抜き出したつもりですが、微妙な結果ですね・・・。スコアが0.1程度でも検索元の単語群のうちのいずれかは含まれているので計算自体は間違ってなさそうです。やはりそう簡単にはいかないということですね^^;
もう少し改良できたらまた続きを書こうかと思います。