Як обчислити коефіцієнт закону Зіпфа з набору верхніх частот?


25

У мене є кілька частот запитів, і мені потрібно оцінити коефіцієнт закону Зіпфа. Це найвищі частоти:

26486
12053
5052
3033
2536
2391
1444
1220
1152
1039

Відповідно до сторінки Вікіпедії Закон Зіпфа має два параметри. Кількість елементів і показник. Що у вашому випадку , 10? А частоти можна обчислити, поділивши надані значення на суму всіх поданих значень? s NNсN
mpiktas

нехай це десять, а частоти можна обчислити, поділивши надані значення на суму всіх поданих значень .. як я можу оцінити?
Дієголо

Відповіді:


22

Оновлення Я оновив код з максимальною оцінкою ймовірності відповідно до пропозиції @whuber. Мінімізація суми квадратів відмінностей між теоретичними ймовірностями журналу та частотами журналу, хоча дає відповідь, була б статистичною процедурою, якщо можна було б показати, що це якийсь М-оцінювач. На жаль, я не міг придумати жодного, який міг би дати однакові результати.

Ось моя спроба. Я обчислюю логарифми частот і намагаюся пристосувати їх до логарифмів теоретичних ймовірностей, заданих цією формулою . Кінцевий результат видається розумним. Ось мій код у Р.

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

Найкраще квадратичне прилягання тоді .s=1.47

Максимальна ймовірність R може бути виконана за допомогою mleфункції (з stats4пакета), яка корисно обчислює стандартні помилки (якщо правильна негативна функція максимальної ймовірності):

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 

Ось графік придатності в масштабі журналу журналу (знову, як запропонував @whuber):

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)

Червона лінія - це сума відповідних квадратів, зелена - максимально можлива.

Журнал-журнал, графік відповідностей


1
Також є пакет R zipfR cran.r-project.org/web/packages/zipfR/index.html Я його ще не пробував.
onestop

@onestop, дякую за посилання. Було б добре, якби хтось відповів на це запитання, використовуючи цей пакет. Моєму рішенню, безумовно, не вистачає глибини, хоча воно дає певну відповідь.
mpiktas

(+1) Ти справді вражаєш. Стільки хороших внесків у стільки різних статистичних областей!
chl

@chl, дякую! Я, звичайно, відчуваю, що я не єдиний, хто має такі характеристики на цьому сайті;)
mpiktas

25

Перед будь-якою проблемою оцінки є кілька питань :

  1. Оцініть параметр.

  2. Оцініть якість цієї оцінки.

  3. Дослідіть дані.

  4. Оцініть придатність.

Для тих, хто використовує статистичні методи для розуміння та спілкування, перший не повинен обійтися без інших.

i=1,2,,ni-ссс>0

Нс(н)=11с+12с++1нс.

i1н

журнал(Пр(i))=журнал(i-сНс(н))=-сжурнал(i)-журнал(Нс(н)).

fi,i=1,2,,н

Пр(f1,f2,,fн)=Пр(1)f1Пр(2)f2Пр(н)fн.

Таким чином, вірогідність журналу даних є

Λ(с)=-сi=1нfiжурнал(i)-(i=1нfi)журнал(Нс(н)).

с

с^=1.45041Λ(с^)=-94046.7с^лс=1,4463946Λ(с^лс)=-94049.5

с[1.43922,1,446162]

Враховуючи характер закону Зіпфа, правильний спосіб зафіксувати цю придатність - на графіку журналу журналу , де відповідність буде лінійною (за визначенням):

введіть тут опис зображення

Щоб оцінити корисність придатності та вивчити дані, подивіться на залишки (дані / примір, осі журналу журналу знову):

введіть тут опис зображення

χ2=656.476


Оскільки залишки виглядають випадковими, ми можемо з задоволенням прийняти Закон Зіпфа (і нашу оцінку параметра) як прийнятний, хоча і приблизний опис частот . Цей аналіз показує, що було б помилкою вважати, що ця оцінка має якесь пояснювальне або прогнозне значення для досліджуваного тут набору даних.


1
@whuber, я можу покірно запропонувати невелику обережність щодо рецептури, наведеної вище. Закон Зіпфа зазвичай зазначається як результат відносної частоти. Це (як правило, не вважається) розподіл, з якого береться зразок iid. База даних iid, мабуть, не найкраща ідея для цих даних. Можливо, я більше про це напишу пізніше.
кардинал

