Entity Extractor について
Entity Extractorは、固有表現認識パイプラインの設計と実装を支援するスキルです。一般テキストや専門分野のテキストを扱うNLP実務者向けに、手法選定、モデル学習、評価、正規化などを扱います。
主な機能
- 01NER手法の選定
- 02抽出パイプラインの実装
- 03独自のエンティティモデル学習
- 04抽出品質の評価
- 05エンティティの正規化とリンク
- 06関係抽出の手法
活用シーン
- 01分野に適したNER手法の選択
- 02独自のエンティティ認識器の構築
- 03種類別の抽出エラーの評価
- 04抽出したエンティティのナレッジベースへのリンク
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ jmsktm/ claude-settings --skill entity-extractorインストール後、Claude Code で/entity-extractorを入力して読み込まれたか確認します。
詳細
エンティティ抽出
エンティティ抽出スキルでは、テキスト内のエンティティを特定し、分類する固有表現認識(NER)システムの実装方法を説明します。人物や組織から、製品、医療用語、金融商品などのドメイン固有のエンティティまで、単純なパターンマッチングから高度なニューラルモデルまで、さまざまな抽出手法を取り上げます。
エンティティ抽出は、検索エンジンからナレッジグラフまで、幅広いアプリケーションを支える基盤的な NLP タスクです。適切に実装するには、対象ドメインを理解し、適切な手法を選び、自然言語に固有の曖昧さに対処する必要があります。
標準的なエンティティタイプの抽出、ドメインに合わせたカスタムエンティティの定義、エンティティ認識を基盤とする関係抽出の構築など、このスキルを通じて、正確で保守しやすい抽出パイプラインを実現できます。
主なワークフロー
ワークフロー 1:抽出手法を選ぶ
- 対象エンティティを定義します:
- 標準タイプ:PERSON、ORG、LOCATION、DATE、MONEY
- ドメイン固有:PRODUCT、SYMPTOM、GENE、CONTRACT
- 関係:エンティティ間のつながり
- 利用可能なリソースを評価します:
- ラベル付き学習データ
- ドメインの専門知識
- 計算リソースの制約
- 手法を選択します:
手法 学習データ 精度 速度 カスタマイズ性 spaCy(事前学習済み) なし 良好 非常に高速 限定的 ルールベース なし 変動あり 高速 高い ファインチューニング済み BERT 100~1000 件 非常に高い 中程度 十分 LLM(ゼロショット) なし 良好 低速 プロンプトベース LLM(フューショット) 少数の例 非常に良好 低速 プロンプトベース - 実装と評価を計画します
ワークフロー 2:エンティティ抽出パイプラインを実装する
- 抽出を設定します:
import spacy class EntityExtractor: def __init__(self, model="en_core_web_trf"): self.nlp = spacy.load(model) def extract(self, text): doc = self.nlp(text) entities = [] for ent in doc.ents: entities.append({ "text": ent.text, "type": ent.label_, "start": ent.start_char, "end": ent.end_char, "confidence": getattr(ent, "confidence", None) }) return entities def extract_batch(self, texts): docs = list(self.nlp.pipe(texts)) return [self.extract_from_doc(doc) for doc in docs] - エンティティを後処理します:
- 表記の揺れを正規化します(IBM と I.B.M. など)
- 略語を解決します
- ナレッジベースにリンクします
- 抽出品質を検証します
- エッジケースに対処します
ワークフロー 3:カスタムエンティティ認識器を構築する
- 学習データを準備します:
# Format for spaCy training TRAIN_DATA = [ ("Apple released the new iPhone today.", { "entities": [(0, 5, "ORG"), (24, 30, "PRODUCT")] }), ("Dr. Smith prescribed metformin for diabetes.", { "entities": [(0, 9, "PERSON"), (21, 30, "DRUG"), (35, 43, "CONDITION")] }) ] - 学習を設定します:
# spaCy config for NER training config = { "training": { "optimizer": {"learn_rate": 0.001}, "batch_size": {"@schedules": "compounding", "start": 4, "stop": 32} }, "components": { "ner": { "factory": "ner", "model": {"@architectures": "spacy.TransitionBasedParser"} } } } - モデルを学習させます:
python -m spacy train config.cfg --output ./models --paths.train ./train.spacy --paths.dev ./dev.spacy - 保留データで評価します
- エラーに基づいて反復します
クイックリファレンス
| アクション | コマンド/トリガー |
|---|---|
| エンティティを抽出 | 「[text] からエンティティを抽出」 |
| NER モデルを選択 | 「[domain] に最適な NER」 |
| カスタムエンティティ | 「カスタムエンティティ認識器を学習」 |
| NER を評価 | 「エンティティ抽出品質を評価」 |
| 曖昧さに対処 | 「曖昧なエンティティを解決」 |
| エンティティリンキング | 「エンティティをナレッジベースにリンク」 |
ベストプラクティス
-
事前学習済みモデルから始める:不必要に一から学習させないでください
- spaCy、Hugging Face、クラウド API は一般的なエンティティをカバーしています
- まず事前学習済みモデルをテストします
- 必要な場合にのみファインチューニングします
-
明確なガイドラインを定める:エンティティの境界は曖昧です
- 「Dr. John Smith」は 1 つのエンティティか、2 つのエンティティか?
- 「New York Times」は ORG か GPE か?
- 一貫したアノテーションガイドラインを作成し、それに従います
-
入れ子になったエンティティに対処する:一部のエンティティはほかのエンティティを含みます
- 「Bank of America headquarters」(LOCATION 内の ORG)
- 入れ子構造の扱い方を事前に決めます
- フラットな構造のみをサポートするモデルもあれば、入れ子構造を扱えるモデルもあります
-
抽出したエンティティを正規化する:生テキストには表記の揺れがあります
- 「IBM」、「I.B.M.」、「International Business Machines」
- 標準形に正規化します
- 可能であればナレッジベースの ID にリンクします
-
詳細に評価する:集計指標では問題が見えにくくなります
- エンティティタイプごとに適合率/再現率を報告します
- エラーパターンを分析します
- エッジケースを明示的にテストします
-
コンテキストウィンドウを考慮する:モデルにはコンテキストの制限があります
- 長いドキュメントはチャンクに分割する必要がある場合があります
- 可能であればチャンク間でコンテキストを保持します
- エンティティが境界をまたぐ可能性がある場合は、境界をまたいで再実行します
高度な手法
LLM ベースのエンティティ抽出
柔軟な抽出には言語モデルを使用します:
def llm_extract_entities(text, entity_types):
prompt = f"""Extract named entities from the following text.
Text: "{text}"
Entity types to extract:
{chr(10).join(f"- {t}: {desc}" for t, desc in entity_types.items())}
Return a JSON array of entities:
[{{"text": "entity text", "type": "ENTITY_TYPE", "start": 0, "end": 10}}]
Only include entities that clearly match the specified types.
"""
response = llm.complete(prompt, response_format={"type": "json_object"})
return json.loads(response)["entities"]
# Example usage
entity_types = {
"COMPANY": "Business organizations",
"PRODUCT": "Commercial products or services",
"PERSON": "Individual people's names"
}
entities = llm_extract_entities(text, entity_types)
ルールと機械学習を組み合わせたアプローチ
パターンとニューラル抽出を組み合わせます:
class HybridExtractor:
def __init__(self):
self.ml_extractor = spacy.load("en_core_web_trf")
self.patterns = load_pattern_rules()
def extract(self, text):
# ML extraction
ml_entities = self.ml_extractor(text).ents
# Pattern-based extraction
pattern_entities = apply_patterns(text, self.patterns)
# Merge with priority rules
merged = merge_entities(
ml_entities,
pattern_entities,
priority="pattern" # Patterns override ML when overlap
)
return merged
def add_pattern(self, pattern, entity_type):
"""Add domain-specific pattern."""
self.patterns.append({
"pattern": pattern,
"type": entity_type
})
エンティティリンキング
抽出したエンティティをナレッジベースに結び付けます:
def link_entity(entity_text, entity_type, knowledge_base):
"""
Link extracted entity to canonical entry in knowledge base.
"""
# Generate candidates
candidates = knowledge_base.search(
query=entity_text,
type_filter=entity_type,
limit=10
)
if not candidates:
return {"entity": entity_text, "linked": None}
# Score candidates
scored = []
for candidate in candidates:
score = compute_linking_score(
entity_text,
candidate.name,
candidate.aliases
)
scored.append((candidate, score))
# Select best match
best = max(scored, key=lambda x: x[1])
if best[1] > LINKING_THRESHOLD:
return {
"entity": entity_text,
"linked": best[0].id,
"canonical_name": best[0].name,
"confidence": best[1]
}
else:
return {"entity": entity_text, "linked": None}
関係抽出
エンティティ間の関係を抽出します:
def extract_relations(text, entities):
"""
Given extracted entities, find relations between them.
"""
prompt = f"""Given this text and extracted entities, identify relationships.
Text: "{text}"
Entities found:
{json.dumps(entities, indent=2)}
Identify relationships between entities. Return JSON:
[{{
"subject": "entity text",
"relation": "relationship type",
"object": "entity text",
"confidence": 0.9
}}]
Common relation types: WORKS_FOR, LOCATED_IN, FOUNDED, ACQUIRED, PARTNER_OF
"""
response = llm.complete(prompt)
return json.loads(response)
NER のアクティブラーニング
対象を絞ったラベル付けで、抽出を効率的に改善します:
def active_learning_sample(unlabeled_texts, model, n_samples=100):
"""
Select texts that would be most valuable to label.
"""
uncertainties = []
for text in unlabeled_texts:
doc = model(text)
# Calculate uncertainty (various strategies)
uncertainty = calculate_ner_uncertainty(doc)
uncertainties.append((text, uncertainty))
# Select most uncertain
uncertainties.sort(key=lambda x: x[1], reverse=True)
return [text for text, _ in uncertainties[:n_samples]]
def calculate_ner_uncertainty(doc):
"""
Calculate uncertainty based on entity confidence scores.
"""
if not doc.ents:
return 0.5 # No entities - medium uncertainty
confidences = [ent._.confidence for ent in doc.ents if hasattr(ent._, "confidence")]
if not confidences:
return 0.5
# High uncertainty = low confidence entities
return 1 - min(confidences)
よくある避けるべき落とし穴
- アノテーションガイドラインが一貫していないために、ノイズの多いトレーニングデータが生じる
- エンティティの境界の曖昧さ(エンティティがどこで終わるか)に対処しない
- 重要な場合でも、入れ子または重複するエンティティを無視する
- 拡張せずに小規模なデータセットでトレーニングする
- 後続の用途で使う前にエンティティを正規化しない
- テストせずに、事前学習済みモデルが自分のドメインで機能すると決めつける
- エンティティタイプごとのパフォーマンスを評価しない
- 曖昧さ解消のためのエンティティリンキングを忘れる