Die Themenmodellierung bleibt ein kritisches Device in der KI- und NLP -Toolbox. Während Großsprachenmodelle (LLMs) den Textual content außergewöhnlich intestine verarbeiten und hochrangige Themen aus massiven Datensätzen extrahieren müssen, erfordert immer noch dedizierte Themenmodellierungstechniken. Ein typischer Workflow enthält vier Kernschritte: Einbettung, Dimensionalitätsreduzierung, Clusterbildung und Themendarstellung.

Frameworks heute ist Bertopicwas jede Stufe mit modularen Komponenten und einer intuitiven API vereinfacht. In diesem Beitrag werde ich praktische Anpassungen durchgehen, die Sie vornehmen können, um die Clustering-Ergebnisse zu verbessern und die Interpretierbarkeit basierend auf praktischen Experimenten mithilfe der Verwendung zu steigern Open-Supply 20 Newsgroups-Datensatzdie unter der Inventive Commons Attribution 4.0 Worldwide Lizenz verteilt ist.

Projektübersicht

Wir beginnen mit den in der Dokumentation von Bertopic empfohlenen Standardeinstellungen und aktualisieren bestimmte Konfigurationen schrittweise, um deren Effekte hervorzuheben. Unterwegs werde ich den Zweck jedes Moduls erläutern und wie man fundierte Entscheidungen beim Anpassen trifft.

Datensatzvorbereitung

Wir laden ein Beispiel von 500 Nachrichtendokumenten.

import random
from datasets import load_dataset
dataset = load_dataset("SetFit/20_newsgroups")
random.seed(42)
text_label = record(zip(dataset("practice")("textual content"), dataset("practice")("label_text")))
text_label_500 = random.pattern(text_label, 500)

Da die Daten aus lässigen Ussenet -Diskussionen stammen, wenden wir Reinigungsschritte an, um Header zu entfernen, Unordnung zu entfernen und nur informative Sätze zu bewahren.

Diese Vorverarbeitung sorgt für höherwertige Einbettungen und einen glatteren stromabwärts gelegenen Clustering-Prozess.

import re

def clean_for_embedding(textual content, max_sentences=5):
    traces = textual content.break up("n")
    traces = (line for line in traces if not line.strip().startswith(">"))
    traces = (line for line in traces if not re.match
            (r"^s*(from|topic|group|traces|writes|article)s*:", line, re.IGNORECASE))
    textual content = " ".be part of(traces)
    textual content = re.sub(r"s+", " ", textual content).strip()
    textual content = re.sub(r"(!?){3,}", "", textual content)
    sentence_split = re.break up(r'(?<=(.!?)) +', textual content)
    sentence_split = (
        s for s in sentence_split
        if len(s.strip()) > 15 and never s.strip().isupper()
    )
    return " ".be part of(sentence_split(:max_sentences))
texts_clean = (clean_for_embedding(textual content) for textual content,_ in text_label_500)
labels = (label for _, label in text_label_500)

Erstbertopische Pipeline

Mit dem modularen Design von Bertopic konfigurieren wir jede Komponente: Sentetransformer für Einbettung, UMAP für die Reduzierung der Dimensionalität, HDBSCAN für Clustering und CountVectorizer + Keybert für die Themendarstellung. Dieses Setup liefert nur wenige breite Themen mit lauten Darstellungen, was die Notwendigkeit einer Feinabstimmung hervorhebt, um kohärentere Ergebnisse zu erzielen.

from bertopic import BERTopic
from umap import UMAP
from hdbscan import HDBSCAN
from sentence_transformers import SentenceTransformer

from sklearn.feature_extraction.textual content import CountVectorizer
from bertopic.vectorizers import ClassTfidfTransformer
from bertopic.illustration import KeyBERTInspired

# Step 1 - Extract embeddings
embedding_model = SentenceTransformer("all-MiniLM-L6-v2")

# Step 2 - Cut back dimensionality
umap_model = UMAP(n_neighbors=10, n_components=5, min_dist=0.0, metric='cosine', random_state=42)

# Step 3 - Cluster lowered embeddings
hdbscan_model = HDBSCAN(min_cluster_size=15, metric='euclidean', cluster_selection_method='eom', prediction_data=True)

