statcpp
C++17 Header-Only Statistics Library
Loading...
Searching...
No Matches
frequency_distribution.hpp
Go to the documentation of this file.
1
10#pragma once
11
12#include <cstddef>
13#include <functional>
14#include <iterator>
15#include <map>
16#include <type_traits>
17#include <unordered_map>
18#include <utility>
19#include <vector>
20
21namespace statcpp {
22
23// ============================================================================
24// Return value structures
25// ============================================================================
26
35template <typename T>
43
51template <typename T>
53 std::vector<frequency_entry<T>> entries;
54 std::size_t total_count;
55};
56
57// ============================================================================
58// Frequency Table
59// ============================================================================
60
73template <typename Iterator>
74auto frequency_table(Iterator first, Iterator last)
76{
77 using value_type = typename std::iterator_traits<Iterator>::value_type;
78
79 if (first == last) {
80 return {{}, 0};
81 }
82
83 // Count frequencies (std::map maintains sorted order)
84 std::map<value_type, std::size_t> freq_map;
85 for (auto it = first; it != last; ++it) {
86 ++freq_map[*it];
87 }
88
89 std::size_t total = static_cast<std::size_t>(std::distance(first, last));
90 double total_d = static_cast<double>(total);
91
92 // Build result
93 std::vector<frequency_entry<value_type>> entries;
94 entries.reserve(freq_map.size());
95
96 std::size_t cumulative = 0;
97 for (const auto& pair : freq_map) {
98 cumulative += pair.second;
99 entries.push_back({
100 pair.first,
101 pair.second,
102 static_cast<double>(pair.second) / total_d,
103 cumulative,
104 static_cast<double>(cumulative) / total_d
105 });
106 }
107
108 return {std::move(entries), total};
109}
110
124template <typename Iterator, typename Projection>
125auto frequency_table(Iterator first, Iterator last, Projection proj)
126 -> frequency_table_result<std::invoke_result_t<Projection,
127 typename std::iterator_traits<Iterator>::value_type>>
128{
129 using result_type = std::invoke_result_t<Projection,
130 typename std::iterator_traits<Iterator>::value_type>;
131
132 if (first == last) {
133 return {{}, 0};
134 }
135
136 std::map<result_type, std::size_t> freq_map;
137 for (auto it = first; it != last; ++it) {
138 ++freq_map[std::invoke(proj, *it)];
139 }
140
141 std::size_t total = static_cast<std::size_t>(std::distance(first, last));
142 double total_d = static_cast<double>(total);
143
144 std::vector<frequency_entry<result_type>> entries;
145 entries.reserve(freq_map.size());
146
147 std::size_t cumulative = 0;
148 for (const auto& pair : freq_map) {
149 cumulative += pair.second;
150 entries.push_back({
151 pair.first,
152 pair.second,
153 static_cast<double>(pair.second) / total_d,
154 cumulative,
155 static_cast<double>(cumulative) / total_d
156 });
157 }
158
159 return {std::move(entries), total};
160}
161
162// ============================================================================
163// Frequency Count
164// ============================================================================
165
177template <typename Iterator>
178auto frequency_count(Iterator first, Iterator last)
179 -> std::unordered_map<typename std::iterator_traits<Iterator>::value_type, std::size_t>
180{
181 using value_type = typename std::iterator_traits<Iterator>::value_type;
182
183 std::unordered_map<value_type, std::size_t> freq;
184 for (auto it = first; it != last; ++it) {
185 ++freq[*it];
186 }
187 return freq;
188}
189
202template <typename Iterator, typename Projection>
203auto frequency_count(Iterator first, Iterator last, Projection proj)
204 -> std::unordered_map<std::invoke_result_t<Projection,
205 typename std::iterator_traits<Iterator>::value_type>, std::size_t>
206{
207 using result_type = std::invoke_result_t<Projection,
208 typename std::iterator_traits<Iterator>::value_type>;
209
210 std::unordered_map<result_type, std::size_t> freq;
211 for (auto it = first; it != last; ++it) {
212 ++freq[std::invoke(proj, *it)];
213 }
214 return freq;
215}
216
217// ============================================================================
218// Relative Frequency
219// ============================================================================
220
231template <typename Iterator>
232auto relative_frequency(Iterator first, Iterator last)
233 -> std::unordered_map<typename std::iterator_traits<Iterator>::value_type, double>
234{
235 using value_type = typename std::iterator_traits<Iterator>::value_type;
236
237 auto n = static_cast<std::size_t>(std::distance(first, last));
238 if (n == 0) {
239 return {};
240 }
241
242 auto freq = frequency_count(first, last);
243 double total = static_cast<double>(n);
244
245 std::unordered_map<value_type, double> result;
246 result.reserve(freq.size());
247 for (const auto& pair : freq) {
248 result[pair.first] = static_cast<double>(pair.second) / total;
249 }
250 return result;
251}
252
265template <typename Iterator, typename Projection>
266auto relative_frequency(Iterator first, Iterator last, Projection proj)
267 -> std::unordered_map<std::invoke_result_t<Projection,
268 typename std::iterator_traits<Iterator>::value_type>, double>
269{
270 using result_type = std::invoke_result_t<Projection,
271 typename std::iterator_traits<Iterator>::value_type>;
272
273 auto n = static_cast<std::size_t>(std::distance(first, last));
274 if (n == 0) {
275 return {};
276 }
277
278 auto freq = frequency_count(first, last, proj);
279 double total = static_cast<double>(n);
280
281 std::unordered_map<result_type, double> result;
282 result.reserve(freq.size());
283 for (const auto& pair : freq) {
284 result[pair.first] = static_cast<double>(pair.second) / total;
285 }
286 return result;
287}
288
289// ============================================================================
290// Cumulative Frequency
291// ============================================================================
292
304template <typename Iterator>
305auto cumulative_frequency(Iterator first, Iterator last)
306 -> std::vector<std::pair<typename std::iterator_traits<Iterator>::value_type, std::size_t>>
307{
308 using value_type = typename std::iterator_traits<Iterator>::value_type;
309
310 if (first == last) {
311 return {};
312 }
313
314 // Get frequency in sorted order
315 std::map<value_type, std::size_t> freq_map;
316 for (auto it = first; it != last; ++it) {
317 ++freq_map[*it];
318 }
319
320 std::vector<std::pair<value_type, std::size_t>> result;
321 result.reserve(freq_map.size());
322
323 std::size_t cumulative = 0;
324 for (const auto& pair : freq_map) {
325 cumulative += pair.second;
326 result.emplace_back(pair.first, cumulative);
327 }
328
329 return result;
330}
331
345template <typename Iterator, typename Projection>
346auto cumulative_frequency(Iterator first, Iterator last, Projection proj)
347 -> std::vector<std::pair<std::invoke_result_t<Projection,
348 typename std::iterator_traits<Iterator>::value_type>, std::size_t>>
349{
350 using result_type = std::invoke_result_t<Projection,
351 typename std::iterator_traits<Iterator>::value_type>;
352
353 if (first == last) {
354 return {};
355 }
356
357 std::map<result_type, std::size_t> freq_map;
358 for (auto it = first; it != last; ++it) {
359 ++freq_map[std::invoke(proj, *it)];
360 }
361
362 std::vector<std::pair<result_type, std::size_t>> result;
363 result.reserve(freq_map.size());
364
365 std::size_t cumulative = 0;
366 for (const auto& pair : freq_map) {
367 cumulative += pair.second;
368 result.emplace_back(pair.first, cumulative);
369 }
370
371 return result;
372}
373
374// ============================================================================
375// Cumulative Relative Frequency
376// ============================================================================
377
389template <typename Iterator>
390auto cumulative_relative_frequency(Iterator first, Iterator last)
391 -> std::vector<std::pair<typename std::iterator_traits<Iterator>::value_type, double>>
392{
393 using value_type = typename std::iterator_traits<Iterator>::value_type;
394
395 auto n = static_cast<std::size_t>(std::distance(first, last));
396 if (n == 0) {
397 return {};
398 }
399
400 auto cum_freq = cumulative_frequency(first, last);
401 double total = static_cast<double>(n);
402
403 std::vector<std::pair<value_type, double>> result;
404 result.reserve(cum_freq.size());
405
406 for (const auto& pair : cum_freq) {
407 result.emplace_back(pair.first, static_cast<double>(pair.second) / total);
408 }
409
410 return result;
411}
412
426template <typename Iterator, typename Projection>
427auto cumulative_relative_frequency(Iterator first, Iterator last, Projection proj)
428 -> std::vector<std::pair<std::invoke_result_t<Projection,
429 typename std::iterator_traits<Iterator>::value_type>, double>>
430{
431 using result_type = std::invoke_result_t<Projection,
432 typename std::iterator_traits<Iterator>::value_type>;
433
434 auto n = static_cast<std::size_t>(std::distance(first, last));
435 if (n == 0) {
436 return {};
437 }
438
439 auto cum_freq = cumulative_frequency(first, last, proj);
440 double total = static_cast<double>(n);
441
442 std::vector<std::pair<result_type, double>> result;
443 result.reserve(cum_freq.size());
444
445 for (const auto& pair : cum_freq) {
446 result.emplace_back(pair.first, static_cast<double>(pair.second) / total);
447 }
448
449 return result;
450}
451
452} // namespace statcpp
auto cumulative_relative_frequency(Iterator first, Iterator last) -> std::vector< std::pair< typename std::iterator_traits< Iterator >::value_type, double > >
Return cumulative relative frequency (for sorted values)
auto cumulative_frequency(Iterator first, Iterator last) -> std::vector< std::pair< typename std::iterator_traits< Iterator >::value_type, std::size_t > >
Return cumulative frequency (for sorted values)
auto frequency_count(Iterator first, Iterator last) -> std::unordered_map< typename std::iterator_traits< Iterator >::value_type, std::size_t >
Return frequency for each value (unordered_map version, fast)
auto relative_frequency(Iterator first, Iterator last) -> std::unordered_map< typename std::iterator_traits< Iterator >::value_type, double >
Return relative frequency for each value.
auto frequency_table(Iterator first, Iterator last) -> frequency_table_result< typename std::iterator_traits< Iterator >::value_type >
Create frequency table (returned with sorted keys)
Frequency table entry.
std::size_t cumulative_count
Cumulative frequency.
double relative_frequency
Relative frequency.
T value
Value.
double cumulative_relative_frequency
Cumulative relative frequency.
std::size_t count
Frequency.
std::vector< frequency_entry< T > > entries
Frequency table entries.
std::size_t total_count
Total frequency.