9#include "MantidKernel/DllConfig.h"
12#include <boost/accumulators/accumulators.hpp>
13#include <boost/accumulators/statistics/max.hpp>
14#include <boost/accumulators/statistics/min.hpp>
15#include <boost/accumulators/statistics/stats.hpp>
16#include <boost/accumulators/statistics/variance.hpp>
26Logger logger(
"Statistics");
28void assertMomentIsValid(
const int maxMoment) {
30 std::stringstream msg;
31 msg <<
"moment = " << maxMoment <<
" is statistically meaningless";
32 throw std::runtime_error(msg.str());
42template <
typename Range> Statistics
getStatisticsImpl(Range
const &data,
const unsigned int flags);
43template <
typename Range> std::vector<double>
getZscoreImpl(Range
const &data);
46 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
58template <
typename Range>
double getMedian(Range
const &data) {
59 using value_type = std::decay_t<
decltype(data[0])>;
60 const size_t size = data.size();
62 return static_cast<double>(data[0]);
64 const bool isSorted = std::is_sorted(data.begin(), data.end());
65 const bool is_even = (size % 2 == 0);
68 return (
static_cast<double>(data[size / 2 - 1]) +
static_cast<double>(data[size / 2])) / 2;
70 return static_cast<double>(data[size / 2]);
72 std::vector<value_type> tmpSortedData(data.begin(), data.end());
73 std::sort(tmpSortedData.begin(), tmpSortedData.end());
75 return (
static_cast<double>(tmpSortedData[size / 2 - 1]) +
static_cast<double>(tmpSortedData[size / 2])) / 2;
77 return static_cast<double>(tmpSortedData[size / 2]);
85template <
typename Range> std::vector<double>
getZscoreImpl(Range
const &data) {
86 std::vector<double> Zscore;
87 if (data.size() < 3) {
88 Zscore.resize(data.size(), 0.);
93 Zscore.resize(data.size(), 0.);
96 for (
auto it = data.begin(); it != data.end(); ++it) {
97 auto tmp =
static_cast<double>(*it);
111template <
typename TYPE> std::vector<double>
getWeightedZscore(
const vector<TYPE> &data,
const vector<TYPE> &weights) {
112 std::vector<double> Zscore;
113 if (data.size() < 3) {
114 Zscore.resize(data.size(), 0.);
119 Zscore.resize(data.size(), 0.);
122 double sumWeights = 0.0;
123 double sumWeightedData = 0.0;
124 double weightedVariance = 0.0;
125 for (
size_t it = 0; it != data.size(); ++it) {
126 sumWeights +=
static_cast<double>(weights[it]);
127 sumWeightedData +=
static_cast<double>(weights[it] * data[it]);
129 double weightedMean = sumWeightedData / sumWeights;
130 for (
size_t it = 0; it != data.size(); ++it) {
131 weightedVariance += std::pow(
static_cast<double>(data[it]) - weightedMean, 2) *
132 std::pow(
static_cast<double>(weights[it]) / sumWeights, 2);
134 for (
auto it = data.cbegin(); it != data.cend(); ++it) {
135 Zscore.emplace_back(
fabs((
static_cast<double>(*it) - weightedMean) / std::sqrt(weightedVariance)));
145 if (data.size() < 3) {
146 std::vector<double> Zscore(data.size(), 0.);
149 std::vector<double> MADvec;
152 for (
auto it = data.cbegin(); it != data.cend(); ++it) {
153 tmp =
static_cast<double>(*it);
154 MADvec.emplace_back(
fabs(
tmp - median));
158 std::vector<double> Zscore(data.size(), 0.);
162 std::vector<double> Zscore;
163 for (
auto it = data.begin(); it != data.end(); ++it) {
164 tmp =
static_cast<double>(*it);
165 Zscore.emplace_back(0.6745 *
fabs((
tmp - median) / MAD));
184 using namespace boost::accumulators;
185 accumulator_set<double, stats<tag::min, tag::max, tag::variance>> acc;
186 for (
auto &
value : data) {
187 acc(
static_cast<double>(
value));
191 statistics.
mean = mean(acc);
192 double var = variance(acc);
195 auto ndofs =
static_cast<double>(data.size());
196 var *= ndofs / (ndofs - 1.0);
201 using namespace boost::accumulators;
202 accumulator_set<double, stats<tag::mean>> acc;
203 for (
auto &
value : data) {
204 acc(
static_cast<double>(
value));
206 statistics.
mean = mean(acc);
246Rfactor getRFactor(std::span<double const> obsI, std::span<double const> calI, std::span<double const> obsE) {
248 if (obsI.size() != calI.size() || obsI.size() != obsE.size()) {
249 std::stringstream errss;
250 errss <<
"GetRFactor() Input Error! Observed Intensity (" << obsI.size() <<
"), Calculated Intensity ("
251 << calI.size() <<
") and Observed Error (" << obsE.size() <<
") have different number of elements.";
252 throw std::runtime_error(errss.str());
255 throw std::runtime_error(
"getRFactor(): the input arrays are empty.");
261 double sumrpdenom = 0;
263 size_t numpts = obsI.size();
264 for (
size_t i = 0; i < numpts; ++i) {
265 double cal_i = calI[i];
266 double obs_i = obsI[i];
267 double sigma = obsE[i];
269 double diff = obs_i - cal_i;
271 if (weight == weight && weight <= DBL_MAX) {
273 sumrpnom +=
fabs(diff);
274 sumrpdenom +=
fabs(obs_i);
276 double tempnom = weight * diff * diff;
277 double tempden = weight * obs_i * obs_i;
282 if (tempnom != tempnom || tempden != tempden) {
283 logger.error() <<
"***** Error! ****** Data indexed " << i <<
" is NaN. "
284 <<
"i = " << i <<
": cal = " << calI[i] <<
", obs = " << obs_i <<
", weight = " << weight
291 rfactor.
Rp = (sumrpnom / sumrpdenom);
292 rfactor.
Rwp = std::sqrt(sumnom / sumdenom);
294 if (rfactor.
Rwp != rfactor.
Rwp)
295 logger.debug() <<
"Rwp is NaN. Denominator = " << sumnom <<
"; Nominator = " << sumdenom <<
". \n";
311template <
typename TYPE>
313 assertMomentIsValid(maxMoment);
316 bool isDensity(
x.size() ==
y.size());
319 if ((!isDensity) && (
x.size() !=
y.size() + 1)) {
320 std::stringstream msg;
321 msg <<
"length of x (" <<
x.size() <<
") and y (" <<
y.size() <<
")do not match";
322 throw std::out_of_range(msg.str());
326 std::vector<double> result(std::size_t(maxMoment + 1), 0.);
329 size_t numPoints =
y.size();
331 numPoints =
x.size() - 1;
337 for (
size_t j = 0; j < numPoints; ++j) {
339 const double xVal = .5 *
static_cast<double>(
x[j] +
x[j + 1]);
341 auto temp =
static_cast<double>(
y[j]);
343 const auto xDelta =
static_cast<double>(
x[j + 1] -
x[j]);
344 temp = .5 * (temp +
static_cast<double>(
y[j + 1])) * xDelta;
349 for (
size_t i = 1; i < result.size(); ++i) {
369template <
typename TYPE>
370std::vector<double>
getMomentsAboutMean(
const std::vector<TYPE> &
x,
const std::vector<TYPE> &
y,
const int maxMoment) {
371 assertMomentIsValid(maxMoment);
375 const double mean = momentsAboutOrigin[1];
378 std::vector<double> result(std::size_t(maxMoment + 1), 0.);
379 result[0] = momentsAboutOrigin[0];
386 bool isDensity(
x.size() ==
y.size());
389 size_t numPoints =
y.size();
391 numPoints =
x.size() - 1;
397 for (
size_t j = 0; j < numPoints; ++j) {
400 const double xVal = .5 *
static_cast<double>(
x[j] +
x[j + 1]) - mean;
405 const auto xDelta =
static_cast<double>(
x[j + 1] -
x[j]);
406 temp = xVal * .5 *
static_cast<double>(
y[j] +
y[j + 1]) * xDelta;
408 temp = xVal *
static_cast<double>(
y[j]);
413 for (
size_t i = 2; i < result.size(); ++i) {
424#define INSTANTIATE(TYPE) \
425 template MANTID_KERNEL_DLL Statistics getStatistics<TYPE>(const vector<TYPE> &, const unsigned int); \
426 template MANTID_KERNEL_DLL std::vector<double> getZscore<TYPE>(const vector<TYPE> &); \
427 template MANTID_KERNEL_DLL std::vector<double> getWeightedZscore<TYPE>(const vector<TYPE> &, const vector<TYPE> &); \
428 template MANTID_KERNEL_DLL std::vector<double> getModifiedZscore<TYPE>(const vector<TYPE> &); \
429 template MANTID_KERNEL_DLL std::vector<double> getMomentsAboutOrigin<TYPE>( \
430 const std::vector<TYPE> &x, const std::vector<TYPE> &y, const int maxMoment); \
431 template MANTID_KERNEL_DLL std::vector<double> getMomentsAboutMean<TYPE>( \
432 const std::vector<TYPE> &x, const std::vector<TYPE> &y, const int maxMoment);
double value
The value of the point.
#define INSTANTIATE(TYPE)
#define UNUSED_ARG(x)
Function arguments are sometimes unused in certain implmentations but are required for documentation ...
std::vector< double > getZscoreImpl(Range const &data)
There are enough special cases in determining the Z score where it useful to put it in a single funct...
std::vector< double > getModifiedZscore(const std::vector< TYPE > &data)
Return the modified Z score values for a dataset.
Statistics getStatistics(const std::vector< TYPE > &data, const unsigned int flags=StatOptions::AllStats)
Return a statistics object for the given data set.
MANTID_KERNEL_DLL Statistics getStatistics< bool >(const vector< bool > &data, const unsigned int flags)
Getting statistics of a boolean array should just give a bunch of NaNs.
Statistics getStatisticsImpl(Range const &data, const unsigned int flags)
Shared implementations, generic over any sized contiguous range, so that the std::vector and std::spa...
std::vector< double > getZscore(const std::vector< TYPE > &data)
Return the Z score values for a dataset.
Rfactor MANTID_KERNEL_DLL getRFactor(std::span< double const > obsI, std::span< double const > calI, std::span< double const > obsE)
Return the R-factors (Rwp) of a diffraction pattern data.
double getMedian(Range const &data)
There are enough special cases in determining the median where it useful to put it in a single functi...
std::vector< double > getMomentsAboutMean(const std::vector< TYPE > &x, const std::vector< TYPE > &y, const int maxMoment=3)
Return the first n-moments of the supplied data.
MANTID_KERNEL_DLL Statistics getStatistics< string >(const vector< string > &data, const unsigned int flags)
Getting statistics of a string array should just give a bunch of NaNs.
std::vector< double > getWeightedZscore(const std::vector< TYPE > &data, const std::vector< TYPE > &weights)
There are enough special cases in determining the Z score where it useful to put it in a single funct...
std::vector< double > getMomentsAboutOrigin(const std::vector< TYPE > &x, const std::vector< TYPE > &y, const int maxMoment=3)
Return the first n-moments of the supplied data.
R factor for powder data analysis.
Simple struct to store statistics.
double median
Median value.
double minimum
Minimum value.
double maximum
Maximum value.
double standard_deviation
standard_deviation of the values
Statistics()
Default value for everything is nan.