From d49e1ad5e9ec120643936d6841996efe5b271d84 Mon Sep 17 00:00:00 2001 From: Rainer Kartmann <rainer.kartmann@kit.edu> Date: Thu, 8 Oct 2020 10:11:51 +0200 Subject: [PATCH] Redirect stats in VirtualRobot to SimoxUtility --- VirtualRobot/CMakeLists.txt | 2 - VirtualRobot/math/statistics/BoxPlot.cpp | 60 ------- VirtualRobot/math/statistics/BoxPlot.h | 31 +--- VirtualRobot/math/statistics/Histogram.cpp | 177 --------------------- VirtualRobot/math/statistics/Histogram.h | 92 +---------- VirtualRobot/math/statistics/measures.cpp | 78 ++------- 6 files changed, 22 insertions(+), 418 deletions(-) delete mode 100644 VirtualRobot/math/statistics/BoxPlot.cpp delete mode 100644 VirtualRobot/math/statistics/Histogram.cpp diff --git a/VirtualRobot/CMakeLists.txt b/VirtualRobot/CMakeLists.txt index 8e32dec13..738f6bd2a 100644 --- a/VirtualRobot/CMakeLists.txt +++ b/VirtualRobot/CMakeLists.txt @@ -271,8 +271,6 @@ SET(SOURCES math/Triangle.cpp math/WeightedAverage.cpp math/statistics/measures.cpp - math/statistics/BoxPlot.cpp - math/statistics/Histogram.cpp MJCF/Document.cpp MJCF/elements/core/AnyElement.cpp diff --git a/VirtualRobot/math/statistics/BoxPlot.cpp b/VirtualRobot/math/statistics/BoxPlot.cpp deleted file mode 100644 index 08b5445a5..000000000 --- a/VirtualRobot/math/statistics/BoxPlot.cpp +++ /dev/null @@ -1,60 +0,0 @@ -#include "BoxPlot.h" - -#include "measures.h" - - -namespace math { namespace stat -{ - - -BoxPlot::BoxPlot() = default; - - -BoxPlot::BoxPlot(const std::vector<float>& values, bool isSorted, float whisk) : - whisk(whisk) -{ - set(values, isSorted); -} - -void BoxPlot::set(const std::vector<float>& _values, bool isSorted) -{ - const std::vector<float>& values = isSorted ? _values : sorted(_values); - - this->minimum = stat::min(values, true); - this->maximum = stat::max(values, true); - - this->lowerQuartile = stat::lowerQuartile(values, true); - this->median = stat::median(values, true); - this->upperQuartile = stat::upperQuartile(values, true); - - const float iqr = interquartileRange(lowerQuartile, upperQuartile); - - this->minWhisker = lowerQuartile - whisk * iqr; - this->maxWhisker = upperQuartile + whisk * iqr; - - - // compute outliers and correct whiskers if necessary - - { - auto it = values.begin(); - for (; it != values.end() && *it < minWhisker; ++it) - { - outliers.push_back(*it); - } - minWhisker = (it != values.begin()) ? *it : minimum; - } - - { - auto rit = values.rbegin(); - for (; rit != values.rend() && *rit > maxWhisker; ++rit) - { - outliers.push_back(*rit); - } - maxWhisker = (rit != values.rbegin()) ? *rit : maximum; - } - -} - - - -}} diff --git a/VirtualRobot/math/statistics/BoxPlot.h b/VirtualRobot/math/statistics/BoxPlot.h index cd9089d6e..5c76ebe82 100644 --- a/VirtualRobot/math/statistics/BoxPlot.h +++ b/VirtualRobot/math/statistics/BoxPlot.h @@ -1,37 +1,10 @@ #pragma once -#include <vector> +#include <SimoxUtility/math/statistics/BoxPlotStats.h> namespace math { namespace stat { - - /** - * @brief Computes and stores statistical measures found in a box plot. - */ - class BoxPlot - { - public: - - - BoxPlot(); - BoxPlot(const std::vector<float>& values, bool isSorted = false, float whisk = 1.5); - - void set(const std::vector<float>& values, bool isSorted = false); - - float whisk = 1.5; - - float minimum; - float minWhisker; - float lowerQuartile; - float median; - float upperQuartile; - float maxWhisker; - float maximum; - - std::vector<float> outliers; - - }; - + using BoxPlot = simox::math::BoxPlotStats; }} diff --git a/VirtualRobot/math/statistics/Histogram.cpp b/VirtualRobot/math/statistics/Histogram.cpp deleted file mode 100644 index 3ec3cd128..000000000 --- a/VirtualRobot/math/statistics/Histogram.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "Histogram.h" - -#include <algorithm> - - -namespace VirtualRobot -{ - -Histogram::Histogram() -{} - -Histogram::Histogram(const std::vector<float>& data, std::size_t numBins) -{ - setMinMax(data); - resetBins(numBins); - insert(data); -} - -Histogram::Histogram(const std::vector<float>& data, float min, float max, std::size_t numBins) -{ - setMinMax(min, max); - resetBins(numBins); - insert(data); -} - -void Histogram::resetBins(std::size_t numBins) -{ - bins.assign(numBins, 0); -} - -std::size_t Histogram::valueToIndex(float value) const -{ - // normalized = 0..1 - float normalized = (value - min) / (max - min); - std::size_t index = static_cast<std::size_t>(normalized * getNumberOfBins()); - - // avoid out-of-bounce errors - // (if histogram is falsely used, this could lead to peaks at the edges) - return std::max(std::size_t(0), std::min(getNumberOfBins() - 1, index)); -} - -float Histogram::indexToValue(std::size_t index) const -{ - float normalized = static_cast<float>(index) / getNumberOfBins(); - float value = normalized * (max - min) + min; - return value; -} - -void Histogram::insert(float value) -{ - bins[valueToIndex(value)]++; -} - -void Histogram::insert(const std::vector<float>& values) -{ - for (float v : values) - { - insert(v); - } -} - -void Histogram::setMinMax(float min, float max) -{ - this->min = min; - this->max = max; -} - -void Histogram::setMinMax(const std::vector<float>& data) -{ - float min = data.front(); - float max = data.front(); - - for (float d : data) - { - min = std::min(min, d); - max = std::max(max, d); - } - setMinMax(min, max); -} - -const std::vector<std::size_t>& Histogram::getBins() const -{ - return bins; -} - -std::size_t Histogram::getNumberOfBins() const -{ - return bins.size(); -} - -float Histogram::getMin() const -{ - return min; -} - -float Histogram::getMax() const -{ - return max; -} - -std::size_t Histogram::getMinBinIndex() const -{ - return static_cast<std::size_t>( - std::distance(bins.begin(), std::min_element(bins.begin(), bins.end()))); -} - -float Histogram::getMinBinValue() const -{ - return indexToValue(getMaxBinIndex()); -} - -std::size_t Histogram::getMaxBinIndex() const -{ - return static_cast<std::size_t>( - std::distance(bins.begin(), std::max_element(bins.begin(), bins.end()))); -} - -float Histogram::getMaxBinValue() const -{ - return indexToValue(getMaxBinIndex()); -} - -void Histogram::applyMedianFilter(std::size_t size) -{ - std::vector<std::size_t> newBins(bins.size()); - std::vector<std::size_t> neighborhood(2 * size + 1); - - for (std::size_t index = 0; index < bins.size(); index++) - { - // handle cases at borders - std::size_t beginIndex = std::max(index - size, std::size_t(0)); - std::size_t endIndex = std::min(index + size + 1, bins.size()); - std::size_t num = endIndex - beginIndex; // common case: num == 2*size+1 - - // example: index = 3, size = 2 - // => beginIndex = 3-2 = 1, endIndex = 3+2+1 = 6, num = 6-1 = 5 - // => neighborhood = [1, 6) == [1,5] - - neighborhood.assign(bins.begin() + beginIndex, bins.begin() + endIndex); - - std::sort(neighborhood.begin(), neighborhood.begin() + num); - - newBins[index] = neighborhood[num / 2]; // == median - // (ignore cases where num is even, this only happens at the borders) - } - - bins = newBins; -} - -std::ostream& operator<<(std::ostream& os, const Histogram& histo) -{ - os << "Histogram:\n"; - os << "min:;" << histo.min << ";max:;" << histo.max << ";\n"; - - os << "Index:;"; - for (std::size_t index = 0; index < histo.bins.size(); index++) - { - os << index << ";"; - } - os << "\n"; - os << "Values:;"; - for (std::size_t index = 0; index < histo.bins.size(); index++) - { - os << histo.indexToValue(index) << ";"; - } - os << "\n"; - os << "Counts:;"; - for (std::size_t index = 0; index < histo.bins.size(); index++) - { - os << histo.bins[index] << ";"; - } - os << "\n"; - - return os; -} - -} diff --git a/VirtualRobot/math/statistics/Histogram.h b/VirtualRobot/math/statistics/Histogram.h index 9ecdc0162..8a369ffd8 100644 --- a/VirtualRobot/math/statistics/Histogram.h +++ b/VirtualRobot/math/statistics/Histogram.h @@ -1,98 +1,14 @@ #pragma once -#include <vector> -#include <ostream> +#include <SimoxUtility/math/statistics/Histogram.h> namespace VirtualRobot { - /** - * @brief Histogram for one-dimensional float data. - */ - class Histogram + namespace math { namespace stat { - public: - - /// No initialization constructor. - Histogram(); - - /// Construct with the given data. - /// Minimum and maximum are derived automatically. - Histogram(const std::vector<float>& data, std::size_t numBins = 128); - - /// Construct with the given data and given limits. - Histogram(const std::vector<float>& data, float min, float max, std::size_t numBins = 128); - - - /// Set the number of bins and set them to 0. - void resetBins(std::size_t numBins); - - /// Insert the given value into the histogram. - void insert(float value); - /// Inserts the given values into the histogram. - void insert(const std::vector<float>& value); - - /// Set the limits. - void setMinMax(float min, float max); - /// Set the limits from the given data. - void setMinMax(const std::vector<float>& data); - - - /// Get the bins. - const std::vector<std::size_t>& getBins() const; - - /// Get the number of bins. - std::size_t getNumberOfBins() const; - - /// Transfer the given value to its corresponding bin index. - std::size_t valueToIndex(float value) const; - /// Get the value at the center of the bin with the given index. - float indexToValue(std::size_t index) const; - - /// Get the minimum, i.e. the lower limit. - float getMin() const; - /// Get the maximum, i.e. the upper limit. - float getMax() const; - - /// Return the index of the bin containing the fewest data points. - std::size_t getMinBinIndex() const; - /// Returns the corresponding value of the bin containing the fewest data points. - float getMinBinValue() const; - - /// Return the index of the bin containing the most data points. - std::size_t getMaxBinIndex() const; - /// Returns the corresponding value of the bin containing the most data points. - float getMaxBinValue() const; - - - /** - * @brief Applies a median filter to the histogram bins. - * - * The size specifies the number of neighours (in each direction) - * considered. - * That is, if k = size, 2k+1 values are considered for each point - * (k neighbours in each direction). - * - * @param size the size of the neighbourhood (in each direction) - */ - void applyMedianFilter(std::size_t size = 2); - - - /// Streams a CVS-like description of the histogram containing the bin data. - friend std::ostream& operator<<(std::ostream& os, const Histogram& histo); - - - private: - - /// The minimum mapped value. - float min; - /// The maximum mapped value. - float max; - - /// The bins. - std::vector<std::size_t> bins; - - }; + using Histogram = simox::math::Histogram; + }} } diff --git a/VirtualRobot/math/statistics/measures.cpp b/VirtualRobot/math/statistics/measures.cpp index 1430b7b22..73aa17070 100644 --- a/VirtualRobot/math/statistics/measures.cpp +++ b/VirtualRobot/math/statistics/measures.cpp @@ -1,120 +1,74 @@ #include "measures.h" -#include <algorithm> -#include <cmath> -#include <stdexcept> +#include <SimoxUtility/math/statistics/measures.h> namespace math { namespace stat { -static void checkNotEmpty(const std::vector<float>& values) -{ - if (values.empty()) - throw std::range_error("Given values are empty."); -} - void sort(std::vector<float>& values) { - std::sort(values.begin(), values.end()); + simox::math::sort(values); } std::vector<float> sorted(const std::vector<float>& values) { - std::vector<float> s = values; - std::sort(s.begin(), s.end()); - return s; + return simox::math::sorted(values); } float min(const std::vector<float>& values, bool isSorted) { - checkNotEmpty(values); - return isSorted ? values.front() : *std::min_element(values.begin(), values.end()); + return simox::math::min(values, isSorted); } float max(const std::vector<float>& values, bool isSorted) { - checkNotEmpty(values); - return isSorted ? values.back() : *std::max_element(values.begin(), values.end()); + return simox::math::max(values, isSorted); } float mean(const std::vector<float>& values) { - checkNotEmpty(values); - - float sum = 0; - for (float v : values) - { - sum += v; - } - return sum / values.size(); + return simox::math::mean(values); } float stddev(const std::vector<float>& values) { - return stddev(values, mean(values)); + return simox::math::stddev(values); } float stddev(const std::vector<float>& values, float mean) { - checkNotEmpty(values); - float sum = 0; - for (float v : values) - { - float diff = v - mean; - sum += diff * diff; - } - float variance = sum / (values.size() - 1); - return std::sqrt(variance); + return simox::math::stddev(values, mean); } -float quantile(const std::vector<float>& _values, float p, bool isSorted) +float quantile(const std::vector<float>& values, float p, bool isSorted) { - checkNotEmpty(_values); - const std::vector<float>& values = isSorted ? _values : sorted(_values); - - float location = p < 1 ? p * values.size() : values.size() - 1; - - std::size_t floor = static_cast<std::size_t>(std::floor(location)); - std::size_t ceil = static_cast<std::size_t>(std::ceil(location)); - - if (floor == ceil) - { - return values.at(floor); - } - else - { - float t = location - floor; - return (1 - t) * values.at(floor) + t * values.at(ceil); - } + return simox::math::quantile(values, p, isSorted); } float lowerQuartile(const std::vector<float>& values, bool isSorted) { - return quantile(values, .25, isSorted); + return simox::math::lower_quartile(values, isSorted); } float median(const std::vector<float>& values, bool isSorted) { - return quantile(values, .5, isSorted); + return simox::math::median(values, isSorted); } float upperQuartile(const std::vector<float>& values, bool isSorted) { - return quantile(values, .75, isSorted); + return simox::math::upper_quartile(values, isSorted); } -float interquartileRange(const std::vector<float>& _values, bool isSorted) +float interquartileRange(const std::vector<float>& values, bool isSorted) { - checkNotEmpty(_values); - - const std::vector<float>& values = isSorted ? _values : sorted(_values); - return interquartileRange(lowerQuartile(values, true), upperQuartile(values, true)); + return simox::math::interquartile_range(values, isSorted); } float interquartileRange(float lowerQuartile, float upperQuartile) { - return upperQuartile - lowerQuartile; + return simox::math::interquartile_range(lowerQuartile, upperQuartile); } -- GitLab