--- id: wiki-2026-0508-named-entity-recognition-ner title: Named Entity Recognition (NER) category: 10_Wiki/Topics status: verified canonical_id: self aliases: [NER, Named Entity Recognition, Entity Tagging, Entity Extraction] duplicate_of: none source_trust_level: A confidence_score: 0.95 verification_status: applied tags: [nlp, information-extraction, ner, bert, transformer, gliner, spacy, conll] raw_sources: [] last_reinforced: 2026-05-10 github_commit: pending tech_stack: { language: python, framework: spacy-transformers } --- ## 한 줄 Named Entity Recognition(NER)은 비정형 텍스트에서 인명·지명·조직·날짜·수량 등 사전 정의된 엔티티 범주를 식별·분류하여 (span, type) 쌍으로 추출하는 정보추출의 기초 작업이다. ## 핵심 ### 표준 태그셋 - **CoNLL-2003** (4종): PER, ORG, LOC, MISC. - **OntoNotes 5** (18종): PERSON, ORG, GPE, DATE, MONEY, PERCENT, EVENT, LAW, … - **BIO/BIOES schema**: B-PER, I-PER, O / E-, S-. - 도메인별 (BioNER): GENE, DRUG, DISEASE. ### 방법론 진화 1. **규칙/사전 기반**: gazetteer + regex — 도메인 특화엔 여전히 강력. 2. **HMM / CRF**: BiLSTM-CRF (Lample et al. 2016) — 신경망 시대 시작. 3. **사전학습 Transformer**: BERT/RoBERTa + token classification head — 표준. 4. **LLM zero/few-shot**: GPT-4, Claude 프롬프팅으로 스키마 정의. 5. **GLiNER (2024)**: 임의의 엔티티 타입을 zero-shot 추출하는 generalist NER. ### Nested NER / Flat NER - Flat: 한 토큰은 하나의 엔티티 — CRF 자연스러움. - Nested: "Bank of America" 안에 "America"(GPE)까지 — span-based 모델 필요. ### 도메인 변종 - BioNER (BC5CDR, NCBI Disease). - LegalNER (사건명, 법조항). - FinancialNER (티커, 금액). - 한국어 NER: KLUE-NER, KoBERT. ### 평가 - Span-level F1 (token-level이 아닌 정확한 boundary+type 일치). - seqeval 라이브러리 표준. ### 응용 - 검색 엔진 enrichment. - 지식 그래프 구축. - 챗봇 슬롯 채우기. - 의료 기록에서 약물·질환 추출. - 컴플라이언스 (PII 탐지). ## 💻 패턴 ```python # 1. spaCy — 즉시 사용 가능한 production NER import spacy nlp = spacy.load("en_core_web_trf") doc = nlp("Apple is opening a new office in Seoul next March.") for ent in doc.ents: print(ent.text, ent.label_, ent.start_char, ent.end_char) # Apple ORG / Seoul GPE / next March DATE ``` ```python # 2. HuggingFace transformers — BERT NER pipeline from transformers import pipeline ner = pipeline("ner", model="dslim/bert-large-NER", aggregation_strategy="simple") print(ner("Tim Cook visited Berlin yesterday.")) ``` ```python # 3. Fine-tune BERT for NER (CoNLL-2003) from transformers import AutoTokenizer, AutoModelForTokenClassification, Trainer model = AutoModelForTokenClassification.from_pretrained( "bert-base-cased", num_labels=9 ) # tokens, labels을 BIO 스킴으로 정렬한 뒤 Trainer로 학습 ``` ```python # 4. GLiNER — zero-shot 임의 타입 from gliner import GLiNER model = GLiNER.from_pretrained("urchade/gliner_medium-v2.1") text = "Elon Musk founded SpaceX in 2002." labels = ["person", "company", "year"] print(model.predict_entities(text, labels)) ``` ```python # 5. LLM JSON 추출 — Claude/GPT import json prompt = """Extract entities. Return JSON list of {"text","type","start","end"}. Types: PERSON, ORG, LOC, DATE, MONEY. Text: Microsoft acquired Activision for $69 billion in October 2023.""" # response → json.loads ``` ```python # 6. seqeval — 평가 from seqeval.metrics import classification_report y_true = [["B-PER","I-PER","O","B-LOC"]] y_pred = [["B-PER","I-PER","O","B-LOC"]] print(classification_report(y_true, y_pred, digits=4)) ``` ```python # 7. 한국어 NER — KLUE-RoBERTa from transformers import pipeline kor_ner = pipeline("ner", model="klue/roberta-base-finetuned-ner", aggregation_strategy="simple") print(kor_ner("김철수는 서울대학교에서 공부한다.")) ``` ```python # 8. BioNER — BERN2 (의료) import requests text = "Aspirin reduces the risk of stroke." r = requests.post("http://bern2.korea.ac.kr/plain", json={"text": text}) print(r.json()) # CHEMICAL: Aspirin, DISEASE: stroke ``` ```python # 9. spaCy 사용자 정의 EntityRuler (규칙) ruler = nlp.add_pipe("entity_ruler", before="ner") patterns = [ {"label": "PRODUCT", "pattern": "iPhone 17 Pro"}, {"label": "ORG", "pattern": [{"LOWER": "openai"}]}, ] ruler.add_patterns(patterns) ``` ```python # 10. Nested NER — span-based (Flair/SpanMarker) from span_marker import SpanMarkerModel model = SpanMarkerModel.from_pretrained("tomaarsen/span-marker-mbert-base-multinerd") print(model.predict("Bank of America is headquartered in Charlotte.")) # Bank of America (ORG) 와 America (LOC) 둘 다 추출 ``` ## 결정 기준 | 상황 | 추천 | |---|---| | 빠른 프로토타입 | spaCy `en_core_web_trf` | | 최고 정확도 (영어) | BERT/RoBERTa fine-tune on OntoNotes | | 임의 타입 / few labeled | GLiNER, LLM zero-shot | | 한국어 | KLUE-RoBERTa, KoBERT-NER | | 의료/생명과학 | BioBERT, BERN2, SciSpaCy | | 규칙 강제 (회사 product 목록) | spaCy EntityRuler 우선 적용 | | Nested entities | SpanMarker, biaffine | | Production 비용 민감 | spaCy / 작은 BERT (distil) | 기본값: spaCy + EntityRuler 보강, 도메인 적응 시 BERT fine-tune, 빠른 PoC는 GLiNER/LLM. ## 🔗 Graph - 부모: [[Natural-Language-Processing-NLP|Natural-Language-Processing]], [[Information-Extraction]] ## 🤖 LLM 활용 - LLM에게 스키마(타입 + 정의) + few-shot 예시 → JSON 출력 요청. - 2024-26 추세: GLiNER + LLM 검증 단계 결합 (LLM이 false positive 제거). - Claude/GPT structured output API로 스키마 강제. - 검색 파이프라인 사전 enrichment에 LLM NER 활용 비용/성능 트레이드오프 평가. ## ❌ 안티패턴 - 토큰 단위 F1 보고 — span 경계 무시. - BIO 정렬 없이 subword 토큰에 라벨 부여 (학습 손상). - 도메인 데이터 없이 일반 NER 모델 그대로 의료/법률 적용. - LLM zero-shot 결과를 검증 없이 KG 적재 (할루시네이션 위험). - gazetteer를 너무 길게 → 메모리/지연 증가. ## 🧪 검증 / 중복 - seqeval span-level F1 표준 (CoNLL). - 별칭: [[Entity-Tagging]], [[Entity-Extraction]] — 본 문서로 통합. - 정기 평가: 도메인 schema drift 점검. ## 🕓 Changelog - Phase 1 (2026-05-08): 초기 생성. - Manual cleanup (2026-05-10): canonical 확정, GLiNER 2024 추가, BIO/BIOES, nested NER, 한국어/생명과학 도메인 정리.