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

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

2026.07.12 갱신 신고·상담 텍스트를 대량으로 비식별해 활용하려는 담당자·연구자
#개인정보#Presidio#비식별#가명화
검토 상태: 전문 검토 전 위험도 미분류

이 안내서는 공식 절차·법령·현장 판단을 대체하지 않으며, 적용 전 소속 기관 기준과 담당자 검토를 확인하세요.

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

이 안내서는 프로젝트 아이디어 신고 텍스트 개인정보 마스킹 파이프라인의 기술 배경을 설명합니다.

🎯 이 장의 목표
  • 패턴 규칙과 문맥 개체명 인식의 역할을 나눠 설계할 수 있습니다.
  • 합성 골든셋으로 탐지 놓침과 과잉 마스킹을 함께 검토할 수 있습니다.
  • 마스킹·가명화 중 업무 목적에 맞는 최소 처리를 선택할 수 있습니다.
  • 원본·비식별본·가명 대응표의 권한을 분리하고 공개 전 사람 검토로 연결할 수 있습니다.

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

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

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

💡 팁
NER이 이름을 아는 원리 — 사람은 '김철수'를 글자 모양이 아니라 자리로 알아봅니다. "신고자 ○○○님"의 빈자리에 오는 말은 이름일 확률이 높습니다. 개체명 인식이 학습하는 것이 이 자리 감각이라, 처음 보는 이름도 문맥만으로 사람이라 짚습니다. 예를 들어 "박초롱 대원과 이가온 반장이 도착"(가상 문장)에서 정규식은 아무 패턴도 못 잡지만, NER은 '대원'·'반장' 앞자리를 근거로 두 이름을 사람으로 표시합니다. 그래서 붙인 NER 모델이 소방 현장 말투를 얼마나 봤는지가 곧 탐지 성능이 됩니다.

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)
⚠️ 흔한 실수
recall 함수의 한계: 골드 span과 탐지 span이 한 글자라도 겹치면 해당 개체를 hit로 집계합니다.
  • 위험: 이름이나 주소의 일부만 가려 나머지가 노출돼도 성공으로 세어집니다
  • 운영 검증: 실제로는 다음을 추가로 구현해야 합니다:
  • 문자/토큰 coverage 검사 (가려야 할 문자의 몇 %를 실제로 가렸는가)
  • 골드 span 완전 포함 검사 (시작점과 끝점이 정확한가)
  • 부분 탐지를 놓침 목록으로 분류 (재검수 대상)
📌 핵심
재현율 100%를 자동으로 달성했다고 믿지 마세요. 골든셋에 없는 표현은 골든셋이 지켜 주지 못합니다. 그래서 비식별 결과는 표본을 사람이 재검수하고, 놓친 유형이 나올 때마다 커스텀 인식기·골든셋을 키웁니다 — RAG 평가의 골든셋 개선 루프와 같은 구조입니다.

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

이름을 전부 <이름>으로 바꾸면 안전하지만, "같은 사람이 여러 번 나온다"는 정보가 사라져 분석이 어려워집니다. 같은 원본은 같은 가명으로 치환하면(가명화) 안전과 활용을 함께 얻습니다 — "김철수→인물A"가 문서 전체에서 일관되게 유지됩니다. 예를 들어 같은 배치의 두 문장에서 '김철수'가 모두 인물A로, '박영희'가 모두 인물B로 바뀌면, 실명은 지워지지만 "A와 B가 같은 사건에 함께 나온다"는 관계는 분석에 그대로 남습니다.

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

또 하나, 이름·번호를 모두 가려도 준식별자가 남습니다. "43세 남성, 마포구 성산동, 소규모 관서 근무"처럼 조각 하나하나는 개인정보가 아니어도, 겹쳐 놓으면 한 사람으로 좁혀집니다 — 희귀한 직책이나 작은 관서일수록 좁혀지기 쉽습니다. 그래서 비식별은 이름을 가리는 데서 끝나지 않고, '남은 조각들의 조합으로 한 명이 특정되는가'까지 표본으로 확인해야 합니다.

운영 루틴 한 장

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

설계 판단

비식별은 가릴 수 있는 것을 모두 가리는 경주가 아닙니다. 사용 목적에 필요한 관계만 남기고 재식별 가능성은 줄이되, 자동 결과를 공개 가능 판정으로 오해하지 않아야 합니다.

방식맞는 상황트레이드오프사람이 확인할 것
패턴 규칙 중심 마스킹전화번호·이메일·정형 ID처럼 형식이 명확할 때빠르고 설명하기 쉬우나 이름·지명 문맥을 놓침새 표기 형식과 오탐 표본
규칙 + NER 결합비정형 이름·주소·직책 표현이 다양할 때놓침을 줄이지만 지명·조직명을 개인으로 오인할 수 있음놓침과 과잉 마스킹의 원문 문맥
일관된 가명화동일 인물·개체의 반복 관계가 분석에 정말 필요할 때대응표가 새로운 최고 민감 자료가 됨재식별 필요성과 대응표 보관·폐기 승인

운영 시나리오

다음 사례의 문장·식별자는 모두 학습을 위해 만든 가상 자료입니다. 실제 신고·상담 원문을 연습에 넣지 않습니다.

