kiyokaのブログアーカイブ

Archive of old blog posts

平仮名フレーズ辞書を追加してみようかな(3)

img 先日来のエントリ 「2011-07-06Sekka* 平仮名フレーズ辞書を追加してみようかな(1)」 「2011-07-07Sekka* 平仮名フレーズ辞書を追加してみようかな(2)」 の続き。

実際にWebコーパスの6-gramのデータの中から、文末に出てくる定型フレーズを集めるスクリプトを書いてみた。 文末で、且つ、平仮名のみで構成されている形態素を連結した文字列をSekka用フレーズとした。 文末は </S> (文境界マーク) で判断した。

入力例

% が 加算 さ れ て	1152
% が 加算 さ れ ます	1463
% しか あり ませ ん </S>	1995
% だっ た そう です </S>	1554
% だっ た の が 、	1142
% だっ た の に対し 、	3496
% で 、 環境 問題 に	1898
% で あっ た が 、	2212
, と し て いる </S>	1007
, と 思い まし た </S>	1780

出力例

しかありません    ;;  7 ;; ("!%" "しか" "あり" "ませ" "ん" "</S>" "1995")
だったそうです    ;;  7 ;; ("!%" "だっ" "た" "そう" "です" "</S>" "1554")
としている    ;;  5 ;; ("!," "と" "し" "て" "いる" "</S>" "1007")
ました    ;;  3 ;; ("!," "と" "思い" "まし" "た" "</S>" "1780")

プログラムは[Nendo]で書いたが、非常に計算が重い。(処理系の問題) Gaucheでも動くポータブルなコードにすべきだったかも。まあ何回も動かすわけではないからいいか。

#!/bin/sh
:; #-*- mode: nendo; syntax: scheme -*-;;
:; exec /usr/local/bin/nendo $0 $*

(use srfi-1)
(use sekka.roman-lib)

(define (hiragana-filter words)
  (define (hiras lst)
    (cond
     ((null? lst)
      lst)
     ((is-hiragana (car lst))
      (cons
       (car lst)
       (hiras (cdr lst))))))
     
  (let1 lst (cdr (reverse words))
    (reverse (hiras lst))))


(define (include-slash-s? lst)
  (any
   (lambda (x y)
     (and
      (string=? "</S>" y)
      (is-hiragana     x)))
   (cons "" lst)
   lst))
   

(define (grep-last-phrase filename)
  (with-open
   filename
   (lambda (f)
     (for-each
      (lambda (line)
        (let* (*lst   (to-list (line.chomp.split #/[ \t*+/))]
               *freq  (take-right lst 1)*
               *words (drop-right lst 1)*)
          (when (include-slash-s? words)
            (let1 phrase (apply + (hiragana-filter words))
              (printf "%s    ;; %2d ;; %s\n"
                      phrase
                      phrase.size
                      (write-to-string lst))))))
      (f.readlines.to_list)))))

(define (main argv)
  (if (> 1 (length argv))
      (error "hiragana_phrase.nnd requires *6gram web corpus file*")
      (grep-last-phrase (car (to-list argv)))))

この処理のあと、「ー」が含まれるフレーズや、「っぁぃぅぇぉ」などで終わるフレーズは固い文章を書いている時に出てくると困るので、外している。 例えば、「どーも」とか「よろしくっ」とかが頻繁にサジェストされてると非常に困る。そういうくだけた表現は自分で故意に入力すればいい。 また、辞書の語彙として有意なものに限定するため 2文字から7文字までの長さのフレーズに絞り込んだ。

プログラムはこちら。

#!/bin/sh
:; #-*- mode: nendo; syntax: scheme -*-;;
:; exec /usr/local/bin/nendo $0 $*

(define (writing-phrase? str)
  (not
   (or
    (rxmatch #// str)
    (rxmatch #/*ぁぃぅぇぉゃゅょっー*$/ str))))
  
(define (writing-phrase-filter filename)
  (with-open
   filename
   (lambda (f)
     (for-each
      (lambda (line)
        (let* (*lst   (to-list (line.chomp.split #/[ \t*+/))]
               *word  (car lst)*)
          (when (and (<= 2 (word.size))
                     (<= (word.size) 7)
                     (writing-phrase? word))
            (printf "%s  //\n" word))))
      (f.readlines.to_list)))))

(define (main argv)
  (if (> 1 (length argv))
      (error "writing_phrase_filter.nnd requires file as 'hiragana  ;; ....' ")
      (writing-phrase-filter (car (to-list argv)))))

ファイルから読みこんで1行ずつ処理するプログラムを書くことが多いので、もっと便利な関数を作りたくなってきた。 Gaucheに習って [Nendo] に port->string-list を作るかな。 あっ、そうか portの概念をどうする決めかねていて止まっているんだった。どうするかなぁ。 とりあえず これでお茶を濁してportとしてしまうかー。いいのかな。

  class LispPort < File
  end