7.1 Verschiedene Elemente in einem Datenstrom zählen

Formale Problembeschreibung

Die Eingabe ist ein Datenstrom x1x2x3xm aus Elementen aus einem Universum U={1,,n}. Im obigen Beispiel war U die Menge aller theoretisch möglichen IP-Adressen, also n=232. Falls es sich um IPv6-Adressen handelt, wäre n=2128. Im Datenstrom kann ein Element xU mehrfach auftreten, und unser Ziel ist es, die Anzahl verschiedener Items zu zählen. Etwas formular:

S:={x1,,xm}k:=|S| .

Falls Elemente mehrfach im Datenstrom vorkommen, gilt |S|<m. Unsere Maschine liest die Eingabedaten nacheinander in zeitlicher Reihenfolge, kann also im Gegensatz zu einer Turing-Maschine nicht zurückspulen oder alte Items noch einmal betrachten. Sie hat einen internen Speicher, der typischerweise extrem klein im Vergleich zu m und n ist. Ziel ist es, nach Ende des Datenstroms einen Schätzwert k^ auszugeben, der nicht allzuweit entfernt von k ist. Wir interessieren uns in diesem Zusammenhang ausschließlich für den Speicherplatz, den die Maschine benötigt, nicht für die Laufzeit ihrer Berechnungen. Sie ist also im Prinzip computationally unbounded. Um es noch formaler zu machen: die Maschine ist, ähnlich einem endlichen Automaten, definiert durch eine Funktion δ:U×QQ; die Interpretation ist, dass xU das nächste Eingabe-Item ist und qQ der derzeitige Speicherinhalt der Maschine; der Wert δ(x,q)Q ist dann der Speicherinhalt im nächsten Schritt. Der benötigte Speicherplatz in Bits ist somit log|Q|. Ein Unterschied zu endlichen Automaten ist, dass Q und auch δ von n und m abhängen dürfen (wir gehen davon aus, dass die Maschine zumindest eine obere Schranke der Datenstromlänge m kennt). Wir interessieren uns also primär für den Speicherplatz log|Q| und nicht dafür, wie komplex die Berechnung von δ ist. In der Praxis ist aber δ meist eine recht einfache Funktion, so dass diese Freiheit keine bösen Konsequenzen hat.

Exakte aber ineffiziente Algorithmen

Unsere Maschine kann natürlich einfach zu jedem Zeitpunkt t die Menge St:={x1,,xt} speichern und Duplikate entfernen. Dafür braucht sie min(m,n)logn Bits: min(m,n) ist eine obere Schranke für die Größe von St und logn ist die Anzahl der Bits, die wir brauchen um ein Item xi aus dem Universum zu speichern.

Alternativ können wir uns eine boolesche Tabelle der Größe n anlegen, alles mit False initialisieren und dann bei Input-Item xt die entsprechende Zelle auf True setzen. Dafür benötigen wir n Bits.

Beobachtung 7.1.1 Wir können mit min(n,mlogn) Bits Speicherplatz die Anzahl der verschiedenen Items exakt berechnen.

Effiziente approximative Algorithmen

Ein Speicherplatzbedarf min(n,mlogn) gilt in diesem Modell als ineffizient. Unser Goldstandard ist O(logm+logn). Dies erlaubt uns, eine konstante Anzahl von Wörtern - O(logn) - sowie zum Beispiel einen Schrittzähler - O(logm) - zu speichern. Die Anzahl k verschiedener Items können wir so nicht mehr exakt berechnen (dies ist selbst ein Theorem, dessen Beweis den Rahmen dieses Vorlesungsskripts sprengen würde; man benötigt hierfür Techniken der Kommunikationskomplexität). Wenn wir Randomisierung zulassen, können wir zumindest mit großer Zuverlässigkeit einen anständigen Schätzwert k^ für k=|S|, also die Anzahl verschiedener Elemente im Datenstrom berechnen.

Der Algorithmus von Flajolet und Martin

