Antrag-Clustering: Netzwerk-Graph aehnlicher Antraege (Embedding-Naehe) #105

Closed
opened 2026-04-10 23:52:43 +02:00 by tobias · 3 comments
Owner

Aehnliche Antraege automatisch gruppieren via Embedding-Cosinus-Naehe.

Visualisierung

  • Netzwerk-Graph mit floatenden Antrag-Nodes
  • Elastische Verbindungen zwischen aehnlichen Antraegen
  • An der Kante: das verbindende Merkmal (z.B. 'Bildungspolitik', 'Klimaschutz')
  • Cluster-Beschreibungen als Labels
  • Inspiriert von Obsidian Graph View / Force-Directed Layout

Technik

  • Embedding-Vektoren der Antraege sind bereits ueber die Analyse vorhanden
  • Cosinus-Aehnlichkeit paarweise berechnen
  • d3.js force-directed graph oder vis.js
  • Klick auf Node oeffnet Assessment-Detail

Scope

Mittlerer Aufwand. Zuerst Backend (Aehnlichkeits-API), dann Frontend (Graph).

Aehnliche Antraege automatisch gruppieren via Embedding-Cosinus-Naehe. ## Visualisierung - Netzwerk-Graph mit floatenden Antrag-Nodes - Elastische Verbindungen zwischen aehnlichen Antraegen - An der Kante: das verbindende Merkmal (z.B. 'Bildungspolitik', 'Klimaschutz') - Cluster-Beschreibungen als Labels - Inspiriert von Obsidian Graph View / Force-Directed Layout ## Technik - Embedding-Vektoren der Antraege sind bereits ueber die Analyse vorhanden - Cosinus-Aehnlichkeit paarweise berechnen - d3.js force-directed graph oder vis.js - Klick auf Node oeffnet Assessment-Detail ## Scope Mittlerer Aufwand. Zuerst Backend (Aehnlichkeits-API), dann Frontend (Graph).
Author
Owner

Offene Frage (Claude-Loop)

Für Clustering brauche ich eine Embedding-Strategie. Zwei Optionen:

A) TF-IDF auf Titel+Themen+Fraktion — keine zusätzlichen API-Calls, läuft lokal, ~80% Qualität. MVP in 1–2h.

B) Echte Embeddings — neue Spalte assessments.summary_embedding (DashScope text-embedding-v3, ~0.0001€/Antrag, bei 1k Anträgen also ~0.10€ einmalig, bei jedem neuen Antrag ein zusätzlicher Call). Bessere semantische Nähe, ermöglicht auch #108.

Frage: A (MVP) oder B (gleich richtig)? Budget für B ok?

Antworte hier als Kommentar — ich lese bei jedem Loop-Tick neue Kommentare.

❓ **Offene Frage (Claude-Loop)** Für Clustering brauche ich eine Embedding-Strategie. Zwei Optionen: **A) TF-IDF auf Titel+Themen+Fraktion** — keine zusätzlichen API-Calls, läuft lokal, ~80% Qualität. MVP in 1–2h. **B) Echte Embeddings** — neue Spalte `assessments.summary_embedding` (DashScope text-embedding-v3, ~0.0001€/Antrag, bei 1k Anträgen also ~0.10€ einmalig, bei jedem neuen Antrag ein zusätzlicher Call). Bessere semantische Nähe, ermöglicht auch #108. **Frage:** A (MVP) oder B (gleich richtig)? Budget für B ok? Antworte hier als Kommentar — ich lese bei jedem Loop-Tick neue Kommentare.
Author
Owner

Embedding-Strategie entschieden: v4 für alles (Diskussion 2026-04-11). Migration wird in Issue #123 umgesetzt. Dieses Issue ist blockiert bis #123 gemerged.

