ktau.hpp
1 // Copyright © 2020 Thomas Nagler
2 //
3 // This file is part of the wdm library and licensed under the terms of
4 // the MIT license. For a copy, see the LICENSE file in the root directory
5 // or https://github.com/tnagler/wdm/blob/master/LICENSE.
6 
7 #pragma once
8 
9 #include "utils.hpp"
10 
11 namespace wdm {
12 
13 namespace impl {
14 
15 inline void
16 normalize_weights(std::vector<double>& w)
17 {
18  if (w.size() > 0) {
19  double s = utils::sum(w);
20  for (size_t i = 0; i < w.size(); i++)
21  w[i] /= s;
22  }
23 }
24 
28 inline double
29 ktau(std::vector<double> x,
30  std::vector<double> y,
31  std::vector<double> weights = std::vector<double>())
32 {
33  utils::check_sizes(x, y, weights);
34 
35  // 1.1 Sort x, y, and weights in x order; break ties in according to y.
36  utils::sort_all(x, y, weights);
37 
38  // 1.2 Count pairs of tied x and simultaneous ties in x and y.
39  double ties_x = utils::count_tied_pairs(x, weights);
40  double ties_both = utils::count_joint_ties(x, y, weights);
41 
42  // 2.1 Sort y again and count exchanges (= number of discordant pairs).
43  double num_d = 0.0;
44  utils::merge_sort(y, weights, num_d);
45 
46  // 2.2 Count pairs of tied y.
47  double ties_y = utils::count_tied_pairs(y, weights);
48 
49  // 3. Calculate Kendall's tau.
50  if (weights.size() == 0)
51  weights = std::vector<double>(x.size(), 1.0);
52  double num_pairs = utils::perm_sum(weights, 2);
53  double num_c = num_pairs - (num_d + ties_x + ties_y - ties_both);
54  double tau = num_c - num_d;
55  tau /= std::sqrt((num_pairs - ties_x) * (num_pairs - ties_y));
56 
57  return tau;
58 }
59 
61 inline double
62 ktau_stat_adjust(std::vector<double> x,
63  std::vector<double> y,
64  std::vector<double> weights)
65 {
66  utils::check_sizes(x, y, weights);
67 
68  if (weights.size() == 0)
69  weights = std::vector<double>(x.size(), 1.0);
70  // Put weights in effective-sample-size units: both their sum and squared
71  // sum then equal n_eff, while their relative magnitudes remain unchanged.
72  double effective_scale =
73  utils::sum(weights) / utils::sum(utils::pow(weights, 2));
74  for (auto& weight : weights)
75  weight *= effective_scale;
76 
77  // 1.1 Sort x, y, and weights in x order; break ties in according to y.
78  utils::sort_all(x, y, weights);
79 
80  // 1.2 Count pairs and triplets of tied x and simultaneous ties in x and y.
81  double pair_x = utils::count_tied_pairs(x, weights);
82  double trip_x = utils::count_tied_triplets(x, weights);
83  double v_x = utils::count_ties_v(x, weights);
84 
85  // 2.1 Sort y and weights in y order; break ties according to x.
86  utils::sort_all(y, x, weights);
87 
88  // 2.2 Count pairs and triplets of tied y.
89  double pair_y = utils::count_tied_pairs(y, weights);
90  double trip_y = utils::count_tied_triplets(y, weights);
91  double v_y = utils::count_ties_v(y, weights);
92 
93  // 3. Calculate adjustment factor.
94  double s = utils::sum(weights);
95  double s2 = utils::perm_sum(weights, 2);
96  double s3 = utils::perm_sum(weights, 3);
97  double v_0 = 2 * s2 * (2 * s + 5);
98  double v_1 = 2 * pair_x * 2 * pair_y / (2 * 2 * s2);
99  double v_2 = 6 * trip_x * 6 * trip_y / (9 * 6 * s3);
100  double v = (v_0 - v_x - v_y) / 18 + v_1 + v_2;
101  return std::sqrt((s2 - pair_x) * (s2 - pair_y) / v);
102 }
103 
104 }
105 
106 }
Weighted dependence measures.
Definition: wdm.hpp:19