Fitting to Poisson histogram

前端 未结 2 2078
臣服心动
臣服心动 2020-12-04 11:52

I am trying to fit a curve over the histogram of a Poisson distribution that looks like this \"histo\"

I have m

相关标签:
2条回答
  • 2020-12-04 12:09

    Thank you for the wonderful discussion!

    You might want to consider the following:

    1) Instead of computing "poisson", compute "log poisson", for better numerical behavior

    2) Instead of using "lamb", use the logarithm (let me call it "log_mu"), to avoid the fit "wandering" into negative values of "mu". So

    log_poisson(k, log_mu): return k*log_mu - loggamma(k+1) - math.exp(log_mu)
    

    Where "loggamma" is the scipy.special.loggamma function.

    Actually, in the above fit, the "loggamma" term only adds a constant offset to the functions being minimized, so one can just do:

    log_poisson_(k, log_mu): return k*log_mu - math.exp(log_mu)
    

    NOTE: log_poisson_() not the same as log_poisson(), but when used for minimization in the manner above, will give the same fitted minimum (the same value of mu, up to numerical issues). The value of the function being minimized will have been offset, but one doesn't usually care about that anyway.

    0 讨论(0)
  • 2020-12-04 12:13

    The problem with your code is that you do not know what the return values of curve_fit are. It is the parameters for the fit-function and their covariance matrix - not something you can plot directly.

    Binned Least-Squares Fit

    In general you can get everything much, much more easily:

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.optimize import curve_fit
    from scipy.special import factorial
    from scipy.stats import poisson
    
    # get poisson deviated random numbers
    data = np.random.poisson(2, 1000)
    
    # the bins should be of integer width, because poisson is an integer distribution
    bins = np.arange(11) - 0.5
    entries, bin_edges, patches = plt.hist(data, bins=bins, density=True, label='Data')
    
    # calculate bin centres
    bin_middles = 0.5 * (bin_edges[1:] + bin_edges[:-1])
    
    
    def fit_function(k, lamb):
        '''poisson function, parameter lamb is the fit parameter'''
        return poisson.pmf(k, lamb)
    
    
    # fit with curve_fit
    parameters, cov_matrix = curve_fit(fit_function, bin_middles, entries)
    
    # plot poisson-deviation with fitted parameter
    x_plot = np.arange(0, 15)
    
    plt.plot(
        x_plot,
        fit_function(x_plot, *parameters),
        marker='o', linestyle='',
        label='Fit result',
    )
    plt.legend()
    plt.show()
    

    This is the result:

    Unbinned Maximum-Likelihood fit

    An even better possibility would be to not use a histogram at all and instead to carry out a maximum-likelihood fit.

    But by closer examination even this is unnecessary, because the maximum-likelihood estimator for the parameter of the poissonian distribution is the arithmetic mean.

    However, if you have other, more complicated PDFs, you can use this as example:

    import numpy as np
    import matplotlib.pyplot as plt
    from scipy.optimize import minimize
    from scipy.special import factorial
    from scipy import stats
    
    
    def poisson(k, lamb):
        """poisson pdf, parameter lamb is the fit parameter"""
        return (lamb**k/factorial(k)) * np.exp(-lamb)
    
    
    def negative_log_likelihood(params, data):
        """
        The negative log-Likelihood-Function
        """
    
        lnl = - np.sum(np.log(poisson(data, params[0])))
        return lnl
    
    def negative_log_likelihood(params, data):
        ''' better alternative using scipy '''
        return -stats.poisson.logpmf(data, params[0]).sum()
    
    
    # get poisson deviated random numbers
    data = np.random.poisson(2, 1000)
    
    # minimize the negative log-Likelihood
    
    result = minimize(negative_log_likelihood,  # function to minimize
                      x0=np.ones(1),            # start value
                      args=(data,),             # additional arguments for function
                      method='Powell',          # minimization method, see docs
                      )
    # result is a scipy optimize result object, the fit parameters 
    # are stored in result.x
    print(result)
    
    # plot poisson-distribution with fitted parameter
    x_plot = np.arange(0, 15)
    
    plt.plot(
        x_plot,
        stats.poisson.pmf(x_plot, *parameters),
        marker='o', linestyle='',
        label='Fit result',
    )
    plt.legend()
    plt.show()
    
    0 讨论(0)
提交回复
热议问题