Wie berechnet man den Zipf-Gesetzeskoeffizienten aus einer Reihe von Spitzenfrequenzen?


25

Ich habe mehrere Abfragehäufigkeiten und muss den Koeffizienten des Zipf-Gesetzes schätzen. Dies sind die Spitzenfrequenzen:

26486
12053
5052
3033
2536
2391
1444
1220
1152
1039

Laut Wikipedia-Seite hat das Zipf-Gesetz zwei Parameter. Anzahl der Elemente und der Exponent. Was ist in deinem Fall, 10? Und Häufigkeiten können berechnet werden, indem Sie Ihre bereitgestellten Werte durch die Summe aller bereitgestellten Werte dividieren? s NNsN
mpiktas

Lassen Sie es zehn sein, und Häufigkeiten können berechnet werden, indem Sie Ihre bereitgestellten Werte durch die Summe aller bereitgestellten Werte dividieren. Wie kann ich schätzen?
Diegolo

Antworten:


22

Aktualisieren Ich habe den Code mit dem Maximum Likelihood Estimator gemäß dem @ whuber-Vorschlag aktualisiert. Das Minimieren der Differenzquadratsumme zwischen logarithmischen Wahrscheinlichkeiten und logarithmischen Häufigkeiten wäre ein statistisches Verfahren, wenn gezeigt werden könnte, dass es sich um eine Art M-Schätzer handelt. Leider fiel mir keiner ein, der die gleichen Ergebnisse liefern könnte.

Hier ist mein Versuch. Ich berechne Logarithmen der Frequenzen und versuche, sie an Logarithmen der theoretischen Wahrscheinlichkeiten anzupassen, die durch diese Formel gegeben sind . Das Endergebnis erscheint vernünftig. Hier ist mein Code in R.

fr <- c(26486, 12053, 5052, 3033, 2536, 2391, 1444, 1220, 1152, 1039)

p <- fr/sum(fr)

lzipf <- function(s,N) -s*log(1:N)-log(sum(1/(1:N)^s))

opt.f <- function(s) sum((log(p)-lzipf(s,length(p)))^2)

opt <- optimize(opt.f,c(0.5,10))

> opt
$minimum
[1] 1.463946

$objective
[1] 0.1346248

Die beste quadratische Anpassung ist dann .s=1,47

Die maximale Wahrscheinlichkeit in R kann mit der mleFunktion (aus stats4Paket) ausgeführt werden, die Standardfehler hilfreich berechnet (wenn die korrekte negative maximale Wahrscheinlichkeitsfunktion angegeben wird):

ll <- function(s) sum(fr*(s*log(1:10)+log(sum(1/(1:10)^s))))

fit <- mle(ll,start=list(s=1))

> summary(fit)
Maximum likelihood estimation

Call:
mle(minuslogl = ll, start = list(s = 1))

Coefficients:
  Estimate  Std. Error
s 1.451385 0.005715046

-2 log L: 188093.4 

Hier ist das Diagramm der Anpassung in der Log-Log-Skala (erneut als @whuber vorgeschlagen):

s.sq <- opt$minimum
s.ll <- coef(fit)

plot(1:10,p,log="xy")
lines(1:10,exp(lzipf(s.sq,10)),col=2)
lines(1:10,exp(lzipf(s.ll,10)),col=3)

Die rote Linie ist die Summe der Quadrate, die grüne Linie ist die maximale Wahrscheinlichkeit.

Log-Log-Diagramm der Anpassungen


1
Es gibt auch ein R-Paket zipfR cran.r-project.org/web/packages/zipfR/index.html Ich habe es aber nicht ausprobiert.
1.

@onestop, danke für den Link. Es wäre schön, wenn jemand diese Frage mit diesem Paket beantworten würde. Meiner Lösung mangelt es definitiv an Tiefe, obwohl sie eine Art Antwort gibt.
mpiktas

