51#ifndef DOXYGEN_SHOULD_SKIP_THIS
82 const std::vector< NodeId >& conditioning_nodes,
83 const bool compute_log_likelihood) {
86 IdCondSet idset(target_node, conditioning_nodes,
true);
91 const std::vector< double >& original_N_ijk = this->
counter_.counts(idset,
true);
92 std::vector< double > N_ijk = original_N_ijk;
93 const bool informative_external_prior = this->
external_prior_->isInformative();
97 if (informative_external_prior) this->
external_prior_->addJointPseudoCount(idset, N_ijk);
98 if (informative_score_internal_prior)
100 double log_likelihood = 0.0;
106 if (!conditioning_nodes.empty()) {
109 std::vector< double > N_ij(this->
counter_.counts(idset.conditionalIdCondSet(),
false));
110 if (informative_external_prior)
112 if (informative_score_internal_prior)
115 const std::size_t conditioning_domsize = N_ij.size();
116 const std::size_t target_domsize = N_ijk.size() / conditioning_domsize;
119 for (std::size_t j = std::size_t(0); j < conditioning_domsize; ++j) {
122 const std::size_t cond_nb = conditioning_nodes.size();
123 std::vector< Idx > cond_domsize(cond_nb);
125 const auto& node2cols = this->
counter_.nodeId2Columns();
127 if (node2cols.empty()) {
128 for (std::size_t i = std::size_t(0); i < cond_nb; ++i) {
129 cond_domsize[i] =
database.domainSize(conditioning_nodes[i]);
132 for (std::size_t i = std::size_t(0); i < cond_nb; ++i) {
133 cond_domsize[i] =
database.domainSize(node2cols.second(conditioning_nodes[i]));
138 std::vector< Idx > offsets(cond_nb);
141 for (i = std::size_t(0); i < cond_nb; ++i) {
143 offset *= cond_domsize[i];
145 std::vector< Idx > values(cond_nb);
148 for (
Idx jj = cond_nb - 1; i < cond_nb; ++i, --jj) {
149 values[jj] = offset / offsets[jj];
150 offset %= offsets[jj];
154 std::string str =
"The conditioning set <";
156 for (i = std::size_t(0); i < cond_nb; ++i) {
157 if (deja) str +=
", ";
159 std::size_t col = node2cols.empty() ? conditioning_nodes[i]
160 : node2cols.second(conditioning_nodes[i]);
161 const DiscreteVariable& var
162 =
dynamic_cast< const DiscreteVariable&
>(
database.variable(col));
163 str += std::format(
"{}={}", var.name(), var.labels()[values[i]]);
165 auto target_col = node2cols.empty() ? target_node : node2cols.second(target_node);
166 const Variable& var =
database.variable(target_col);
167 str += std::format(
"> for target node {} never appears in the database. "
168 "Please consider using priors such as smoothing.",
176 if (compute_log_likelihood) {
177 for (std::size_t j = std::size_t(0), k = std::size_t(0); j < conditioning_domsize; ++j) {
178 for (std::size_t i = std::size_t(0); i < target_domsize; ++i, ++k) {
180 if (original_N_ijk[k]) { log_likelihood += original_N_ijk[k] * std::log(N_ijk[k]); }
184 for (std::size_t j = std::size_t(0), k = std::size_t(0); j < conditioning_domsize; ++j) {
185 for (std::size_t i = std::size_t(0); i < target_domsize; ++i, ++k) {
195 for (
const double n_ijk: N_ijk)
199 if (compute_log_likelihood) {
200 for (std::size_t k = std::size_t(0), end = N_ijk.size(); k < end; ++k) {
202 if (original_N_ijk[k]) { log_likelihood += original_N_ijk[k] * std::log(N_ijk[k]); }
205 for (
double& n_ijk: N_ijk)
209 const auto& node2cols = this->
counter_.nodeId2Columns();
211 auto target_col = node2cols.empty() ? target_node : node2cols.second(target_node);
212 const Variable& var =
database.variable(target_col);
214 std::format(
"No data for target node {}. It is impossible to estimate "
215 "the parameters by maximum likelihood",
220 return {std::move(N_ijk), log_likelihood};
The class for estimating parameters of CPTs using Maximum Likelihood.
ParamEstimatorML & operator=(const ParamEstimatorML &from)
copy operator
std::pair< std::vector< double >, double > _parametersAndLogLikelihood_(const NodeId target_node, const std::vector< NodeId > &conditioning_nodes, const bool compute_log_likelihood)
ParamEstimatorML(const DBRowGeneratorParser &parser, const Prior &external_prior, const Prior &_score_internal_prior, const std::vector< std::pair< std::size_t, std::size_t > > &ranges, const Bijection< NodeId, std::size_t > &nodeId2columns=Bijection< NodeId, std::size_t >())
default constructor
~ParamEstimatorML() override
destructor
RecordCounter counter_
the record counter used to parse the database
ParamEstimator & operator=(const ParamEstimator &from)
copy operator
Prior * score_internal_prior_
if a score was used for learning the structure of the PGM, this is the priori internal to the score
const DatabaseTable & database() const
returns the database on which we perform the counts
Prior * external_prior_
an external a priori
#define GUM_ERROR(type, msg)
Size Idx
Type for indexes.
Size NodeId
Type for node ids.
include the inlined functions if necessary
gum is the global namespace for all aGrUM entities
the class for estimating parameters of CPTs using Maximum Likelihood
the class for estimating parameters of CPTs using Maximum Likelihood