11#include <boost/accumulators/accumulators.hpp>
12#include <boost/accumulators/statistics/max.hpp>
13#include <boost/accumulators/statistics/min.hpp>
14#include <boost/accumulators/statistics/stats.hpp>
15#include <boost/accumulators/statistics/variance.hpp>
25Logger logger(
"Statistics");
27void assertMomentIsValid(
const int maxMoment) {
29 std::stringstream msg;
30 msg <<
"moment = " << maxMoment <<
" is statistically meaningless";
31 throw std::runtime_error(msg.str());
41template <
typename Range> Statistics
getStatisticsImpl(Range
const &data,
const unsigned int flags);
42template <
typename Range> std::vector<double>
getZscoreImpl(Range
const &data);
45 constexpr double nan = std::numeric_limits<double>::quiet_NaN();
57template <
typename Range>
double getMedian(Range
const &data) {
58 using value_type = std::decay_t<
decltype(data[0])>;
59 const size_t size = data.size();
61 return static_cast<double>(data[0]);
63 const bool isSorted = std::is_sorted(data.begin(), data.end());
64 const bool is_even = (size % 2 == 0);
67 return (
static_cast<double>(data[size / 2 - 1]) +
static_cast<double>(data[size / 2])) / 2;
69 return static_cast<double>(data[size / 2]);
71 std::vector<value_type> tmpSortedData(data.begin(), data.end());
72 std::sort(tmpSortedData.begin(), tmpSortedData.end());
74 return (
static_cast<double>(tmpSortedData[size / 2 - 1]) +
static_cast<double>(tmpSortedData[size / 2])) / 2;
76 return static_cast<double>(tmpSortedData[size / 2]);
84template <
typename Range> std::vector<double>
getZscoreImpl(Range
const &data) {
85 std::vector<double> Zscore;
86 if (data.size() < 3) {
87 Zscore.resize(data.size(), 0.);
92 Zscore.resize(data.size(), 0.);
95 for (
auto it = data.begin(); it != data.end(); ++it) {
96 auto tmp =
static_cast<double>(*it);
110template <
typename TYPE> std::vector<double>
getWeightedZscore(
const vector<TYPE> &data,
const vector<TYPE> &weights) {
111 std::vector<double> Zscore;
112 if (data.size() < 3) {
113 Zscore.resize(data.size(), 0.);
118 Zscore.resize(data.size(), 0.);
121 double sumWeights = 0.0;
122 double sumWeightedData = 0.0;
123 double weightedVariance = 0.0;
124 for (
size_t it = 0; it != data.size(); ++it) {
125 sumWeights +=
static_cast<double>(weights[it]);
126 sumWeightedData +=
static_cast<double>(weights[it] * data[it]);
128 double weightedMean = sumWeightedData / sumWeights;
129 for (
size_t it = 0; it != data.size(); ++it) {
130 weightedVariance += std::pow(
static_cast<double>(data[it]) - weightedMean, 2) *
131 std::pow(
static_cast<double>(weights[it]) / sumWeights, 2);
133 for (
auto it = data.cbegin(); it != data.cend(); ++it) {
134 Zscore.emplace_back(
fabs((
static_cast<double>(*it) - weightedMean) / std::sqrt(weightedVariance)));
144 if (data.size() < 3) {
145 std::vector<double> Zscore(data.size(), 0.);
148 std::vector<double> MADvec;
151 for (
auto it = data.cbegin(); it != data.cend(); ++it) {
152 tmp =
static_cast<double>(*it);
153 MADvec.emplace_back(
fabs(
tmp - median));
157 std::vector<double> Zscore(data.size(), 0.);
161 std::vector<double> Zscore;
162 for (
auto it = data.begin(); it != data.end(); ++it) {
163 tmp =
static_cast<double>(*it);
164 Zscore.emplace_back(0.6745 *
fabs((
tmp - median) / MAD));
183 using namespace boost::accumulators;
184 accumulator_set<double, stats<tag::min, tag::max, tag::variance>> acc;
185 for (
auto &
value : data) {
186 acc(
static_cast<double>(
value));
190 statistics.
mean = mean(acc);
191 double var = variance(acc);
194 auto ndofs =
static_cast<double>(data.size());
195 var *= ndofs / (ndofs - 1.0);
200 using namespace boost::accumulators;
201 accumulator_set<double, stats<tag::mean>> acc;
202 for (
auto &
value : data) {
203 acc(
static_cast<double>(
value));
205 statistics.
mean = mean(acc);
245Rfactor getRFactor(std::span<double const> obsI, std::span<double const> calI, std::span<double const> obsE) {
247 if (obsI.size() != calI.size() || obsI.size() != obsE.size()) {
248 std::stringstream errss;
249 errss <<
"GetRFactor() Input Error! Observed Intensity (" << obsI.size() <<
"), Calculated Intensity ("
250 << calI.size() <<
") and Observed Error (" << obsE.size() <<
") have different number of elements.";
251 throw std::runtime_error(errss.str());
254 throw std::runtime_error(
"getRFactor(): the input arrays are empty.");
260 double sumrpdenom = 0;
262 size_t numpts = obsI.size();
263 for (
size_t i = 0; i < numpts; ++i) {
264 double cal_i = calI[i];
265 double obs_i = obsI[i];
266 double sigma = obsE[i];
268 double diff = obs_i - cal_i;
270 if (weight == weight && weight <= DBL_MAX) {
272 sumrpnom +=
fabs(diff);
273 sumrpdenom +=
fabs(obs_i);
275 double tempnom = weight * diff * diff;
276 double tempden = weight * obs_i * obs_i;
281 if (tempnom != tempnom || tempden != tempden) {
282 logger.error() <<
"***** Error! ****** Data indexed " << i <<
" is NaN. "
283 <<
"i = " << i <<
": cal = " << calI[i] <<
", obs = " << obs_i <<
", weight = " << weight
290 rfactor.
Rp = (sumrpnom / sumrpdenom);
291 rfactor.
Rwp = std::sqrt(sumnom / sumdenom);
293 if (rfactor.
Rwp != rfactor.
Rwp)
294 logger.debug() <<
"Rwp is NaN. Denominator = " << sumnom <<
"; Nominator = " << sumdenom <<
". \n";
310template <
typename TYPE>
312 assertMomentIsValid(maxMoment);
315 bool isDensity(
x.size() ==
y.size());
318 if ((!isDensity) && (
x.size() !=
y.size() + 1)) {
319 std::stringstream msg;
320 msg <<
"length of x (" <<
x.size() <<
") and y (" <<
y.size() <<
")do not match";
321 throw std::out_of_range(msg.str());
325 std::vector<double> result(std::size_t(maxMoment + 1), 0.);
328 size_t numPoints =
y.size();
330 numPoints =
x.size() - 1;
336 for (
size_t j = 0; j < numPoints; ++j) {
338 const double xVal = .5 *
static_cast<double>(
x[j] +
x[j + 1]);
340 auto temp =
static_cast<double>(
y[j]);
342 const auto xDelta =
static_cast<double>(
x[j + 1] -
x[j]);
343 temp = .5 * (temp +
static_cast<double>(
y[j + 1])) * xDelta;
348 for (
size_t i = 1; i < result.size(); ++i) {
368template <
typename TYPE>
369std::vector<double>
getMomentsAboutMean(
const std::vector<TYPE> &
x,
const std::vector<TYPE> &
y,
const int maxMoment) {
370 assertMomentIsValid(maxMoment);
374 const double mean = momentsAboutOrigin[1];
377 std::vector<double> result(std::size_t(maxMoment + 1), 0.);
378 result[0] = momentsAboutOrigin[0];
385 bool isDensity(
x.size() ==
y.size());
388 size_t numPoints =
y.size();
390 numPoints =
x.size() - 1;
396 for (
size_t j = 0; j < numPoints; ++j) {
399 const double xVal = .5 *
static_cast<double>(
x[j] +
x[j + 1]) - mean;
404 const auto xDelta =
static_cast<double>(
x[j + 1] -
x[j]);
405 temp = xVal * .5 *
static_cast<double>(
y[j] +
y[j + 1]) * xDelta;
407 temp = xVal *
static_cast<double>(
y[j]);
412 for (
size_t i = 2; i < result.size(); ++i) {
423#define INSTANTIATE(TYPE) \
424 template MANTID_KERNEL_DLL Statistics getStatistics<TYPE>(const vector<TYPE> &, const unsigned int); \
425 template MANTID_KERNEL_DLL std::vector<double> getZscore<TYPE>(const vector<TYPE> &); \
426 template MANTID_KERNEL_DLL std::vector<double> getWeightedZscore<TYPE>(const vector<TYPE> &, const vector<TYPE> &); \
427 template MANTID_KERNEL_DLL std::vector<double> getModifiedZscore<TYPE>(const vector<TYPE> &); \
428 template MANTID_KERNEL_DLL std::vector<double> getMomentsAboutOrigin<TYPE>( \
429 const std::vector<TYPE> &x, const std::vector<TYPE> &y, const int maxMoment); \
430 template MANTID_KERNEL_DLL std::vector<double> getMomentsAboutMean<TYPE>( \
431 const std::vector<TYPE> &x, const std::vector<TYPE> &y, const int maxMoment);
double value
The value of the point.
#define INSTANTIATE(TYPE)
#define DLLExport
Definitions of the DLLImport compiler directives for MSVC.
#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.
DLLExport Statistics getStatistics< string >(const vector< string > &data, const unsigned int flags)
Getting statistics of a string array should just give a bunch of NaNs.
Statistics getStatistics(const std::vector< TYPE > &data, const unsigned int flags=StatOptions::AllStats)
Return a statistics object for the given data set.
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.
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...
DLLExport Statistics getStatistics< bool >(const vector< bool > &data, const unsigned int flags)
Getting statistics of a boolean array should just give a bunch of NaNs.
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.