(+1) Du bist wirklich beeindruckend. So viele gute Beiträge in so vielen verschiedenen statistischen Bereichen!
chl

@chl, danke! Ich bin sicher der Meinung, dass ich nicht der einzige bin, der solche Eigenschaften auf dieser Seite aufweist;)
mpiktas

25

Bei jedem Schätzungsproblem liegen uns mehrere Probleme vor :

  1. Schätzen Sie den Parameter.

  2. Bewerten Sie die Qualität dieser Schätzung.

  3. Erforschen Sie die Daten.

  4. Bewerten Sie die Passform.

Für diejenigen, die statistische Methoden zum Verständnis und zur Kommunikation verwenden würden, sollte die erste Methode niemals ohne die anderen durchgeführt werden.

i=1,2,,nisss>0

Hs(n)=11s+12s++1ns.

ich1n

Log(Pr(ich))=Log(ich-sHs(n))=-sLog(ich)-Log(Hs(n)).

fich,ich=1,2,,n

Pr(f1,f2,,fn)=Pr(1)f1Pr(2)f2Pr(n)fn.

Somit ist die Log-Wahrscheinlichkeit für die Daten

Λ(s)=-sich=1nfichLog(ich)-(ich=1nfich)Log(Hs(n)).

s

s^=1,45041Λ(s^)=-94046.7s^ls=1.463946Λ(s^ls)=-94049.5

s[1,43922,1.46162]

In Anbetracht der Natur des Zipf-Gesetzes ist der richtige Weg, diese Anpassung grafisch darzustellen, ein Log-Log-Diagramm , in dem die Anpassung (per Definition) linear ist:

Bildbeschreibung hier eingeben

Um die Anpassungsgüte zu bewerten und die Daten zu untersuchen, sehen Sie sich die Residuen an (Daten / Anpassung, Log-Log-Achsen erneut):

Bildbeschreibung hier eingeben

χ2=656,476


Da die Residuen zufällig erscheinen, akzeptieren wir in einigen Anwendungen möglicherweise das Zipf-Gesetz (und unsere Schätzung des Parameters) als akzeptable, wenn auch grobe Beschreibung der Frequenzen . Diese Analyse zeigt jedoch, dass es ein Fehler wäre anzunehmen, dass diese Schätzung einen erklärenden oder vorhersagenden Wert für den hier untersuchten Datensatz hat.


1
@whuber, ich könnte demütig ein wenig Vorsicht mit der oben angegebenen Formulierung vorschlagen. Das Zipf-Gesetz wird normalerweise als relatives Häufigkeitsergebnis angegeben. Es ist nicht (normalerweise betrachtet) die Verteilung, aus der eine iid-Probe gezogen wird. Ein iid-Framework ist wahrscheinlich nicht die beste Idee für diese Daten. Vielleicht poste ich später mehr dazu.
Kardinal

3
@ Cardinal Ich freue mich auf das, was Sie zu sagen haben. Wenn Sie keine Zeit für eine gründliche Antwort haben, wäre sogar eine Skizze der Ihrer Meinung nach "besten Idee für diese Daten" sehr willkommen. Ich kann mir vorstellen, wohin Sie damit gehen: Die Daten wurden klassifiziert, ein Prozess, der Abhängigkeiten erzeugt und von mir verlangt, eine abgeleitete Wahrscheinlichkeit zu verteidigen, ohne die möglichen Auswirkungen des Rankings zu erkennen. Es wäre schön, ein Schätzverfahren mit besserer Begründung zu sehen. Ich hoffe jedoch, dass meine Analyse durch die schiere Größe des Datensatzes gerettet werden kann.
whuber

1
@cardinal, tu uns nicht Fermat :) Wenn du andere Einsichten hast als andere Antwortende, kannst du sie gerne in der separaten Antwort ausdrücken, auch wenn sie per se keine gültige Antwort darstellt. In math.SE zum Beispiel treten solche Situationen ziemlich häufig auf.
mpiktas

