Newer
Older
Peterson, Peter
committed
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
#include <algorithm>
#include <functional>
#include <limits>
#include <math.h>
#include <numeric>
#include <string>
#include "MantidKernel/Statistics.h"
namespace Mantid
{
namespace Kernel
{
using std::string;
using std::vector;
/**
* Generate a Statistics object where all of the values are NaN. This is a good initial default.
*/
Statistics getNanStatistics()
{
double nan = std::numeric_limits<double>::quiet_NaN();
Statistics stats;
stats.minimum = nan;
stats.maximum = nan;
stats.mean = nan;
stats.median = nan;
stats.standard_deviation = nan;
return stats;
}
/**
* There are enough special cases in determining the median where it useful to
* put it in a single function.
*/
template<typename TYPE>
double getMedian(const vector<TYPE>& data, const size_t num_data)
{
if (num_data == 1)
return static_cast<double>(*(data.begin()));
bool is_even = ((num_data % 2) == 0);
if (is_even) {
double left = static_cast<double>(*(data.begin() + num_data/2 - 1));
double right = static_cast<double>(*(data.begin() + num_data/2));
return (left + right) / 2.;
}
else {
return static_cast<double>(*(data.begin() + num_data/2));
}
}
/**
* Determine the statistics for a vector of data. If it is sorted then let the
* function know so it won't make a copy of the data for determining the median.
*/
template<typename TYPE>
Statistics getStatistics(const vector<TYPE>& data, const bool sorted)
{
Statistics stats = getNanStatistics();
size_t num_data = data.size(); // chache since it is frequently used
if (num_data == 0) { // don't do anything
return stats;
}
Peterson, Peter
committed
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
// calculate the mean
stats.mean = std::accumulate(data.begin(), data.end(), 0., std::plus<double>());
stats.mean /= (static_cast<double>(num_data));
// calculate the standard deviation, min, max
stats.minimum = stats.mean;
stats.maximum = stats.mean;
double stddev = 0.;
double temp;
typename vector<TYPE>::const_iterator it = data.begin();
for ( ; it != data.end(); ++it)
{
temp = static_cast<double>(*it);
stddev += ((temp-stats.mean)* (temp-stats.mean));
if (temp > stats.maximum)
stats.maximum = temp;
if (temp < stats.minimum)
stats.minimum = temp;
}
stats.standard_deviation = sqrt(stddev / (static_cast<double>(num_data)));
// calculate the median
if (sorted) {
stats.median = getMedian(data, num_data);
}
else {
vector<TYPE> temp(data.begin(), data.end());
std::nth_element(temp.begin(), temp.begin()+num_data/2, temp.end());
stats.median = getMedian(temp, num_data);
}
return stats;
}
/// Getting statistics of a string array should just give a bunch of NaNs
template<>
DLLExport Statistics getStatistics<string>(const vector<string>& data, const bool sorted)
Peterson, Peter
committed
{
(void) sorted; (void) data;
Peterson, Peter
committed
return getNanStatistics();
}
// -------------------------- concrete instantiations
template DLLExport Statistics getStatistics<double>(const vector<double> &, const bool);
template DLLExport Statistics getStatistics<int32_t>(const vector<int32_t> &, const bool);
} // namespace Kernel
} // namespace Mantid