Ich beschreibe zuerst eine impraktikable aber leichter zu analysierende Version des Algorithmus. Sei S={s1,,sk} die Menge der k verschiedenen Items. Jedes xi in unserem Datenstrom ist also eines dieser sj. Wir wählen eine zufällige Funktion π:[n][n] und speichern diese für die Dauer des Datenstroms. Dies ist natürlich nicht praktikabel, weil wir dafür nlogn Bits bräuchten (Sie können sich vorstellen, wir legen eine Tabelle A der Größe n an; eine Zelle A[x] muss nun den Wert π(x) speichern, wofür sie wiederum logn Bits braucht; etwas informationstheoretischer: es gibt nn Funktionen [n][n] und somit braucht man log(nn)=nlogn Bits, um eine zu codieren).

Wir ignorieren diese Bedenken vorerst, tun so, als hätten wir π gespeichert und schauen uns an, was π mit dem Datenstrom macht:

Sehen wir uns das Endergebnis noch einmal an:

Links sehen Sie am Beispiel die k Werte s1,,sk. Rechts die Bilder π(s1),,π(sk). Da π eine zufällige Funktion ist, sind diese Werte gleichverteilt und unabhängig. Setzen wir Yi:=π(si). Wir haben also k unabhängige Zufallsvariable Y1,,Yk, von denen jede in [n] gleichverteilt ist. Machen wir nun eine Bierdeckelrechnung: diese k Zufallszahlen teilen [n] in k+1 Intervalle ein, die im Schnitt nk+1 Zahlen haben. Also besteht auch das linkeste Intervall {1,2,,min(Y1,,Yk)} im Schnitt aus nk+1 Zahlen und somit ist

E[min(Y1,,Yk)]nk+1 .

Wenn wir nach k auflösen, erhalten wir

knE[min(Y1,,Yk)]1 .

Den Erwartungswert von min(Y1,,Yk) kennen wir nicht; den Wert min(Y1,,Yk) allerdings können wir einfach berechnen, indem sich unsere Maschine zu jedem Zeitpunkt das Minimum der gesehenen Elemente (bzw. deren Bilder unter π) merkt. Hier nun also unser Algorithmus:

def FlajoletMartinImpraktikabel:
  1. Wähle π:[n][n] zufällig # dies ist impraktikabel, weil dies nlogn Bits Speicher benötigt.
  2. y:=
  3. for x im Datenstrom:
    1. y:=min(y,π(x))
  4. return k^:=n/y.

Das folgende Theorem besagt nun, dass k^ mit guter Wahrscheinlichkeit weder zu klein noch zu groß ist.

Theorem 7.1.2 Für den Schätzwert k^:=FlajoletMartinImpraktikabel(x) gilt:

  1. Pr[k^>3k]13.
  2. Pr[k^<k/3]e3.

Beweis. Für Punkt 1 sehen wir, dass

k^>3kny>3ky<n3kmin(Y1,,Yk)<n3kY1<n3kY2<n3kYk<n3k .

In Worten: das Minimum von k Zahlen ist kleiner als eine Schranke genau dann, wenn mindestens eine der Zahlen kleiner als diese Schranke ist. Wir rechnen nun weiter:

Pr[k^>3k]=Pr[Y1<n3kY2<n3kYk<n3k](Union Bound)i=1kPr[Yin3k]

Zur Erinnerung: der Union Bound besagt, dass für zwei Ereigbnisse A und B Pr[AB]Pr[A]+Pr[B] gilt. Dies lässt sich unmittelbar von zwei auf k Ereignisse verallgemeinern. Für ein festes i können wir Pr[Yi<n/3k] wie folgt bestimmen: der Wert Yi ist ja π(si) und ist somit ein zufälliger Wert in {1,,n}. Die Wahrscheinlichkeit, dass er kleiner als n/3k ist, ist

Pr[Yi<n3k]Pr[Yin3k]=n3knn3kn=13k .

Wir setzen das in den obigen Union Bound ein und erhalten

Pr[k^>3k]i=1kPr[Yin3k]i=1k13k=13 ,

wie behauptet. Somit ist Punkt 1 gezeigt. Für Punkt 2 gehen wir anfangs ähnlich vor:

k^<k3ny<k3y>3nkmin(Y1,,Yk)>3nkY1>3nkY2>3nkYk>3nk .

