본문 바로가기
/ 학습 / 안내서 / 보안·윤리
L3 심화 · 8분 읽기

개인정보 비식별 파이프라인, 이름·주소까지 자동으로

안전·윤리팀 2026.07.03 갱신 신고·상담 텍스트를 대량으로 비식별해 활용하려는 담당자·연구자
#개인정보#Presidio#비식별#가명화

입문편의 정규식 점검은 주민번호·전화번호처럼 모양이 정해진 개인정보를 잡습니다. 하지만 정규식이 원리상 못 잡는 것이 있습니다 — "김철수 소방관이 마포구 성산동 현장에서"의 이름과 주소입니다. 모양이 없고 문맥으로만 사람이라는 걸 알 수 있기 때문입니다. 통화 몇 건이라면 입문편의 3단 점검 마지막 단계에서 사람이 지우면 되지만, 수천 건을 AI 학습·분석에 쓰려면 사람이 일일이 지울 수 없습니다.

이 안내서를 끝내면 이름·지명 같은 문맥 개체까지 자동 탐지하고, 소방 특화 개체를 커스텀 인식기로 보강하고, 같은 사람을 일관된 가명으로 치환하고, 골든셋으로 "얼마나 놓쳤는가"를 재는 비식별 파이프라인을 만들 수 있습니다. 이 안내서는 현업 프로젝트 신고 텍스트 개인정보 마스킹 파이프라인의 기술 배경입니다.

왜 정규식만으로는 부족한가

개인정보모양(패턴)정규식문맥 탐지(NER)
주민번호·전화·차량번호있음✅ 강함불필요
이름없음❌ 못 잡음✅ 문맥으로
상세주소·지명약함△ 일부✅ 문맥으로
병원명·직책 조합없음△ 커스텀 필요

핵심은 두 방식을 겹치는 것입니다. 정규식은 패턴 있는 것을 확실히, NER(개체명 인식)은 문맥 있는 것을. Presidio는 이 둘을 한 엔진에서 묶어 줍니다.

1. Presidio — 탐지와 익명화 분리

Presidio는 탐지(Analyzer)익명화(Anonymizer) 를 나눕니다. 먼저 무엇이 어디 있는지 찾고, 그 다음 어떻게 가릴지 정합니다. 전 과정 로컬에서 돕니다 — 신고 전사와 같은 원칙입니다.

PYTHON
from presidio_analyzer import AnalyzerEngine
from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import OperatorConfig

analyzer = AnalyzerEngine()
anonymizer = AnonymizerEngine()

text = "신고자 김철수님, 마포구 성산동, 연락처 010-1234-5678"

# 1) 탐지 — 한국어 NER 모델을 spaCy/HuggingFace로 구성(아래 주의 참고)
found = analyzer.analyze(text=text, language="ko",
                         entities=["PERSON", "LOCATION", "PHONE_NUMBER"])

# 2) 익명화 — 개체 유형별로 가리는 방식 지정
result = anonymizer.anonymize(
    text=text, analyzer_results=found,
    operators={
        "PERSON":       OperatorConfig("replace", {"new_value": "<이름>"}),
        "LOCATION":     OperatorConfig("replace", {"new_value": "<지역>"}),
        "PHONE_NUMBER": OperatorConfig("mask", {"masking_char": "*", "chars_to_mask": 8, "from_end": True}),
    })
print(result.text)   # 신고자 <이름>님, <지역>, 연락처 010-********
⚠️ 흔한 실수
Presidio의 한국어 개체명 인식은 한국어 NER 모델을 따로 붙여야 제대로 됩니다(기본 제공 모델은 영어 중심). spaCy 한국어 모델이나 HuggingFace 한국어 NER를 NlpEngine으로 연결하며, 붙인 모델의 성능이 곧 이름·지명 탐지의 성능입니다 — 3단계에서 반드시 재현율을 재세요.

2. 소방 특화 커스텀 인식기

일반 NER는 소방 고유 표현을 모릅니다 — 사건번호, 출동번호, 관서 내부 코드 같은 것입니다. 입문편의 정규식 자산을 Presidio 커스텀 인식기로 옮겨, 기존 엔진에 합칩니다.

PYTHON
from presidio_analyzer import Pattern, PatternRecognizer

# 입문편 BLOCK_PATTERNS를 그대로 재사용 — 사건·출동번호도 추가
rrn = PatternRecognizer(
    supported_entity="KR_RRN",   # 주민등록번호
    patterns=[Pattern("rrn", r"\b\d{6}[-\s]?[1-8]\d{6}\b", 0.9)])
case_no = PatternRecognizer(
    supported_entity="KR_CASE_NO",   # 사건번호(관서 서식에 맞춰 조정)
    patterns=[Pattern("case", r"\b\d{4}-\d{5,6}\b", 0.6)])

