前回 の処理に似たようなことを行い、
- 接頭詞 + 名詞 = 名詞
- 名詞 + 名詞 = 名詞
- 名詞 + 動詞 = 動名詞 + 動詞
- 動詞 + 動詞 = 動詞
- 動詞 + 助動詞 = 動詞
- 動詞 + 助詞 = 動詞
で区切ったあと、句読点が「記号」と認識されていることに着目。
記号で区切られた範囲を最少の「文」として区分けする。
すると、
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
パッと見そんなでもないように見えて、組み合わせパターンが意味不明な一部を除いては概ね面白い結果に。