# Step 4 - Tokenize subjects
vectorizer_model = CountVectorizer(stop_words="english")

# Step 5 - Create subject illustration
ctfidf_model = ClassTfidfTransformer()

# Step 6 - (Non-obligatory) Wonderful-tune subject representations with
# a `bertopic.illustration` mannequin
representation_model = KeyBERTInspired()

# All steps collectively
topic_model = BERTopic(
  embedding_model=embedding_model,          # Step 1 - Extract embeddings
  umap_model=umap_model,                    # Step 2 - Cut back dimensionality
  hdbscan_model=hdbscan_model,              # Step 3 - Cluster lowered embeddings
  vectorizer_model=vectorizer_model,        # Step 4 - Tokenize subjects
  ctfidf_model=ctfidf_model,                # Step 5 - Extract subject phrases
  representation_model=representation_model # Step 6 - (Non-obligatory) Wonderful-tune subject representations
)
subjects, probs = topic_model.fit_transform(texts_clean)

Dieses Setup liefert nur ein paar breite Themen mit lauten Darstellungen. Dieses Ergebnis unterstreicht die Notwendigkeit von Finetuning, um kohärentere Ergebnisse zu erzielen.

Bild vom Autor generiert
Authentic entdeckte Themen (Bild erzeugt vom Autor)

Parameterabstimmung für körnige Themen

N_Neighbors aus dem UMAP -Modul

Umap ist das Dimensionality -Reduktionsmodul, um die Einbettung von Ursprungs in einen niedrigeren Dimensionsvektor zu verringern. Durch die Anpassung von UMAPs N_Neighbors steuern wir, wie lokal oder world die Daten während der Reduzierung der Dimensionalität interpretiert werden. Die Senkung dieses Wertes deckt feinere Cluster auf und verbessert die Unterscheidungskraft des Themas.

umap_model_new = UMAP(n_neighbors=5, n_components=5, min_dist=0.0, metric='cosine', random_state=42)
topic_model.umap_model = umap_model_new
subjects, probs = topic_model.fit_transform(texts_clean)
topic_model.get_topic_info()
Bild vom Autor generiert
Themen, die nach dem Einstellen des N_Neighbors -Parameters der UMAP entdeckt wurden (Bild erzeugt vom Autor)

min_cluster_size und cluster_selection_method aus dem HDBSCAN -Modul

Hdbscan ist das Clustering -Modul standardmäßig für Bertopic eingestellt. Durch Ändern von HDBSCANs min_cluster_size und Umstellung des Cluster_Selection_Method von „EOM“ auf „Blatt“ schärfen die Themenauflösung weiter. Diese Einstellungen können kleinere, fokussiertere Themen aufdecken und die Verteilung über Cluster hinweg ausgleichen.

hdbscan_model_leaf = HDBSCAN(min_cluster_size=5, metric='euclidean', cluster_selection_method='leaf', prediction_data=True)
topic_model.hdbscan_model = hdbscan_model_leaf
subjects, _ = topic_model.fit_transform(texts_clean)
topic_model.get_topic_info()

Die Anzahl der Cluster erhöht sich auf 30, indem Cluster_Selection_Method auf Blatt und min_cluster_size auf 5 festgelegt wird.

Bild vom Autor generiert
Themen, die nach Einstellung der zugehörigen Parameter von HDBSCAN entdeckt wurden (Bild erzeugt vom Autor)

Zufälligkeit der Reproduzierbarkeit kontrollieren

UMAP ist von Natur aus nicht deterministisch, was bedeutet, dass es bei jedem Lauf unterschiedliche Ergebnisse erzielen kann, es sei denn, Sie legen explizit einen festen random_state fest. Dieses Element wird häufig in Beispielcode weggelassen. Achten Sie daher darauf, dass es die Reproduzierbarkeit gewährleistet.

In ähnlicher Weise, wenn Sie eine API von Drittanbitten verwenden (wie OpenAI), sollten Sie vorsichtig sein. Einige APIs führen geringfügige Abweichungen bei wiederholten Aufrufen ein. Bei reproduzierbaren Ausgängen Einbettungen und Futtermittel direkt in Bertopic.