1
@ Kardinal leicht. Beispielsweise sammeln Sie Frequenzen und identifizieren und ordnen die zehn höchsten. Sie nehmen das Zipf-Gesetz an. Sie sammeln einen neuen Satz von Frequenzen und melden sie gemäß dem vorherigen Ranking. Das ist die Situation, für die meine Analyse perfekt geeignet ist, abhängig davon , dass die neuen Ränge mit den alten übereinstimmen.
Whuber

1
@whuber, danke für deine Geduld. Jetzt bin ich mir Ihrer Argumentation ganz sicher. Unter dem Stichprobenmodell, das Sie jetzt vollständig ausgearbeitet haben, stimme ich Ihrer Analyse zu. Vielleicht ist Ihre allerletzte Aussage noch etwas rutschig. Wenn die Sortierung keine starke Abhängigkeit hervorruft, wäre Ihre Methode konservativ. Wenn die induzierte Abhängigkeit mäßig stark wäre, könnte sie antikonservativ werden. Vielen Dank für Ihre Geduld angesichts meiner Pedanterie.
Kardinal

2

s

Eine der probabilistischen Programmiersprachen wie PyMC3 macht diese Schätzung relativ einfach. Andere Sprachen sind Stan, der großartige Features und eine unterstützende Community hat.

Hier ist meine Python-Implementierung des auf die OP-Daten angepassten Modells (auch auf Github ):

import theano.tensor as tt
import numpy as np
import pymc3 as pm
import matplotlib.pyplot as plt

data = np.array( [26486, 12053, 5052, 3033, 2536, 2391, 1444, 1220, 1152, 1039] )

N = len( data )

print( "Number of data points: %d" % N )

def build_model():
    with pm.Model() as model:
        # unsure about the prior...
        #s = pm.Normal( 's', mu=0.0, sd=100 )
        #s = pm.HalfNormal( 's', sd=10 )
        s = pm.Gamma('s', alpha=1, beta=10)

        def logp( f ):
            r = tt.arange( 1, N+1 )
            return -s * tt.sum( f * tt.log(r) ) - tt.sum( f ) * tt.log( tt.sum(tt.power(1.0/r,s)) )

        pm.DensityDist( 'obs', logp=logp, observed={'f': data} )

    return model


def run( n_samples=10000 ):
    model = build_model()
    with model:
        start = pm.find_MAP()
        step = pm.NUTS( scaling=start )
        trace = pm.sample( n_samples, step=step, start=start )

    pm.summary( trace )
    pm.traceplot( trace )
    pm.plot_posterior( trace, kde_plot=True )
    plt.show()

if __name__ == '__main__':
    run()

ss

Bildbeschreibung hier eingeben

Um eine grundlegende Stichprobendiagnose zu ermöglichen, können wir feststellen, dass sich die Stichprobe "gut vermischt" hat, da in der Kurve keine Struktur zu sehen ist:

Bildbeschreibung hier eingeben

Um den Code auszuführen, muss Python mit Theano- und PyMC3-Paketen installiert sein.

Vielen Dank an @ w-huber für seine großartige Antwort und seine Kommentare!


1

Hier ist mein Versuch, die Daten anzupassen, die Ergebnisse mit VGAM auszuwerten und zu untersuchen:

require("VGAM")

freq <- dzipf(1:100, N = 100, s = 1)*1000 #randomizing values
freq <- freq  + abs(rnorm(n=1,m=0, sd=100)) #adding noize

zdata <- data.frame(y = rank(-freq, ties.method = "first") , ofreq = freq)
fit = vglm(y ~ 1, zipf, zdata, trace = TRUE,weight = ofreq,crit = "coef")
summary(fit)

