如何从一组最高频率中计算Zipf定律系数?


25

我有几个查询频率,我需要估计Zipf定律的系数。这些是最高频率:

26486
12053
5052
3033
2536
2391
1444
1220
1152
1039

根据维基百科页面,齐普夫定律有两个参数。元素数和的指数。什么是你的情况,10?可以通过将您提供的值除以所有提供的值之和来计算频率?小号ñNsN
mpiktas,2011年

设为十,可以通过将您提供的值除以所有提供的值的总和来计算频率。如何估算?
Diegolo 2011年

Answers:


22

更新我已经按照@whuber建议使用最大似然估计器更新了代码。尽管可以给出答案,但使对数理论概率和对数频率之间的差异的平方和最小化是一个统计过程,如果可以证明它是某种M估计量的话。不幸的是,我想不出任何可以带来相同结果的东西。

这是我的尝试。我计算频率的对数,并尝试使它们符合该公式给出的理论概率的对数。最终结果似乎是合理的。这是我在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

最佳二次拟合为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,感谢您的链接。如果有人会使用此软件包回答这个问题,那就太好了。我的解决方案当然缺乏深度,尽管它给出了某种答案。
mpiktas 2011年

(+1)您真是令人印象深刻。在许多不同的统计领域中做出了许多杰出贡献!
chl

@chl,谢谢!我当然觉得我不是这个站点中唯一具有这种特征的人;)
mpiktas 2011年

25

任何估算问题都面临着几个问题:

  1. 估计参数。

  2. 评估该估计的质量。

  3. 探索数据。

  4. 评估适合度。

对于那些将要使用统计方法进行理解和交流的人,首先应该没有其他人。

为了进行估计,使用最大似然(ML)很方便。频率是如此之大,我们可以期望保持众所周知的渐近性质。ML使用假定的数据概率分布。齐普夫定律假设的概率为正比于- š一段恒定功率小号(通常š > 0)。因为这些概率必须加起来等于1,所以比例常数是总和的倒数一世=1个2ñ一世-sss>0

Hsñ=1个1个s+1个2s++1个ñs

因此,介于1n之间的任何结果的概率的对数为一世1个ñ

log(Pr(i))=log(isHs(n))=slog(i)log(Hs(n)).

fi,i=1,2,,n

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

因此,数据的对数概率为

Λs=-s一世=1个ñF一世日志一世-一世=1个ñF一世日志Hsñ

s

s^=1.45041Λs^=-94046.7s^s=1.463946Λs^s=-94049.5

s[1.439221.46162]

鉴于Zipf定律的性质,绘制此拟合的正确方法是在对数对数图上,其中拟合将是线性的(根据定义):

在此处输入图片说明

要评估拟合优度并探索数据,请查看残差(数据/拟合,再次为对数-对数轴):

在此处输入图片说明

χ2=656.476


因为残差看起来是随机的,所以在某些应用中,尽管可以粗略地描述频率,但我们还是可能会满意接受齐普夫定律(以及我们对参数的估计)。但是,该分析表明,假设此估计对于此处检查的数据集具有任何解释性或预测性的值,将是一个错误。


1
@whuber,我可能会谦虚地建议您谨慎使用上述公式。Zipf定律通常表示为相对频率结果。它不是(通常考虑)从中提取iid样本的分布。一个iid框架可能不是这些数据的最佳选择。也许我稍后再发布更多。
主教

3
@cardinal我期待您的发言。如果您没有时间做出全面的答复,那么即使您认为可能是“这些数据的最佳想法”的草图也将是最可取的。我可以猜到您要怎么做:对数据进行排名,这是一个创建依赖项的过程,应该要求我捍卫衍生出来的可能性,而又没有意识到排名的潜在影响。看到有合理依据的估算程序会很高兴。不过,我希望可以通过数据集的庞大规模来挽救我的分析。
Whuber

1
@cardinal,不要对我们进行费马:)如果您的理解力与其他回答者不同,请随意在单独的答案中表达它,即使它本身并不构成有效的答案。例如在math.SE中,这种情况经常出现。
mpiktas,2011年

1
@cardinal轻松。例如,您收集频率并确定十个最高频率并对其进行排名。您假设齐普夫定律。您收集了一组新的频率,并根据以前的排名进行报告。这是独立同分布的情况下,到我的分析是完全适合,队伍在新队伍与旧的同意。
ub

1
@whuber,感谢您的耐心配合。现在,我很清楚您的推理思路。在您现在已经充实的采样模型下,我同意您的分析。也许您的最后声明仍然有点滑。如果排序没有引起强烈的依赖性​​,那么您的方法将很保守。如果诱导的依赖性适度强,它可能会变成保守的。谢谢您在面对我的学步时的耐心。
主教

2

s

诸如PyMC3之类的概率编程语言使这种估计相对简单。其他语言包括具有强大功能和支持社区的Stan

这是我在OPs数据上安装的模型的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()

ss

在此处输入图片说明

为了提供一些基本的采样诊断,我们可以看到采样“混合得很好”,因为在跟踪中看不到任何结构:

在此处输入图片说明

要运行代码,需要安装Theano和PyMC3软件包的Python。

感谢@ 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

在我们的案例中,卡方的原假设是数据是根据zipf定律分布的,因此较大的p值支持根据数据进行分布的说法。请注意,即使非常大的p值也不能证明,而只是一个指标。


0

X=1个wX=1个^

süw ^小号Ë^=H10-1个1个wX=1个^

wX=1个^=0.4695599775

süw ^小号Ë^=1.4

同样,UWSE仅提供一致的估计-没有置信区间,我们可以看到在准确性方面需要进行一些权衡。mpiktas的上述解决方案也是UWSE的一种应用-尽管需要进行编程。有关估算器的完整说明,请参见:https : //paradsp.wordpress.com/-始终在底部。


UWSE与Zipf定律有何关系?
Michael R. Chernick

UWSE(唯一权重空间估计)使用以下事实:对于给定的N,最高的概率/频率在参数s的不同值之间是唯一的,以找到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])

由于我们的函数并未在所有范围内定义,因此我们需要在每次计算时都检查是否在规范化。在离散情况下,一个简单的近似值是除以所有y(x)的总和。这样,我们可以比较不同的参数。

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,如先前的答案一样。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.