自然言語処理はじめました - ngramを数え上げまくる

40
DSIRNLP #2 phyllo

Upload: phyllo

Post on 11-Jun-2015

6.363 views

Category:

Documents


4 download

DESCRIPTION

DS

TRANSCRIPT

Page 1: 自然言語処理はじめました - Ngramを数え上げまくる

DSIRNLP #2

phyllo

Page 2: 自然言語処理はじめました - Ngramを数え上げまくる

自己紹介

ID : phyllo

ブログ : http://d.hatena.ne.jp/jetbead

• 某Web企業の新卒

• 入社してから自然言語処理始めました!!

• 最近の興味 – 自然言語処理を使って、効果的なダイエット法を見つけること

Page 3: 自然言語処理はじめました - Ngramを数え上げまくる

今日の概要

Page 4: 自然言語処理はじめました - Ngramを数え上げまくる

いろんな方法で Ngram頻度を 数え上げる!!

Page 5: 自然言語処理はじめました - Ngramを数え上げまくる

Ngram頻度を数える

• 超基礎!

– 「入門自然言語処理」でいうと18ページ目の内容

– というか、ただの統計処理

• しかし!

–頻度分布

– Ngram言語モデル

–その他いろんな応用が考えられる!(はず)

Page 6: 自然言語処理はじめました - Ngramを数え上げまくる

Ngramとは?

• 「隣り合うN個の塊」のこと

–単語ngramや文字ngramなどがある

「金持ち喧嘩せず」の文字2gram(bigram)

→{金持, 持ち, ち喧, 喧嘩, 嘩せ, せず}

「This is apple computer」の単語3gram(trigram)

→{This-is-apple, is-apple-computer}

Page 7: 自然言語処理はじめました - Ngramを数え上げまくる

方法

Page 8: 自然言語処理はじめました - Ngramを数え上げまくる

方法

1. ナイーブな方法

2. Suffix Arrayを使った方法

3. 近似カウント法

4. 分散処理を使う方法

Page 9: 自然言語処理はじめました - Ngramを数え上げまくる

1.ナイーブな方法

Page 10: 自然言語処理はじめました - Ngramを数え上げまくる

1.ナイーブな方法

• やるだけ!

