std.stats — Statistik über Zahlenfelder
Auswertung von int64-Feldern: Summe, Minimum, Maximum, Mittelwert, Median, Varianz, Standardabweichung, Suchen und Zählen. Dazu ein paar Rechenhilfen und Aggregatfunktionen für Map-Werte.
Alle Feldfunktionen arbeiten auf einem rohen Speicherblock mit 8 Byte Schrittweite; n zählt Elemente, nicht Bytes.
Autor: Andreas Röne
Copyright: 2024–2025 Andreas Röne
Quelle: std/stats.lyx
Zwei früher hier verzeichnete Defekte sind behoben. Nachgemessen mit 1.0.21A:
* DieMap*-Aggregate rechnen wieder — für{1: 10, 2: 20, 3: 30}liefernMapCount/MapSum/MapMaxdie Werte 3, 60 und 30 (#1491).
*std.statsundstd.mathlassen sich gemeinsam importieren; die frühere Mehrdeutigkeit beiClamp64undInRange64besteht nicht mehr (#1492).
Import
import std.stats;
Nicht zusammen mit std.math importierbar (#1492). Zieht std.sort mit — ArrayMedian und ArraySort bauen darauf auf.
Funktionen
Kennzahlen
| Signatur | Beschreibung |
|---|---|
ArraySum(arr, n: int64): int64 | Summe aller Werte |
ArrayCount(arr, n: int64): int64 | Gibt n zurück — der Vollständigkeit halber |
ArrayMin(arr, n: int64): int64 | Kleinster Wert; leeres Feld ergibt 0 |
ArrayMax(arr, n: int64): int64 | Größter Wert; leeres Feld ergibt 0 |
ArrayAvg(arr, n: int64): int64 | Mittelwert, ganzzahlig abgerundet |
ArrayRange(arr, n: int64): int64 | Spannweite: Maximum minus Minimum |
ArrayProduct(arr, n: int64): int64 | Produkt aller Werte; leeres Feld ergibt 0 |
ArraySumSquares(arr, n: int64): int64 | Summe der Quadrate |
ArrayVariance(arr, n: int64): int64 | Varianz, durch n geteilt — Rückgabe ist int64 |
ArrayStdDev(arr, n: int64): int64 | Standardabweichung, ganzzahlig abgerundet |
<WRAP alert>
Varianz und Standardabweichung sind hier ganzzahlig — das ist selten die gewünschte Antwort. Eine Varianz ist fast nie eine ganze Zahl; ArrayStdDev rundet ab und liefert für die Werte 2…6 den Wert 1 statt 1,58. Bei kleinen Streuungen wird daraus 0.
Für Statistik in f64 gibt es std.prob — mit dem Unterschied zwischen Grundgesamtheit (ProbVarianceP) und Stichprobe (ProbVarianceS), den diese Unit gar nicht führt. std.stats bleibt richtig, wenn tatsächlich über ganze Zahlen gezählt und aggregiert wird.
</WRAP>
ArrayMedian(arr, n: int64): int64 | Mittlerer Wert — sortiert das übergebene Feld |
Ein leeres Feld (n == 0) liefert bei allen Funktionen 0, ohne zu lesen. Beim Produkt ist das eine bewusste Abweichung von der Mathematik, wo das leere Produkt 1 wäre.
Die Varianz teilt durch n, nicht durch n − 1 — sie beschreibt also die vorliegenden Werte selbst und ist keine Schätzung für eine größere Grundgesamtheit.
Suchen und Zählen
| Signatur | Beschreibung |
|---|---|
ArrayFirst(arr, n, fallback: int64): int64 | Erster Wert, sonst fallback |
ArrayLast(arr, n, fallback: int64): int64 | Letzter Wert, sonst fallback |
ArrayIndexOf(arr, n, value: int64): int64 | Erste Fundstelle, -1 wenn nicht enthalten |
ArrayLastIndexOf(arr, n, value: int64): int64 | Letzte Fundstelle |
ArrayContains(arr, n, value: int64): bool | Ob der Wert vorkommt |
ArrayCountValue(arr, n, value: int64): int64 | Wie oft der Wert vorkommt |
Sortieren
| Signatur | Beschreibung |
|---|---|
ArraySort(arr, n: int64): void | Sortiert aufsteigend — reicht an SortInt64 aus std.sort weiter |
Rechenhilfen
| Signatur | Beschreibung |
|---|---|
Clamp64(value, minVal, maxVal: int64): int64 | Wert auf einen Bereich begrenzen |
InRange64(value, minVal, maxVal: int64): bool | Ob der Wert im Bereich liegt, Grenzen eingeschlossen |
Percentage64(value, total: int64): int64 | Prozentanteil, ganzzahlig; total == 0 ergibt 0 |
AbsDiff64(a, b: int64): int64 | Betrag der Differenz |
Clamp64 und InRange64 gibt es namensgleich auch in std.math (#1492).
Map-Aggregate
| Signatur | Beschreibung | Status |
|---|---|---|
MapCount(m: int64): int64 | Zahl der Einträge | liefert 0 (#1491) |
MapSum(m: int64): int64 | Summe der Werte | liefert 0 (#1491) |
MapMin(m: int64): int64 · MapMax · MapAvg | Kleinster/größter/mittlerer Wert | liefert 0 (#1491) |
Übergeben wird die Map als m as int64.
Beispiel
import std.stats;
import std.alloc;
fn main(): int64 {
// Messreihe
var a: int64 := alloc(6 * 8);
poke64(a, 4); poke64(a+8, 8); poke64(a+16, 15); poke64(a+24, 16); poke64(a+32, 23); poke64(a+40, 42);
PrintLn("Werte: 4 8 15 16 23 42");
PrintLn("Summe = ", IntToStr(ArraySum(a, 6)));
PrintLn("Minimum = ", IntToStr(ArrayMin(a, 6)));
PrintLn("Maximum = ", IntToStr(ArrayMax(a, 6)));
PrintLn("Mittelwert = ", IntToStr(ArrayAvg(a, 6)));
PrintLn("Spannweite = ", IntToStr(ArrayRange(a, 6)));
PrintLn("Varianz = ", IntToStr(ArrayVariance(a, 6)));
PrintLn("Standardabw. = ", IntToStr(ArrayStdDev(a, 6)));
PrintLn("-- Suchen:");
PrintLn("IndexOf(15) = ", IntToStr(ArrayIndexOf(a, 6, 15)));
PrintLn("Contains(99) = ", IntToStr(ArrayContains(a, 6, 99) as int64));
PrintLn("CountValue(8) = ", IntToStr(ArrayCountValue(a, 6, 8)));
PrintLn("-- Median sortiert die Eingabe:");
var b: int64 := alloc(5 * 8);
poke64(b, 50); poke64(b+8, 10); poke64(b+16, 40); poke64(b+24, 20); poke64(b+32, 30);
Print("vorher: ");
var i: int64 := 0;
while (i < 5) { Print(IntToStr(peek64(b + i*8)), " "); i := i + 1; }
PrintLn("");
PrintLn("Median = ", IntToStr(ArrayMedian(b, 5)));
Print("nachher: ");
i := 0;
while (i < 5) { Print(IntToStr(peek64(b + i*8)), " "); i := i + 1; }
PrintLn("");
return 0;
}
Ausgabe:
Werte: 4 8 15 16 23 42
Summe = 108
Minimum = 4
Maximum = 42
Mittelwert = 18
Spannweite = 38
Varianz = 151
Standardabw. = 12
-- Suchen:
IndexOf(15) = 2
Contains(99) = 0
CountValue(8) = 1
-- Median sortiert die Eingabe:
vorher: 50 10 40 20 30
Median = 30
nachher: 10 20 30 40 50
Fallstricke
ArrayMedian verändert das Feld
Um den mittleren Wert zu finden, sortiert die Funktion die Eingabe — dauerhaft, wie die Ausgabe oben zeigt. Wer die ursprüngliche Reihenfolge braucht, arbeitet auf einer Kopie:
var kopie: int64 := alloc(n * 8);
var i: int64 := 0;
while (i < n) { poke64(kopie + i*8, peek64(arr + i*8)); i := i + 1; }
var med: int64 := ArrayMedian(kopie, n);
free(kopie, n * 8);
Dasselbe gilt für ArraySort, dort ist es allerdings der erklärte Zweck.
Median bei gerader Anzahl
Bei einer geraden Zahl von Werten gibt die Funktion das obere der beiden mittleren Elemente zurück, nicht deren Mittelwert:
Median(10, 20, 30, 40) = 30 statistisch üblich wären 25
Wer den üblichen Wert braucht, bildet ihn selbst aus den Positionen n/2 − 1 und n/2 des sortierten Feldes.
Ganzzahlige Ergebnisse
Mittelwert, Varianz, Standardabweichung und Prozentangaben werden abgerundet: aus 12,3 wird 12, aus 12,5 % werden 12 %. Bei kleinen Werten fällt das ins Gewicht — ein Mittelwert von 0 kann sowohl „alle Werte sind 0„ als auch „alle Werte liegen unter 1“ bedeuten. Wo es genauer sein muss, vorher mit 100 oder 1000 skalieren und am Ende zurückrechnen.
Überlauf bei Produkt und Quadratsummen
ArrayProduct multipliziert ungeprüft — sechs dreistellige Werte genügen bereits für einen Überlauf. Auch ArraySumSquares und die Varianz quadrieren, ohne den Bereich zu prüfen. Bei großen Messwerten vorher überschlagen oder die Werte herunterskalieren.