가상 시나리오 1: 새 사건번호 표기를 인식기가 놓친 경우

  • 탐지: 합성 골든셋에 추가한 새 형식의 사건번호가 그대로 남았고, 사람 표본 검토에서도 같은 유형이 반복해 나왔습니다.
  • 원인 가설: 현재 규칙이 이전 구분자와 자릿수만 알고 있어 새 형식을 식별자가 아닌 일반 문자열로 보았다고 봅니다.
  • 대응: 해당 배치의 공개·외부 전달을 멈추고, 형식을 과도하게 넓게 잡지 않는 커스텀 인식기와 정상 문자열 음성 픽스처를 함께 추가합니다.
  • 재발 확인: 신·구 형식과 비슷한 일반 문자열을 함께 재실행해 식별자는 가리고 일반 문자열은 보존하는지 사람이 확인합니다.

가상 시나리오 2: 이름 일부만 탐지됐는데 재현율이 통과한 경우

  • 탐지: 집계 재현율은 기준을 통과했지만 비식별 결과를 사람이 보니 가상 이름의 한 글자만 가려지고 나머지 글자가 그대로 남았습니다.
  • 원인 가설: 본문의 overlap 기반 계산은 골드 span과 탐지 span이 한 글자라도 겹치면 hit로 세므로, 부분 노출을 성공으로 집계했다고 봅니다.
  • 대응: 해당 배치의 공개·외부 전달을 멈추고 문자·토큰 coverage 또는 골드 span 완전 포함 검사를 별도 지표로 추가해 부분 탐지를 놓침으로 분리합니다.
  • 재발 확인: 완전 탐지·한 글자 겹침·앞뒤 일부 누락 합성 픽스처를 함께 실행해 완전 포함만 통과하고 부분 노출은 사람 검토 대상으로 남는지 확인합니다.

한계와 리스크

리스크발생 조건영향완화·사람 승인
새 표현의 놓침골든셋과 인식기가 기존 형식에만 맞춰짐한 건의 식별자가 외부 자료에 남을 수 있음표본 재검수와 놓침 목록을 계속 보강하고 공개·배포는 사람 승인
가명 대응표 노출대응표를 비식별본과 같은 저장소·권한에 둠비식별본을 원본 인물에게 다시 연결할 수 있음재식별이 불필요하면 대응표를 만들지 않고, 필요하면 분리·최소 권한·폐기를 보안 담당자가 승인
준식별자 조합이름·번호는 가렸지만 나이·지역·희귀 직책이 함께 남음조각을 결합해 특정 인물을 추정할 수 있음희소 조합을 일반화·제거하고 보안된 표본 검토 후 활용 담당자 승인

자주 묻는 질문

Q. 골든셋 재현율이 높으면 공개해도 되나요?

아닙니다. 골든셋은 그 안에 든 표현만 검증합니다. 새 표현·오탈자·준식별자 조합을 놓칠 수 있으므로 공개·배포 전 사람 표본 검토와 소속 기관 기준을 따로 통과해야 합니다.

Q. 가명 대응표는 항상 필요한가요?

아닙니다. 반복 관계 분석이 없다면 대응표를 만들지 않는 편이 더 안전합니다. 필요할 때만 용도·권한·보관·폐기를 먼저 승인받습니다.

Q. 과잉 마스킹은 안전하므로 무시해도 되나요?

놓침보다 노출 위험은 낮지만, 분석 의미를 파괴하면 잘못된 결론을 낳습니다. 놓침을 늘리지 않는 범위에서 개체 유형·문맥별 과탐을 같이 검토합니다.

Q. 자동 비식별 후 외부 AI에 넣어도 되나요?

자동 비식별은 외부 전송 허가가 아닙니다. 자료의 외부 제공 가능 여부, 준식별자, 계약·보안·보존 조건을 소속 기관 기준에 따라 별도로 판단합니다.

핵심 정리

  • 패턴 규칙은 정형 표현을, NER은 문맥 개체를 담당하며 서로의 놓침을 보완합니다.
  • 예제의 overlap 재현율은 한 글자만 겹쳐도 성공으로 세므로, 문자·토큰 coverage나 완전 포함 검사로 부분 노출을 따로 잡습니다.
  • 재현율과 놓침 목록을 우선하되 과잉 마스킹으로 업무 의미가 파괴되지 않는지도 봅니다.
  • 가명 대응표는 필요할 때만 만들고 비식별본과 분리하며 권한을 최소화합니다.
  • 자동 비식별은 공개 가능 보증이 아니며 공개·배포 전에는 사람과 소속 기관 기준이 최종 경계입니다.

다음 단계

  • 개인정보 입문 점검: 자동 파이프라인 전에 block·warn 경계와 사람 확인 원칙을 다시 점검합니다.
  • 합성 데이터 만들기: 실제 개인정보 없이 놓침·과탐·준식별자 픽스처를 만드는 기초를 익힙니다.
  • RAG 운영 평가: 인식기·모델·규칙 변경 전후를 골든셋 회귀로 관리하는 방식을 연결합니다.

사람 검토 체크리스트

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