summaryrefslogtreecommitdiffstats
path: root/ml/dlib/dlib/optimization/isotonic_regression.h
diff options
context:
space:
mode:
Diffstat (limited to 'ml/dlib/dlib/optimization/isotonic_regression.h')
-rw-r--r--ml/dlib/dlib/optimization/isotonic_regression.h169
1 files changed, 169 insertions, 0 deletions
diff --git a/ml/dlib/dlib/optimization/isotonic_regression.h b/ml/dlib/dlib/optimization/isotonic_regression.h
new file mode 100644
index 000000000..e89e70b48
--- /dev/null
+++ b/ml/dlib/dlib/optimization/isotonic_regression.h
@@ -0,0 +1,169 @@
+// Copyright (C) 2018 Davis E. King (davis@dlib.net)
+// License: Boost Software License See LICENSE.txt for the full license.
+#ifndef DLIB_ISOTONIC_ReGRESSION_H_
+#define DLIB_ISOTONIC_ReGRESSION_H_
+
+#include "isotonic_regression_abstract.h"
+#include <vector>
+#include <utility>
+
+namespace dlib
+{
+ class isotonic_regression
+ {
+ public:
+
+ template <
+ typename const_iterator,
+ typename iterator
+ >
+ void operator() (
+ const_iterator begin,
+ const_iterator end,
+ iterator obegin
+ )
+ {
+ do_isotonic_regression(begin, end);
+
+ // unpack blocks to output
+ for (auto& block : blocks)
+ {
+ for (size_t k = 0; k < block.num; ++k)
+ set_val(*obegin++, block.avg);
+ }
+
+ blocks.clear();
+ }
+
+ void operator() (
+ std::vector<double>& vect
+ ) { (*this)(vect.begin(), vect.end(), vect.begin()); }
+
+ template <typename T, typename U>
+ void operator() (
+ std::vector<std::pair<T,U>>& vect
+ ) { (*this)(vect.begin(), vect.end(), vect.begin()); }
+
+
+ template <
+ typename const_iterator,
+ typename iterator
+ >
+ void fit_with_linear_output_interpolation (
+ const_iterator begin,
+ const_iterator end,
+ iterator obegin
+ )
+ {
+ do_isotonic_regression(begin, end);
+
+ // Unpack blocks to output, but here instead of producing the step function
+ // output we linearly interpolate. Note that this actually fits the data less
+ // than the step-function, but in many applications might be closer to what you
+ // really when when using isotonic_regression than the step function.
+ for (size_t i = 0; i < blocks.size(); ++i)
+ {
+ auto& block = blocks[i];
+
+ double prev = (blocks.front().avg + block.avg)/2;
+ if (i > 0)
+ prev = (blocks[i-1].avg+block.avg)/2;
+
+ double next = (blocks.back().avg + block.avg)/2;
+ if (i+1 < blocks.size())
+ next = (blocks[i+1].avg+block.avg)/2;
+
+ for (size_t k = 0; k < block.num; ++k)
+ {
+ const auto mid = block.num/2.0;
+ if (k < mid)
+ {
+ const double alpha = k/mid;
+ set_val(*obegin++, (1-alpha)*prev + alpha*block.avg);
+ }
+ else
+ {
+ const double alpha = k/mid-1;
+ set_val(*obegin++, alpha*next + (1-alpha)*block.avg);
+ }
+ }
+ }
+
+ blocks.clear();
+ }
+
+ void fit_with_linear_output_interpolation (
+ std::vector<double>& vect
+ ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); }
+
+ template <typename T, typename U>
+ void fit_with_linear_output_interpolation (
+ std::vector<std::pair<T,U>>& vect
+ ) { fit_with_linear_output_interpolation(vect.begin(), vect.end(), vect.begin()); }
+
+ private:
+
+ template <
+ typename const_iterator
+ >
+ void do_isotonic_regression (
+ const_iterator begin,
+ const_iterator end
+ )
+ {
+ blocks.clear();
+
+ // Do the actual isotonic regression. The output is a step-function and is
+ // stored in the vector of blocks.
+ for (auto i = begin; i != end; ++i)
+ {
+ blocks.emplace_back(get_val(*i));
+ while (blocks.size() > 1 && prev_block().avg > current_block().avg)
+ {
+ // merge the last two blocks.
+ prev_block() = prev_block() + current_block();
+ blocks.pop_back();
+ }
+ }
+ }
+
+
+ template <typename T>
+ static double get_val(const T& v) { return v;}
+
+ template <typename T, typename U>
+ static double get_val(const std::pair<T,U>& v) { return v.second;}
+
+ template <typename T>
+ static void set_val(T& v, double val) { v = val;}
+
+ template <typename T, typename U>
+ static void set_val(std::pair<T,U>& v, double val) { v.second = val;}
+
+
+
+ struct block_t
+ {
+ block_t(double val) : num(1), avg(val) {}
+ block_t(size_t n, double val) : num(n), avg(val) {}
+
+ size_t num;
+ double avg;
+
+ inline block_t operator+(const block_t& rhs) const
+ {
+ return block_t(num+rhs.num,
+ (num*avg + rhs.num*rhs.avg)/(num+rhs.num));
+ }
+ };
+
+ inline block_t& prev_block() { return blocks[blocks.size()-2]; }
+ inline block_t& current_block() { return blocks.back(); }
+
+ std::vector<block_t> blocks;
+ };
+}
+
+#endif // DLIB_ISOTONIC_ReGRESSION_H_
+
+