#ifndef XGBOOST_REG_EVAL_H #define XGBOOST_REG_EVAL_H /*! * \file xgboost_reg_eval.h * \brief evaluation metrics for regression and classification * \author Kailong Chen: chenkl198812@gmail.com, Tianqi Chen: tianqi.tchen@gmail.com */ #include #include #include #include "../utils/xgboost_utils.h" #include "../utils/xgboost_omp.h" namespace xgboost{ namespace regression{ /*! \brief evaluator that evaluates the loss metrics */ struct IEvaluator{ /*! * \brief evaluate a specific metric * \param preds prediction * \param labels label */ virtual float Eval(const std::vector &preds, const std::vector &labels) const = 0; /*! \return name of metric */ virtual const char *Name(void) const = 0; }; /*! \brief RMSE */ struct EvalRMSE : public IEvaluator{ virtual float Eval(const std::vector &preds, const std::vector &labels) const{ const unsigned ndata = static_cast(preds.size()); float sum = 0.0; #pragma omp parallel for reduction(+:sum) schedule( static ) for (unsigned i = 0; i < ndata; ++i){ float diff = preds[i] - labels[i]; sum += diff * diff; } return sqrtf(sum / ndata); } virtual const char *Name(void) const{ return "rmse"; } }; /*! \brief Error */ struct EvalError : public IEvaluator{ virtual float Eval(const std::vector &preds, const std::vector &labels) const{ const unsigned ndata = static_cast(preds.size()); unsigned nerr = 0; #pragma omp parallel for reduction(+:nerr) schedule( static ) for (unsigned i = 0; i < ndata; ++i){ if (preds[i] > 0.5f){ if (labels[i] < 0.5f) nerr += 1; } else{ if (labels[i] > 0.5f) nerr += 1; } } return static_cast(nerr) / ndata; } virtual const char *Name(void) const{ return "error"; } }; /*! \brief Error */ struct EvalLogLoss : public IEvaluator{ virtual float Eval(const std::vector &preds, const std::vector &labels) const{ const unsigned ndata = static_cast(preds.size()); unsigned nerr = 0; #pragma omp parallel for reduction(+:nerr) schedule( static ) for (unsigned i = 0; i < ndata; ++i){ const float y = labels[i]; const float py = preds[i]; nerr -= y * std::log(py) + (1.0f - y)*std::log(1 - py); } return static_cast(nerr) / ndata; } virtual const char *Name(void) const{ return "negllik"; } }; }; namespace regression{ /*! \brief a set of evaluators */ struct EvalSet{ public: inline void AddEval(const char *name){ if (!strcmp(name, "rmse")) evals_.push_back(&rmse_); if (!strcmp(name, "error")) evals_.push_back(&error_); if (!strcmp(name, "logloss")) evals_.push_back(&logloss_); } inline void Init(void){ std::sort(evals_.begin(), evals_.end()); evals_.resize(std::unique(evals_.begin(), evals_.end()) - evals_.begin()); } inline void Eval(FILE *fo, const char *evname, const std::vector &preds, const std::vector &labels) const{ for (size_t i = 0; i < evals_.size(); ++i){ float res = evals_[i]->Eval(preds, labels); fprintf(fo, "\t%s-%s:%f", evname, evals_[i]->Name(), res); } } private: EvalRMSE rmse_; EvalError error_; EvalLogLoss logloss_; std::vector evals_; }; }; }; #endif