4#include <gsl/gsl_cdf.h>
5#include <gsl/gsl_randist.h>
11 fitted_distribution_(),
12 estimated_distribution_()
18 fitted_distribution_(other.fitted_distribution_),
19 estimated_distribution_(other.estimated_distribution_)
25 fitted_distribution_(),
26 estimated_distribution_()
36 vector<double>::operator=(other);
52 insert(end(), other.begin(), other.end());
57 if (other !=
nullptr) {
58 insert(end(), other->begin(), other->end());
71 for (
const double value : *
this) {
75 return sum /
static_cast<double>(size());
84 if (mean_value == -999) {
89 for (
const double value : *
this) {
90 sum += pow(value - mean_value, 2);
93 return sqrt(sum /
static_cast<double>(size() - 1));
102 if (mean_value == -999) {
107 for (
const double value : *
this) {
108 sum += pow(
log(value) - mean_value, 2);
111 return sqrt(sum /
static_cast<double>(size() - 1));
116 if (mean_value == -999) {
121 for (
const double value : *
this) {
122 sum += pow(value - mean_value, 2);
130 if (mean_value == -999) {
135 for (
const double value : *
this) {
136 sum += pow(
log(value) - mean_value, 2);
149 for (
const double value : *
this) {
153 return sum /
static_cast<double>(size());
159 for (
const double value : *
this) {
160 sum += pow(value,
power);
169 for (
const double value : *
this) {
180 for (
size_t i = 0; i < size(); i++) {
181 transformed[i] =
log(at(i));
189 return aquiutils::Min(*
this);
194 return aquiutils::Max(*
this);
202 vector<double> parameters;
234 const vector<double>& params,
237 double log_likelihood = 0.0;
241 for (
const double value : *
this) {
251 for (
const double value : *
this) {
252 log_likelihood +=
log(dist.
Eval(value));
256 return log_likelihood;
274 vector<double> sorted_data = QSort(*
this);
277 double probability_increment = 1.0 /
static_cast<double>(sorted_data.size());
279 for (
size_t i = 0; i < sorted_data.size(); i++) {
280 double cumulative_probability = (
static_cast<double>(i) + 0.5) * probability_increment;
281 cdf.append(sorted_data[i], cumulative_probability);
296 double x_min = comparison[0].mint();
297 double x_max = comparison[0].maxt();
298 double step_size = (x_max - x_min) / 50.0;
300 for (
double x = x_min;
x <= x_max;
x += step_size) {
301 double cumulative_prob = 0.0;
312 fitted_cdf.append(
x, cumulative_prob);
315 comparison.append(fitted_cdf,
"Fitted");
316 comparison.append(comparison[0] - comparison[1],
"Error");
329 vector<double> parameters;
341 double x_min = result[0].mint();
342 double x_max = result[0].maxt();
343 double step_size = (x_max - x_min) / 50.0;
345 for (
double x = x_min;
x <= x_max;
x += step_size) {
350 result[
"Observed"] = fitted_pdf.maxC() / 2.0;
351 result.append(fitted_pdf,
"Fitted");
362 double max_positive_diff = fabs(observed_fitted[2].maxC());
363 double max_negative_diff = fabs(observed_fitted[2].minC());
365 return std::max(max_positive_diff, max_negative_diff);
377 double variance_term = 0.0;
378 double jacobian_term = 0.0;
380 for (
size_t i = 0; i < size(); i++) {
381 variance_term += -1.0 /
static_cast<double>(size()) *
382 pow(transformed[i] - transformed_mean, 2);
383 jacobian_term += (lambda - 1.0) *
log(at(i) / std_dev);
386 return -
static_cast<double>(size()) / 2.0 *
log(variance_term) - jacobian_term;
391 bool normalize)
const
398 for (
size_t i = 0; i < size(); i++) {
399 scaled[i] = at(i) / std_dev;
409 for (
size_t i = 0; i < size(); i++) {
410 scaled[i] = at(i) / std_dev;
416 for (
size_t i = 0; i < size(); i++) {
417 if (fabs(lambda) > 1e-5) {
419 transformed[i] = (pow(scaled[i], lambda) - 1.0) / lambda;
423 transformed[i] =
log(scaled[i]);
433 int n_intervals)
const
442 std::cerr <<
"Warning: NaN detected in concentration data" << std::endl;
447 if (fabs(min_lambda - max_lambda) < 1e-6) {
448 return (min_lambda + max_lambda) / 2.0;
452 vector<double> ks_statistics;
453 double lambda_step = (max_lambda - min_lambda) /
static_cast<double>(n_intervals);
455 for (
double lambda = min_lambda; lambda <= max_lambda; lambda += lambda_step) {
460 ks_statistics.push_back(ks_stat);
464 int min_index = aquiutils::MinElement(ks_statistics);
467 int lower_index = std::max(min_index - 1, 0);
468 int upper_index = std::min(min_index + 1,
static_cast<int>(ks_statistics.size() - 1));
470 double refined_min = min_lambda + lower_index * lambda_step;
471 double refined_max = min_lambda + upper_index * lambda_step;
480 return aquiutils::Rank(*
this);
Collection of time series with labels and observed values.
Time series data container with Interface support.
Manages a collection of concentration measurements with statistical analysis.
double CalculateSSE(double mean_value=-999) const
Calculate sum of squared errors from mean.
ConcentrationSet CreateLogTransformed() const
Create log-transformed copy.
double CalculateMean() const
Calculate arithmetic mean.
double CalculateLogLikelihood(const vector< double > ¶ms=vector< double >(), distribution_type dist_type=distribution_type::none) const
Calculate log-likelihood of data given distribution parameters.
CMBTimeSeriesSet CreateCDFComparison(distribution_type dist_type) const
Create comparison of empirical vs fitted CDF.
double CalculateStdDevLog(double mean_value=-999) const
Calculate standard deviation of log-transformed values.
vector< double > EstimateDistributionParameters(distribution_type dist_type=distribution_type::none)
Estimate distribution parameters from data.
Distribution estimated_distribution_
Distribution being optimized (e.g., in MCMC)
CMBTimeSeries CreateDataCDF() const
Create empirical CDF from data.
double CalculateMeanLog() const
Calculate mean of log-transformed values.
double CalculateBoxCoxLogLikelihood(double lambda) const
Calculate Box-Cox log-likelihood for given lambda.
double CalculateNormLog(double power=2.0) const
Calculate sum of log-transformed values raised to a power.
double CalculateKolmogorovSmirnovStatistic(distribution_type dist_type) const
Calculate Kolmogorov-Smirnov statistic.
vector< unsigned int > CalculateRanks() const
Calculate ranks of values (1 = smallest)
double GetMaximum() const
Get maximum value.
distribution_type SelectBestDistribution()
Select best-fitting distribution (normal vs lognormal)
void AppendSet(const ConcentrationSet &other)
Append all values from another set.
double GetMinimum() const
Get minimum value.
double FindOptimalBoxCoxParameter(double min_lambda, double max_lambda, int n_intervals) const
Find optimal Box-Cox lambda parameter.
ConcentrationSet ApplyBoxCoxTransform(double lambda, bool normalize) const
Apply Box-Cox transformation.
double CalculateNorm(double power=2.0) const
Calculate sum of values raised to a power.
void AppendValue(double value)
Append a single concentration value.
CMBTimeSeriesSet CreateFittedDistribution(distribution_type dist_type) const
Create fitted distribution visualization.
ConcentrationSet & operator=(const ConcentrationSet &other)
double CalculateSSELog(double mean_value=-999) const
Calculate sum of squared errors from log mean.
double CalculateStdDev(double mean_value=-999) const
Calculate standard deviation.
Distribution fitted_distribution_
Distribution fitted to observed data.
Represents a parametric probability distribution for uncertainty quantification.
double Eval(const double &x) const
Evaluate probability density function at a given value.
vector< double > parameters
Distribution parameters vector.
distribution_type distribution
The type of probability distribution.
void SetDataMean(const double &val)
Set the empirical mean from original data.
void SetType(const distribution_type &typ)
Set the distribution type and resize parameters vector.
void SetDataSTDev(const double &val)
Set the empirical standard deviation from original data.
distribution_type
Enumeration of probability distribution types supported in SedSat3.
@ none
No distribution assigned (uninitialized state)
@ lognormal
Lognormal distribution: ln(x) ~ N(μ, σ²), for strictly positive variables.
@ normal
Normal (Gaussian) distribution: p(x) = N(μ, σ²)