1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
|
#ifndef MEDIANWINDOW_H
#define MEDIANWINDOW_H
#include <algorithm>
#include <limits>
#include <vector>
#include "../structures/samplerow.h"
namespace algorithms {
template <typename NumType>
class MedianWindow {
public:
static void SubtractMedian(SampleRow& sampleRow, unsigned windowSize) {
if (windowSize > sampleRow.Size() * 2) windowSize = sampleRow.Size() * 2;
SampleRow copy(sampleRow);
MedianWindow<num_t> window;
unsigned rightPtr, leftPtr = 0;
for (rightPtr = 0; rightPtr < ((windowSize - 1) / 2); ++rightPtr) {
if (!copy.ValueIsMissing(rightPtr)) window.Add(copy.Value(rightPtr));
}
for (unsigned i = 0; i < sampleRow.Size(); ++i) {
if (rightPtr < sampleRow.Size()) {
if (!copy.ValueIsMissing(rightPtr)) window.Add(copy.Value(rightPtr));
++rightPtr;
}
if (rightPtr > windowSize) {
if (!copy.ValueIsMissing(leftPtr)) window.Remove(copy.Value(leftPtr));
++leftPtr;
}
sampleRow.SetValue(i, copy.Value(i) - window.Median());
}
}
private:
std::vector<NumType> data_;
void Add(NumType sample) {
// Add after the last value, to reduce the number of elements to shift.
data_.insert(std::upper_bound(data_.begin(), data_.end(), sample), sample);
}
void Remove(NumType sample) {
// Remove the last occurance, to reduce the number of elements to shift.
data_.erase(std::upper_bound(data_.begin(), data_.end(), sample) - 1);
}
NumType Median() const {
if (data_.size() == 0) return std::numeric_limits<NumType>::quiet_NaN();
if (data_.size() % 2 == 0) {
unsigned m = data_.size() / 2 - 1;
typename std::vector<NumType>::const_iterator i = data_.begin();
i += m;
NumType lMid = *i;
++i;
NumType rMid = *i;
return (lMid + rMid) / 2.0;
} else {
unsigned m = data_.size() / 2;
typename std::vector<NumType>::const_iterator i = data_.begin();
i += m;
return *i;
}
}
};
} // namespace algorithms
#endif
|