Landtage und Regierungen im Lexikon, Rang als Gleichstandsregel

Drei neue Spiegelabfragen schliessen die gemessene Luecke im
Akteurslexikon: landtage (1539), regierung (2003), sondergesandte (5).
Lexikon 5540 -> 8856 Akteure, Aufloesung 21,1 % -> 23,2 % ueber 5018
Items. Der Gewinn steckt in wenigen Personen - Siegmund 123, Witkoff
102, Kushner 93, Lawrow 21.

Drei Abfragen, weil Wikidata drei Wege verlangt:

  landtage        P31/P279*, nicht P279* - "Mitglied des Landtag
                  Sachsen-Anhalt" ist eine Instanz von Q1939559, keine
                  Unterklasse. Dazu ein schaerferer Datumsfilter: von
                  11464 je gewaehlten Personen tragen 9700 keinerlei
                  Zeitangabe, ein blosses "kein Ende gesetzt" liesse die
                  Weimarer Republik herein.
  regierung       P1308, Amt -> derzeitiger Inhaber. Ueber die Amtszeit
                  der Person faellt Lawrow (amtiert seit 2004) aus jedem
                  Datumsfenster, ohne Fenster kommen Tausende Minister
                  herein, deren Amtszeit nie zu Ende gepflegt wurde.
  sondergesandte  Der andere Weg, fuer Witkoff - sein Amt traegt kein
                  P1308. Beide Wege in einer Abfrage laufen in die
                  Zeitgrenze der WDQS.

Kushner steht in hand.json: sein Amt endete 2021, seine Rolle nicht.

Die Erweiterung hat zuerst Schaden angerichtet. Mit den Landtagen kamen
Janine und Heiner Merz ins Lexikon, "Merz" wurde mehrdeutig, und 125
Nennungen des Bundeskanzlers fielen aus. Aus jedem "Hamburg" wurde eine
Kultusministerin (22-mal), aus "KI" ein Nachname (16-mal). Daher sieben
neue Sperreintraege und eine dritte Regel in waehle(): traegt genau ein
Kandidat den niedrigsten Rang, gewinnt er. Der Rang kommt aus der
Spiegelabfrage, Staatsfuehrung vor Bundestag vor Landtag - keine
Wichtigkeitsordnung, sondern eine Erwartung darueber, wen eine deutsche
Schlagzeile mit blossem Nachnamen meint. Abschlag 0,15, Grund steht in
der Nutzlast. Die Amtstabelle bekommt den schlechtesten Rang: sie reicht
bis 1794 zurueck, mit Rang 0 wurde aus "Teufel" ein
Ministerpraesident a. D.

