前回 の処理に似たようなことを行い、
- 接頭詞 + 名詞 = 名詞
- 名詞 + 名詞 = 名詞
- 名詞 + 動詞 = 動名詞 + 動詞
- 動詞 + 動詞 = 動詞
- 動詞 + 助動詞 = 動詞
- 動詞 + 助詞 = 動詞
で区切ったあと、句読点が「記号」と認識されていることに着目。
記号で区切られた範囲を最少の「文」として区分けする。
すると、
List(Token(名詞,田村憲久厚生労働相,タムラケンヒサコウセイロウドウショウ), Token(助詞,は,ハ), Token(名詞,22日,ニニニチ)) List(Token(名詞,2階,ニカイ), Token(助詞,の,ノ), Token(名詞,飲食店,インショクテン), Token(助詞,を,ヲ), Token(動名詞,予約,ヨヤク), Token(動詞,した,シタ), Token(名詞,作家,サッカ), Token(助詞,の,ノ), Token(名詞,乙武洋匡さん,オツタケヒロタダシサン), Token(助詞,が,ガ)) List(Token(名詞,車いす,クルマイス), Token(助詞,を,ヲ), Token(名詞,理由,リユウ), Token(助詞,に,ニ), Token(動名詞,入店拒否,ニュウミセキョヒ), Token(動詞,された,サレタ), Token(助詞,と,ト), Token(名詞,ネット,ネット), Token(助詞,で,デ), Token(名詞,明らか,アキラカ), Token(助詞,に, ニ), Token(動詞,し,シ), Token(助詞,て,テ), Token(動詞,いる,イル), Token(名詞,こと,コト), Token(助詞,に対し,ニタイシ)) List(Token(名詞,店員,テンイン), Token(助詞,が,ガ), Token(動名詞,協力,キョウリョク), Token(動詞,し,シ), Token(助詞,て,テ), Token(動詞,連れ,ツレ), Token(助詞,て,テ), Token(動詞,行く,イク), Token(名詞,努力,ドリョク), Token(助詞,を,ヲ), Token(動詞,すべきだ,スベキダ), Token(助詞, と,ト), Token(動詞,思う,オモウ), Token(助詞,が,ガ)) List(Token(名詞,店,ミセ), Token(助詞,の,ノ), Token(名詞,状況,ジョウキョウ), Token(助詞,や,ヤ), Token(名詞,対応,タイオウ), Token(助詞,が,ガ), Token(動詞,分からず,ワカラズ)) List(Token(名詞,これ以上,コレイジョウ), Token(助詞,の,ノ), Token(名詞,コメント,コメント), Token(助詞,は,ハ), Token(動詞,差し控えたい,サシ ヒカエタイ)) List(Token(助詞,と,ト), Token(動詞,述べた,ノベタ))
名詞/動名詞を抽出して
List(Token(名詞,田村憲久厚生労働相,タムラケンヒサコウセイロウドウショウ), Token(名詞,22日,ニニニチ)) List(Token(名詞,2階,ニカイ), Token(名詞,飲食店,インショクテン), Token(動名詞,予約,ヨヤク), Token(名詞,作家,サッカ), Token(名詞,乙武洋匡さん,オツタケヒロタダシサン)) List(Token(名詞,車いす,クルマイス), Token(名詞,理由,リユウ), Token(動名詞,入店拒否,ニュウミセキョヒ), Token(名詞,ネット,ネット), Token(名 詞,明らか,アキラカ), Token(名詞,こと,コト)) List(Token(名詞,店員,テンイン), Token(動名詞,協力,キョウリョク), Token(名詞,努力,ドリョク)) List(Token(名詞,店,ミセ), Token(名詞,状況,ジョウキョウ), Token(名詞,対応,タイオウ)) List(Token(名詞,これ以上,コレイジョウ), Token(名詞,コメント,コメント))
うーんここまで来ると、1つの文で一緒に使用された名詞と動名詞の関係も残したくなるな。
で、ここまで来たら
- 単語をカウント
- 1文の中で一緒に発言された名詞・動名詞を1セットとして、カウント
してみる。
お題はこれ
話の前に、もう一つ知っておいてもらいたいことがあります。私はかつてシャア・アズナブルという名で呼ばれたこともある男だ。私はこの場を借りて、ジオンの遺志を継ぐものとして語りたい。もちろん、ジオン公国のシャアとしてではなく、ジオン・ダイクンの子としてである。ジオン・ダイクンの遺志は、ザビ家のような欲望に根差したものではない。ジオン・ダイクンがジオン公国を作ったのでは無い。現在ティターンズが地球連邦軍を我が物にしている事実は、ザビ家のやり方より悪質であると気付く。
シャア様ですね
で、コードがこんなんになって
import net.reduls.igo.Tagger import scala.collection.mutable object Token { def toToken(morpheme:String, original:String) = { val elements = morpheme.split(",") Token(elements(0), original, elements(6)) } private def compareType(l:Token, r:Token, types:String):Boolean = l.tokenType == r.tokenType && l.tokenType == types private def compareType(l:Token, r:Token, lTypes:String, rType:String):Boolean = l.tokenType == lTypes && r.tokenType == rType def splitBySymbol(tokens:List[Token]):List[List[Token]] = { val result = mutable.MutableList.newBuilder[List[Token]].result() var currentTokens = mutable.MutableList.newBuilder[Token].result() tokens.foreach { token => if (token.tokenType == "記号") { result += currentTokens.toList currentTokens = mutable.MutableList.newBuilder[Token].result() } else { currentTokens += token } } result.filterNot(_.isEmpty).toList } def combineTokens(tokens:Iterable[Token]):mutable.MutableList[Token] = tokens.foldLeft(mutable.MutableList.newBuilder[Token].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) += Token("名詞", l.currentToken + r.currentToken, l.sound + r.sound) case (l, r) if compareType(l, r, "名詞") => lists.dropRight(1) += Token("名詞", l.currentToken + r.currentToken, l.sound + r.sound) case (l, r) if compareType(l, r, "名詞", "動詞") => lists.dropRight(1) += Token("動名詞", l.currentToken , l.sound) += r case (l, r) if compareType(l, r, "動詞", "動詞") => lists.dropRight(1) += Token("動詞", l.currentToken + r.currentToken, l.sound + r.sound) case (l, r) if compareType(l, r, "動詞", "助動詞") => lists.dropRight(1) += Token("動詞", l.currentToken + r.currentToken, l.sound + r.sound) case o => lists += token } } } } case class Token(tokenType:String, currentToken:String, sound:String) class SentenceCalc { val wordMap = collection.mutable.Map.empty[Int, String] val wordCount = collection.mutable.Map.empty[Int, Int] val pairCount = collection.mutable.Map.empty[(Int, Int), Int] def calcSentence(sentence:List[Token]) { sentence.foreach(t => { countWord(t.currentToken.hashCode, t.currentToken) }) makeCombination(sentence.map(_.currentToken)).foreach { case (left, right) => val (leftHash, rightHash) = (left.hashCode -> right.hashCode) val key = if (leftHash < rightHash) (leftHash -> rightHash) else (rightHash -> leftHash) pairCount.get(key) match { case Some(v) => pairCount.+=(key -> (v + 1)) case None => pairCount.+=(key -> 1) } } } def makeCombination(tgt:List[String]):List[(String, String)] = { def pairComparator(head:String, tail:List[String]):List[(String, String)] = { 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[(String, String)] } else { pairComparator(tgt.head, tgt.tail) } } def countWord(hash:Int, s:String) { wordMap += (hash -> s) wordCount.get(hash) match { case Some(i) => wordCount += (hash -> (i + 1)) case None => wordCount += (hash -> 1) } } } object IgoSample extends App { val tagger = new Tagger("ipadic") val parsedList = tagger.parse("話の前に、もう一つ知っておいてもらいたいことがあります。" + "私はかつてシャア・アズナブルという名で呼ばれたこともある男だ。" + "私はこの場を借りて、ジオンの遺志を継ぐものとして語りたい。" + "もちろん、ジオン公国のシャアとしてではなく、ジオン・ダイクンの子としてである。" + "ジオン・ダイクンの遺志は、ザビ家のような欲望に根差したものではない。" + "ジオン・ダイクンがジオン公国を作ったのでは無い。現在ティターンズが地球連邦軍を我が物にしている事実は、ザビ家のやり方より悪質であると気付く。") import scala.collection.JavaConversions._ val filter = List("名詞", "動名詞") def tokens = Token.combineTokens(parsedList.map(v => Token.toToken(v.feature, v.surface)).toIterable) val sentences = Token.splitBySymbol(tokens.toList) val names = sentences map { sentence => sentence.filter(t => filter.contains(t.tokenType)) } filterNot(_.isEmpty) val calc = new SentenceCalc names.foreach(calc.calcSentence) println("Result ========================================") println("MessageDetect : ") calc.wordCount.foreach(v => println(" %s\t%d".format(calc.wordMap(v._1), v._2))) println("Result : ") calc.pairCount.foreach(v => { val (left,right) = v._1 println(" %s = %s\t%d".format(calc.wordMap(left), calc.wordMap(right), v._2)) }) }
でして結果が
Result ======================================== MessageDetect : もの 2 名 1 話 1 シャア 1 男 1 地球連邦軍 1 悪質 1 の 1 こと 2 物 1 よう 1 遺志 2 やり方 1 シャア・アズナブル 1 事実 1 ジオン・ダイクン 3 欲望 1 ジオン 1 子 1 場 1 私 2 現在ティターンズ 1 ザビ家 2 ジオン公国 2 前 1 一つ 1 Result : やり方 = ザビ家 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
パッと見そんなでもないように見えて、組み合わせパターンが意味不明な一部を除いては概ね面白い結果に。