// Fit sets the parameters of the probability distribution from the // data samples x with relative weights w. // If weights is nil, then all the weights are 1. // If weights is not nil, then the len(weights) must equal len(samples). // // Note: Laplace distribution has no FitPrior because it has no sufficient // statistics. func (l *Laplace) Fit(samples, weights []float64) { if len(samples) != len(weights) { panic(badLength) } if len(samples) == 0 { panic(badNoSamples) } if len(samples) == 1 { l.Mu = samples[0] l.Scale = 0 return } var ( sortedSamples []float64 sortedWeights []float64 ) if sort.Float64sAreSorted(samples) { sortedSamples = samples sortedWeights = weights } else { // Need to copy variables so the input variables aren't effected by the sorting sortedSamples = make([]float64, len(samples)) copy(sortedSamples, samples) sortedWeights := make([]float64, len(samples)) copy(sortedWeights, weights) stat.SortWeighted(sortedSamples, sortedWeights) } // The (weighted) median of the samples is the maximum likelihood estimate // of the mean parameter // TODO: Rethink quantile type when stat has more options l.Mu = stat.Quantile(0.5, stat.Empirical, sortedSamples, sortedWeights) sumWeights := floats.Sum(weights) // The scale parameter is the average absolute distance // between the sample and the mean absError := stat.MomentAbout(1, samples, l.Mu, weights) l.Scale = absError / sumWeights }
// SuffStat computes the sufficient statistics of a set of samples to update // the distribution. The sufficient statistics are stored in place, and the // effective number of samples are returned. // // The normal distribution has two sufficient statistics, the mean of the samples // and the standard deviation of the samples. // // If weights is nil, the weights are assumed to be 1, otherwise panics if // len(samples) != len(weights). Panics if len(suffStat) != 2. func (Normal) SuffStat(samples, weights, suffStat []float64) (nSamples float64) { lenSamp := len(samples) if len(weights) != 0 && len(samples) != len(weights) { panic("dist: slice size mismatch") } if len(suffStat) != 2 { panic("dist: incorrect suffStat length") } if len(weights) == 0 { nSamples = float64(lenSamp) } else { nSamples = floats.Sum(weights) } mean := stat.Mean(samples, weights) suffStat[0] = mean // Use Moment and not StdDev because we want it to be uncorrected variance := stat.MomentAbout(2, samples, mean, weights) suffStat[1] = math.Sqrt(variance) return nSamples }