| 78 | } |
| 79 | |
| 80 | void CalMapAtK(std::vector<int> ks, data_size_t npos, const label_t* label, |
| 81 | const double* score, data_size_t num_data, std::vector<double>* out) const { |
| 82 | // get sorted indices by score |
| 83 | std::vector<data_size_t> sorted_idx; |
| 84 | for (data_size_t i = 0; i < num_data; ++i) { |
| 85 | sorted_idx.emplace_back(i); |
| 86 | } |
| 87 | std::stable_sort(sorted_idx.begin(), sorted_idx.end(), |
| 88 | [score](data_size_t a, data_size_t b) {return score[a] > score[b]; }); |
| 89 | |
| 90 | int num_hit = 0; |
| 91 | double sum_ap = 0.0f; |
| 92 | data_size_t cur_left = 0; |
| 93 | for (size_t i = 0; i < ks.size(); ++i) { |
| 94 | data_size_t cur_k = static_cast<data_size_t>(ks[i]); |
| 95 | if (cur_k > num_data) { cur_k = num_data; } |
| 96 | for (data_size_t j = cur_left; j < cur_k; ++j) { |
| 97 | data_size_t idx = sorted_idx[j]; |
| 98 | if (label[idx] > 0.5f) { |
| 99 | ++num_hit; |
| 100 | sum_ap += static_cast<double>(num_hit) / (j + 1.0f); |
| 101 | } |
| 102 | } |
| 103 | if (npos > 0) { |
| 104 | (*out)[i] = sum_ap / std::min(npos, cur_k); |
| 105 | } else { |
| 106 | (*out)[i] = 1.0f; |
| 107 | } |
| 108 | cur_left = cur_k; |
| 109 | } |
| 110 | } |
| 111 | std::vector<double> Eval(const double* score, const ObjectiveFunction*) const override { |
| 112 | // some buffers for multi-threading sum up |
| 113 | std::vector<std::vector<double>> result_buffer_; |
nothing calls this directly
no test coverage detected