<НА ГЛАВНУЮ

Осваиваем Microsoft Presidio: детекция и анонимизация персональных данных в тексте с практическими примерами

Изучите возможности Microsoft Presidio для обнаружения и анонимизации персональных данных в тексте с практическими примерами на Python, включая создание кастомных распознавателей и хеш-анонимизацию.

Введение в Microsoft Presidio

Microsoft Presidio — это открытая платформа для обнаружения, анализа и анонимизации персональных данных (PII) в неструктурированном тексте. Построенная на основе мощной библиотеки обработки естественного языка spaCy, Presidio имеет легковесную и модульную архитектуру, что позволяет легко интегрировать её в приложения и конвейеры обработки данных в реальном времени.

Установка Presidio и зависимостей

Для начала работы установите библиотеки presidio-analyzer и presidio-anonymizer, а также рекомендуемую модель spaCy для английского языка:

pip install presidio-analyzer presidio-anonymizer
python -m spacy download en_core_web_lg

При необходимости перезапустите рабочее окружение, особенно если вы используете Jupyter или Google Colab.

Базовое обнаружение PII с помощью Presidio Analyzer

AnalyzerEngine загружает NLP-пайплайн spaCy и встроенные распознаватели для поиска чувствительных данных, например, телефонных номеров. Пример обнаружения номера телефона в тексте с подавлением лишних логов:

import logging
logging.getLogger("presidio-analyzer").setLevel(logging.ERROR)
 
from presidio_analyzer import AnalyzerEngine
 
analyzer = AnalyzerEngine()
 
results = analyzer.analyze(text="My phone number is 212-555-5555",
                           entities=["PHONE_NUMBER"],
                           language='en')
print(results)

Создание кастомных распознавателей с помощью deny-листов

Presidio позволяет создавать собственные распознаватели. Например, можно определить распознаватель для академических титулов, используя deny-лист:

from presidio_analyzer import AnalyzerEngine, PatternRecognizer, RecognizerRegistry
 
academic_title_recognizer = PatternRecognizer(
    supported_entity="ACADEMIC_TITLE",
    deny_list=["Dr.", "Dr", "Professor", "Prof."]
)
 
registry = RecognizerRegistry()
registry.load_predefined_recognizers()
registry.add_recognizer(academic_title_recognizer)
 
analyzer = AnalyzerEngine(registry=registry)
 
text = "Prof. John Smith is meeting with Dr. Alice Brown."
results = analyzer.analyze(text=text, language="en")
 
for result in results:
    print(result)

Также можно создавать распознаватели на основе регулярных выражений или использовать внешние модели, как описано в официальной документации.

Анонимизация PII с помощью Presidio Anonymizer

После обнаружения PII их можно анонимизировать. Пример замены имен на плейсхолдер:

from presidio_anonymizer import AnonymizerEngine
from presidio_anonymizer.entities import RecognizerResult, OperatorConfig
 
engine = AnonymizerEngine()
 
result = engine.anonymize(
    text="My name is Bond, James Bond",
    analyzer_results=[
        RecognizerResult(entity_type="PERSON", start=11, end=15, score=0.8),
        RecognizerResult(entity_type="PERSON", start=17, end=27, score=0.8),
    ],
    operators={"PERSON": OperatorConfig("replace", {"new_value": "BIP"})},
)
 
print(result)

Доступны и другие методы анонимизации, включая редактирование, хеширование и псевдонимизацию.

Расширенные возможности: кастомные сущности и консистентная реанонимизация

Можно определить свои PII-сущности с помощью регулярных выражений и создать пользовательский анонимизатор, который хеширует данные и сохраняет сопоставления для консистентности.

Кастомный хеш-анонимайзер

Этот оператор использует SHA-256 и хранит соответствия для одинаковых значений:

from presidio_anonymizer.operators import Operator, OperatorType
import hashlib
from typing import Dict
 
class ReAnonymizer(Operator):
    """
    Анонимайзер, заменяющий текст на повторно используемый SHA-256 хеш,
    сохранённый в общем словаре сопоставлений.
    """
 
    def operate(self, text: str, params: Dict = None) -> str:
        entity_type = params.get("entity_type", "DEFAULT")
        mapping = params.get("entity_mapping")
 
        if mapping is None:
            raise ValueError("Отсутствует параметр `entity_mapping` в params")
 
        if entity_type in mapping and text in mapping[entity_type]:
            return mapping[entity_type][text]
 
        hashed = "<HASH_" + hashlib.sha256(text.encode()).hexdigest()[:10] + ">"
        mapping.setdefault(entity_type, {})[text] = hashed
        return hashed
 
    def validate(self, params: Dict = None) -> None:
        if "entity_mapping" not in params:
            raise ValueError("Необходимо передать словарь 'entity_mapping'.")
 
    def operator_name(self) -> str:
        return "reanonymizer"
 
    def operator_type(self) -> OperatorType:
        return OperatorType.Anonymize

Кастомные распознаватели для PAN и Aadhaar

Регулярные распознаватели для индийских номеров PAN и Aadhaar:

from presidio_analyzer import AnalyzerEngine, PatternRecognizer, Pattern
 
pan_recognizer = PatternRecognizer(
    supported_entity="IND_PAN",
    name="PAN Recognizer",
    patterns=[Pattern(name="pan", regex=r"\b[A-Z]{5}[0-9]{4}[A-Z]\b", score=0.8)],
    supported_language="en"
)
 
aadhaar_recognizer = PatternRecognizer(
    supported_entity="AADHAAR",
    name="Aadhaar Recognizer",
    patterns=[Pattern(name="aadhaar", regex=r"\b\d{4}[- ]?\d{4}[- ]?\d{4}\b", score=0.8)],
    supported_language="en"
)
 
analyzer = AnalyzerEngine()
analyzer.registry.add_recognizer(pan_recognizer)
analyzer.registry.add_recognizer(aadhaar_recognizer)
 
anonymizer = AnonymizerEngine()
anonymizer.add_anonymizer(ReAnonymizer)
 
entity_mapping = {}

Консистентный анализ и анонимизация нескольких текстов

from pprint import pprint
 
text1 = "My PAN is ABCDE1234F and Aadhaar number is 1234-5678-9123."
text2 = "His Aadhaar is 1234-5678-9123 and PAN is ABCDE1234F."
 
results1 = analyzer.analyze(text=text1, language="en")
anon1 = anonymizer.anonymize(
    text1,
    results1,
    {"DEFAULT": OperatorConfig("reanonymizer", {"entity_mapping": entity_mapping})}
)
 
results2 = analyzer.analyze(text=text2, language="en")
anon2 = anonymizer.anonymize(
    text2,
    results2,
    {"DEFAULT": OperatorConfig("reanonymizer", {"entity_mapping": entity_mapping})}
)
 
print(" Оригинал 1:", text1)
print(" Анонимизировано 1:", anon1.text)
print(" Оригинал 2:", text2)
print(" Анонимизировано 2:", anon2.text)
 
print("\n Используемая карта сопоставлений:")
pprint(entity_mapping)

Такой подход позволяет сохранять согласованность псевдонимизации в разных документах — важная функция для анализа данных и соблюдения требований конфиденциальности.

Presidio предоставляет гибкий и мощный инструмент для обнаружения и анонимизации PII, позволяя разработчикам надежно защищать чувствительную информацию с помощью настраиваемых процессов.

🇬🇧

Switch Language

Read this article in English

Switch to English