In Worten: das Minimum von k Zahlen ist größer als eine Schranke, wenn jede diese Zahlen größer als die Schranke ist. Somit gilt

Pr[k^<k3]=Pr[Y1>3nkY2>3nkYk>3nk](Unabhängigkeit)=i=1kPr[Yi>3nk]

Für festes i schätzen wir Pr[Yi>3n/k] wie folgt ab:

Pr[Yi>3nk]=1Pr[Yi3nk]=13nkn=13k ,

und somit

Pr[k^<k3]=i=1kPr[Yi>3nk]=(13k)ke3 ,

wobei wir in der letzten Ungleichung die Tatsache 1+xex verwendet haben.

Den Algorithmus praktikabel machen: paarweise unabhängige Zufallsvariable

Statt π:[n][n] zufällig zu wählen, wählen wir es pseudozufällig. Hierfür wählen wir eine Primzahl pn und betrachten die Menge Zp:={0,,p1} als unser neues Universum. Wir wählen zwei zufällige Zahlen a,bZp gleichverteil und unabhängig und setzen

π:ZpZpxax+bmodp .

Der Rest des Algorithmus ist identisch:

def FlajoletMartin:
  1. Wähle eine Primzahl p[n,2n] und setze Zp:={0,1,,p1}.
  2. Wähle a,bZp und definiere π:xax+bmodp
  3. y:=
  4. for x im Datenstrom:
    1. y:=min(y,π(x))
  5. return k^:=n/y.

Zur Erinnerung: ymodp ist der Rest, der bei der Division von y durch p übrigbleibt. Wenn zwei Zahlen y und z modulo p den gleichen Rest ergeben, dann schreiben wir ypz und lesen "y ist äquivalent zu z modulo p". Dies gilt genau dann, wenn p|(yz), wenn also p ein Teiler der Differenz yz ist.

Wenn wir jetzt den Beweis von Theorem 7.1.2 durchgehen, sehen wir, dass dieser spätestens bei dem Argument der Unabhängigkeit scheitern wird. Die Werte Y1:=π(x1),,Yk:=π(xk) sind nicht mehr unabhängig. Ist zumindest Yi gleichverteilt?

Lemma 7.1.3 Sei sZp. Dann ist der Wert π(s) gleichverteilt in Zp.

Beweis. Um zu zeigen, dass π(si) gleichverteilt in Zp ist, müssen wir zeigen, dass für jedes feste zZp gilt, dass Pr[π(s)=z]. Es gilt

π(s)=zas+bpzbpzas .

Wieviele Möglichkeiten (a,b) gibt es, für die bpzas gilt? Für jede Wahl von aZp gibt es genau eine Möglichkeit für b, nämlich eben zas. In anderen Worten: die Gleichung bpzas in den Unbekannten a und b hat p Lösungen. Insgesamt gibt es für (a,b) genau p2 Möglichkeiten; p viele davon erfüllen bpzas, und somit gilt

Pr[π(s)=z]=1p . Wir sehen: π(s) ist gleichverteilt in Zp.

Das nächste Lemma zeigt, dass die π(s1),,π(sk) paarweise unabhängig sind. Hier werden wir benötigen, dass p eine Primzahl ist.

Lemma 7.1.4 Seien s1,s2 zwei verschiedene Werte in Zp. Dann sind π(s1),π(s2) gleichverteilt in Zp und unabhängig.

Beweis. Wir müssen nun zeigen, dass das Paar (π(s1),π(s2)) gleichverteilt in Zp×Zp ist. Dass also für jedes (z1,z2)Zp×Zp gilt: Pr[(π(s1),π(s2))=(z1,z2)]=1/p2. Wir sehen, dass (π(s1),π(s2))=(z1,z2) genau dann gilt, wenn

as1+bpz1as2+bpz2 .

Dies ist ein Gleichungssystem mit zwei Gleichungen und zwei Unbekannten a und b.

Wir können nun das Gleichungssystem in Matrix-Vektor-Form schreiben [s11s21][ab]=[z1z2] Die Matrix hat vollen Rang und somit hat das Gleichungssytem genau eine Lösung.

