青空文庫のデータを形態素解析・感情分析してみた

Ruby データ分析 自然言語処理




青空文庫の文書データを形態素解析し、分割された単語ごとにネガティブかポジティブかの判定を行なって、スコアを計算させてみました。
形態素解析にはMecabを、ネガポジの判定には下記の単語感情極性対応表を使わせていただきました。
青空文庫 : http://www.aozora.gr.jp/
MeCab : http://taku910.github.io/mecab/
単語感情極性対応表 : http://www.lr.pi.titech.ac.jp/~takamura/pndic_ja.html
Rubyで青空文庫の解析したい文書のページをスクレイピングして、HTML構造解析で本文のみ抽出し、形態素解析・ネガポジ判定を行なうプログラムを作成します。
ちなみにスクレピングにはRubyには便利なWebクローリング&スクレイピングモジュールとして「Anemone」というものがありますので、こちらを使います。
Anemone : https://github.com/chriskite/anemone

# -*- coding: utf-8 -*-
require 'kconv'
require 'bundler'
Bundler.require
STDOUT.sync = true
url = ARGV[0]
negapozi_master = Hash.new()
File.open("pn_ja.dic", "r:UTF-8") do |f|
    while line = f.gets
        arr = line.gsub(/(\r|\n)/, "").split(":")
        negapozi_master[arr[0]] = arr[arr.size - 1].to_f
    end
end
mecab = Natto::MeCab.new
options = {
    :depth_limit => 0,
    :skip_query_strings => false,
    :read_timeout => 60,
}
title = ""
author = ""
surface_cnt = Hash.new()
feature_cnt = Hash.new()
negapozi_score = 0
Anemone.crawl(url, options) do |anemone|
    anemone.skip_links_like /.*\.doc|.*\.jpg|.*\.png|.*\.gif|.*\.pdf|.*\.zip/
    anemone.on_every_page do |page|
        doc = Nokogiri::HTML.parse(page.body)
        doc.xpath("//h1[@class='title']").each do |element|
            text = element.content
            text = text.gsub(/(\t|\s|\n|\r|\f|\v)/, "")
            title = text
        end
        doc.xpath("//h2[@class='author']").each do |element|
            text = element.content
            text = text.gsub(/(\t|\s|\n|\r|\f|\v)/, "")
            author = text
        end
        doc.xpath("//div[@class='main_text']").each do |element|
            text = element.content
            text.force_encoding("UTF-8")
            text = text.scrub("?")
            text = text.gsub(/*<\/rt>/, "")
            text = text.gsub(/<\/?[^>]*>/, "")
            text = text.gsub(/(\t|\s|\n|\r|\f|\v)/, "")
            text = text.gsub(/(\(|\))/, "")
            mecab.parse(text) do |node|
                next if node.surface.nil? || node.feature.nil?
                surface = node.surface
                feature = node.feature.split(",")[0]
                next if feature == "記号" || surface == "、" || surface == "。"
                surface_cnt[surface] = surface_cnt.has_key?(surface) ? surface_cnt[surface] + 1 : 1
                feature_cnt[feature] = feature_cnt.has_key?(feature) ? feature_cnt[feature] + 1 : 1
                negapozi_score = negapozi_score + negapozi_master[surface] if negapozi_master.has_key?(surface)
            end
        end
    end
end
surface_cnt = surface_cnt.sort_by{|key, value| -value}
feature_cnt = feature_cnt.sort_by{|key, value| -value}
puts  "title : " + title + ", author: " + author
puts "++++ surface count ++++"
cnt = 0
surface_cnt.each do |key, value|
    cnt = cnt + 1
    break if cnt > 5
    puts key + ": " + value.to_s
end
puts "++++ feature count ++++"
feature_cnt.each do |key, value|
    cnt = cnt + 1
    break if cnt > 5
    puts key + " : " + value.to_s
end
puts "++++ negapozi score ++++"
puts negapozi_score.to_s
exit

いくつかのページに対して実行してみました。

# ruby sc.rb http://www.aozora.gr.jp/cards/000035/files/301_14912.html
title : 人間失格, author: 太宰治
++++ surface count ++++
の: 2672
に: 1696
て: 1606
は: 1366
た: 1333
++++ feature count ++++
助詞 : 12749
名詞 : 12542
動詞 : 5866
助動詞 : 4499
副詞 : 1316
++++ negapozi score ++++
-5414.021331189988
# ruby sc.rb http://www.aozora.gr.jp/cards/000081/files/456_15050.html
title : 銀河鉄道の夜, author: 宮沢賢治
++++ surface count ++++
の: 1275
た: 948
て: 866
に: 780
は: 624
++++ feature count ++++
名詞 : 6536
助詞 : 6484
動詞 : 3305
助動詞 : 2651
副詞 : 925
++++ negapozi score ++++
-2613.359258273997
# ruby sc.rb http://www.aozora.gr.jp/cards/000140/files/50131_42408.html
title : アーサー王物語, author: テニソン Tennyson
++++ surface count ++++
e: 825
t: 637
h: 605
a: 597
の: 562
++++ feature count ++++
名詞 : 13347
助詞 : 3164
動詞 : 1365
助動詞 : 806
副詞 : 200
++++ negapozi score ++++
-1171.1144158299985

ネガティブですねー。
単語数や品詞数は上位5番目まで出してみましたが、特に面白いものはなかった感じです。
ネガポジ判定は、MeCabのユーザー辞書を作成して、当てる方が確実だったかと思います。
結構ネガポジの表自体がネガティブ寄りなので、アーサー王物語は英語が多い分、スコアも下がらなかったのでしょうか。
文章量が多ければ多いほどネガティブになりそうなので、量で割るなどの正規化が必要かと思います。



コメント