形態素解析のサンプルアプリが面白かったので、シャァの演説を見てもらった - 謎言語使いの徒然 の続き。
やってみたら案外よさげになった。
code
import net.reduls.igo.Tagger import scala.collection.mutable import scala.io.{Codec, Source} case class Word(word:String, wordType:String, subType:String) object Word { def apply(word:String, attribute:String):Word = { val element = attribute.split(",") Word(word, element(0), element(1)) } private def compareType(l:Word, r:Word, types:String):Boolean = l.wordType == r.wordType && l.wordType == types private def compareType(l:Word, r:Word, lTypes:String, rType:String):Boolean = l.wordType == lTypes && r.wordType == rType def combine(tokens:Iterable[Word]):mutable.MutableList[Word] = tokens.foldLeft(mutable.MutableList.newBuilder[Word].result()) { case (lists, token) => if (lists.size == 0) { lists += token } else { (lists.last, token) match { case (l, r) if compareType(l, r, "接頭詞", "名詞") => lists.dropRight(1) += Word(l.word + r.word, "名詞", "固有名詞") case (l, r) if compareType(l, r, "名詞") => lists.dropRight(1) += Word(l.word + r.word, "名詞", "固有名詞") case (l, r) if compareType(l, r, "名詞", "動詞") => lists.dropRight(1) += Word(l.word , "動名詞", "自立") += r case (l, r) if compareType(l, r, "動詞", "動詞") => lists.dropRight(1) += Word(l.word + r.word, "動詞", "自立") case (l, r) if compareType(l, r, "動詞", "助動詞") => lists.dropRight(1) += Word(l.word + r.word, "動詞", "自立") case o => lists += token } } } def splitBySymbol(tokens:List[Word]):List[List[Word]] = { val result = mutable.MutableList.newBuilder[List[Word]].result() var currentTokens = mutable.MutableList.newBuilder[Word].result() val newWord = List("。", "「", "」", "、") tokens.foreach { token => if (token.wordType == "記号" && newWord.contains(token.word)) { result += currentTokens.toList currentTokens = mutable.MutableList.newBuilder[Word].result() } else { currentTokens += token } } result.filterNot(_.isEmpty).toList } } class SentenceCalc { val wordCount = collection.mutable.Map.empty[Word, Int] val pairCount = collection.mutable.Map.empty[(Word, Word), Int] def calcSentence(sentence:List[Word]) { sentence.foreach(t => { countWord(t, t.word) }) makeCombination(sentence).foreach { case (left, right) => val (leftHash, rightHash) = (left.hashCode -> right.hashCode) val key = if (leftHash < rightHash) (left -> right) else (right -> left) pairCount.get(key) match { case Some(v) => pairCount.+=(key -> (v + 1)) case None => pairCount.+=(key -> 1) } } } private def makeCombination(tgt:List[Word]):List[(Word, Word)] = { def pairComparator(head:Word, tail:List[Word]):List[(Word, Word)] = { tail.size match { case 1 => List(head -> tail.head) case e => tail.map(v => head -> v) ++ pairComparator(tail.head, tail.tail) } } if (tgt.isEmpty || tgt.size == 1) { List.empty[(Word, Word)] } else { pairComparator(tgt.head, tgt.tail) } } private def countWord(hash:Word, s:String) { wordCount.get(hash) match { case Some(i) => wordCount += (hash -> (i + 1)) case None => wordCount += (hash -> 1) } } } object IgoSample extends App { import Word._ import scala.collection.JavaConversions._ val tagger = new Tagger("ipadic") val source = Source.fromFile("sample.txt")(Codec.UTF8) val enableName = List("名詞", "動名詞") val calc = new SentenceCalc source.getLines().foreach(messageLine => { val parsedList = combine(tagger.parse(messageLine).map(m => Word(m.surface, m.feature))).toList val sentences = splitBySymbol(parsedList.filter(_.subType != "代名詞")) sentences.map(sentence => { sentence.filter(w => enableName.contains(w.wordType)).filter(w => w.subType != "非自立") }).filterNot(_.isEmpty).foreach(calc.calcSentence) }) source.close() println("Result ========================================") println("MessageDetect : ") calc.wordCount.toList.sortWith({ case ((_, l), (_, r)) => l > r}).foreach(v => println(" %s\t%d".format(v._1, v._2))) println("Combinations : ") calc.pairCount.toList.sortWith({ case ((_, l), (_, r)) => l > r }).foreach(v => { val (left,right) = v._1 println(" %s = %s\t%d".format(left.word, right.word, v._2)) }) }
Result ======================================== MessageDetect : Word(地球,名詞,一般) 12 Word(宇宙,名詞,一般) 4 Word(人,名詞,一般) 3 Word(ジオン・ダイクン,名詞,一般) 3 Word(人類,名詞,一般) 3 Word(議会,名詞,一般) 3 Word(人間,名詞,一般) 3 Word(ザビ家,名詞,固有名詞) 3 Word(ティターンズ,名詞,一般) 3 Word(地球連邦軍,名詞,固有名詞) 2 Word(やり方,名詞,一般) 2 Word(テレビ,名詞,一般) 2 Word(ジオン公国,名詞,固有名詞) 2 Word(遺志,名詞,一般) 2 Word(籠,名詞,一般) 2 Word(歴史,名詞,一般) 2 Word(悪,名詞,一般) 2 Word(能力,名詞,一般) 1 Word(誤解,名詞,サ変接続) 1 Word(寄生虫,名詞,一般) 1 Word(人類同士,名詞,固有名詞) 1 Word(武力,名詞,一般) 1 Word(場,名詞,一般) 1 Word(制圧,動名詞,自立) 1 Word(御覧,名詞,一般) 1 Word(魂,名詞,一般) 1 Word(一つ,動名詞,自立) 1 Word(ダカール,名詞,固有名詞) 1 Word(クワトロ・バジーナ大尉,名詞,固有名詞) 1 Word(欲望,名詞,一般) 1 Word(力,名詞,一般) 1 Word(身,名詞,一般) 1 Word(惑星,名詞,一般) 1 Word(人類そのもの,名詞,固有名詞) 1 Word(暴虐,名詞,形容動詞語幹) 1 Word(現在ティターンズ,名詞,固有名詞) 1 Word(行為,名詞,サ変接続) 1 Word(事実,名詞,副詞可能) 1 Word(集まり,名詞,一般) 1 Word(ティターズ,名詞,一般) 1 Word(人々,名詞,一般) 1 Word(話,名詞,サ変接続) 1 Word(今,名詞,副詞可能) 1 Word(戦い,名詞,一般) 1 Word(勢力,名詞,一般) 1 Word(方々,名詞,一般) 1 Word(全て,名詞,副詞可能) 1 Word(破壊,動名詞,自立) 1 Word(子,名詞,一般) 1 Word(間,名詞,一般) 1 Word(連邦国々民,名詞,固有名詞) 1 Word(エゥーゴ,名詞,一般) 1 Word(悪質,名詞,形容動詞語幹) 1 Word(シャア,名詞,一般) 1 Word(時,名詞,一般) 1 Word(手,名詞,一般) 1 Word(不幸,名詞,形容動詞語幹) 1 Word(シャア・アズナブル,名詞,一般) 1 Word(戦闘,名詞,サ変接続) 1 Word(衰退,動名詞,自立) 1 Word(前,名詞,副詞可能) 1 Word(議員,名詞,一般) 1 Word(汚染,動名詞,自立) 1 Word(名,名詞,一般) 1 Word(自分,名詞,一般) 1 Word(男,名詞,一般) 1 Word(砂漠,名詞,一般) 1 Word(欲求,名詞,サ変接続) 1 Word(自然,名詞,形容動詞語幹) 1 Word(拡大,動名詞,自立) 1 Word(自分達,名詞,固有名詞) 1 Word(生活圏,名詞,固有名詞) 1 Word(味方,名詞,サ変接続) 1 Word(水,名詞,一般) 1 Word(その後,名詞,副詞可能) 1 Word(ジオン,名詞,一般) 1 Word(自立,動名詞,自立) 1 Word(無礼,名詞,一般) 1 Word(重み,名詞,一般) 1 Combinations : 地球 = 籠 2 味方 = 自分達 1 事実 = 現在ティターンズ 1 地球 = 惑星 1 議会 = 破壊 1 魂 = ティターンズ 1 地球 = 人 1 自分達 = ティターンズ 1 事実 = 地球連邦軍 1 地球 = 時 1 欲望 = ザビ家 1 人間 = 能力 1 味方 = 議会 1 地球 = 人類 1 自立 = 人間 1 人々 = 魂 1 議会 = 自分達 1 やり方 = ザビ家 1 身 = 力 1 戦闘 = ティターンズ 1 悪質 = ザビ家 1 悪質 = やり方 1 重み = 人間 1 力 = 人類そのもの 1 身 = 人類そのもの 1 悪 = 全て 1 地球 = 自然 1 地球 = 汚染 1 勢力 = ザビ家 1 生活圏 = 拡大 1 誤解 = 力 1 集まり = ティターンズ 1 籠 = 自然 1 男 = 名 1 自分達 = 議員 1 武力 = 制圧 1 名 = シャア・アズナブル 1 ジオン = 遺志 1 地球 = 手 1 地球 = 水 1 議会 = ティターンズ 1 議会 = 制圧 1 クワトロ・バジーナ大尉 = エゥーゴ 1 前 = 話 1 自分 = 欲求 1 地球 = 人間 1 誤解 = 人類そのもの 1 勢力 = 歴史 1 連邦国々民 = テレビ 1 ジオン公国 = シャア 1 間 = 人 1 砂漠 = ダカール 1 地球連邦軍 = 現在ティターンズ 1 地球 = 重み 1 地球 = 人々 1 ティターンズ = 破壊 1 味方 = 議員 1 議会 = 議員 1 寄生虫 = 地球 1 歴史 = ザビ家 1 御覧 = テレビ 1 水 = 惑星 1 手 = 人 1 その後 = 人類同士 1 ジオン・ダイクン = 遺志 1 人々 = ティターンズ 1 やり方 = ティターズ 1 人類 = 時 1 味方 = ティターンズ 1 味方 = 破壊 1 方々 = テレビ 1 議会 = 武力 1 自立 = 宇宙 1 議員 = 破壊 1 その後 = 戦い 1 方々 = 御覧 1 人類 = 宇宙 1 集まり = 魂 1 人類 = 衰退 1 宇宙 = 人 1 ティターンズ = 議員 1 集まり = 地球 1 ジオン・ダイクン = 子 1 人間 = 宇宙 1 暴虐 = 行為 1 ジオン・ダイクン = ジオン公国 1 男 = シャア・アズナブル 1 地球 = ティターンズ 1 身 = 誤解 1 自分達 = 破壊 1 地球 = 魂 1 集まり = 人々 1 人類同士 = 戦い 1