from bertopic.backend import BaseEmbedder
import numpy as np
class CustomEmbedder(BaseEmbedder):
    """Lightweight wrapper to name NVIDIA's embedding endpoint by way of OpenAI SDK."""

    def __init__(self, embedding_model, consumer):
        tremendous().__init__()
        self.embedding_model = embedding_model
        self.consumer = consumer

    def encode(self, paperwork):  # kind: ignore(override)
        response = self.consumer.embeddings.create(
            enter=paperwork,
            mannequin=self.embedding_model,
            encoding_format="float",
            extra_body={"input_type": "passage", "truncate": "NONE"},
        )
        embeddings = np.array((embed.embedding for embed in response.information))
        return embeddings
topic_model.embedding_model = CustomEmbedder()
subjects, probs = topic_model.fit_transform(texts_clean, embeddings=embeddings)

Für jede Datensatzdomäne ist möglicherweise unterschiedliche Clustering -Einstellungen für optimale Ergebnisse erforderlich. Um das Experimentieren zu optimieren, sollten Sie die Bewertungskriterien definieren und den Tuning -Prozess automatisieren. Für dieses Tutorial verwenden wir die Cluster -Konfiguration, die N_Neighbors auf 5, min_cluster_size auf 5 und cluster_Selection_method an „EOM“ festlegt. Dies ist eine Kombination, die ein Gleichgewicht zwischen Granularität und Kohärenz trifft.

Verbesserung von Themenrepräsentationen

Die Darstellung spielt eine entscheidende Rolle bei der interpretierbaren Auseinandersetzung mit Clustern. Standardmäßig erzeugt Bertopic Unigrammbasis Darstellungen, denen häufig ein ausreichender Kontext fehlt. Im nächsten Abschnitt werden wir verschiedene Techniken untersuchen, um diese Darstellungen zu bereichern und die Interpretierbarkeit der Themen zu verbessern.

Ngram

N-Gramm-Reichweite

In Bertopic ist CountVectorizer das Commonplace-Device zum Umwandeln von Textdaten in Darstellungen von Wörtern. Anstatt sich auf generische Unigramme zu verlassen, wechseln Sie zu Bigrams oder Trigramme Verwenden von ngram_range in countVectorizer. Diese einfache Änderung fügt einen dringend benötigten Kontext hinzu.

Da wir nur die Darstellung aktualisieren, bietet Bertopic die Funktion update_topics an, um zu vermeiden, dass die Modellierung erneut wiederholt wird.

topic_model.update_topics(texts_clean, vectorizer_model=CountVectorizer(stop_words="english", ngram_range=(2,3)))
topic_model.get_topic_info()
Bild vom Autor generiert
Themen Darstellungen mit Bigrams (Bild generiert vom Autor)

Benutzerdefinierte Tokenizer

Einige Bigrams sind immer noch schwer zu interpretieren, z. benutzerdefinierte Tokenizer Das filtert N-Gramm basierend auf Teil der Sprachmuster. Dies beseitigt bedeutungslose Kombinationen und erhöht die Qualität Ihres Themas.

import spacy
from typing import Checklist

class ImprovedTokenizer:
    def __init__(self):
        self.nlp = spacy.load("en_core_web_sm", disable=("parser", "ner"))
        self.MEANINGFUL_BIGRAMS = {
            ("ADJ", "NOUN"),
            ("NOUN", "NOUN"),
            ("VERB", "NOUN"),
        }
    # Preserve solely probably the most significant syntactic bigram patterns
    def __call__(self, textual content: str, max_tokens=200) -> Checklist(str):
        doc = self.nlp(textual content(:3000))  # truncate lengthy docs for velocity
        tokens = ((t.textual content, t.lemma_.decrease(), t.pos_) for t in doc if t.is_alpha)
       
        bigrams = ()
        for i in vary(len(tokens) - 1):
            word1, lemma1, pos1 = tokens(i)
            word2, lemma2, pos2 = tokens(i + 1)
            if (pos1, pos2) in self.MEANINGFUL_BIGRAMS:
                # Optionally lowercase each phrases to normalize
                bigrams.append(f"{lemma1} {lemma2}")
       
        return bigrams