3
@cardinal Я з нетерпінням чекаю, що ти маєш сказати. Якщо у вас немає часу на ретельну відповідь, навіть ескіз того, що, на вашу думку, може бути "найкращою ідеєю для цих даних", буде дуже вітається. Я можу здогадатися, куди ви з цим рухаєтесь: дані були класифіковані, процес, який створює залежності, і повинен вимагати від мене захищати ймовірність, отриману без визнання потенційних наслідків рейтингу. Було б непогано побачити процедуру оцінки з обґрунтуванням. Я сподіваюся, що мій аналіз може бути врятований рівним набором даних.
whuber

1
@cardinal, не робіть на нас Ферма :) Якщо у вас є інше розуміння, ніж інші відповідачі, не соромтесь висловити це в окремій відповіді, навіть якщо вона сама по собі не являє собою дійсну відповідь. Наприклад, в math.SE такі ситуації виникають досить часто.
mpiktas

1
@cardinal Легко. Наприклад, ви збираєте частоти і визначаєте та класифікуєте десятку найвищих. Ви гіпотезуєте закон Зіпфа. Ви збираєте новий набір частот і повідомляєте про них відповідно до попереднього рейтингу. Це та сама ситуація, до якої мій аналіз ідеально підходить, залежно від нових звань, що погоджуються зі старими.
whuber

1
@whuber, дякую за терпіння. Тепер я повністю зрозумів вашу думку міркувань. Відповідно до вашої моделі вибірки, яку ви зараз повністю розробили, я згоден з вашим аналізом. Можливо, ваше останнє твердження все-таки трохи слизьке. Якщо сортування не викликає сильної залежності, то ваш метод був би консервативним. Якби індукована залежність була помірно сильною, вона може стати антиконсервативною. Thx для вас терпіння перед лицем моєї педантичності.
кардинал

2

с

Однією з імовірнісних мов програмування, наприклад, PyMC3, зробити цю оцінку досить просто. Інші мови включають Стен, який має чудові функції та підтримуючу спільноту.

Ось моя реалізація Python моделі, встановленої на даних ОП (також у 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()

сс

введіть тут опис зображення

Для надання основної діагностики вибірки ми можемо побачити, що вибірка "добре перемішувалася", оскільки ми не бачимо жодної структури в сліді:

введіть тут опис зображення

Для запуску коду потрібен Python із встановленими пакетами Theano та PyMC3.

Дякуємо @ w-huber за його чудову відповідь та коментарі!


1

Ось моя спроба встановити дані, оцінити та вивчити результати за допомогою VGAM:

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

введіть тут опис зображення

    Chi-squared test for given probabilities

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

У нашому випадку нульова гіпотеза квадрата Chi полягає в тому, що дані поширюються відповідно до закону zipf, отже, більші р-значення підтримують твердження, що дані поширюються відповідно до нього. Зауважте, що навіть дуже великі значення p не є доказом, а лише показником.


0

х=1шх=1^

сUWSЕ^=Н10-1(1шх=1^)

шх=1^=0.4695599775

сUWSЕ^=1.4

Знову ж таки, UWSE надає лише послідовну оцінку - відсутність довірчих інтервалів, і ми можемо побачити деякий компроміс у точності. Рішення mpiktas вище - це також програма UWSE - хоча програмування потрібно. Повне пояснення оцінювача див: https://paradsp.wordpress.com/ - повністю внизу.


Як UWSE ставиться до закону Зіпфа?
Майкл Р. Черник

UWSE (Унікальна оцінка простору ваги) використовує той факт, що найвища ймовірність / частота є унікальною для різних значень параметра s для даного N для знаходження s. Що стосується закону Зіпфа, це говорить нам про те, що з огляду на ряд елементів, які належать до ранжування, N та найвищої частоти, існує лише один спосіб присвоїти частоти решті елементів (2, ..., N) таким чином, щоб ми могли скажіть, "n-й елемент у 1 / n ^ s разів більший, ніж найчастіший елемент, для деяких s". Іншими словами, з огляду на цю інформацію, закон закону Зіпфа є лише одним із способів - звичайно, якщо припустити, що закон Зіпфа насправді виконується.
CYP450

0

Моє рішення намагається доповнювати відповіді, надані mpiktas та whuber, що виконують реалізацію в Python. Наші частоти та діапазони x:

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])

Оскільки наша функція не визначена у всьому діапазоні, нам потрібно перевіряти, що ми нормалізуємо кожного разу, коли ми її обчислюємо. У дискретному випадку просте наближення - ділити на суму всіх у (х). Таким чином ми можемо порівняти різні параметри.

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)

введіть тут опис зображення

Результат дає нам нахил 1.450408, як у попередніх відповідях.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.