Zum Hauptinhalt springen

Methodik

parlhub listet nicht nur Datensätze auf: es berechnet Abstimmungsübereinstimmung, Fraktionstreue, Lobby-Netzwerke, Wortkarten und mehr auf Basis der offenen Daten. Diese Seite legt genau dar, wie jede Kennzahl entsteht, und verlinkt jede von ihnen zum Quellcode, der sie erzeugt.

Parlamente

Kennzahlen über eine ganze Kammer

Abstimmungsübereinstimmung

Für jedes Mitgliederpaar, das in denselben Abstimmungen votiert hat, ist die Übereinstimmung der Anteil der gemeinsamen Abstimmungen, in denen beide gleich stimmten (Ja, Nein, Enthaltung oder abwesend), wobei abwesend zu abwesend passt. Ein Mitglied braucht mindestens 20 gewertete Abstimmungen, ein Paar mindestens 20 gemeinsame. Die Partei-Heatmap mittelt diese paarweisen Übereinstimmungen über jedes ungeordnete Parteipaar (mit einer 95-%-Konfidenz-Halbbreite von 1,96·σ/√n). Der Streuplot bringt die Übereinstimmungsmatrix per klassischer multidimensionaler Skalierung in zwei Dimensionen: Distanzen d = 1 − Übereinstimmung werden doppelt zentriert zu B, nach B + σI verschoben (Gershgorin-Schranke), damit die Matrix positiv semidefinit ist, und die beiden positivsten Eigenvektoren liefern die Koordinaten. Das Layout ist deterministisch initialisiert und wackelt daher zwischen Neuladen nie.

Wie es berechnet wird
agreement(a,b) = |{ ballots where vote_a = vote_b }| / |shared(a,b)|
distance      d = 1 − agreement
B  = −½ · J · (D∘D) · J            (double-centred squared distances)
B' = B + σ·I,   σ = maxᵢ Σⱼ |Bᵢⱼ|   (Gershgorin PSD shift)
coords = 2 most-positive eigenvectors of B'

Fraktionstreue & Geschlossenheit

Für jede Abstimmung ist die Linie einer Fraktion die Position (Ja, Nein oder Enthaltung), die eine strikte Mehrheit ihrer Stimmenden einnahm; Gleichstände und Fraktionen mit weniger als 4 Stimmenden in dieser Abstimmung werden nicht gewertet. Ein Mitglied weicht ab, sobald sein Votum von der Fraktionslinie abweicht; seine Abweichungsrate ist Abweichungen ÷ gewertete Abstimmungen (Mitglieder mit weniger als 10 gewerteten Abstimmungen fallen weg). Verwendet wird die Fraktion zum Abstimmungszeitpunkt, ersatzweise die aktuelle Partei des Mitglieds, wo kein Schnappschuss vorliegt (z. B. Liechtenstein). Die Geschlossenheit einer Fraktion ist der mittlere Agreement-Index (Hix–Noury–Roland) über ihre Abstimmungen: 1, wenn eine Fraktion geschlossen stimmt, 0 bei gleichmässiger Dreiteilung.

Wie es berechnet wird
group line      = strict plurality of {yes, no, abstain}   (≥ 4 voters, no tie)
dissent_rate(m) = dissents(m) / scored_ballots(m)           (m needs ≥ 10 ballots)
cohesion (AI)   = [ max(Y,N,A) − ½·((Y+N+A) − max(Y,N,A)) ] / (Y+N+A)

Lobby-Netzwerk

Mitglieder und die Organisationen, die sie im Interessenregister angeben, bilden einen bipartiten Graphen; behalten werden nur Organisationen mit mindestens 2 verbundenen Mitgliedern, sodass das Bild geteilte Verbindungen statt isolierter Mandate zeigt. Jede angegebene Verbindung wird als bezahlt, unbezahlt oder unbekannt klassifiziert (zuerst über den harmonisierten Code, dann über einen deutschen / französischen / italienischen Text-Fallback), und bezahlt geht vor unbezahlt vor unbekannt, wenn ein Mitglied mehrere Verbindungen zu einer Organisation hat. Das Netzwerk wird mit einer deterministischen Fruchterman-Reingold-Kraftsimulation angeordnet: ideale Kantenlänge k = √(Fläche/n), Abstossung k²/Distanz, Anziehung Distanz²/k, über 300 abkühlende Iterationen. Es wird kein Zufall verwendet, der Graph bleibt daher über Neuladen stabil.

Wie es berechnet wird
graph     = members ↔ organisations declared by ≥ 2 members
k         = √(area / n)                    (ideal edge length)
repulsion = k² / distance,   attraction = distance² / k
layout    = 300 Fruchterman–Reingold iterations, cooling ×0.985

Debatten-Skalierung (Wordfish)

Reden aller aktiven Mitglieder über ein gemeinsames Zeitfenster werden pro Sprache tokenisiert und um Stoppwörter bereinigt, dann auf ein Wortzähl-Dokument je Mitglied reduziert. Wordfish (Slapin & Proksch 2008) passt ein Poisson-Modell E[y] = exp(α + ψ + β·θ) durch abwechselnde Poisson-Regressionen an und verortet jede Rednerin und jeden Redner allein anhand der Wortwahl auf einer einzigen latenten Skala θ: α ist die Redseligkeit, ψ die Häufigkeit eines Wortes und β, wie scharf ein Wort trennt. Die Anpassung ist gehärtet (begrenzt, mit Schritthalbierung, Ridge-regularisiert) und deterministisch initialisiert. η² (der Anteil der θ-Varianz, den die Partei erklärt) steht daneben, und die Achse nutzt eine robuste 2.–98.-Perzentil-Spanne, damit einige wenige wortarme Redner mit hoher Varianz den Massstab nicht bestimmen.

