in lib/maths/time_series/CTimeSeriesModel.cc [953:1078]
bool CUnivariateTimeSeriesModel::uncorrelatedProbability(
const common::CModelProbabilityParams& params,
const TTime2Vec1Vec& time_,
const TDouble2Vec1Vec& value,
common::SModelProbabilityResult& result) const {
maths_t::EProbabilityCalculation calculation{params.calculation(0)};
maths_t::TDoubleWeightsAry1Vec weights{unpack(params.weights()[0])};
TDouble4Vec probabilities;
common::SModelProbabilityResult::TFeatureProbability4Vec featureProbabilities;
double pl;
double pu;
maths_t::ETail tail;
core_t::TTime time{time_[0][0]};
TDouble1Vec sample{m_TrendModel->detrend(
time, value[0][0], params.seasonalConfidenceInterval(), m_IsNonNegative)};
if (m_ResidualModel->probabilityOfLessLikelySamples(calculation, sample,
weights, pl, pu, tail)) {
LOG_TRACE(<< "P(" << sample << " | weight = " << weights
<< ", time = " << time << ") = " << (pl + pu) / 2.0);
double pSingleBucket{(pl + pu) / 2.0};
probabilities.push_back(pSingleBucket);
featureProbabilities.emplace_back(
common::SModelProbabilityResult::E_SingleBucketProbability, pSingleBucket);
if (pSingleBucket < common::LARGEST_SIGNIFICANT_PROBABILITY) {
result.s_AnomalyScoreExplanation.s_SingleBucketImpact =
static_cast<int>(std::round(-std::log10(pSingleBucket)));
}
if (maths_t::seasonalVarianceScale(weights[0]) > 1.0) {
result.s_AnomalyScoreExplanation.s_HighVariancePenalty = true;
}
if (maths_t::countVarianceScale(weights[0]) > 1.0) {
result.s_AnomalyScoreExplanation.s_IncompleteBucketPenalty = true;
}
} else {
LOG_ERROR(<< "Failed to compute P(" << sample
<< " | weight = " << weights << ", time = " << time << ")");
return false;
}
double correlation{0.0};
if (m_MultibucketFeatureModel != nullptr && params.useMultibucketFeatures()) {
double pMultiBucket{1.0};
TDouble1Vec feature;
std::tie(feature, std::ignore) = m_MultibucketFeature->value();
if (feature.empty() == false) {
for (auto calculation_ : expand(calculation)) {
maths_t::ETail dummy;
if (m_MultibucketFeatureModel->probabilityOfLessLikelySamples(
calculation_, feature,
maths_t::CUnitWeights::SINGLE_UNIT, pl, pu, dummy)) {
LOG_TRACE(<< "P(" << feature << ") = " << (pl + pu) / 2.0);
} else {
LOG_ERROR(<< "Failed to compute P(" << feature << ")");
return false;
}
pMultiBucket = std::min(pMultiBucket, (pl + pu) / 2.0);
}
correlation = m_MultibucketFeature->correlationWithBucketValue();
}
if (pMultiBucket < common::LARGEST_SIGNIFICANT_PROBABILITY) {
result.s_AnomalyScoreExplanation.s_MultiBucketImpact =
static_cast<int>(std::round(-std::log10(pMultiBucket)));
}
probabilities.push_back(pMultiBucket);
featureProbabilities.emplace_back(
common::SModelProbabilityResult::E_MultiBucketProbability, pMultiBucket);
}
double pOverall{aggregateFeatureProbabilities(probabilities, correlation)};
if (m_AnomalyModel != nullptr && params.useAnomalyModel()) {
TDouble2Vec seasonalWeight;
this->seasonalWeight(0.0, time, seasonalWeight);
double residual{
(sample[0] - m_ResidualModel->nearestMarginalLikelihoodMean(sample[0])) /
std::max(std::sqrt(seasonalWeight[0]), 1.0)};
double pSingleBucket{probabilities[0]};
m_AnomalyModel->sample(params, time, residual, pSingleBucket, pOverall);
double pAnomaly;
std::tie(pOverall, pAnomaly) = m_AnomalyModel->probability(pSingleBucket, pOverall);
if (pAnomaly < common::LARGEST_SIGNIFICANT_PROBABILITY) {
result.s_AnomalyScoreExplanation.s_AnomalyType =
(m_AnomalyModel->sumPredictionError() > (0.0))
? common::SAnomalyScoreExplanation::E_SPIKE
: common::SAnomalyScoreExplanation::E_DIP;
result.s_AnomalyScoreExplanation.s_AnomalyLength = m_AnomalyModel->length(time);
result.s_AnomalyScoreExplanation.s_AnomalyCharacteristicsImpact =
static_cast<int>(std::round(-std::log10(pAnomaly)));
}
probabilities.push_back(pAnomaly);
featureProbabilities.emplace_back(
common::SModelProbabilityResult::E_AnomalyModelProbability, pAnomaly);
}
if (pOverall < common::LARGEST_SIGNIFICANT_PROBABILITY) {
LOG_TRACE(<< "Computing confidence bounds");
TDouble2Vec3Vec interval(this->confidenceInterval(
time, CModel::DEFAULT_BOUNDS_PERCENTILE, params.weights()[0]));
result.s_AnomalyScoreExplanation.s_LowerConfidenceBound = interval[0][0];
result.s_AnomalyScoreExplanation.s_TypicalValue = interval[1][0];
result.s_AnomalyScoreExplanation.s_UpperConfidenceBound = interval[2][0];
}
result.s_AnomalyScoreExplanation.s_MultimodalDistribution =
m_ResidualModel->isSelectedModelMultimodal();
LOG_TRACE(<< "Multimodel distribution: "
<< result.s_AnomalyScoreExplanation.s_MultimodalDistribution);
result.s_Probability = pOverall;
result.s_FeatureProbabilities = std::move(featureProbabilities);
result.s_Tail = {tail};
return true;
}