Arbeitsschritte (nach #123):

  • Clustering-Modul app/clustering.py: sklearn AgglomerativeClustering über assessments.summary_embedding
  • Hierarchie: Cluster > Anträge, bei n>30 Untercluster (laut Wiki-Entscheidung)
  • API-Endpoint GET /api/clusters?wahlperiode=...&bundesland=...
  • UI: Netzwerk-Graph (d3.js oder vis.js), Cluster als Blasen, Anträge als Knoten, Kanten nach Cosine-Distance unter Schwellwert
  • Zoombar (Cluster → Anträge → Details)
  • Farbkodierung nach dominanter Fraktion im Cluster
Embedding-Strategie entschieden: **v4 für alles** (Diskussion 2026-04-11). Migration wird in Issue #123 umgesetzt. Dieses Issue ist blockiert bis #123 gemerged. **Arbeitsschritte (nach #123):** - [ ] Clustering-Modul `app/clustering.py`: sklearn AgglomerativeClustering über `assessments.summary_embedding` - [ ] Hierarchie: Cluster > Anträge, bei n>30 Untercluster (laut Wiki-Entscheidung) - [ ] API-Endpoint `GET /api/clusters?wahlperiode=...&bundesland=...` - [ ] UI: Netzwerk-Graph (d3.js oder vis.js), Cluster als Blasen, Anträge als Knoten, Kanten nach Cosine-Distance unter Schwellwert - [ ] Zoombar (Cluster → Anträge → Details) - [ ] Farbkodierung nach dominanter Fraktion im Cluster
Author
Owner

Live 2026-04-11

Clustering-Modul app/clustering.py:

  • Pure Python (kein sklearn/numpy Dep)
  • Union-Find über Cosine-Similarity-Kanten
  • Hierarchisches Clustering: Haupt-Threshold (default 0.55) + Subcluster-Threshold (0.70) bei Clustern > 30 Items
  • Empirisch kalibriert an Prod-Daten: 0.55 liefert 5 sinnvolle Cluster aus 57 Anträgen (Förderschulen, Klimaschutz, Schule/Lehrer, Pflege, Kita)

API:

  • GET /api/clusters?bundesland=...&threshold=...
  • Response: {meta, clusters: [{size, label, dominant_fraktion, avg_gwoe_score, drucksachen, subclusters}], singletons: []}

UI:

  • Neuer Mode-Button 🎯 Cluster im Haupt-Menü
  • Bundesland-Filter + Threshold-Slider (0.40-0.80)
  • Kollapsibles Cluster-Layout (Header → Liste der Anträge)
  • Klick auf Antrag → Sprung ins browse-Mode-Detail-Panel
  • Singletons separat ausklappbar

Test in Prod: https://gwoe.toppyr.de → "🎯 Cluster" klicken. 5 Cluster bei Default-Schwelle, Threshold-Slider live adjustable.

Schließe.

## Live 2026-04-11 ✅ **Clustering-Modul `app/clustering.py`:** - Pure Python (kein sklearn/numpy Dep) - Union-Find über Cosine-Similarity-Kanten - Hierarchisches Clustering: Haupt-Threshold (default 0.55) + Subcluster-Threshold (0.70) bei Clustern > 30 Items - Empirisch kalibriert an Prod-Daten: 0.55 liefert 5 sinnvolle Cluster aus 57 Anträgen (Förderschulen, Klimaschutz, Schule/Lehrer, Pflege, Kita) **API:** - `GET /api/clusters?bundesland=...&threshold=...` - Response: `{meta, clusters: [{size, label, dominant_fraktion, avg_gwoe_score, drucksachen, subclusters}], singletons: []}` **UI:** - Neuer Mode-Button `🎯 Cluster` im Haupt-Menü - Bundesland-Filter + Threshold-Slider (0.40-0.80) - Kollapsibles Cluster-Layout (Header → Liste der Anträge) - Klick auf Antrag → Sprung ins browse-Mode-Detail-Panel - Singletons separat ausklappbar **Test in Prod:** https://gwoe.toppyr.de → "🎯 Cluster" klicken. 5 Cluster bei Default-Schwelle, Threshold-Slider live adjustable. Schließe.
Sign in to join this conversation.
No description provided.