s <- (shat <- Coef(fit)) # the coefficient we've found
probs <- dzipf(zdata$y, N = length(freq), s = s) # expected values
chisq.test(zdata$ofreq, p = probs) 
plot(zdata$y,(zdata$ofreq),log="xy") #log log graph
lines(zdata$y, (probs)*sum(zdata$ofreq),  col="red") # red line, num of predicted frequency

Bildbeschreibung hier eingeben

    Chi-squared test for given probabilities

data:  zdata$ofreq
X-squared = 99.756, df = 99, p-value = 0.4598

In unserem Fall lautet die Nullhypothese von Chi square, dass die Daten gemäß dem zipf-Gesetz verteilt werden. Daher stützen größere p-Werte die Behauptung, dass die Daten gemäß diesem Gesetz verteilt werden. Beachten Sie, dass selbst sehr große p-Werte kein Beweis sind, sondern nur ein Indikator.


0

x=1wx=1^

sUWSE^=H10-1(1wx=1^)

wx=1^=0,4695599775

sUWSE^=1.4

Auch hier liefert die UWSE nur eine konsistente Schätzung - keine Konfidenzintervalle, und wir können einen gewissen Kompromiss bei der Genauigkeit feststellen. Die oben genannte Lösung von mpiktas ist auch eine Anwendung von UWSE - obwohl Programmierung erforderlich ist. Eine vollständige Erklärung des Schätzers finden Sie unter: https://paradsp.wordpress.com/ - ganz unten.


In welcher Beziehung steht UWSE zum Zipf-Gesetz?
Michael R. Chernick

Die UWSE (Unique Weight Space Estimation) verwendet die Tatsache, dass die höchste Wahrscheinlichkeit / Häufigkeit für verschiedene Werte des Parameters s für ein gegebenes N eindeutig ist, um s zu finden. In Bezug auf das Zipf-Gesetz besagt dies, dass es nur eine Möglichkeit gibt, den verbleibenden Elementen (2, ..., N) Frequenzen zuzuweisen, wenn wir eine Reihe von Elementen für den Rang N und die höchste Frequenz angeben Sagen Sie "das n-te Element ist 1 / n ^ s mal so groß wie das häufigste Element, für einige s". Mit anderen Worten, angesichts dieser Informationen gibt es für Zipfs Gesetz nur einen Weg - natürlich unter der Annahme, dass Zipfs Gesetz tatsächlich gilt.
CYP450

0

Meine Lösung soll zu den Antworten von mpiktas und whuber, die eine Implementierung in Python durchführen, komplementär sein. Unsere Frequenzen und Bereiche x sind:

freqs = np.asarray([26486, 12053, 5052, 3033, 2536, 2391, 1444, 1220, 1152, 1039])
x = np.asarray([1, 2, 3, 4, 5 ,6 ,7 ,8 ,9, 10])

Da unsere Funktion nicht in allen Bereichen definiert ist, müssen wir bei jeder Berechnung überprüfen, ob wir uns normalisieren. Im diskreten Fall besteht eine einfache Annäherung darin, durch die Summe aller y (x) zu dividieren. Auf diese Weise können wir verschiedene Parameter vergleichen.

f,ax = plt.subplots()
ax.plot(x, f1, 'o')
ax.set_xscale("log")
ax.set_yscale("log")

def loglik(b):  
    # Power law function
    Probabilities = x**(-b)

    # Normalized
    Probabilities = Probabilities/Probabilities.sum()

    # Log Likelihoood
    Lvector = np.log(Probabilities)

    # Multiply the vector by frequencies
    Lvector = np.log(Probabilities) * freqs

    # LL is the sum
    L = Lvector.sum()

    # We want to maximize LogLikelihood or minimize (-1)*LogLikelihood
    return(-L)

s_best = minimize(loglik, [2])
print(s_best)
ax.plot(x, freqs[0]*x**-s_best.x)

Bildbeschreibung hier eingeben

Das Ergebnis ergibt eine Steigung von 1.450408 wie in den vorherigen Antworten.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.