topic_model.update_topics(docs=texts_clean,vectorizer_model=CountVectorizer(tokenizer=ImprovedTokenizer()))
topic_model.get_topic_info()
Bild vom Autor generiert
Themen Darstellungen, die unordentliche Bigrams entfernt (Bild erzeugt vom Autor)

Llm

Schließlich kannst du LLMs integrieren Um kohärente Titel oder Zusammenfassungen für jedes Thema zu generieren. Bertopic unterstützt die OpenAI -Integration direkt oder durch benutzerdefinierte Aufforderung. Diese LLM-basierten Zusammenfassungen verbessern die Erklärung drastisch.

import openai
from bertopic.illustration import OpenAI

consumer = openai.OpenAI(api_key=os.environ("OPENAI_API_KEY"))
topic_model.update_topics(texts_clean, representation_model=OpenAI(consumer, mannequin="gpt-4o-mini", delay_in_seconds=5))
topic_model.get_topic_info()

Die Darstellungen sind jetzt alle sinnvollen Sätze.

Bild vom Autor generiert
Themen Darstellungen, die LLM-generierte Sätze sind (Bild, das vom Autor generiert wird)

Sie können auch Ihre eigene Funktion zum Erhalten des von LLM generierten Titels schreiben und ihn mithilfe von UPDATE_TOPIC_LABELS-Funktion auf das Themenmodellobjekt aktualisieren. Weitere Informationen finden Sie im folgenden Beispielcode -Snippet.

import openai
from typing import Checklist
def generate_topic_titles_with_llm(
    topic_model,
    docs: Checklist(str),
    api_key: str,
    mannequin: str = "gpt-4o"
) -> Dict(int, Tuple(str, str)):
    consumer = openai.OpenAI(api_key=api_key)
    topic_info = topic_model.get_topic_info()
    topic_repr = {}
    subjects = topic_info(topic_info.Matter != -1).Matter.tolist()

    for subject in tqdm(subjects, desc="Producing titles"):
        indices = (i for i, t in enumerate(topic_model.topics_) if t == subject)
        if not indices:
            proceed
        top_doc = docs(indices(0))

        immediate = f"""You're a useful summarizer for subject clustering.
        Given the next textual content that represents a subject, generate:
        1. A brief **title** for the subject (2–6 phrases)
        2. A one or two sentence **abstract** of the subject.
        Textual content:
        """
        {top_doc}
        """
        """

        attempt:
            response = consumer.chat.completions.create(
                mannequin=mannequin,
                messages=(
                    {"function": "system", "content material": "You're a useful assistant for summarizing subjects."},
                    {"function": "person", "content material": immediate}
                ),
                temperature=0.5
            )
            output = response.decisions(0).message.content material.strip()
            traces = output.break up('n')
            title = traces(0).substitute("Title:", "").strip()
            abstract = traces(1).substitute("Abstract:", "").strip() if len(traces) > 1 else ""
            topic_repr(subject) = (title, abstract)
        besides Exception as e:
            print(f"Error with subject {subject}: {e}")
            topic_repr(subject) = ("(Error)", str(e))

    return topic_repr

topic_repr = generate_topic_titles_with_llm( topic_model, texts_clean, os.environ("OPENAI_API_KEY"))
topic_repr_dict = {
    subject: topic_repr.get(subject, "Matter")
    for subject in subject.get_topic_info()("Matter")
 }
topic_model.set_topic_labels(topic_repr_dict)

Abschluss

In diesem Leitfaden wurden umsetzbare Strategien beschrieben, um die Ergebnisse der Themenmodellierung mit Bertopic zu steigern. Durch das Verständnis der Rolle jedes Moduls und der Tuning -Parameter für Ihre spezifische Domäne können Sie fokussiertere, stabilere und interpretierbare Themen erreichen.

Repräsentation ist genauso wichtig wie das Clustering. Ob durch N-Gramm, syntaktische Filterung oder LLMs, das Investieren in bessere Darstellungen erleichtert Ihre Themen in der Praxis einfacher und nützlicher.

Bertopic bietet außerdem fortschrittliche Modellierungstechniken über die hier behandelten Grundlagen hinaus. In einem zukünftigen Beitrag werden wir diese Funktionen ausführlich untersuchen. Bleiben Sie dran!

Von admin

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert