我有一个集合。计数器对象,其中包含不同值的出现次数,如下所示:
1:193260
2:51794
3:19112
4:9250
5:6486
如何在scipy中将概率分布拟合到这些数据中?scipy.stats.expon.fit()似乎想要一个数字列表。创建一个包含 193260 [1]、51794 [2] 等的列表似乎很浪费。有没有更优雅或更有效的方法?
scipy.stats.expon.fit基本上是scipy.optimize.minimize上的一个小包装器,它首先创建一个函数来计算neg-log-likelihood,然后使用scipy.optimize.minime来适应pdf参数。
所以,我认为你在这里需要做的是编写你自己的函数来计算计数器对象的负对数可能性,然后调用scipy.optimize.最小化自己。
更具体地说,scipy在这里定义了expon'scale'参数http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.expon.html
因此,pdf 是:
pdf(x) = 1 / scale * exp ( - x / scale)
因此,取两边的对数,我们得到:
log_pdf(x) = - log(scale) - x / scale
因此,计数器对象中所有内容的负对数相似性将是:
def neg_log_likelihood(scale):
total = 0.0
for x, count in counter.iteritems():
total += (math.log(scale) + x / scale) * count
return total
这是一个尝试的程序。
import scipy.stats
import scipy.optimize
import math
import collections
def fit1(counter):
def neg_log_likelihood(scale):
total = 0.0
for x, count in counter.iteritems():
total += (math.log(scale) + x / scale) * count
return total
optimize_result = scipy.optimize.minimize(neg_log_likelihood, [1.0])
if not optimize_result.success:
raise Exception(optimize_result.message)
return optimize_result.x[0]
def fit2(counter):
data = []
# Create an array where each key is repeated as many times
# as the value of the counter.
for x, count in counter.iteritems():
data += [x] * count
fit_result = scipy.stats.expon.fit(data, floc = 0)
return fit_result[-1]
def test():
c = collections.Counter()
c[1] = 193260
c[2] = 51794
c[3] = 19112
c[4] = 9250
c[5] = 6486
print "fit1 'scale' is %f " % fit1(c)
print "fit2 'scale' is %f " % fit2(c)
test()
这是输出:
fit1 'scale' is 1.513437
fit2 'scale' is 1.513438