Пригодете разпределение към брояч в scipy

Имам обект collections.Counter с брой на срещанията на различни стойности като тази:

1:193260
2:51794
3:19112
4:9250
5:6486

Как мога да напасна разпределение на вероятността към тези данни в scipy? scipy.stats.expon.fit() изглежда иска списък с числа. Изглежда разточително да се създаде списък с 193260 [1]s, 51794 [2]s и т.н. Има ли по-елегантен или ефективен начин?


person Thomas Johnson    schedule 19.02.2014    source източник
comment
Може би това може да помогне? stackoverflow.com/questions/7805552/   -  person Sahand    schedule 19.02.2014


Отговори (1)


Изглежда, че scipy.stats.expon.fit е основно малка обвивка над scipy.optimize.minimize, където първо създава функция за изчисляване на neg-log-вероятност и след това използва scipy.optimize.minimize, за да пасне на pdf параметрите.

И така, мисля, че това, което трябва да направите тук, е да напишете своя собствена функция, която изчислява neg-log-вероятността на обекта на брояча, и след това да извикате scipy.optimize.minimize себе си.

По-конкретно, scipy дефинира параметъра 'scale' на expon тук 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 
person mattsh    schedule 23.02.2014