TT Lab
はじめる
学ぶ 学習パス コース

保険ドメイン深化

同じ領収書でも文字が少し違えば、システムは別の請求とみなす

TT Labで続きを見る

一言でいうと

重複請求を探すことは、同じ文字列を探すことではなく、正規化したあとで同じになるものを探し、そのうち本当の重複だけを残すことです。難しくて高くつくのは探す側ではなく、誤検知を減らす側です。

なぜ必要なのか

保険の請求受付の窓口は複数あります。アプリで写真をアップロードし、ウェブでもう一度入れ、窓口で紙で出し、FAXでも届きます。通信が切れると、アプリが同じリクエストをもう一度送ります。そのため、同じ診療1件が受付システムに複数行残ることは、例外ではなく日常です。

ここには、異なる2つのものが混ざっています。1つは完全重複です。請求番号まで同じものが2行入っています。これは再送で、請求番号でまとめれば終わりです。もう1つは事実上の重複です。請求番号は違うのに、同じ領収書です。アプリで出したあと、処理が遅いようなので窓口でもう一度出しました。こちらは文字が正確に同じではありません。アプリは名前を「キムソジュン」と受け取り、窓口の職員は「キム ソジュン」と書きます。領収書番号をアプリはハイフンまでそのまま移し、窓口システムは全角文字で保存します。

2つ目を見逃すと、同じお金が2回出ていきます。ところが、逆方向の事故のほうが静かです。同じ日に同じ病院で本当に2回診療を受けた人の請求を重複として止めると、顧客は理由もわからないまま支払いを受けられず、コールセンターに電話します。検知器を作る仕事の半分は、この誤検知を減らす仕事です。

どう動くのか

順序は常に同じです。正規化 → ブロッキング → 類似度 → しきい値 → 許容誤差 → 誤検知ルール。

正規化。表記の揺れを先にならします。Unicode正規化形式のうちNFKCは、互換分解のあとに正規結合を行う形式で(UAX #15)、全角英数字のように、形だけが違う互換文字を通常の形にならします。ラボのイメージで実際に測ってみると、unicodedata.normalize("NFKC", "RC-2026")が"RC-2026"を返します。ここに空白の除去とハイフンの除去を加えると、窓口ごとに違う表記が1つの値に集まります。unicodedataモジュールとUnicodeの扱い方の案内が、これらの形式を説明しています。

ブロッキング。25万件を互いにすべて比べると、ペアが300億個になります。そこで、同じ値を共有するもの同士だけをまとめて、その中だけで比べます。このラボでは、正規化した病院名と診療日をブロックキーに使います。ブロッキングはただではありません。ブロックキーが間違っていれば、そのペアはそもそも候補になれません。病院名の表記が揺れてブロックが分かれることがよくあるので、ブロックキーにも正規化した値を使います。

類似度。difflibのSequenceMatcherを使います。ratio()は、2つの列の全要素数をT、一致した要素数をMとするとき、2.0*M / Tです。同じなら1.0、重なるものがなければ0.0です。落とし穴が1つあります。2つ目の列が200個以上だと、自動junkヒューリスティックが有効になり、1%を超えて占める要素をjunkとみなします。名前と領収書番号は短いので関係ありませんが、長いテキストを比べるときは、autojunk=Falseを考える必要があります。そして、このヒューリスティックは非対称なので、AとBを入れ替えると結果が変わることがあります。

しきい値と許容誤差。項目ごとの類似度を加重和にして点数を出し、2つのしきい値で区切ります。高いほうの上は重複、真ん中は人が見る区間、下は別物です。ここに金額と日付の許容誤差を掛けます。点数が1.0でも、金額が4,000ウォン離れていれば、それは同じ領収書ではないかもしれません。自動で止めずに、人に回します。

誤検知ルール。同じ日に同じ病院で続けて受け取った領収書は、番号が連番です。文字列の類似度で見ると、12桁のうち1文字だけが違うので0.93が出て、名前と病院まで同じなので、合算した点数がしきい値を超えます。これは重複ではなく、隣り合った書類です。番号の最後の数字の塊だけが1から5だけ違えば、重複候補から外します。

청구 25만 ──▶ 정규화 ──▶ 블록 ──▶ 블록 안의 쌍 ──▶ 점수 ──▶ 허용 오차 ──▶ 오탐 규칙
                                                         │            │          │
                                                    duplicate      review     distinct

現場での姿

最もよくある間違いは、請求番号だけでまとめることです。そうすると、再送は捕まえられますが、事実上の重複は1件も捕まえられません。そしてその事実が画面に現れません。「重複0件」というレポートが毎日出て、支払われたあとの監査で引っかかります。

2つ目は、点数だけを出して根拠を残さないことです。審査担当者は「0.94」を受け取っても、何を確認すべきかわかりません。どの項目が同じで点数が上がったのかを一覧として残せば、担当者はその項目だけを目で見て、5秒で終わらせます。判定結果は、自動化の出力ではなく人への入力です。

3つ目は、しきい値をデータなしで決めることです。0.9がよさそうだという理由で決めると、1日に何件が人に回るのかわからないまま運用を始めます。調査の人員が1日30件なのに200件が回ってくれば、その一覧は数日で無視されます。しきい値はルールではなく、人員との契約です。

実務で本当に大切なこと

次のラボですること

次のラボで使う重み(0.45・0.35・0.20)としきい値(0.92・0.80)、許容誤差(100ウォン・0日)は、このラボの仮定です。実際には、過去の判定履歴と調査人員の1日の処理量で決め、ルールセットにバージョン番号を付けて、変えるたびに記録します。

受付システムの1日分の請求表を自分で作り、完全重複から始めて、正規化、ブロッキング、類似度、許容誤差、連番の誤検知除去まで、ステップごとに積み上げます。採点ツールは、毎回異なる患者と病院、領収書番号で自分の請求表を作って検知器を実行し、判定を突き合わせます。最後には、自分の表で判定を出し、審査担当者がそのまま見られるレビューリストと報告書を出します。