analyzer.registry.add_recognizer(rrn)
analyzer.registry.add_recognizer(case_no)

정규식 인식기는 문맥이 없어도 확실히 잡고, NER 인식기는 문맥으로 잡습니다. 둘을 한 레지스트리에 넣으면 탐지 한 번으로 양쪽을 받습니다.

3. 재현율 검증 — 놓친 것이 진짜 위험

비식별에서 최악의 실수는 놓치는 것(재현율 실패)입니다. 가려야 할 이름을 하나 흘리면 그 한 건으로 개인정보가 노출됩니다. 반대로 안 가려도 될 걸 가리는 것(정밀도)은 데이터가 조금 뭉개질 뿐 안전은 지켜집니다. 그래서 재현율을 정밀도보다 우선해 관리합니다.

합성 신고 데이터로 골든셋을 만듭니다 — 문장마다 "가려야 할 개체 목록"을 사람이 표시합니다. 파이프라인을 돌려 얼마나 놓쳤는지 셉니다.

PYTHON
def recall(gold_spans, found_spans):
    """가려야 할 것 중 실제로 잡은 비율. 놓친 개수를 함께 본다."""
    hit = sum(1 for g in gold_spans if any(overlap(g, f) for f in found_spans))
    missed = [g for g in gold_spans if not any(overlap(g, f) for f in found_spans)]
    return hit / max(len(gold_spans), 1), missed

r, missed = recall(gold, found)
print(f"재현율 {r:.1%}, 놓친 개체 {len(missed)}건")
for m in missed:            # 놓친 것은 전부 사람이 보고 커스텀 인식기를 보강
    print("  놓침:", m)
📌 핵심
재현율 100%를 자동으로 달성했다고 믿지 마세요. 골든셋에 없는 표현은 골든셋이 지켜 주지 못합니다. 그래서 비식별 결과는 표본을 사람이 재검수하고, 놓친 유형이 나올 때마다 커스텀 인식기·골든셋을 키웁니다 — RAG 평가의 골든셋 개선 루프와 같은 구조입니다.

4. 일관된 가명화 — 재식별과 활용의 균형

이름을 전부 <이름>으로 바꾸면 안전하지만, "같은 사람이 여러 번 나온다"는 정보가 사라져 분석이 어려워집니다. 같은 원본은 같은 가명으로 치환하면(가명화) 안전과 활용을 함께 얻습니다 — "김철수→인물A"가 문서 전체에서 일관되게 유지됩니다.

단, 이때 원본↔가명 대응표(entity_mapping)는 그 자체가 최고 민감 자료입니다. 이 표만 있으면 재식별이 되기 때문입니다. 대응표는 비식별 데이터와 절대 같은 곳에 두지 않고, 분석에 재식별이 필요 없다면 만들지 않는 것이 가장 안전합니다.

운영 루틴 한 장

언제무엇을통과 기준
파이프라인·모델 변경 시골든셋 재현율 회귀이전 대비 하락 없음
매 배치비식별 결과 표본 재검수놓친 개체 0 (나오면 인식기 보강)
놓침 발견 시커스텀 인식기·골든셋 보강같은 유형 재발 방지
상시원본↔가명 대응표 격리비식별 데이터와 분리 저장·최소 권한
▸ 소방 활용 포인트
수천 건의 신고·상담 텍스트를 AI 학습·통계 분석에 쓸 수 있도록 이름·주소까지 자동 비식별하고, "얼마나 놓쳤는가"를 재현율로 관리해 개인정보 노출 위험을 숫자로 통제합니다. 단 자동 비식별은 대량 처리의 1차 방어선일 뿐, 공개·배포 전 표본 재검수는 사람이 반드시 합니다.

사람 검토 체크리스트

TEXT
- [ ] 정규식(패턴)과 NER(문맥) 인식기를 함께 써서 이름·주소까지 탐지했습니다.
- [ ] 한국어 NER 모델을 붙였고, 그 모델의 재현율을 골든셋으로 확인했습니다.
- [ ] 재현율을 정밀도보다 우선해 관리하고, 놓친 개체를 사람이 검토했습니다.
- [ ] 소방 특화 개체(사건·출동번호 등)를 커스텀 인식기로 보강했습니다.
- [ ] 가명화 대응표를 비식별 데이터와 분리 저장하고 권한을 최소화했습니다.
- [ ] 연습·검증은 합성 데이터로만 했습니다.
⚠️ 흔한 실수
자동 비식별은 도구이지 보증이 아닙니다 — 골든셋에 없는 새 표현, 오탈자로 깨진 이름, 문맥이 모호한 지명은 놓칠 수 있습니다. 입문편의 원칙 그대로, block은 중단 신호이고 최종 확인은 사람이며, 공개하지 않을 자료는 자동 비식별을 거쳤더라도 외부 AI에 넣지 마세요.