ฉันมีความถี่ในการสืบค้นหลายครั้งและฉันจำเป็นต้องประเมินค่าสัมประสิทธิ์ของกฎหมายของ Zipf นี่คือความถี่สูงสุด:
26486
12053
5052
3033
2536
2391
1444
1220
1152
1039
ฉันมีความถี่ในการสืบค้นหลายครั้งและฉันจำเป็นต้องประเมินค่าสัมประสิทธิ์ของกฎหมายของ Zipf นี่คือความถี่สูงสุด:
26486
12053
5052
3033
2536
2391
1444
1220
1152
1039
คำตอบ:
อัปเดตฉันได้อัปเดตโค้ดด้วยตัวประมาณโอกาสสูงสุดตามคำแนะนำ @whuber การลดผลรวมกำลังสองของความแตกต่างระหว่างความน่าจะเป็นในทางทฤษฎีของการบันทึกและความถี่ของการบันทึกแม้ว่าจะให้คำตอบจะเป็นขั้นตอนทางสถิติถ้ามันแสดงให้เห็นว่ามันเป็น M-estimator น่าเสียดายที่ฉันไม่สามารถนึกถึงสิ่งใดที่สามารถให้ผลลัพธ์เดียวกัน
นี่คือความพยายามของฉัน ฉันคำนวณลอการิทึมของความถี่และพยายามปรับให้เข้ากับลอการิทึมของความน่าจะเป็นเชิงทฤษฎีที่กำหนดโดยสูตรนี้ ผลลัพธ์สุดท้ายดูเหมือนสมเหตุสมผล นี่คือรหัสของฉันในอาร์
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
ความน่าจะเป็นสูงสุดใน 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)
เส้นสีแดงคือผลรวมของกำลังสองพอดีเส้นสีเขียวเป็นความเหมาะสมสูงสุด
มีหลายประเด็นก่อนหน้าเราในปัญหาการประมาณค่าใด ๆ :
ประเมินพารามิเตอร์
ประเมินคุณภาพของการประเมินนั้น
สำรวจข้อมูล
ประเมินความเหมาะสม
สำหรับผู้ที่จะใช้วิธีการทางสถิติเพื่อความเข้าใจและการสื่อสารไม่ควรทำสิ่งแรกโดยไม่ใช้วิธีอื่น
ดังนั้นความน่าจะเป็นบันทึกสำหรับข้อมูลคือ
เมื่อพิจารณาถึงกฎของ Zipf วิธีที่ถูกต้องในการทำกราฟฟิตนี้อยู่บนพล็อตการบันทึกล็อกซึ่งความพอดีจะเป็นแบบเส้นตรง (ตามคำนิยาม):
หากต้องการประเมินความดีของการฟิตและสำรวจข้อมูลให้ดูที่ส่วนที่เหลือ (ข้อมูล / พอดีแกนล็อก - บันทึกอีกครั้ง):
เพราะเหลือปรากฏสุ่มในการใช้งานบางอย่างที่เราอาจจะมีเนื้อหาที่จะยอมรับกฎหมาย Zipf (และประมาณการของเราที่พารามิเตอร์) ในฐานะที่เป็นที่ยอมรับได้แม้ว่าหยาบคำอธิบายของความถี่ การวิเคราะห์นี้แสดงให้เห็นว่ามันจะเป็นความผิดพลาดในการสมมติว่าการประเมินนี้มีค่าที่อธิบายหรือคาดการณ์สำหรับชุดข้อมูลที่ตรวจสอบที่นี่
หนึ่งในภาษาโปรแกรมที่น่าจะเป็นเช่นPyMC3ทำให้การประมาณค่านี้ค่อนข้างตรงไปตรงมา ภาษาอื่น ๆ รวมถึงStanซึ่งมีคุณสมบัติที่ยอดเยี่ยมและชุมชนที่สนับสนุน
นี่คือการใช้งาน Python ของรุ่นที่ติดตั้งบนข้อมูล OPs (บน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 สำหรับคำตอบและความคิดเห็นที่ยอดเยี่ยมของเขา!
นี่คือความพยายามของฉันเพื่อให้พอดีกับข้อมูลประเมินและสำรวจผลลัพธ์โดยใช้ 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 square คือข้อมูลถูกแจกจ่ายตามกฎหมายของ zipf ดังนั้นค่า p ที่ใหญ่กว่าจึงสนับสนุนการอ้างสิทธิ์ที่ว่าข้อมูลนั้นถูกกระจายตามนั้น โปรดทราบว่าแม้ค่า p ที่มีขนาดใหญ่มากก็ไม่ใช่ข้อพิสูจน์เพียงแค่ตัวบ่งชี้
อีกครั้ง UWSE ให้การประเมินที่สอดคล้องกันเท่านั้น - ไม่มีช่วงความมั่นใจและเราสามารถเห็นการแลกเปลี่ยนที่แม่นยำ วิธีการแก้ปัญหาของ mpiktas ด้านบนยังเป็นแอปพลิเคชั่นของ UWSE - แม้ว่าจะต้องมีการเขียนโปรแกรม สำหรับคำอธิบายโดยละเอียดของตัวประมาณโปรดดู: https://paradsp.wordpress.com/ - ไปถึงด้านล่าง
โซลูชันของฉันพยายามที่จะเสริมคำตอบของ 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เหมือนกับคำตอบก่อนหน้า