Um das Argument mit der Matrix und dem vollen Rang zu verstehen, müssen Sie sich (1) an Ihre lineare Algebra erinnern und wahrscheinlich auch (2) davon überzeugen, dass alles, was Sie in linearer Algebra mit reellen Zahlen gemacht haben, auch funktioniert, wenn Sie nun mit Zahlen modulo p zu tun haben. Ich möchte allerdings in diesem Skript so wenig Grundlagen wie möglich voraussetzen. Daher werde ich im nächsten Teilkapitel den Beweis "zu Fuß" ablaufen. Nehmen wir nun aber für erste Lemma 7.1.4 als gegeben an.

Theorem 7.1.5 Für den Schätzwert k^:=FlajoletMartin(x) gilt:

  1. Pr[k^>3k]13.
  2. Pr[k^<k/3]1/3.

Beweis. Punkt 1 geht genau so wie der Beweis von Theorem 7.1.2, da wir hierfür nur benötigen, dass für jedes feste sZp der Wert π(s) gleichverteilt in Zp ist. Für Punkt 2 werden wir benötigen, dass die Y1:=π(s1),,Yk:=π(sk) paarweise unabhängig sind. Fast genau so wie beim Beweis von Theorem 7.1.2 gilt

k^<k3ny<k3y>3pkmin(Y1,,Yk)>3pkY1>3pkY2>3pkYk>3pk .

Wir können die Wahrscheinlichkeit des Schnitts der k Ereignisse [Yi>3p/k] nicht per Unabhängigkeit abschätzen und gehen daher einen alternativen Weg. Wir führen Indikatorvariable ein:

Zi:={1 falls π(si)3pk ,0 sonst.

Des Weiteren setzen wir Z:=Z1++Zk. Wir sehen: k^<k3 tritt genau dann ein, wenn kein Yi in den Bereich [0,3p/k] fällt; wenn also Z=0 eintritt. Als erstes berechnen wir den Erwartungswert von Z:

E[Z]=E[i=1kZi]=i=1kE[Zi]=i=1kPr[π(si)3pk]=k3pkp=3 .

Hierfür reicht ein Union Bound leider nicht aus. Wir brauchen die sogenannte Tschebyschow-Ungleichung.

Markov-Ungleichung und Tschebyschow-Ungleichung

Lemma 7.1.6 Sei X eine Zufallsvariable, die Werte in R0+ annimmt. Dann gilt für jedes c0:

Pr[Xc]E[X]c .

Als Beispiel: höchstens ein drittel aller Deutschen haben ein Einkommen, dass das deutsche Durchschnittseinkommen um das Dreifache oder mehr übersteigt. Die Markow-Ungleichung ist oft eine sehr schwache Schranke. Die Durchschnittshöhe einer deutschen Frau liegt laut https://en.wikipedia.org/wiki/Average_human_height_by_country bei circa 1,66 Metern Zentimetern. Lauf Markow-Ungleichung ist höchstens jede zweite deutsche Frau größer als 3,32 Meter. Wahr, aber nicht sehr aussagekräftig.

Beweis von Reference "lemma-markov-inequality" not found. Go to put-all-in-one-page.html and read the instructions. Wir beschränken uns auf endliche Wahrscheinlichkeitsräume Ω. Jedes Element ωΩ hat eine Wahrscheinlichkeit Pr[ω]. Die Zufallsvariable X ist nun eine Funktion

X:ΩR0+ .

Der Erwartungswert von X ist definiert als die Summe

(1)E[X]=ωΩPr[ω]X(ω) .

Wir teilen Ω in zwei Teile auf, je nachdem, ob X groß ist oder klein:

Ωklein:={ωΩ | X(ω)<c}Ωgroß:={ωΩ | X(ω)c}

Wir teilen nun die Summe (1) auf:

E[X]=ωΩPr[ω]X(ω)=ωΩkleinPr[ω]X(ω)+ωΩgroßPr[ω]X(ω)(weil X(ω)0)ωΩgroßPr[ω]X(ω)(weil X(ω)c in Ωgroß)ωΩgroßPr[ω]c=cωΩgroßPr[ω]=cPr[Ωgross]

Zusammenfassend erhalten wir E[X]cPr[Ωgross] und somit

Pr[Xc]=Pr[Ωgroß]E[X]c .

Die Markow-Ungleichung hat den Vorteil, dass sie auf jede nicht-negative Zufallsvariable anwendbar ist. Der Nachteil ist, dass sie oft sehr schwach ist, also keine guten Schranken liefert, und nichts über Wahrscheinlichkeiten der Form Pr[Xc] aussagt. Sie beschränkt nur Abweichungen nach oben, nicht nach unten. Um genauere Schranken zu beweisen, können wir die Varianz der Zufallsvariable betrachten.

Varianz. Sei X eine Zufallsvariable, die reelle Werte (gerne auch negative) annimmt. Sei μ:=E[X] ihr Erwartungswert. Um zu messen, wie sehr X typischerweise von μ abweicht, betrachten wir den Wert (Xμ)2; dieser ist immer positiv, und somit ist auch

Var(X):=E[(Xμ)2] ,

die Varianz von X, immer positiv. Wenn wir die Varianz einer Zufallsvariable kennen und diese klein ist, so können wir Abschätzungen angeben, die genauer sind als die Markow-Ungleichung:

Tschebyschow-Ungleichung 7.1.7 Sei X eine Zufallsvariable und μ:=E[X]. Dann gilt

Pr[|Xμ|c]Var(X)c2 .

Beweis. Die Ungleichung |Xμ|c gilt genau dann, wenn auch (Xμ)2c2 gilt. Sei nun Y:=(Xμ)2. Dies ist wiederum eine Zufallsvariable, und es gilt E[Y]=Var(X) nach Definition der Varianz. Wir wenden jetzt die Markow-Ungleichung auf Y an:

Pr[|Xμ|c]=Pr[(Xμ)2c2]=Pr[Yc2](Markow-Ungleichung)E[Y]c2=Var(X)c2 ,

wie behauptet.

Weiterhin ist die Varianz nützlich, wenn die Zufallsvariable X die Summe unabhängig (oder auch paarweise unabhängiger) Zufallsvariablen ist. In diesem Falle ist die Varianz üblicherweise klein. Dies entspricht der Intuition: wenn wir unabhängige Zufallszahlen aufaddieren, sollten sich die Abweichungen in den meisten Fällen in etwa ausgleichen. Wir beginnen mit einer alternativen Formel für Var(X):

Beobachtung 7.1.8 Var(X)=E[X2](E[X])2.

Beweis. Sei μ:=E[X]. Wir rechnen:

Var(X)=E[(Xμ)2]=E[X22Xμ+μ2]=E[X2]2μE[X]+μ2=E[[X2]2μ2+μ2=E[[X2]μ2 , Wie behauptet.

Lemma 7.1.9 Seien Z1,,Zk paarweise unabhängige Zufallsvariable und Z:=Z1++Zk. Dann gilt

Var(Z)=Var(Z1)++Var(Zk) .

Beweis. Sei μi:=E[Zi] und μ=E[Z]=μ1++μk. Wir berechnen als erstes E[Z2]:

E[Z2]=E[(Z1++Zk)2]=E[i=1kj=1kZiZj]=i=1kj=1kE[ZiZj] .

Da die Zi paarweise unabhängig sind, gilt E[ZiZj]=E[Zi]E[Zj]=μiμj für ij. Für i=j gilt E[ZiZj]=E[Zi2]. Somit ist

E[Z2]=i=1kj=1k[ij]μiμj+i=1kE[Zi2]=i=1kj=1kμiμji=1kμi2+i=1kE[Zi2]=(μ1++μk)2i=1k(E[Zi2]μi2)=μ2+i=1kVar(Zi)

Und somit gilt Var(Z)=E[Z2]μ2=i=1kVar(Zi), wie behauptet.

Wenden wir diese Maschinerie auf unsere Zufallsvariablen Zi an. Zur Erinnerung: diese haben wir definiert als

Zi:={1 falls π(si)3pk ,0 sonst.

Es gilt E[Zi]=3k und