Dabei fiel ein Loch im Fingerabdruck auf: NACHNAMEN_SPERRE stand nicht
in EINSTELLUNGEN_FEST. Ein Eintrag mehr aenderte das Ergebnis von 4868
auf 4820 aufgeloeste Nennungen unter derselben coder_version - genau
der Fehler, den die Version verhindern soll. Sperrliste und Rangordnung
gehen jetzt als Hash ein.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
irrlicht
2026-09-08 12:11:56 +02:00
co-authored by Claude Opus 5
parent a2e62a7d5e
commit 3a9c000a0e
9 changed files with 21239 additions and 5 deletions
+68 -4
View File
@@ -87,6 +87,17 @@ NACHNAMEN_SPERRE = {
"zeit",
"spiegel",
"focus",
# Staedtenamen, die zugleich Nachnamen von Abgeordneten sind. Erst mit
# den Landtagen kamen sie ins Lexikon, und sofort wurde aus jedem
# "Hamburg" eine niedersaechsische Kultusministerin - 22-mal im Korpus
# vom 08.09.2026.
"hamburg", # Julia Willie Hamburg, MdL Niedersachsen
"rostock", # Clemens Rostock, MdL Brandenburg
"oldenburg", # Simone Oldenburg, MdL Mecklenburg-Vorpommern
"ki", # Ki-hong Nam - in deutschen Schlagzeilen die KI
"nothing", # Volker Nothing, MdL - sonst das englische Wort
"andrew", # Stuart Andrew, MP - sonst ein Vorname
"champagne", # Francois-Philippe Champagne - sonst das Getraenk
}
# Aliase, die Wikidata fuehrt, die in Schlagzeilen aber regelmaessig etwas
@@ -99,6 +110,37 @@ FORMEN_SPERRE = {
# entscheiden, und beide Lesarten sind haeufig.
}
# Rangordnung der Spiegelabfragen fuer den Gleichstandsfall. Sie ist eine
# Aussage darueber, wen eine deutsche Schlagzeile mit blossem Nachnamen
# meint, nicht darueber, wer wichtiger ist. Der Anlass ist messbar: mit den
# Landtagen kamen Janine und Heiner Merz ins Lexikon, und "Merz" war
# schlagartig mehrdeutig - 125 Nennungen des Bundeskanzlers fielen aus.
#
# Ein Rang entscheidet nur, wenn genau ein Kandidat den niedrigsten traegt.
# Bei Gleichstand innerhalb eines Rangs bleibt es beim Muenzwurfverbot.
RANG = {
"hand": 0,
"staatsfuehrung": 1,
"regierung": 1,
"sondergesandte": 1,
"bundestag": 2,
"landtage": 3,
# Die Amtstabelle reicht bis 1794 zurueck und besteht ueberwiegend aus
# Verstorbenen. Sie darf einen Gleichstand nicht gewinnen: sonst wird
# aus "Teufel" ein Ministerpraesident a.D. und aus "Otto" ein Bremer
# Buergermeister des 18. Jahrhunderts. Wer heute im Amt ist, steht
# ohnehin in einer der Personenabfragen.
"aemter": 5,
}
RANG_SONST = 4
def rang(quelle):
"""'wikidata:landtage@2026-09-08' -> 3."""
name = (quelle or "").split(":")[-1].split("@")[0]
return RANG.get(name, RANG_SONST)
EINSTELLUNGEN_FEST = {
"ner_modell": NER_MODELL,
"basis": "titel+teaser",
@@ -106,7 +148,16 @@ EINSTELLUNGEN_FEST = {
"ner_typen": list(TYPEN),
"typ_aus": "lexikon",
"fuzzy": "editierdistanz_nach_laenge",
"nachnamen": "eindeutig_oder_kontext",
"nachnamen": "eindeutig_kontext_rang",
"rang": "|".join(f"{k}={v}" for k, v in sorted(RANG.items())),
# Die Sperrliste gehoert in die Version, nicht nur in den Quelltext.
# Sie aendert das Ergebnis - ein Eintrag mehr, und aus 22 Nennungen
# der Hansestadt wird keine Ministerin mehr. Ohne sie im Fingerabdruck
# traegt dieselbe coder_version zwei verschiedene Auszaehlungen, und
# genau das soll die Version verhindern.
"nachnamen_sperre": hashlib.blake2b(
"|".join(sorted(NACHNAMEN_SPERRE)).encode(), digest_size=8
).hexdigest(),
}
_UMLAUTE = str.maketrans({"ä": "ae", "ö": "oe", "ü": "ue", "ß": "ss"})
@@ -238,10 +289,10 @@ class Lexikon:
def lade_lexikon(conn):
with conn.cursor() as k:
k.execute("select id, typ, name, aliase, land, rolle from akteure")
k.execute("select id, typ, name, aliase, land, rolle, quelle from akteure")
akteure = [
{"id": r[0], "typ": r[1], "name": r[2], "aliase": r[3],
"land": r[4], "rolle": r[5]}
"land": r[4], "rolle": r[5], "rang": rang(r[6])}
for r in k.fetchall()
]
k.execute("select amt_id, person_id, von, bis from amtsinhaber")
@@ -260,7 +311,8 @@ def waehle(lexikon, ids, kontext):
1. Ist genau einer gemeint, ist die Sache erledigt.
2. Wird die Partei eines Kandidaten im selben Item genannt, gewinnt er.
3. Sonst bleibt die Nennung unaufgeloest. Ein Muenzwurf waere hier der
3. Traegt genau einer den niedrigsten Rang, gewinnt er - siehe RANG.
4. Sonst bleibt die Nennung unaufgeloest. Ein Muenzwurf waere hier der
schlimmere Fehler, weil er in der Zeitreihe nicht auffaellt.
"""
if len(ids) == 1:
@@ -270,6 +322,11 @@ def waehle(lexikon, ids, kontext):
vergleichsform(lexikon.akteure[i]["notiz"]) in kontext]
if len(mit_partei) == 1:
return mit_partei[0], "kontext_partei"
beste = min(lexikon.akteure[i].get("rang", RANG_SONST) for i in ids)
vorn = [i for i in ids
if lexikon.akteure[i].get("rang", RANG_SONST) == beste]
if len(vorn) == 1:
return vorn[0], "rang"
return None, "mehrdeutig"
@@ -319,10 +376,17 @@ def aufloesen(lexikon, spannen, datum):
a = lexikon.akteure[gewaehlt]
konfidenz = {"alias": 0.95, "alias_ohne_anrede": 0.9,
"nachname": 0.8, "fuzzy": 0.6}[methode]
# Abschlaege fuer die Gleichstandsregeln. Der Rang ist die
# schwaechere der beiden: die Partei steht im Text, der Rang ist
# nur eine Erwartung darueber, wer gemeint sein duerfte.
if grund == "kontext_partei":
konfidenz -= 0.1
elif grund == "rang":
konfidenz -= 0.15
eintrag.update({"id": gewaehlt, "typ": a["typ"], "rolle": a["rolle"],
"methode": methode, "konfidenz": round(konfidenz, 2)})
if grund != "eindeutig":
eintrag["grund"] = grund
# Aemter gegen das Datum des Items aufloesen. Das Amt bleibt stehen,
# die Person kommt daneben - beides ist eine Aussage ueber den Text.