Skip to content Skip to sidebar Skip to footer

Fitting "multimodal" Lognormal Distributions To Data Using Python

I have the following data measured using an instrument in the lab. Since the instrument collects particles of different sizes in bins based upon their diameter the measurements are

Solution 1:

lmfit.Models can be added together, as with:

model = (models.LognormalModel(prefix='p1_') +
         models.LognormalModel(prefix='p2_') +
         models.LognormalModel(prefix='p3_') )

params = model.make_params(p1_center=0.3, p1_sigma=0.2, p1_amplitude=1e4,
                           p2_center=1.0, p2_sigma=0.4, p2_amplitude=1e6,
                           p3_center=1.5, p3_sigma=0.6, p3_amplitude=2e7)

In a composite model, each component of the Model gets its own "prefix" (any string) that prepends the parameter names. You can get a dictionary of a Models components after the fit with:

components = result.eval_components()
# {'p1_': Array, 'p2_': Array, 'p3_': Array}
forcompname, comp in components.keys():
    plt.plot(x, comp, label=compname)

For fitting data that you would represent on a semi-log or log-log plot, you might consider fitting a model to log(y). Otherwise, the fit will not be very sensitive to misfit at very low values of y.

Note that lmfit models and parameters support bounds. You may want to or find that you need to place bounds such as

params['p1_amplitude'].min = 0params['p1_sigma'].min = 0params['p1_center'].max = 0.5params['p3_center'].min = 1.0

Solution 2:

This is a log-normal mixture distribution you're trying to fit. You can simply take the log of your data and fit a gaussian mixture instead:

import numpy as np
from sklearn.mixture import GaussianMixture

# Make data from two log-normal distributions# NOTE: 2d array of shape (n_samples, n_features)
n = 10000
x = np.zeros((n,1))
x[:n//2] = np.random.lognormal(0,1, size=(n//2,1))
x[n//2:] = np.random.lognormal(2,0.5, size=(n//2,1))# Log transform the data
x_transformed = np.log(x)

# Make gaussian mixture model.# n_init makes multiple initial guesses and# depending on data, 1 might be good enough# Decrease tolerance for speedup or increase for better precision
m = GaussianMixture(n_components=2, n_init=10, tol=1e-6)

# Fit the model
m.fit(x_transformed)

# Get the fitted parameters# NOTE: covariances are stdev**2print(m.weights_) # [0.50183897 0.49816103]print(m.means_) # [1.99866785, -0.00528186]print(m.covariances_) # [0.25227372,0.99692494]

Post a Comment for "Fitting "multimodal" Lognormal Distributions To Data Using Python"