보험 도메인 심화 · 중복 청구 탐지 · 실습
같은 영수증을 두 번 청구한 건 찾아내기
목표
접수된 청구에서 완전 중복과 사실상 중복을 갈라내고, 같은 날 같은 병원의 다른 진료라는 오탐을 뺀 판정을 근거와 함께 내는 탐지기 dedup.py 를 만든다.
왜 중요한가
같은 진료 한 건이 앱·웹·창구로 여러 번 들어오는 일은 예외가 아니라 일상이다. 청구번호까지 같은 재전송은 묶으면 끝나지만, 청구번호가 다르고 표기만 흔들린 사실상 중복은 정규화해야 드러난다. 놓치면 같은 돈이 두 번 나간다.
반대 방향의 사고가 더 조용하다. 같은 날 같은 병원에서 정말로 두 번 진료받은 사람의 청구를 중복으로 막으면, 고객은 이유도 모른 채 지급을 못 받는다. 탐지기를 만드는 일의 절반은 이 오탐을 줄이는 일이고, 그래서 판정에는 반드시 근거가 붙는다.
채점기는 여러분의 판정을 믿지 않는다. 임시 청구 표를 차려 놓고 여러분의 dedup.py 를 실행해 정규화 결과·블록·점수·판정을 채점기가 계산한 값과 대조한다. 환자와 병원, 영수증 번호, 금액은 실행마다 바뀐다.
단계
1. /root/dupclaim/gen_claims.py 를 만들어 실행해 /root/dupclaim/claims.db 에 하루치 접수분을 만든다.
2. 청구번호가 같은 재전송을 /root/dupclaim/exact_dup.csv 로 뽑는다.
3. /root/dupclaim/dedup.py 가 환자·병원·영수증을 정규화하고 블록 키를 계산하게 한다.
4. dedup.py 가 블록을 만들어 견줄 쌍을 줄이게 한다.
5. dedup.py 가 블록 안의 모든 쌍에 유사도와 합산 점수, 점수 등급을 매기게 한다.
6. dedup.py 에 금액과 날짜의 허용 오차를 넣는다.
7. dedup.py 가 연번 영수증을 오탐으로 빼고 최종 판정과 근거를 내게 한다.
8. 자기 청구 표로 판정해 /root/dupclaim/dedup_result.json, /root/dupclaim/review.csv, /root/dupclaim/dup_report.md 를 남긴다.
참고
- 표
claim의 열은claim_nopatienthospitalreceipt_noservice_date(YYYY-MM-DD)amount(정수)channelreceived_at(RFC 3339 지역시각) 여덟 개입니다. - 실행 계약:
python3 /root/dupclaim/dedup.py --db <claims.db> --out <결과.json> - 재전송은 청구번호마다 한 줄로 접습니다. 접수 시각이 가장 이른 줄을 남깁니다.
- 정규화:
patient_nhospital_n은 NFKC 정규화 뒤 모든 공백 제거.receipt_n은 NFKC 뒤 영숫자만 남기고 대문자화. 블록 키는hospital_n과service_date를 세로막대로 이은 것입니다. blocks에는 구성원이 둘 이상인 블록만 넣고, 값은 청구번호를 오름차순으로 정렬한 배열입니다.- 쌍은 블록 안에서만 만들고 청구번호 오름차순으로
a가b보다 앞입니다. - 점수:
name_sim과receipt_sim은difflib.SequenceMatcher(None, x, y).ratio()를 소수 넷째 자리에서 반올림.score=0.45 * receipt_sim + 0.35 * name_sim + 0.20 * (병원이 같으면 1.0, 아니면 0.0), 역시 넷째 자리 반올림. score_verdict: 0.92 이상 duplicate, 0.80 이상 review, 그 아래 distinct.- 허용 오차:
amount_gap은 금액 차의 절댓값,day_gap은 진료일 차의 일수.in_tolerance는amount_gap이 100 이하이고day_gap이 0 일 때만 참입니다. serial_neighbor: 두receipt_n이 서로 다르고 길이가 같으며, 마지막 숫자 덩어리를 뺀 앞부분이 같고 그 숫자 길이도 같으며, 숫자 차이가 1 이상 5 이하일 때 참입니다.- 최종
verdict:serial_neighbor면 distinct. 아니면score_verdict가 duplicate 일 때in_tolerance면 duplicate, 아니면 review. 그 밖에는score_verdict그대로입니다. reasons는 이 순서로 담습니다:receipt_exact(receipt_sim 이 1.0) 또는receipt_similar(0.8 이상),name_exact(name_sim 이 1.0),hospital_same,amount_gap(0 초과),day_gap(0 초과),serial_neighbor.- 직접 시험:
python3 /root/dupclaim/dedup.py --db /root/dupclaim/claims.db --out /tmp/r.json - 흔한 실수: 청구번호로만 묶어 사실상 중복을 놓치기, 블록 키에 정규화 전 값을 쓰기, 점수만 내고 근거를 안 남기기.
단계 8개
- 하루치 접수분 만들기
- 청구번호가 같은 재전송부터 묶기
- 표기 흔들림을 정규화로 접기
- 블록으로 견줄 쌍 줄이기
- 유사도와 합산 점수 매기기
- 금액과 날짜의 허용 오차
- 연번 영수증이라는 오탐 빼기
- 심사 담당자가 그대로 볼 수 있게 내기