9#include "nan_handling.hpp"
27inline std::vector<size_t>
28draw_tie_order(
size_t size, random::RandomGenerator& generator)
30 std::vector<size_t> ord(size);
31 std::iota(ord.begin(), ord.end(), 0);
33 random::shuffle(ord, generator);
49inline std::vector<size_t>
50tie_order(
const std::vector<size_t>& group_sizes,
51 std::vector<int> seeds = std::vector<int>())
53 random::RandomGenerator generator(seeds);
54 std::vector<size_t> ord;
55 for (
size_t size : group_sizes) {
57 throw std::runtime_error(
"tie group sizes must be positive.");
58 auto group = draw_tie_order(size, generator);
59 ord.insert(ord.end(), group.begin(), group.end());
73inline std::vector<double>
74rank(std::vector<double> x,
75 std::vector<double> weights = std::vector<double>(),
76 std::string ties_method =
"min",
77 std::vector<int> seeds = std::vector<int>())
79 if ((ties_method !=
"min") && (ties_method !=
"average") &&
80 (ties_method !=
"first") && (ties_method !=
"random"))
81 throw std::runtime_error(
82 "ties method must be one of 'min', 'average', 'first', 'random'.");
86 if (weights.size() == 0)
87 weights = std::vector<double>(n, 1.0);
89 if (weights.size() != n) {
90 throw std::runtime_error(
"weights and data must have same size.");
94 std::vector<double> nans;
95 if (utils::any_nan(x)) {
97 for (
size_t i = 0; i < n; i++) {
98 if (std::isnan(x[i])) {
99 x[i] = std::numeric_limits<double>::max();
107 utils::sum(weights) /
static_cast<double>(n - utils::sum(nans));
108 for (
auto& w : weights) {
113 std::vector<size_t> perm = utils::get_order(x);
117 std::unique_ptr<random::RandomGenerator> random_gen;
118 if (ties_method ==
"random")
119 random_gen.reset(
new random::RandomGenerator(seeds));
121 double w_acc = 0.0, w_batch;
122 for (
size_t i = 0, reps; i < n; i += reps) {
126 while ((i + reps < n) && (x[perm[i]] == x[perm[i + reps]]))
127 w_batch += weights[perm[i + reps++]];
130 for (
size_t k = 0; k < reps; ++k)
131 x[perm[i + k]] = w_acc + weights[perm[i]];
134 if ((ties_method ==
"first") || (ties_method ==
"random")) {
137 std::vector<size_t> ord(reps);
138 std::iota(ord.begin(), ord.end(), 0);
139 if (ties_method ==
"random")
140 ord = draw_tie_order(reps, *random_gen);
143 for (
size_t k = 0; k < reps; ++k) {
144 ww += weights[perm[i + ord[k]]];
145 x[perm[i + ord[k]]] = w_acc + ww;
147 }
else if (ties_method ==
"average") {
149 for (
size_t k = 0; k < reps; ++k)
150 x[perm[i + k]] += (w_batch - weights[perm[i]]) / 2;
158 if (nans.size() == n) {
159 for (
size_t i = 0; i < x.size(); i++) {
178inline std::vector<double>
179rank0(std::vector<double> x,
180 std::vector<double> weights = std::vector<double>(),
181 std::string ties_method =
"min")
183 if ((ties_method !=
"min") && (ties_method !=
"average") &&
184 (ties_method !=
"max"))
185 throw std::runtime_error(
186 "ties_method must be either 'min', 'average', or 'max'.");
190 if (weights.size() == 0)
191 weights = std::vector<double>(n, 1.0);
194 std::vector<size_t> perm = utils::get_order(x);
196 double w_acc = 0.0, w_batch;
197 for (
size_t i = 0, reps; i < n; i += reps) {
201 while ((i + reps < n) && (x[perm[i]] == x[perm[i + reps]]))
202 w_batch += weights[perm[i + reps++]];
205 for (
size_t k = 0; k < reps; ++k)
206 x[perm[i + k]] = w_acc;
212 if ((ties_method ==
"average") && (reps > 1)) {
213 std::vector<double> ww(reps);
214 for (
size_t k = 0; k < reps; ++k)
215 ww[k] = weights[perm[i + k]];
216 double offset = utils::perm_sum(ww, 2) / w_batch;
217 for (
size_t k = 0; k < reps; ++k)
218 x[perm[i + k]] += offset;
219 }
else if (ties_method ==
"max") {
221 for (
size_t k = 0; k < reps; ++k)
222 x[perm[i + k]] = w_acc;
235inline std::vector<double>
236bivariate_rank(
const std::vector<double>& x,
237 const std::vector<double>& y,
238 std::vector<double> weights = std::vector<double>())
240 utils::check_sizes(x, y, weights);
242 if (weights.size() == 0)
243 weights = std::vector<double>(n, 1.0);
248 std::vector<size_t> order(n);
249 std::iota(order.begin(), order.end(), 0);
250 std::stable_sort(order.begin(), order.end(), [&](
size_t i,
size_t j) {
251 return (x[i] < x[j]) || ((x[i] == x[j]) && (y[i] > y[j]));
256 std::vector<double> levels = y;
257 std::sort(levels.begin(), levels.end());
258 levels.erase(std::unique(levels.begin(), levels.end()), levels.end());
259 utils::FenwickTree seen(levels.size());
261 std::vector<double> counts(n);
262 for (
size_t i : order) {
264 size_t level =
static_cast<size_t>(
265 std::lower_bound(levels.begin(), levels.end(), y[i]) - levels.begin());
267 counts[i] = seen.prefix_sum(level);
269 seen.add(level, weights[i]);
278median(
const std::vector<double>& x,
279 std::vector<double> weights = std::vector<double>())
281 utils::check_sizes(x, x, weights);
285 auto perm = utils::get_order(x);
288 for (
size_t i = 0; i < n; i++) {
291 w[i] = weights[perm[i]];
296 auto ranks = rank0(xx, w,
"average");
297 if (weights.size() == 0)
298 weights = std::vector<double>(n, 1.0);
299 double rank_avrg = utils::perm_sum(weights, 2) / utils::sum(weights);
303 while (ranks[i] < rank_avrg)
305 if (ranks[i] == rank_avrg)
308 return 0.5 * (xx[i - 1] + xx[i]);
Weighted dependence measures.
Definition wdm.hpp:19