Die Hälfte Ihrer gewichteten Liste ist nicht gewichtet
Eine gewichtete Liste, in der die Hälfte der Zeilen dasselbe Mindestgewicht trägt, ist keine gewichtete Liste. Sie ist eine uniforme Liste mit einem gewichteten Präfix — und nichts in der Datei, im Schema oder in der Testsuite sagt das.
Wir betrieben genau so eine. In einem Korpus schwedischer Vornamen saßen 997 von 1.865 weiblichen Einträgen (53,5 %) und 1.115 von 2.015 männlichen Einträgen (55,3 %) auf Gewicht 1. Ihre wahren Häufigkeiten waren nicht gleich und nicht annähernd gleich: innerhalb dieses eingeebneten Blocks liefen die echten Zählungen von 36 bis 567 bei den Frauen und von 31 bis 479 bei den Männern. Ein Name, den 567 Menschen tragen, wurde genau so oft gezogen wie ein Name, den 36 tragen.
Die Datei war valide. Die Gewichte summierten sich korrekt. Die Zeilen waren absteigend sortiert. Jeder Validator lief mit null Fehlern und null Warnungen durch. Nach jeder Prüfung, die wir hatten, sah die Liste aus wie eine ordentlich gewichtete Liste.
Der Mechanismus: ein Byte
Die Gewichte waren in den Bereich 1–255 quantisiert worden, damit jedes in ein Byte passt. Die Transformation ist die naheliegende:
weight = round(count * CEILING / max_count)
if (weight < 1) weight = 1 // never drop a row entirely
Das erzeugt einen Bucket der Breite max_count / CEILING. Jeder Eintrag kleiner als ein halber Bucket rundet auf null und wird dann auf 1 geklemmt; jeder Eintrag kleiner als anderthalb Buckets rundet ebenfalls auf 1. Also landet alles unterhalb von 1.5 * max_count / CEILING auf dem Boden, ununterscheidbar.
In unseren Daten war die größte weibliche Zählung 96.428. Ein Bucket ist daher 96.428 / 255 = 378,1, und die Kollapsschwelle ist 1,5 × 378,1 = 567,2. Die größte echte Zählung, die auf Gewicht 1 gefunden wurde, war 567. Der Mechanismus ist nicht erschlossen; er reproduziert die Grenze auf die Ziffer genau.
Die Umkehrung der Abbildung zeigt die Form deutlich:
| Gespeichertes Gewicht | Zeilen | Echte Zählungen, min | Echte Zählungen, max | Mittel | Lineare Vorhersage (w * max / 255) |
|---|---|---|---|---|---|
| 1 | 997 | 36 | 567 | 318 | 378 |
| 2 | 269 | 568 | 938 | 727 | 756 |
| 3 | 113 | 946 | 1.320 | 1.115 | 1.134 |
| 4 | 87 | 1.326 | 1.698 | 1.492 | 1.513 |
| 5 | 40 | 1.705 | 2.070 | 1.870 | 1.891 |
| 10 | 15 | 3.626 | 3.965 | 3.793 | 3.781 |
| 50 | 3 | 18.766 | 19.055 | 18.921 | 18.907 |
| 100 | 1 | 37.922 | 37.922 | 37.922 | 37.815 |
| 255 | 1 | 96.428 | 96.428 | 96.428 | 96.428 |
Der Kopf der Liste ist in Ordnung. Gewicht 255 hält genau einen Namen; Gewicht 100 hält einen; Gewicht 50 hält drei. Der Kopf ist mit im Wesentlichen voller Präzision abgebildet. Jedes bisschen des Schadens sitzt am Boden, wo die Buckets breiter sind als der gesamte verbleibende Bereich.
Die Größe des Schadens wird vom einzelnen größten Eintrag bestimmt
Das ist der Teil, der den Defekt schwer vorhersehbar macht, und er verallgemeinert sich auf jede Quantisierung mit fester Obergrenze.
Die Kollapsschwelle ist 1.5 * max / CEILING. Sie hängt nicht davon ab, wie viele Zeilen Sie haben, wie schief der Schwanz ist oder wie sorgfältig Sie ihn gebaut haben. Sie hängt von einer Zahl ab: dem größten Wert in der Liste. Das populärste Element in Ihren Daten entscheidet, wie viel vom Rest Ihrer Daten aufhört, als unterscheidbar zu existieren.
Wir haben das direkt gemessen, indem wir die obersten K Zeilen verworfen und den Rest bei derselben Obergrenze von 255 neu quantisiert haben:
| Entfernte Spitzenzeilen | Neues Maximum | Auf den Boden kollabierte Zeilen |
|---|---|---|
| 0 | 96.428 | 997 von 1.865 (53,5 %) |
| 1 | 82.976 | 909 von 1.864 (48,8 %) |
| 2 | 78.280 | 866 von 1.863 (46,5 %) |
| 5 | 50.763 | 525 von 1.860 (28,2 %) |
| 10 | 37.922 | 220 von 1.855 (11,9 %) |
| 20 | 30.219 | 14 von 1.845 (0,8 %) |
| 50 | 18.766 | 6 von 1.815 (0,3 %) |
Zwanzig Zeilen von 1.865 — ein Prozent der Datei — sind dafür verantwortlich, dass die anderen 53,5 % eingeebnet werden. Wenn Sie irgendetwas Zipf-förmiges quantisieren — wozu Namen, Wörter, Städte, Produkte, Fehlercodes und nahezu jede Häufigkeitstabelle gehören, die irgendjemand ausliefert —, ist das Ihre Lage. Das Verhältnis, das Sie abbilden müssen, ist max / min, und für diese Liste ist es 2.679. Ein Byte bietet 255 Stufen. Die Arithmetik war verloren, bevor irgendjemand die Transformation wählte.
Der andere Hebel ist die Obergrenze selbst, und sie ist brutal nichtlinear:
| Obergrenze | Kollapsschwelle | Zeilen am Boden | Erzeugte verschiedene Gewichte |
|---|---|---|---|
| 15 | 9.642,8 | 94,2 % | 12 |
| 31 | 4.665,9 | 88,6 % | 20 |
| 63 | 2.295,9 | 82,1 % | 33 |
| 127 | 1.138,9 | 71,3 % | 54 |
| 255 | 567,2 | 53,5 % | 86 |
| 511 | 283,1 | 25,5 % | 127 |
| 1.023 | 141,4 | 0,4 % | 181 |
| 4.095 | 35,3 | 0,0 % | 357 |
Der Schritt von 255 auf 1.023 — von einem Byte auf zehn Bit — bringt den Kollaps von 53,5 % auf 0,4 %. Die Kosten des Defekts und die Kosten der Behebung sind wild asymmetrisch, was zu wissen sich lohnt, bevor Sie einen Nachmittag mit dem Streit darüber verbringen, ob der Schwanz eine Rolle spielt.
Warum nichts es auffing
Hier ist die unbequeme Hälfte der Geschichte. Wir haben die Liste neu vermessen, nachdem wir die quantisierten Gewichte durch die echten Zählungen ersetzt hatten, und nahezu jede zusammenfassende Kennzahl, zu der man greifen würde, sagt, dass nichts geschehen ist:
| Kennzahl | Quantisiert | Echte Zählungen |
|---|---|---|
| Massenanteil der Top-10-Namen | 13,05 % | 13,28 % |
| Namen bis zur halben Gesamtmasse | 92 | 89 |
| Effektive Anzahl der Alternativen (Perplexität) | 542 | 514 |
| Totale Variationsdistanz zwischen beiden | — | 2,45 % |
Der Top-10-Anteil bewegte sich um 0,2 Prozentpunkte. Die Perplexität bewegte sich um 5 %. Die totale Variationsdistanz zwischen der kaputten Verteilung und der korrekten liegt unter zweieinhalb Prozent. Wenn Ihr Abnahmetest lautet „sieht die aggregierte Form richtig aus", besteht die kaputte Datei ihn, und sie besteht ihn überzeugend.
Sie besteht, weil aggregierte Maße vom Kopf dominiert werden, und der Kopf wurde nie beschädigt. Der Schwanz hält 8,34 % der Wahrscheinlichkeitsmasse in der kaputten Version gegen 7,14 % in der korrekten. Fehler, die auf 8 % der Masse beschränkt sind, können eine zusammenfassende Kennzahl nicht stark bewegen, egal wie falsch sie innerhalb dieser 8 % sind.
Aber sehen Sie, was darin falsch ist. Wir haben zufällige Namenspaare gezogen und gefragt, wie oft zwei Namen mit tatsächlich verschiedenen Häufigkeiten dasselbe Gewicht zugewiesen bekommen hatten: 31,1 % aller Paare bei den Frauen, 33,2 % bei den Männern. Ein Drittel der Liste verlor seine Ordnung vollständig. Pro Name reicht die Korrektur von ×0,10 bis ×1,52 — eine Größenordnung für einzelne Zeilen, innerhalb einer Verteilung, deren globale Distanz zur Wahrheit 2,4 % beträgt.
Das ist die allgemeine Lehre, und sie verdient eine eigene Zeile: eine Metrik auf Verteilungsebene kann einen auf den Schwanz beschränkten Defekt nicht erkennen, weil der Schwanz per Definition der Teil ist, der am wenigsten zu Metriken auf Verteilungsebene beiträgt. Wenn Sie gewichtete Daten nur aggregiert prüfen, sind Schwanz-Defekte konstruktionsbedingt unsichtbar — nicht weil Sie nachlässig waren, sondern weil Sie ein Instrument gewählt haben, das genau über die Region mittelt, in der das Problem lebt.
Ehrlich über die Schwere sein
Zwei Dinge ziehen in die andere Richtung, und beide gehören hierher.
Erstens war innerhalb des kollabierten Blocks die wahre Verteilung selbst ziemlich flach. Als Perplexität gemessen, ergeben die echten Zählungen jener 997 Namen effektiv 944 Alternativen von möglichen 997 — 94,7 % einer perfekt uniformen Verteilung. Einen fast flachen Block auf exakt flach einzuebnen ist ein kleineres Verbrechen, als die Spanne von ×15,8 klingen lässt. Die Spanne ist eine Aussage über die zwei extremen Zeilen, nicht über den Block.
Zweitens bewahrte die Quantisierung die Rangordnung für den Kopf fehlerfrei und kehrte sie nirgends um; sie erzeugte nur Gleichstände. Gleichstände sind ein schwächerer Fehler als Umkehrungen. Eine Liste, die sagt „diese 997 Elemente sind gleich wahrscheinlich", ist falsch; eine Liste, die sagt „das seltenste ist wahrscheinlicher als das häufigste", wäre schlimmer.
Die ehrliche Zusammenfassung lautet also: der aggregierte Fehler ist klein, der Fehler pro Element ist groß, und was davon zählt, hängt vollständig davon ab, wozu die Liste dient. Um einen plausiblen anzuzeigenden Namen auszuwählen, ist eine Verteilungsverschiebung von 2,4 % nichts. Für alles, wo die Wahrscheinlichkeit eines einzelnen Elements die Ausgabe ist — ein Sampler, der eine Simulation speist, eine gewichtete A/B-Zuteilung, der Prior eines Empfehlungssystems, die Shard-Gewichte eines Load Balancers —, sind ein Drittel Ihrer Einträge, die am Boden gleichauf liegen, die ganze Geschichte.
Wir haben unsere behoben, weil die Behebung kostenlos war: die Zeilenmenge änderte sich nicht, kein Eintrag wurde hinzugefügt oder entfernt, und die gespeicherten Zähler wurden schlicht 32-bittig. Die Liste ging von 86 verschiedenen Gewichten auf 1.084.
Die Diagnostik
Nichts davon erfordert Zugriff auf die Originalquelle. Alles Folgende lässt sich allein aus der ausgelieferten Datei berechnen, in wenigen Zeilen, und jede einzelne davon hätte unseren Defekt Jahre früher aufgefangen.
1. Verschiedene Gewichte geteilt durch Zeilenzahl. Das ist das einzelne beste Signal, und es ist nahezu kostenlos.
distinct = count(unique(weights))
ratio = distinct / rows
Bei uns waren es 86 verschiedene Werte über 1.865 Zeilen — 4,6 %. Nach der Behebung: 1.084 über 1.865, 58 %. Für Häufigkeitsdaten, die aus Zählungen abgeleitet sind, liegt ein gesundes Verhältnis bei zig Prozent. Alles im niedrigen einstelligen Bereich bedeutet, dass die Gewichte keine Zählungen sind; sie sind Etiketten.
2. Anteil der Zeilen auf dem Mindestgewicht. Eine zipfsche Liste hat etwas Masse am Boden — es gibt tatsächlich viele seltene Elemente. Was sie nicht hat, ist ein Boden, der die halbe Datei hält.
floor_share = count(w == min(weights)) / rows
Oberhalb von etwa 20 % braucht das eine Erklärung. Bei 53,5 % lautet die Antwort nicht „die Daten sind eben so".
3. Die größte Äquivalenzklasse. Nach Gewicht gruppieren und die größte Gruppe nehmen. Bei uns: 997 Zeilen teilten sich einen Wert, dann 269 den nächsten, dann 113. Drei Werte deckten 74 % der Datei ab.
4. Die verdächtige Obergrenze. Wenn max(weights) genau 255, 127, 100, 1.000 oder 65.535 ist, ist die Zahl keine Messung. Sie ist der Rand eines Behälters. Das ist die billigste Prüfung von allen, und in Kombination mit (1) ist sie eine nahezu sichere Diagnose.
5. Der Dynamikumfang, den Sie tatsächlich brauchen. Berechnen Sie max / min über die Quell-Zählungen, vor der Quantisierung. Das ist die Anzahl verschiedener Stufen, die eine getreue lineare Kodierung erfordert. Bei uns waren es 2.679 gegen 255 verfügbare. Diese beiden Zahlen zu vergleichen dauert zehn Sekunden und nennt Ihnen die Antwort, bevor Sie den Encoder schreiben.
6. Die echte Spanne innerhalb der Bodenklasse. Diese braucht die Quelle, und sie ist die Zahl, die einen Verdacht in eine Messung verwandelt: verbinden Sie die ausgelieferten Gewichte zurück mit den Originalzählungen, nehmen Sie nur die Zeilen auf dem Mindestgewicht und melden Sie max / min ihrer wahren Werte. Bei uns: ×15,8 und ×15,5. Das ist die Menge zerstörter Information, ausgedrückt in den Einheiten, die irgendjemanden interessieren werden.
Eine nützliche Eigenschaft dieser Liste: die Prüfungen 1–5 laufen auf dem Artefakt, das Sie ausliefern, ohne Quellzugriff, ohne Historie und ohne Kontext. Es sind die Art von Prüfungen, die Sie an einem Nachmittag über jede Datendatei in einem Repository laufen lassen können, und das ist die einzige Art, die tatsächlich gelaufen wird.
Wenn Sie quantisieren müssen
Manchmal ist das Byte tatsächlich festgelegt — ein Wire-Format, das Ihnen nicht gehört, ein Embedded-Target, ein Spaltentyp, den Sie aus einem Schema geerbt haben, das Sie nicht migrieren können. Die Transformation muss trotzdem nicht linear sein.
Quantisieren Sie im Log-Raum. Häufigkeiten sind multiplikativ; eine lineare Skala verausgabt ihre Auflösung dort, wo die Daten keine haben. round(k * ln(count)) verteilt die Stufen gleichmäßig über Verhältnisse statt über Absolutwerte, und 255 Stufen, die einen Faktor von 2.679 abdecken, ergeben überall etwa 3 % relativen Fehler statt perfekter Präzision oben und totalem Kollaps unten.
Oder speichern Sie den Rang und halten Sie die Zählungen andernorts. Wenn der Konsument nur die relative Ordnung und eine grobe Form braucht, liefern Sie die Ordnung und rekonstruieren die Gewichte aus einer parametrischen Kurve.
Oder teilen Sie das Feld. Ein Byte Mantisse und ein Nibble Exponent ist immer noch billiger als ein 32-Bit-Zähler und bildet den Bereich exakt ab.
Und was auch immer Sie wählen, halten Sie den Dynamikumfang fest, den Sie verwerfen. Schreiben Sie ihn in den Datei-Header, nicht in eine Commit-Nachricht. „Diese Spalte ist quantisiert; die Quelle umspannt einen Faktor von 2.679 und diese Kodierung löst 255 Stufen auf" ist ein Satz, der den Defekt selbstmeldend gemacht hätte.
Der Fehler war nie „wir haben ein Byte benutzt". Er war, dass die Kompression auf eine Weise verlustbehaftet war, die niemand quantifiziert hatte, und eine verlustbehaftete Transformation, deren Verlust ungemessen ist, ist von einer korrekten ununterscheidbar — bis genau zu dem Moment, in dem jemand die Ausgabe zurück mit der Eingabe verbindet.
Die Checkliste
- Zählen Sie die verschiedenen Gewichte und teilen Sie durch die Zeilen. Unter ein paar Prozent bedeutet, dass die Gewichte Etiketten sind, keine Messungen.
- Messen Sie den Anteil der Zeilen, die auf dem Mindestgewicht sitzen. Die halbe Datei am Boden ist keine Eigenschaft der Daten.
- Suchen Sie nach einer Obergrenze, die eine Behältergrenze ist — 255, 127, 65.535, 100, 1.000. Messungen landen nicht auf solchen.
- Berechnen Sie
max / minauf den Quellzählungen, bevor Sie eine Kodierung wählen. Das ist die Anzahl der Stufen, die Sie brauchen; vergleichen Sie sie mit der Anzahl, die Sie haben. - Verbinden Sie nach der Quantisierung zurück und melden Sie die echte Spanne innerhalb der Bodenklasse. Das ist die einzige Zahl, die den Schaden in den Einheiten benennt, die zählen.
- Akzeptieren Sie aggregierte Übereinstimmung nicht als Beweis. Top-10-Anteil, Entropie und totale Variationsdistanz werden alle vom Kopf dominiert und lagen alle im Rauschen bei einer Datei, in der ein Drittel der Paare seine Ordnung verloren hatte.
- Quantisieren Sie im Log-Raum, wenn der Bereich multiplikativ ist, was er für alles Zipf-förmige ist.
- Schreiben Sie den verworfenen Bereich in das Artefakt. Eine ungemessene verlustbehaftete Transformation sieht genau aus wie eine verlustfreie.
- Denken Sie daran, dass der Kopf den Boden bestimmt. Zwanzig von 1.865 Zeilen entschieden, dass 997 andere gleichauf liegen würden. Nichts davon ist in den zwanzig sichtbar.
Der Defekt war ausgeliefert worden, solange der Korpus existierte. Er überlebte einen Validator, der Zeilenzahlen, Sortierreihenfolge, Kodierung, Byte-Order-Markierungen, Gewichtssummen gegen eine 32-Bit-Grenze und den Top-10-Konzentrationsanteil gegen eine Bevölkerungszahl prüft — 261 Dateien, null Fehler, null Warnungen. Jede einzelne dieser Prüfungen war korrekt, und keine von ihnen sah auf das einzige, was falsch war: ob die Zahlen in der Gewichtsspalte noch Zahlen waren oder zu Kategorien geworden waren.
Für das begleitende Versagen — bei dem eine Null in den Daten zwei verschiedene Dinge bedeutete und kein struktureller Validator sie auseinanderhalten konnte — siehe Wenn Null zwei verschiedene Dinge bedeutet. Zur allgemeinen Methode, Häufigkeitsdaten gegen ihre Quelle zu prüfen, siehe Wie man Namenshäufigkeitsdaten prüft. Wie der Kopf dieser Verteilungen aussieht, wenn er intakt ist, siehe Nachnamen-Konzentrationskurven. Für Prüfungen, die bestehen, weil sie nie hinsahen, siehe Die Prüfung, die genau dort blind wird, wo Sie sie brauchen.
Daten mit Stand 2026-07-21
Alle Zahlen wurden am 21. Juli 2026 gegen die Korpusdateien auf der Festplatte und gegen ein Backup derselben Dateien von vor der Änderung gemessen und für diesen Artikel unabhängig neu abgeleitet, statt aus dem Änderungsprotokoll zitiert.
Quellen und Anmerkungen:
- Die schwedischen Zahlen sind unsere eigene Berechnung. Sie sind von uns aus Vornamen-Zählungen abgeleitet, die von Statistics Sweden (SCB) veröffentlicht wurden; das aufbereitete Material, die Gewichte und jeder Prozentsatz in diesem Artikel sind unsere und nicht die von SCB, und SCB ist nicht die Quelle der aufbereiteten Zahlen. Nur die zugrunde liegenden Zählungen sind der Behörde zuzuschreiben.
- Frauenliste — 1.865 Zeilen. Quantisiert: 86 verschiedene Gewichte, Minimum 1, Maximum 255, Summe 11.954, 997 Zeilen (53,5 %) auf Gewicht 1, Top-10-Anteil 13,05 %. Echte Zählungen: 1.084 verschiedene Gewichte, Minimum 36, Maximum 96.428, Summe 4.445.328, Top-10-Anteil 13,28 %.
- Männerliste — 2.015 Zeilen. Quantisiert: 100 verschiedene Gewichte, Minimum 1, Maximum 255, Summe 14.744, 1.115 Zeilen (55,3 %) auf Gewicht 1, Top-10-Anteil 13,21 %. Echte Zählungen: 1.074 verschiedene Gewichte, Minimum 31, Maximum 81.754, Summe 4.655.153, Top-10-Anteil 13,42 %.
- Der kollabierte Block — für die Frauenliste haben die 997 auf Gewicht 1 gespeicherten Zeilen wahre Zählungen von 36 bis 567, eine Spanne von ×15,75; Quartile 228 / 291 / 393. Für die Männerliste 1.115 Zeilen von 31 bis 479, Spanne ×15,45. Der Block hält 8,34 % der quantisierten Masse gegen 7,14 % der wahren Masse (Frauen) und 7,56 % gegen 6,44 % (Männer).
- Der Mechanismus — rekonstruiert durch Verbinden der quantisierten Gewichte mit den wahren Zählungen und Vergleich gegen
w * max / 255. Die mittlere wahre Zählung pro gespeichertem Gewicht folgt der linearen Vorhersage auf etwa 1 % genau auf jeder Stufe ab 2 aufwärts, und das beobachtete Maximum auf Gewicht 1 ist 567 gegen eine vorhergesagte Kollapsgrenze von 567,2. Die Zeilenmenge ist vorher und nachher identisch: 0 hinzugefügt, 0 entfernt, 0 umbenannt. - Verteilungsdistanz — die totale Variationsdistanz zwischen der quantisierten und der wahren Verteilung beträgt 2,446 % (Frauen) und 2,252 % (Männer). Größter Anstieg pro Name ×1,52, größter Rückgang ×0,10, in beiden Listen. Perplexität 542 → 514 und 482 → 456. Namen bis zur halben Masse: 92 → 89 und 76 → 74.
- Gleichauf-Paare — geschätzt durch Ziehen von 200.000 zufälligen Zeilenpaaren aus einem festen Seed und Zählen der Paare, deren wahre Zählungen sich unterscheiden, deren quantisierte Gewichte aber gleich sind: 31,1 % (Frauen), 33,2 % (Männer).
- Flachheit innerhalb des Blocks — die Perplexität der wahren Zählungen der 997 Bodenzeilen ist 944, d. h. 94,7 % der 997, die ein perfekt uniformer Block ergäbe; für den Männerblock 1.057 von 1.115, also 94,8 %. Das ist die Zahl, die die Spanne von ×15,8 im Verhältnis hält, und sie wird hier genannt, weil ihr Weglassen den Defekt überzeichnen würde.
- Empfindlichkeit von Obergrenze und Kopf — beide Tabellen wurden auf den wahren Frauenzählungen berechnet, indem
round(count * C / max)mit einem Boden von 1 für jede Obergrenze C neu angewandt und die obersten K Zeilen vor der Neuquantisierung entfernt wurden. Dynamikumfang der Frauenliste:max / min= 2.678,6;max / median= 188. - Validator-Zustand — der Korpus-Validator meldet 261 Dateien, 0 Fehler, 0 Warnungen, sowohl vor als auch nach der Änderung. Er prüft Zeilenzahlen, absteigende Sortierung, UTF-8 ohne Byte-Order-Markierung, Abwesenheit von Wagenrückläufen, Gewichtssummen innerhalb einer 32-Bit-Grenze und Top-10-Konzentration gegen einen Bevölkerungsanteil. Keine davon ist in der Lage, den hier beschriebenen Defekt zu erkennen, und das ist keine Kritik am Validator — es ist der Kernpunkt des Artikels.
- Was geändert wurde — nur die Gewichtsspalte. Kein Eintrag wurde hinzugefügt, entfernt oder umsortiert, und keine andere Sprachregion wurde berührt. Die gespeicherten Zähler sind nun 32-bittig; die Kollapsschwelle bei dieser Breite liegt unter 1, und keine Zeile kann den Boden durch Rundung erreichen.