LoginSignup
3
2

More than 3 years have passed since last update.

なぜかRustで言語処理100本ノック ~第5章 後編~

Last updated at Posted at 2019-01-01

前編はこちら

第5章: 係り受け解析

45. 動詞の格パターンの抽出

今回用いている文章をコーパスと見なし,日本語の述語が取りうる格を調査したい. 動詞を述語,動詞に係っている文節の助詞を格と考え,述語と格をタブ区切り形式で出力せよ. ただし,出力は以下の仕様を満たすようにせよ.

(一部抜粋)

長くなってしまいましたが、やっていることは、動詞を含む文節それぞれに対し係っている助詞を全て取り出しているだけです。
また、

コーパス中で頻出する述語と格パターンの組み合わせ

のコマンドはcat $FILE | sort --key=1 | uniq -c | sort -r --key=1で、

「する」「見る」「与える」という動詞の格パターン(コーパス中で出現頻度の高い順に並べよ)

のコマンドはcat $FILE | grep -e '^する' -e '^見る' -e '^与える' | sort --key=1 | uniq -c | sort -r --key=1です。

実装コード
pub fn verbs(cabocha: &Vec<Vec<Chunk>>, out_file: &Path) {
    let file = OpenOptions::new().write(true).create(true).open(out_file);
    if file.is_err() { return; }
    let mut bw = BufWriter::new(file.unwrap());
    cabocha.iter().for_each(|sentence| {
        sentence.iter()
                .enumerate()
                .filter_map(|(index, chunk)|
                    chunk.morphs.iter()
                                .find(|m| m.pos == "動詞")
                                .map(|m| (index, m.base.clone()))
                ).for_each(|verb| {
            let kaku = sentence.iter()
                .filter(|chunk| chunk.dst as usize == verb.0)
                .filter_map(|chunk| chunk.morphs.iter().find(|m| m.pos == "助詞"))
                .map(|morph| morph.surface.clone())
                .collect::<Vec<_>>();
            kaku.sort();
            if !kaku.is_empty() {
                bw.write(format!("{}\t{}\n", verb.1, kaku.join(" ")).as_bytes()).unwrap();
            }
        });
    });
}

46. 動詞の格フレーム情報の抽出

45のプログラムを改変し,述語と格パターンに続けて項(述語に係っている文節そのもの)をタブ区切り形式で出力せよ.45の仕様に加えて,以下の仕様を満たすようにせよ.

45とほとんど一緒な上に長くなるので省略します。

47. 機能動詞構文のマイニング

動詞のヲ格にサ変接続名詞が入っている場合のみに着目したい.46のプログラムを以下の仕様を満たすように改変せよ.

これもかなり似ているので省略します。

48. 名詞から根へのパスの抽出

文中のすべての名詞を含む文節に対し,その文節から構文木の根に至るパスを抽出せよ. ただし,構文木上のパスは以下の仕様を満たすものとする.

(一部抜粋)

DOT言語として書き出したときと似て非なる感じです。

pub fn noun_to_root(cabocha: &Vec<Vec<Chunk>>) {
    cabocha.iter().for_each(|sentence|
        sentence.into_iter()
                .filter(|chunk|
                    chunk.morphs.iter().find(|m| m.pos == "名詞").is_some()
                    && chunk.dst != -1)
                .for_each(|chunk| {
                    let mut dst = chunk.dst;
                    print!("{}", chunk.get_text());
                    while dst != -1 {
                        print!(" -> {}", sentence[dst as usize].get_text());
                        dst = sentence[dst as usize].dst;
                    }
                    println!("");
                })
    );
}

49. 名詞間の係り受けパスの抽出

じつはここで諸事情あってしばらく中止してしまったので、第5章はちょっとここで終了します。恐らく48と似たような処理になると思うので、許してください。

第5章の感想

この感想を書いているのは、しばらく中止した後なので正直殆ど覚えていないのですが、第5章は特に後編で省略が多くなってしまいました。次章からは題材も変わるようなので、なんとか最後まで走りきりたいです。 むしろ題材が変わってPython依存が大きそうなので恐らくこの先はないです。申し訳ないです。

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2