50 template <
typename T>
class NumberArrayStatistics
52 static_assert(std::is_arithmetic_v<T>,
"Template parameter T must be an integral or floating-point type.");
53 static_assert(!std::is_same_v<T, bool>,
"bool is not allowed");
56 NumberArrayStatistics() =
default;
66 NumberArrayStatistics(T
const* values,
size_t valueCount,
size_t valueCountPerIndexableElement = 1, T nullVal = getDefaultNullValue())
69 computeFrom(values, valueCount, valueCountPerIndexableElement);
72 void computeFrom(T
const* values,
size_t valueCount,
size_t valueCountPerIndexableElement) {
74 validValueCount = std::vector<uint64_t>(valueCountPerIndexableElement);
75 minimumValue = std::vector<T>(valueCountPerIndexableElement);
76 maximumValue = std::vector<T>(valueCountPerIndexableElement);
77 valuesMean = std::vector<double>(valueCountPerIndexableElement);
78 valuesMedian = std::vector<double>(valueCountPerIndexableElement);
79 valuesMode = std::vector<T>(valueCountPerIndexableElement);
80 modePercentage = std::vector<double>(valueCountPerIndexableElement);
81 valuesStandardDeviation = std::vector<double>(valueCountPerIndexableElement);
83 for (
size_t j = 0; j < valueCountPerIndexableElement; ++j) {
84 std::map<T, size_t> mapView;
85 for (
size_t i = j; i < valueCount; i += valueCountPerIndexableElement) {
86 if constexpr (std::is_integral_v<T>) {
87 if (values[i] != nullValue) {
93 if (!std::isnan(values[i])) {
99 if (mapView.empty()) {
102 minimumValue[j] = mapView.begin()->first;
103 maximumValue[j] = mapView.rbegin()->first;
106 size_t mid1 = (validValueCount[j] - 1) / 2;
107 size_t mid2 = validValueCount[j] / 2;
108 size_t currentCount = 0;
109 T median1 = 0, median2 = 0;
110 bool found1 =
false, found2 =
false;
111 for (
const auto& pair : mapView) {
113 if (pair.second > maxCount) {
114 maxCount = pair.second;
115 valuesMode[j] = pair.first;
120 currentCount += pair.second;
121 if (!found1 && currentCount > mid1) {
122 median1 = pair.first;
125 if (currentCount > mid2) {
126 median2 = pair.first;
132 valuesMean[j] += (pair.second * pair.first) / validValueCount[j];
134 valuesMedian[j] = (validValueCount[j] % 2 == 0) ? (median1 + median2) / 2.0 : median2;
135 modePercentage[j] =
static_cast<double>(maxCount) / validValueCount[j];
139 double variance = 0.0;
140 for (
const auto& pair : mapView) {
141 double diff =
static_cast<double>(pair.first) - valuesMean[j];
142 variance += pair.second * diff * diff;
144 valuesStandardDeviation[j] = std::sqrt(variance / validValueCount[j]);
148 T getNullValue()
const {
152 uint64_t getValidValueCount(
size_t valueIndex = 0)
const {
153 return validValueCount.at(valueIndex);
156 uint64_t getValidValueCountSize()
const {
157 return validValueCount.size();
160 T getMinimum(
size_t valueIndex = 0)
const {
161 return minimumValue.at(valueIndex);
164 uint64_t getMinimumSize()
const {
165 return minimumValue.size();
168 T getMaximum(
size_t valueIndex = 0)
const {
169 return maximumValue.at(valueIndex);
172 uint64_t getMaximumSize()
const {
173 return maximumValue.size();
176 double getMean(
size_t valueIndex = 0)
const {
177 return valuesMean.at(valueIndex);
180 uint64_t getMeanSize()
const {
181 return valuesMean.size();
184 double getMedian(
size_t valueIndex = 0)
const {
185 return valuesMedian.at(valueIndex);
188 uint64_t getMedianSize()
const {
189 return valuesMedian.size();
192 T getMode(
size_t valueIndex = 0)
const {
193 return valuesMode.at(valueIndex);
196 uint64_t getModeSize()
const {
197 return valuesMode.size();
200 double getModePercentage(
size_t valueIndex = 0)
const {
201 return modePercentage.at(valueIndex);
204 uint64_t getModePercentageSize()
const {
205 return modePercentage.size();
208 double getStandardDeviation(
size_t valueIndex = 0)
const {
209 return valuesStandardDeviation.at(valueIndex);
212 uint64_t getStandardDeviationSize()
const {
213 return valuesStandardDeviation.size();
216 void setNullValue(T value) {
220 void setValidValueCount(uint64_t value,
size_t valueIndex = 0) {
221 while (validValueCount.size() <= valueIndex) {
222 validValueCount.push_back((std::numeric_limits<size_t>::max)());
224 validValueCount[valueIndex] = value;
227 void setMinimum(T value,
size_t valueIndex = 0) {
228 while (minimumValue.size() <= valueIndex) {
229 minimumValue.push_back(getDefaultNullValue());
231 minimumValue[valueIndex] = value;
234 void setMaximum(T value,
size_t valueIndex = 0) {
235 while (maximumValue.size() <= valueIndex) {
236 maximumValue.push_back(getDefaultNullValue());
238 maximumValue[valueIndex] = value;
241 void setMean(
double value,
size_t valueIndex = 0) {
242 while (valuesMean.size() <= valueIndex) {
243 valuesMean.push_back(std::numeric_limits<double>::quiet_NaN());
245 valuesMean[valueIndex] = value;
248 void setMedian(
double value,
size_t valueIndex = 0) {
249 while (valuesMedian.size() <= valueIndex) {
250 valuesMedian.push_back(std::numeric_limits<double>::quiet_NaN());
252 valuesMedian[valueIndex] = value;
255 void setMode(T value,
size_t valueIndex = 0) {
256 while (valuesMode.size() <= valueIndex) {
257 valuesMode.push_back(getDefaultNullValue());
259 valuesMode[valueIndex] = value;
262 void setModePercentage(
double value,
size_t valueIndex = 0) {
263 while (valuesMean.size() <= valueIndex) {
264 valuesMean.push_back(std::numeric_limits<double>::quiet_NaN());
266 valuesMean[valueIndex] = value;
269 void setStandardDeviation(
double value,
size_t valueIndex = 0) {
270 while (valuesStandardDeviation.size() <= valueIndex) {
271 valuesStandardDeviation.push_back(std::numeric_limits<double>::quiet_NaN());
273 valuesStandardDeviation[valueIndex] = value;
278 T nullValue = getDefaultNullValue();
279 std::vector<uint64_t> validValueCount;
280 std::vector<T> minimumValue;
281 std::vector<T> maximumValue;
282 std::vector<double> valuesMean;
283 std::vector<double> valuesMedian;
284 std::vector<T> valuesMode;
285 std::vector<double> modePercentage;
286 std::vector<double> valuesStandardDeviation;
288 static constexpr T getDefaultNullValue() {
289 if constexpr (std::is_floating_point<T>::value) {
290 return std::numeric_limits<T>::quiet_NaN();
293 return (std::numeric_limits<T>::max)();