– Perlだとハッシュに入れて数えたり use strict; use warnings; use utf8; use encoding "utf8"; my $ngram = shift; my %hash; while(my $line = <>){ #一行とってきて chomp $line; #最後の改行を削って for(my $i=0; $i<length($line)-$ngram+1; $i++){ #ずらしながら $hash{substr($line,$i,$ngram)}++; #ngram文字ずつ数える } } foreach my $key (keys %hash){ print $key,"¥t",$hash{$key},"¥n"; }

Page 11: 自然言語処理はじめました - Ngramを数え上げまくる

1.ナイーブな方法

[入力文]

イカちゃんかわいい

[出力]

ゃん 1 かわ 1

ちゃ 1 イカ 1

カち 1 んか 1

わい 1 いい 1

Page 12: 自然言語処理はじめました - Ngramを数え上げまくる

1.ナイーブな方法

• これでいいじゃん!

• 大規模テキストやNを大きくしたら?

– 1GBのデータとかは?

– Ngramの種類が増える

– メモリが足りなくなる…

Page 13: 自然言語処理はじめました - Ngramを数え上げまくる

• これでいいじゃん!

• 大規模テキストやNを大きくしたら?

– 1GBのデータとかは?

– Ngramの種類が増える

– メモリが足りなくなる…

1.ナイーブな方法 ラピュタのセリフのngramを取ってみると… (全1426文)

2gram(5000種類) ・・ 1632 !! 375 ーー 168 っ! 143 って 134 ああ 134 んだ 120 ー! 111 ない 105 った 103

3gram(10209種類) ・・・ 671 ・・。 101 っ・・ 88 シータ 79 !・・ 76 ーーー 67 ・・あ 67 はっは 64 ー!! 61 っはっ 58

4gram(13066種類) ・・・。 78 っはっは 56 !・・・ 55 ラピュタ 54 。・・・ 47 はっはっ 44 っ・・・ 42 ・・・あ 38 ・・・・ 36 ん・・・ 33

http://faithrm-zero-zero.blog.so-net.ne.jp/2010-06-24-2

Page 14: 自然言語処理はじめました - Ngramを数え上げまくる

1.ナイーブな方法

• これでいいじゃん!

• 大規模テキストやNを大きくしたら?

– 1GBのデータとかは?

– Ngramの種類が増える

– メモリが足りなくなる…

Ngramを保存しなければいいんだ!!

Page 15: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Array を使った方法

Page 16: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• Ngramをメモリに保存しない??

–ハッシュに保存しない!!

• 入力文のSuffix Arrayを作ってみてみる 入力文:イカちゃんかわいいイカちゃん

イカちゃんかわいいイカちゃん カちゃんかわいいイカちゃん ちゃんかわいいイカちゃん ゃんかわいいイカちゃん んかわいいイカちゃん かわいいイカちゃん わいいイカちゃん いいイカちゃん ・・・

いいイカちゃん いイカちゃん かわいいイカちゃん ちゃん ちゃんかわいいイカちゃん ゃん ゃんかわいいイカちゃん わいいイカちゃん ・・・

Page 17: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• Ngramをメモリに保存しない??

–ハッシュに保存しない!!

• 入力文のSuffix Arrayを作ってみてみる 入力文:イカちゃんかわいいイカちゃん

イカちゃんかわいいイカちゃん カちゃんかわいいイカちゃん ちゃんかわいいイカちゃん ゃんかわいいイカちゃん んかわいいイカちゃん かわいいイカちゃん わいいイカちゃん いいイカちゃん ・・・

いいイカちゃん いイカちゃん かわいいイカちゃん ちゃん ちゃんかわいいイカちゃん ゃん ゃんかわいいイカちゃん わいいイカちゃん ・・・

Bigramが欲しい!

Page 18: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• 上からなぞっていけばNgramが数えられる!

いいイカちゃん いイカちゃん かわいいイカちゃん ちゃん ちゃんかわいいイカちゃん ゃん ゃんかわいいイカちゃん わいいイカちゃん ん んかわいいイカちゃん イカちゃん イカちゃんかわいいイカちゃん カちゃん カちゃんかわいいイカちゃん

いい 1 いイ 1 かわ 1 ちゃ 2 ゃん 2 わい 1 んか 1 イカ 2 カち 2

(ドヤッ

Page 19: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• メモリの節約になってる?

UTF8で1文字3byteとすると、

「(3*N+int4byte) * (Ngramの種類)」

「(先頭アドレス4byte) * (入力文字数)」

になっている

• 効率的に実装すればかなり節約になります

Page 20: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法 /* 効率的ではないC++のコード */ vector<size_t> ptr; //★先頭位置を保持するポインタ(のかわりのindex) for(size_t i=0; i<ustr.length()-N+1; i++){ ptr.push_back(i); } vector<int> cmn_char; //次の文字との共通文字数 Cmp cmp(ustr); //ポインタで文字列を比較するためのファンクタ //★Suffix Arrayの辞書順ソート sort(ptr.begin(), ptr.end(), cmp); //★共通文字数カウント for(size_t i=0; i<ptr.size(); i++){ if(i+1<ptr.size()){ cmn_char.push_back(common_prefix_length(ustr, N, ptr[i], ptr[i+1])); //次の文と何文字共通しているか }else{ cmn_char.push_back(0); } } //★順番にptrを見ていって、cmn_charがN以上な個数を数える ...

Page 21: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• これでいいじゃん!

• さらに大規模になったら?

– 1TBのデータとかは?(twitterのデータとか)

• 1TBのメモリがあれば…

–どうしよう…

Page 22: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• これでいいじゃん!

• さらに大規模になったら?

– 1TBのデータとかは?(twitterのデータとか)

• 1TBのメモリがあれば…

–どうしよう… メモリが無いと俺はNgramも カウントできないのかよ!!

Page 23: 自然言語処理はじめました - Ngramを数え上げまくる

2.Suffix Arrayを使った方法

• これでいいじゃん!

• さらに大規模になったら?

– 1TBのデータとかは?(twitterのデータとか)

• 1TBのメモリがあれば…

–どうしよう…

近似値でいいからできるだけカウント!

Page 24: 自然言語処理はじめました - Ngramを数え上げまくる

3.近似カウント法

Page 25: 自然言語処理はじめました - Ngramを数え上げまくる

3.近似カウント法

• 大まかに2つのアプローチ

–全部は無理なので、頻度が多いものに注目しカウント(Counter-based)

– Hash関数とかを使って全部を大体正確にカウント(Sketches)

Page 26: 自然言語処理はじめました - Ngramを数え上げまくる

3.近似カウント法

• Counter-Based Algorithm – Sticky Sampling

– Lossy Counting

– Frequent

– Space-Saving

• Sketches – Count Sketch

– Group Test

– CountMin Sketch

– hCount

Page 27: 自然言語処理はじめました - Ngramを数え上げまくる

3.近似カウント法

• Counter-Based Algorithm – Sticky Sampling

– Lossy Counting

– Frequent

– Space-Saving

• Sketches – Count Sketch

– Group Test

– CountMin Sketch

– hCount

Page 28: 自然言語処理はじめました - Ngramを数え上げまくる

3.Lossy Counting

• ストリームデータの基本的なカウント法

–どんどん要素がくるようなデータ

• 何を保持するの?

– 3つのペア

• 要素名e, 頻度の推定値f, 最大許容誤差値Δ

–定期的に保存しているペアでいらない

ものを捨てる(整理)

Page 29: 自然言語処理はじめました - Ngramを数え上げまくる

3.Lossy Counting

# 新しい要素が来た!

# n個目だね

# もし保存してたら頻度+1

# 新しい要素なら

## 新たに保存

## 頻度はΔ+1

# 定期的に

## Δを更新して

## すべての要素を確認

## 頻度がΔより小さければ 削除

Graham Cormode and Marios Hadjieleftheriou, “Methods for finding frequent items in data streams”, The VLDB Journal

※Δを要素ごとに保存してない

Page 30: 自然言語処理はじめました - Ngramを数え上げまくる

3.Lossy Counting

• C++のmapで実装すると… /* 効率的でないC++のコード */ class LossyCounter { //★保存している要素リスト map<string,pair<int,int> > S; //パラメータ int N; double gamma, epsilon; int b_current; //Δ //★保存している要素で頻度がΔより小さいものを削除 void next_backet(); public: //★初期化 LossyCounter(double gamma, double epsilon); //★新しい要素をSに追加 void add(const string &str); //要素strの頻度 int get(const string &str); //要素リストをすべて表示 void show(); //要素リストのサイズを返す int size(); };

Page 31: 自然言語処理はじめました - Ngramを数え上げまくる

3.近似カウント法

• これでいいじゃん!

• 確かに、ここまでできれば十分かも

– Lossy Couting以外の優れた方法もある

• Space-Savingとか

–世の中のほとんどのNgram頻度は数えられる

• でも、近似値だよね、、、

Page 32: 自然言語処理はじめました - Ngramを数え上げまくる

4.分散処理を使う方法

Page 33: 自然言語処理はじめました - Ngramを数え上げまくる

4.分散処理を使う方法

• 近似じゃだめなんだ!

• 正確な頻度が欲しいんだ!!

• Hadoop

–個人のPCで試すことができる

– Amazon EC2上で個人でも利用できる(有料)

• Amazon Elastic MapReduce

(今回はコード例は略)

Page 34: 自然言語処理はじめました - Ngramを数え上げまくる

まとめ

Page 35: 自然言語処理はじめました - Ngramを数え上げまくる

まとめ

• これでどんなでかいデータが来ても大丈夫!!

• 「やるだけ」だと思ったけど、実際にやってみるといろいろ問題があることがわかります – 今回は文書量の問題 – 高速化や効率化も必要

• 「やってみた」からわかったこと – これから研究開発したいと思っている人

• 「なにすればいいかわからん」と思っている人

– どんどん作ってやってみましょう!! – 新しい問題の発見があるかも…! :)

Page 36: 自然言語処理はじめました - Ngramを数え上げまくる
Page 37: 自然言語処理はじめました - Ngramを数え上げまくる

補足情報

• 他のNgram数え上げ方法

– PrefixSpan

• http://www.cs.uiuc.edu/~hanj/pdf/span01.pdf

• http://chasen.org/~taku/publications/nlp2002.pdf

• http://2boy.org/~yuta/publications/substring_mining.pdf

Page 38: 自然言語処理はじめました - Ngramを数え上げまくる

補足情報

• ちょっと試してみたい!

– (自己責任で自由に使用・加工してください)

– SuffixArrayを使った頻度カウント

• http://d.hatena.ne.jp/jetbead/20111012/1318422417

– Lossy Countingを使った頻度カウント

• http://d.hatena.ne.jp/jetbead/20111014/1318547950

Page 39: 自然言語処理はじめました - Ngramを数え上げまくる

補足情報

• 参考資料など

–岩波講座ソフトウェア科学15「自然言語処理」

–アルゴリズム・サイエンスシリーズ5 数理技法編

「オンラインアルゴリズムとストリームアルゴリズム」

–入門「自然言語処理」