LabHub
学习 学习路径 课程

保险领域进阶

找出用同一张收据重复申请的理赔

在 LabHub 中继续学习

한국어 원문으로 표시합니다.

목표

접수된 청구에서 완전 중복과 사실상 중복을 갈라내고, 같은 날 같은 병원의 다른 진료라는 오탐을 뺀 판정을 근거와 함께 내는 탐지기 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 를 남긴다.

참고

하루치 접수분 만들기

/root/dupclaim/gen_claims.py 를 만들어 실행해 /root/dupclaim/claims.db 를 만드세요. claim 표는 261행이고 서로 다른 청구번호는 250개입니다. 청구번호가 같은 재전송 10건(그중 한 건은 세 번 들어왔습니다), 정규화하면 환자·병원·영수증이 완전히 같아지지만 원문 표기는 다른 쌍 12쌍, 같은 블록 안에서 영수증이 연번인 쌍 6쌍을 심고, channel 은 app·web·counter 세 가지를 씁니다.

표기 흔들림은 공백 넣기, 하이픈을 전각으로 바꾸기, 숫자를 전각으로 쓰기, 소문자로 쓰기 네 가지면 넉넉합니다. 연번 쌍은 같은 환자·병원·진료일에 영수증 번호 끝자리만 1 올리면 됩니다. 병원과 진료일 가짓수를 좁게 잡아야 블록에 둘 이상이 모입니다.

청구번호가 같은 재전송부터 묶기

/root/dupclaim/exact_dup.csv 에 같은 청구번호가 두 번 이상 들어온 건을 머리글 claim_no,copies,first_received,last_received 로 뽑으세요. 청구번호마다 한 줄입니다.

1단계에서 만든 /root/dupclaim/claims.db 를 읽습니다. GROUP BY 와 HAVING COUNT(*) > 1 이면 끝납니다. first_received 와 last_received 는 그 청구번호로 들어온 접수 시각의 최솟값과 최댓값이고, 재전송 횟수가 늘 2 인 것은 아닙니다. 이건 사실상 중복이 아니라 재전송이라 중복 건수로 세지 않습니다.

표기 흔들림을 정규화로 접기

/root/dupclaim/dedup.py 가 재전송을 청구번호마다 한 줄로 접고, 각 청구의 patient_n hospital_n receipt_n block 을 계산해 결과 JSON 의 normalized 에 넣게 하세요.

unicodedata.normalize("NFKC", s) 가 전각 영숫자와 전각 하이픈을 보통 문자로 접습니다. 그다음 공백을 지우고, 영수증은 영숫자만 남겨 대문자로 맞춥니다. 접을 때는 접수 시각이 가장 이른 줄을 남깁니다.

블록으로 견줄 쌍 줄이기

/root/dupclaim/dedup.pyblocks 를 내게 하세요. 키는 블록 키이고 값은 그 블록에 속한 청구번호를 오름차순으로 정렬한 배열이며, 구성원이 둘 이상인 블록만 넣습니다.

블록 키에 정규화 전 병원명을 쓰면 표기가 흔들린 짝이 서로 다른 블록으로 갈라져 애초에 후보가 되지 못합니다. 25만 건을 전부 견주면 쌍이 300억 개라, 블로킹은 성능이 아니라 실현 가능성의 문제입니다.

유사도와 합산 점수 매기기

/root/dupclaim/dedup.py 가 블록 안의 모든 쌍에 name_sim receipt_sim hospital_same score score_verdict 를 매겨 pairs 에 넣게 하세요.

difflib.SequenceMatcher(None, x, y).ratio() 는 두 열의 전체 원소 수 T 와 일치 원소 수 M 에 대해 2.0*M/T 입니다. 소수 넷째 자리에서 반올림하세요. 쌍은 청구번호 오름차순으로 a 가 b 보다 앞입니다.

금액과 날짜의 허용 오차

/root/dupclaim/dedup.py 가 각 쌍에 amount_gap day_gap in_tolerance 를 붙이게 하세요. in_tolerance 는 금액 차가 100 이하이고 진료일 차가 0 일 때만 참입니다.

점수가 1.0 이어도 금액이 수천 원 벌어져 있으면 같은 영수증이 아닐 수 있습니다. 진료일은 datetime.date.fromisoformat 으로 읽어 빼면 일수가 나옵니다. 접수일이 아니라 진료일을 봅니다.

연번 영수증이라는 오탐 빼기

/root/dupclaim/dedup.py 가 각 쌍에 serial_neighbor 와 최종 verdict, 그리고 reasons 를 붙이게 하세요. 연번 영수증은 점수가 높아도 distinct 입니다.

열두 자리 번호에서 한 글자만 다르면 유사도가 0.93 을 넘습니다. 이름과 병원까지 같으니 합산 점수가 문턱을 넘지만, 이건 같은 서류가 아니라 이웃한 서류입니다. 마지막 숫자 덩어리만 떼어 비교하세요.

심사 담당자가 그대로 볼 수 있게 내기

자기 청구 표로 판정해 /root/dupclaim/dedup_result.json 을 남기고, 판정이 distinct 가 아닌 쌍을 /root/dupclaim/review.csv 에 머리글 a,b,verdict,score,amount_gap,day_gap,reasons 로 (reasons 는 세로막대로 이어서) 적으세요. /root/dupclaim/dup_report.md 에는 ## 판정 요약 ## 완전 중복과 사실상 중복 ## 사람이 봐야 하는 건 ## 오탐으로 뺀 것 ## 정규화 규칙 다섯 절을 쓰고, 요약에는 duplicate·review·distinct·serial_neighbor 의 쌍 수를 표로 적습니다.

앞 단계에서 만든 /root/dupclaim/dedup.py 에 /root/dupclaim/claims.db 를 물리면 됩니다. 검토 목록은 담당자가 스프레드시트로 여는 파일입니다. 점수만 있으면 무엇을 확인할지 모르니 근거를 같이 넣습니다. 오탐 절에는 실제로 뺀 쌍의 청구번호를 적어야 다음 사람이 규칙을 검증할 수 있습니다.