I'm trying to extract the distribution parameters of the sub-distributions which comprise a mixed normal distribution.
I'll give my attempts so far.
First the simulated data:
MixedGaussiaData = Apply[Join, {RandomVariate[NormalDistribution[0, 2], 300], RandomVariate[NormalDistribution[0, 0.7], 500], RandomVariate[NormalDistribution[0, 0.4], 500], RandomVariate[NormalDistribution[0, 1], 200]}];
Which when plotted looks like this:
So we have four normal distributions with different $\sigma$ values and different number of points, but all distributions have a common mean value $\mu = 0$.
I define my $n$ mixed-normal distribution as:
NMixedGaussian[n_] := MixtureDistribution[Array[w, n], MapThread[NormalDistribution[#1, #2] &, {Array[m, n], Array[s, n]}]]
Then using FindDistributionParameters
FourMixedNormalMLE = FindDistributionParameters[MixedGaussiaData, NMixedGaussian[4], ParameterEstimator->{"MaximumLikelihood", PrecisionGoal->1, AccuracyGoal->1}]
If I plot the result, it looks pretty good:
However if we take a look at the results, they're not that good when compared to the inputs of the simulation:
mMLE = Array[m, 4] /. FourMixedNormalMLE
sMLE = Array[s, 4] /. FourMixedNormalMLE
wMLE = Array[w, 4] /. FourMixedNormalMLE
{0.0284676, 0.00902554, 0.0930328, -0.470579}
{1.8648, 0.274301, 0.667947, 0.385259}
{0.237727, 0.192302, 0.475281, 0.0946906}
Second attempt:
I tried explicitly defining the Mixed-Gaussain function with ProbabilityDensity
:
Clear[w, m, s, n];
NMixedGaussian[n_] := MixtureDistribution[Array[w, n], MapThread[NormalDistribution[#1, #2] &, {Array[m, n], Array[s, n]}]]
NMixGauss = NMixedGaussian[4];
NMixGaussPDF[z_] = FullSimplify[PDF[NMixGauss, z], DistributionParameterAssumptions[NMixGauss]]
NMixGaussPD = ProbabilityDistribution[NMixGaussPDF[z], {z, -Infinity, Infinity}, Assumptions -> DistributionParameterAssumptions[NMixGauss]]
FourMixedNormalPDFMLE = FindDistributionParameters[MixedGaussiaData, NMixGaussPD, ParameterEstimator->{"MaximumLikelihood", PrecisionGoal->1, AccuracyGoal->1}]
This makes it worse. I think the main issue might be initial values and constraints, but I'm not sure how to best implement this. Does anyone have any suggestions?
One thing I noticed is that the weights produced by FindDistributionParameters
don't seem to make sense. They sum to one, but none seem to correspond to weights defined by $1/\sigma^{2}$ or $1/\sigma_{\rm{SE}}^{2}$
Addition: What I'm trying to achieve is another way of performing a weighted mean. I could divide the simulated data up into chunks/bins, find the $\mu$ and $\sigma$ for each one and perform a weighted mean. I want to avoid binning if possible, hence this approach.
Just to be a bit more explicit in what I am trying to do/expect to see. Here I've just performed a simple weighted average and determined the associated standard error:
SeedRandom[1]
Gaussian1 = RandomVariate[NormalDistribution[0, 2], 300];
Gaussian2 = RandomVariate[NormalDistribution[0, 0.7], 500];
Gaussian3 = RandomVariate[NormalDistribution[0, 0.4], 500];
Gaussian4 = RandomVariate[NormalDistribution[0, 1], 200];
M = {Mean[Gaussian1], Mean[Gaussian2], Mean[Gaussian3], Mean[Gaussian4]};
S = {StandardDeviation[Gaussian1], StandardDeviation[Gaussian2], StandardDeviation[Gaussian3], StandardDeviation[Gaussian4]};
SE = {StandardDeviation[Gaussian1]/Sqrt[Length[Gaussian1]], StandardDeviation[Gaussian2]/Sqrt[Length[Gaussian2]], StandardDeviation[Gaussian3]/Sqrt[Length[Gaussian3]], StandardDeviation[Gaussian4]/Sqrt[Length[Gaussian4]]};
W = 1 / SE^2;
Around[WU = Total[W M]/Total[W], WSE = Sqrt[(Total[W M^2]/Total[W] - (Total[W M]/Total[W])^2 Length[W]/(Length[W] - 1)) / Length[W]]]
OUT = Around[-0.010808335694884515`, 0.0184845352965455]
mMLE = Array[m, 4] /. FourMixedNormalMLE
sMLE = Array[s, 4] /. FourMixedNormalMLE
wMLE = Array[w, 4] /. FourMixedNormalMLE
Around[WUMLE = Total[wMLE mMLE], WSEMLE = Sqrt[(Total[wMLE mMLE^2] - (Total[wMLE mMLE])^2 Length[wMLE]/(Length[wMLE] - 1)) / Length[wMLE]]]
OUT = Around[0.008160465141904528, 0.07937540663098669]
If I compare the results from those determined from a weighted mean, to those I get from FindDistributionParameters
they are quite different.
skd = SmoothKernelDistribution[data]; {weights, means, bandwidth} = skd[[2]]; Show[Histogram[data, Automatic, "PDF"], Plot[PDF[skd, x], {x, -3, 3}, PlotStyle -> Thick]]
then you haveMean[WeightedData[means, weights]]
which coincides withMean[data]
anyway. Also it has an option likeMaxMixtureKernels -> 50
so you can limit the number of mixture distributions, but don't set this too low or it starts to misrepresent the data. $\endgroup$parms = {Thread[Array[w, 4] -> {300, 500, 500, 200}], Thread[Array[m, 4] -> {0, 0, 0, 0}], Thread[Array[s, 4] -> {2, 0.7, 0.4, 1}]} // Flatten; data = RandomVariate[NMixedGaussian[4] /. parms, 1500]
. $\endgroup$