Wie es berechnet wird
E[y_ij] = exp( α_i + ψ_j + β_j · θ_i )      (Wordfish, Poisson)
  θ_i = speaker position    α_i = talkativeness
  ψ_j = word frequency      β_j = word discrimination
η²  = SS_between(party) / SS_total          (θ variance explained by party)

Personen

Kennzahlen für ein einzelnes Mitglied

Wortschatz (Worthäufigkeit)

Jedes Redetranskript eines Mitglieds wird von HTML befreit, kleingeschrieben und an Nicht-Buchstaben in Tokens von mehr als einem Zeichen zerlegt (Akzente bleiben, Ziffern und Satzzeichen fallen weg). Jedes Token wird gegen die Stoppwortliste der jeweiligen Sprache der Rede gefiltert, sodass die deutschen und französischen Reden eines zweisprachigen Mitglieds mit der richtigen Liste bereinigt werden. Ergebnis sind die häufigsten Wörter des Mitglieds (die Top 120 mit einer Häufigkeit von mindestens 2, über ein optionales Zeitfenster), gezeichnet als squarified Treemap, dimensioniert nach Häufigkeit.

Wie es berechnet wird
tokens = lowercase(strip_html(text)) split on [^\p{L}]+,  length > 1
keep   = tokens NOT IN stopwords[ speech language ]
result = top 120 words with count ≥ 2   →   squarified treemap

Abstimmungsnachbarn

Dies ist die paarweise Hälfte der Abstimmungsübereinstimmung, aus Sicht eines Mitglieds: über die Abstimmungen, in denen beide votierten, ist die Übereinstimmung mit jedem anderen Mitglied Treffer ÷ gemeinsame Abstimmungen (abwesend passt zu abwesend). Paare mit weniger als 10 gemeinsamen Abstimmungen werden als Rauschen ausgeblendet, und die Liste lässt sich auf einen Zeitraum eingrenzen. Anders als beim Parlaments-Streuplot wird keine Dimensionsreduktion angewendet. Es ist eine gereihte Nachbarliste.

Wie es berechnet wird
agreement(subject, other) = matches / shared_ballots   (absent = absent)
keep pairs with shared_ballots ≥ 10   →   ranked neighbour list
Wo es erscheint
  • /people/:id/alignment

Interessen-Klassifikation

Jeder Eintrag im Interessenregister wird als bezahlt, unbezahlt oder unbekannt eingeordnet: Zuerst zählt der harmonisierte Zahlungscode (unbezahlt und ehrenamtlich gelten beide als unbezahlt), sonst liest ein deutscher / französischer / italienischer Stichwort-Fallback den Freitext. Einträge werden nach normalisiertem Organisationsnamen gruppiert, um die Mandate eines Mitglieds je Organisation zusammenzufassen. Dieselbe Regel speist die Aufteilung bezahlt / unbezahlt im Lobby-Netzwerk.

Wie es berechnet wird
class = paid    if harmonised code = paid
        unpaid  if code ∈ {unpaid, honorary}   else de/fr/it text match
        else unknown        (paid ≻ unpaid ≻ unknown, per organisation)

Abstimmungen

Wie eine einzelne Abstimmung gezeichnet wird

Abstimmungs-Halbkreis

Der Sitzbogen wird im Browser berechnet: Ringe werden hinzugefügt, bis sie alle Stimmenden fassen, die Sitze werden per Restausgleich (largest remainder), gewichtet nach Ringradius, auf die Ringe verteilt, und jeder Sitz wird auf seinem Bogen platziert und von links nach rechts sortiert. Koordinaten werden auf zwei Nachkommastellen gerundet, damit Server und Client identisch rendern und die Hydration nie abweicht. Parteien werden nach absteigender Mitgliederzahl aus einer festen Palette eingefärbt, und der Bogen wird nur gezeichnet, wenn mindestens 80 % der Stimmenden einen bekannten Sitz haben.

Wie es berechnet wird
rings grown until Σ capacity ≥ N voters
seats per ring = largest-remainder allocation weighted by ring radius
coordinates rounded to 2 dp   (identical SSR + client render)

Die Website selbst

Betriebskennzahlen

Zugriffsstatistik

Zugriffsprotokolle werden zu unveränderlichen Tages-Faktenzeilen zusammengefasst (eine je Periode, Route, Sprache, Besucherklasse und Gerät) mit additiven Zählern (Anfragen, summierte und maximale Latenz) und einem Latenz-Histogramm mit acht Klassen; Tage älter als 90 werden auf Monatskörnung verdichtet. Das Dashboard aggregiert diese clientseitig neu: Zähler und Maxima lassen sich direkt zusammenführen, der Mittelwert wird als summierte Latenz ÷ Anfragen abgeleitet und das 95. Perzentil aus dem Histogramm genähert (die Obergrenze der Klasse, die die 95. Anfrage enthält), weil sich echte Mittelwerte und Perzentile nicht aus gespeicherten Summen neu zusammenführen lassen. User-Agents werden einmalig beim Verdichten in Besucherklasse und Gerät eingeordnet, damit die Regeln revidierbar bleiben.

Wie es berechnet wird
fact = (period, route, lang, visitor, device) → reqs, sum_ms, max_ms, hist[8]
avg  = sum_ms / reqs
p95  ≈ upper edge of the latency bucket holding the 95th request