Comments
Description
Transcript
近似文字列照合
Gonzalo Navarro, Ricardo Baeza-yates, Erkki Sutinen, Jorma Tarhio: Indexing Methods for Approximate String Matching 近似文字列照合 IEEE Data Engineering Bulletin , 2001 ( Oct.7, 2008, 勝俣 担当) 近似文字列照合とは • パターン類似文字列をテキストからサーチ (⇔完全一致文字照合) • 応用可能な分野 – 音楽:類似楽節のチェック – 生物:突然変異DNA配列の発見 – 文章:テキストタイプミス、スペルミスの発見 パターン 照合例 ABCDE ABCDE ABC1DE ABCE AB1DE 定義 • テキスト(被照合文章) : T1…n (|T| = n) • パターン(照合文字列) : P1…m (|P| = m) • アルファベット : Σ (|Σ| = σ ) T∈Σ*、P∈Σ* • パターン照合におけるエラーの最大値: k • T,P比較時のエラー → 距離d(P, T) ⇒距離: d(P, T) ≦ k が条件 編集距離(edit distance) • 2文字列の異なり度合を距離として示す • マッチング操作:挿入、削除、置換 • 操作1回でコスト1(文字列照合までの操作回数) P T1 パターン 挿入 abcde abc1de T2 T3 削除 abcd 置換 abc1e コスト1 ⇒ d(P, T1) = d(P, T2) = d(P, T3) = 1 エラーレベル • パターン長さはm ⇔ 照合時の許容エラー数: 0 < k < m • エラーレベル・・・照合で許すエラー割合(近似度) α = k/m 近似文字列照合研究の流れ • 10年前まで⇒オンラインサーチ研究中心 – パターンにのみチェック用の前処理→テキスト照合 – 現在: O(mn)→O((k+logσm)n/m)に改善 高速なアルゴリズムもアリ but.文を多く扱うアプリケーションにはまだ× • 最近10年⇒インデックスサーチが中心 – テキストで索引を作ってパターン照合 • 最近10年⇒インデックスサーチにも注目 – 文字列で索引を作って相手文字列と照合 • インデックスとオンラインの組合せで使うものもアリ ①.インデックスサーチ – – – – suffix tree(接尾辞木) suffix array(接尾辞配列) q-grams q-sample ②.オンラインサーチ – Neighborhood Generation(全近傍列挙) – Partitioning into Exact Searching(部分完全一致) – Intermediate Partitioning Suffix tree&array • 接尾辞(suffix)とは… – 語の後ろにつき派生語生成、品詞を変換する形態素 ex. 圧倒的、 耐熱性、 reliable、 happiness • ここではテキスト位置i番目以降の部分文字列を指す ※ i=1~n ex. abcdef の bcdef、 def、 abcdef など suffix tree (接尾辞木) • テキストからできる全接尾辞を木構造に – 左から右に辞書順ソート 1. ABCABDABE$ 2. BCABDABE$ 3. CABDABE$ 4. ABDABE$ 5. BDABE$ 6. DABE$ 7. ABE$ 8. BE$ 9. E$ 接尾辞木作成法(1) • 各文字列先頭から1文字ずつ連結 • 同じ深さに同じ文字ノード⇒1本にまとめる • 終端に文字列開始位置を格納 A A A B B B C D E B B B C D E A A C D E A A $ B B A A $ B B D E B B D E A $ D E A $ B A $ B E B E $ E $ $ $ suffix tree で近似照合 ①.深さ+1下に、左から探索 ②.そのノードまでの文字列とパターンをDP ⇒パターンから取った深さと同じ長さ分の文字列と比較 ③.≧k ⇔ さらに深さ+1 <k ⇔ 同じ深さの隣のノードに進む suffix array (接尾辞配列) • 部分文字列開始位置番号を配列化 – ①.文字列の接尾部を全列挙 – ②.その接尾部を辞書順にソート – ③.順に開始位置番号だけ配列に ② ① 1. abracadabra$ 2. bracadabra$ 3. racadabra$ 4. acadabra$ 5. cadabra$ 6. adabra$ 7. dabra$ 8. abra$ 9. bra$ 10. ra$ 11. a$ 11. 8. 1. 4. 6. 2. 9. 5. 7. 10. 3. a$ abra$ abracadabra$ acadabra$ adabra$ bracadabra$ bra$ cadabra$ dabra$ ra$ racadabra$ ③ suffix array –特徴• 辞書順ソート⇒二分探索による探索 – Suffix treeのシミュレートが可能 suffix array –特徴• 時間計算量 – 完全一致 : O(m log n) • 空間計算量 – Array生成 : 最悪O(n log n) , 平均O(n log ( log n)) – 補助記憶域保存でO(n^2 log M /M) ※M:主記憶利用域 最善でテキストサイズの約4倍 Suffix Arrayで近似照合(1) • Suffix Treeのシミュレートにより照合 – ①.深さ+1の出現文字の範囲を調べる – ②.深さ分のパターン文字列と近似照合 – ③.エラーk以内なら①・②の再帰 ⇒LCP配列を使う?? s[0] 11. s[1] 8. 1. s[2] s[3] 4. 6. s[4] s[5] 2. s[6] 9. s[7] 5. 7. s[8] s[9] 10. s[10] 3. a$ abra$ abracadabra$ acadabra$ adabra$ bracadabra$ bra$ cadabra$ dabra$ ra$ racadabra$ パターン : abcd a:0~4 比較 b:5~6 c:7 d:8 b : 9 ~ 10 a (1文字目) Q-grams • 長さqの部分文字列を1字ずらして取り出し – そのテキスト位置と共にインデックス化 – 重複したらテキスト開始位置を共に格納 生成されるQ-gram数: (n-q+1)個 index 文字列にエラーがあったら… • kエラーに対し、最大kq個のq-gramにエラー出現 ⇒ パターンと照合するなら(m-q+1-kq)個が完全一致 Text エラー0 エラー1 ABCDEFGHIJKLMNO ABCDEF1HIJKLMNO EFG Q-gram (q = 3) EF1 FGH F1H GHI 1HI Q-samples • Q-gramを少なく配置 – 互いに重ならない – 使用メモリ少 ⇒長文に対して効果期待 • Partition into Exact Searchなどと組み合わせ照合 両者の特徴 • • • • パターンがQ-gramと一致⇒その周辺を近似照合 インデックス作成に線形時間 長文に対してはO(n log (n/M)) 使用領域はqによりテキストサイズ0.5~3倍 編集距離計算 • 動的計画法(DP)により距離計算 – 与えられた2文字列(行:T、列:P)よりグラフ作成 – 左上からの各パスが文字の比較の仕方に対応 テキスト テキスト パターン パターン ノードNijの値Cij=編集距離d(P1…i , T1…j) 動的計画法 • あるノードの値 Cj,i = d(p1…j , t1…i) • δ(pi, t j):文字piとt jの置換コスト(pi = t j ⇔ 0 , pi ≠ t j ⇔ 1) • pi:パターンのi番目の文字,t j:テキストのj番目の文字 Cj,i = min Cj-1,i-1 + δ(pi , t j ) Cj-1,i + 1 Cj,i-1+1 Cj,i-1 Cj-1,i-1 δ(pi,t j) C0,i = i (1≦i≦m) Cj,0 = j (1≦j≦n) Cj-1,i Cj,i テキスト検索での動的計画法 • 1行目の値をすべて0(全 jにおいて Cj,0 = 0) ⇒どんなテキスト位置からでもマッチング開始可能 Cj,i = min Cj-1,i-1 + δ(a, b) Cj-1,i + 1 Cj,i-1+1 C0,i = i (1≦i≦m) Cj,0 = 0 (1≦j≦n) テキスト途中から計算してもOK! DPの欠点 グラフ作成O(mn) ・・・ 計算量大 エラーk以上の計算は余分 省ければ効率的 ⇒ Landau-Vishkinアルゴリズム Landau-Vishkin アルゴリズム • 列ごとの計算から対角線ごとの計算でグラフ作成 • 各対角線⇒ストロークに分割 – ストローク : ある対角線での同じエラー数集合 • 列⇒エラー数e : 0~k • 行⇒対角線番号d : d = j - i (-e ~ n) • L[d, e] : 対角線におけるエラーe以内の対角線の長さ j(テキストT) d(対角線:j – i ) eエ(ラー数 ) パ i (ターン P) Ld,-1 = Ln+1,e = -1 , for all e,d Ld,|d|-2 = |d|-2 , for -(k+1)≦d≦-1 Ld,|d|-1 = |d|-1 , for -(k+1)≦d≦-1 row : eストロークが現れるまでの対角線の長さ Neighborhood Generation(全近傍列挙) • パターンに対するエラーk以内の文字列を列挙 – Pの「k近傍」集合: Uk(P) = {x ∈ Σ* , d(x, P) ≦ k} – | Uk(P) | = O( (mσ)^k ) ⇒ k ,m, σ増加で計算量急増 テキスト 照合 パターン Neighborhood Generation(全近傍列挙) • suffix tree/array と組合せて照合 ①.パターンからのk近傍文字列 ②.テキストから生成したsuffix tree/array、q-gram ⇒①、②で完全一致照合したらそれが近似一致文字列 パターンのk近傍文字列集合 partitioning into Exact Searching(分割完全一致検索) • エラーがあってもある部分はパターン完全一致 ex) k=1でパターンABCDE (パターンをABC、DEに分割) テキストにマッチング ⇔ ABC or DEが存在するはず! 完全一致したらそのテキスト部分周辺で近似照合 無い範囲は調べる必要なし(Filtering) テキスト • αが小さければ効率的に働く パターン • 定理 ①.2文字列A,Bに対し、 d(A,B)≦k が成立 ②.A = A1x1A2x2…xk+s-1Ak+s (s≧1) – 少なくとも部分文字列s = Ai1…Ais はBに完全一致で存在 – 近似一致部分にはk+1個以上のエラーはない • 想定されるエラー発生場所によりアルゴリズム差異 – パターンでエラー / テキストでエラー パターンでエラー • パターンを (k+s)個に分割して完全一致照合 ⇒近似しているなら s個は必ず完全一致 ex) アルファベットABCDE…YZ に k=2 の近似 パターン:A1C2DE (Bを置換、CD間に挿入で2) 3分割(s = 1) : A1, C2, DE 4分割(s = 2) : A1, C, 2, DE ⇒ s個完全一致なら、近傍m+2k以内の距離部分を近似チェック • インデックスサーチと組合せて照合 – 接尾辞木O(m) 、接尾辞配列O(m log n)で断片探索可能 – さらに近似照合平均時間O(m^2*kn / σ^(m/k+1)) ※s = 1のとき • s増で範囲内で必要一致数も増 – パターンが長いとうまく働く – 断片も短くなるためパターン短いと検証が複雑化 テキストでエラー • テキストを長さhの「テキスト窓」に分割 – h≧q (h≦[(m-k-q+1) / (k+s) • パターンからはq-gram⇒テキスト窓と照合 – s個の完全一致あればその付近でパターンと検証 • 最善のq = Θ(logσ n) • s値についてはまだ最善値は未分析 – ただし、sが大きければ検証が少なくすむかも・・・ Intermediate Partitioning • パターンが長い⇒断片にしてもエラーがある可能性大 • but. 分割でエラー数減少 ⇒ そこで全近傍列挙 分割完全一致検索と全近傍列挙の組合せ照合 (片方ずつの方法より優れている) 定理 –Intermediate Partition• 2文字列A、B間の編集距離d(A,B)≦k • A = A1x1A2x2…xj-1Ajk 定理:まだ未編集・・・ パターンでエラー(Intermediate Partition) 1.パターンをj個に分割 (完全完全一致検索) ⇒ 長さ [m / j] , エラー許容 [k / j]個 , エラーレベルはαのまま 2.エラー減小した各断片を全近傍列挙 3.インデックス作成したテキストと[k / j]近傍照合 j値について • 計算量 j = 1 : 全近傍列挙に同じ j = k+1 : O(m) • 完全一致数 j = 2 : 1個以下 , j = 4 : 2個以下 ・・・ , j = k+1 : 最大 • 最善の j : Θ(m / logσn) – 計算量 : O(n^λ) for 0≦λ≦1 (λ<1, for α<1-e/√σ) 時間と一致数のトレードオフ テキストでエラー(Intermediate Partition) • テキスト側 – テキストを長さhで分割 (h ≦ [ (m-k-q+1) / j ]) – 各h部分でq-sample テキスト 分割 • パターン側 – パターンを j 分割 – パターンでブロック作成: Qi = P(i−1)h+1...ih+q−1+k パターン • テキストのq-sampleをQブロックから検索 – 連続sampleがkエラー以内で存在 ⇒そこの部分でオンラインサーチ テキストでエラー(続き) • 未編集 e値について • 最善のe = [k / j] (最小値) – e が大きくなると検索コストが増大してしまう – まだ十分な結果ではないが実験した結果の最善値