scran_markers
Marker detection for single-cell data
Loading...
Searching...
No Matches
score_markers_pairwise.hpp
Go to the documentation of this file.
1#ifndef SCRAN_MARKERS_SCORE_MARKERS_PAIRWISE_HPP
2#define SCRAN_MARKERS_SCORE_MARKERS_PAIRWISE_HPP
3
4#include "cohens_d.hpp"
5#include "simple_diff.hpp"
6
7#include "scan_matrix.hpp"
8#include "average_group_stats.hpp"
9#include "PrecomputedPairwiseWeights.hpp"
10#include "create_combinations.hpp"
11
12#include <vector>
13
15#include "tatami/tatami.hpp"
16#include "tatami_stats/tatami_stats.hpp"
17
23namespace scran_markers {
24
76
81template<typename Stat_>
88 std::vector<Stat_*> mean;
89
95 std::vector<Stat_*> detected;
96
112 Stat_* cohens_d = NULL;
113
126 Stat_* auc = NULL;
127
134 Stat_* delta_mean = NULL;
135
142 Stat_* delta_detected = NULL;
143};
144
149template<typename Stat_>
155 std::vector<std::vector<Stat_> > mean;
156
161 std::vector<std::vector<Stat_> > detected;
162
169 std::vector<Stat_> cohens_d;
170
177 std::vector<Stat_> auc;
178
185 std::vector<Stat_> delta_mean;
186
193 std::vector<Stat_> delta_detected;
194};
195
199namespace internal {
200
201template<typename Index_, typename Stat_>
202void process_simple_pairwise_effects(
203 Index_ ngenes,
204 size_t ngroups,
205 size_t nblocks,
206 size_t ncombos,
207 std::vector<Stat_>& combo_means,
208 std::vector<Stat_>& combo_vars,
209 std::vector<Stat_>& combo_detected,
211 const std::vector<Stat_>& combo_weights,
212 double threshold,
213 int num_threads)
214{
215 std::vector<Stat_> total_weights_per_group;
216 const Stat_* total_weights_ptr = combo_weights.data();
217 if (nblocks > 1) {
218 total_weights_per_group = compute_total_weight_per_group(ngroups, nblocks, combo_weights.data());
219 total_weights_ptr = total_weights_per_group.data();
220 }
221 PrecomputedPairwiseWeights<Stat_> preweights(ngroups, nblocks, combo_weights.data());
222
223 tatami::parallelize([&](size_t, Index_ start, Index_ length) -> void {
224 size_t in_offset = ncombos * static_cast<size_t>(start);
225 const auto* tmp_means = combo_means.data() + in_offset;
226 const auto* tmp_variances = combo_vars.data() + in_offset;
227 const auto* tmp_detected = combo_detected.data() + in_offset;
228
229 size_t squared = ngroups * ngroups;
230 for (size_t gene = start, end = start + length; gene < end; ++gene) {
231 average_group_stats(gene, ngroups, nblocks, tmp_means, tmp_detected, combo_weights.data(), total_weights_ptr, output.mean, output.detected);
232
233 // Computing the effect sizes.
234 size_t out_offset = gene * squared;
235 if (output.cohens_d != NULL) {
236 internal::compute_pairwise_cohens_d(tmp_means, tmp_variances, ngroups, nblocks, preweights, threshold, output.cohens_d + out_offset);
237 }
238
239 if (output.delta_detected != NULL) {
240 internal::compute_pairwise_simple_diff(tmp_detected, ngroups, nblocks, preweights, output.delta_detected + out_offset);
241 }
242
243 if (output.delta_mean != NULL) {
244 internal::compute_pairwise_simple_diff(tmp_means, ngroups, nblocks, preweights, output.delta_mean + out_offset);
245 }
246
247 tmp_means += ncombos;
248 tmp_variances += ncombos;
249 tmp_detected += ncombos;
250 }
251 }, ngenes, num_threads);
252}
253
254template<typename Stat_>
255ScoreMarkersPairwiseBuffers<Stat_> fill_pairwise_results(size_t ngenes, size_t ngroups, ScoreMarkersPairwiseResults<Stat_>& store, const ScoreMarkersPairwiseOptions& opt) {
256 ScoreMarkersPairwiseBuffers<Stat_> output;
257
258 internal::fill_average_results(ngenes, ngroups, store.mean, store.detected, output.mean, output.detected);
259
260 size_t num_effect_sizes = ngenes * ngroups * ngroups; // already size_t's, no need to cast.
261
262 if (opt.compute_cohens_d) {
263 store.cohens_d.resize(num_effect_sizes
264#ifdef SCRAN_MARKERS_TEST_INIT
265 , SCRAN_MARKERS_TEST_INIT
266#endif
267 );
268 output.cohens_d = store.cohens_d.data();
269 }
270 if (opt.compute_auc) {
271 store.auc.resize(num_effect_sizes
272#ifdef SCRAN_MARKERS_TEST_INIT
273 , SCRAN_MARKERS_TEST_INIT
274#endif
275 );
276 output.auc = store.auc.data();
277 }
278 if (opt.compute_delta_mean) {
279 store.delta_mean.resize(num_effect_sizes
280#ifdef SCRAN_MARKERS_TEST_INIT
281 , SCRAN_MARKERS_TEST_INIT
282#endif
283 );
284 output.delta_mean = store.delta_mean.data();
285 }
286 if (opt.compute_delta_detected) {
287 store.delta_detected.resize(num_effect_sizes
288#ifdef SCRAN_MARKERS_TEST_INIT
289 , SCRAN_MARKERS_TEST_INIT
290#endif
291 );
292 output.delta_detected = store.delta_detected.data();
293 }
294
295 return output;
296}
297
298}
367template<typename Value_, typename Index_, typename Group_, typename Stat_>
370 const Group_* group,
373{
374 Index_ NC = matrix.ncol();
375 auto group_sizes = tatami_stats::tabulate_groups(group, NC);
376
377 // In most cases this doesn't really matter, but we do it for consistency with the 1-block case,
378 // and to account for variable weighting where non-zero block sizes get zero weight.
379 auto group_weights = scran_blocks::compute_weights<Stat_>(group_sizes, options.block_weight_policy, options.variable_block_weight_parameters);
380
381 size_t ngroups = group_sizes.size();
382 size_t payload_size = static_cast<size_t>(matrix.nrow()) * ngroups; // cast to size_t to avoid overflow.
384
385 if (output.auc != NULL || matrix.prefer_rows()) {
386 internal::scan_matrix_by_row<true>(
387 matrix,
388 ngroups,
389 group,
390 1,
391 static_cast<int*>(NULL),
392 ngroups,
393 NULL,
397 output.auc,
400 options.threshold,
401 options.num_threads
402 );
403
404 } else {
405 internal::scan_matrix_by_column(
406 matrix,
407 ngroups,
408 group,
413 options.num_threads
414 );
415 }
416
417 internal::process_simple_pairwise_effects(
418 matrix.nrow(),
419 ngroups,
420 1,
421 ngroups,
425 output,
427 options.threshold,
428 options.num_threads);
429}
430
469template<typename Value_, typename Index_, typename Group_, typename Block_, typename Stat_>
472 const Group_* group,
473 const Block_* block,
476{
477 Index_ NC = matrix.ncol();
478 size_t ngroups = output.mean.size();
479 size_t nblocks = tatami_stats::total_groups(block, NC);
480
481 auto combinations = internal::create_combinations(ngroups, group, block, NC);
482 auto combo_sizes = internal::tabulate_combinations<Index_>(ngroups, nblocks, combinations);
483 size_t ncombos = combo_sizes.size();
484 auto combo_weights = scran_blocks::compute_weights<Stat_>(combo_sizes, options.block_weight_policy, options.variable_block_weight_parameters);
485
486 size_t payload_size = static_cast<size_t>(matrix.nrow()) * ncombos; // cast to size_t to avoid overflow.
488
489 if (output.auc != NULL || matrix.prefer_rows()) {
490 internal::scan_matrix_by_row<false>(
491 matrix,
492 ngroups,
493 group,
494 nblocks,
495 block,
496 ncombos,
497 combinations.data(),
501 output.auc,
504 options.threshold,
505 options.num_threads
506 );
507
508 } else {
509 internal::scan_matrix_by_column(
510 matrix,
511 ncombos,
512 combinations.data(),
517 options.num_threads
518 );
519 }
520
521 internal::process_simple_pairwise_effects(
522 matrix.nrow(),
523 ngroups,
524 nblocks,
525 ncombos,
529 output,
531 options.threshold,
532 options.num_threads);
533}
534
550template<typename Stat_ = double, typename Value_, typename Index_, typename Group_>
552 size_t ngroups = tatami_stats::total_groups(group, matrix.ncol());
554 auto buffers = internal::fill_pairwise_results(matrix.nrow(), ngroups, res, options);
556 return res;
557}
558
577template<typename Stat_ = double, typename Value_, typename Index_, typename Group_, typename Block_>
585
586}
587
588#endif
Marker detection for single-cell data.
Definition score_markers_pairwise.hpp:23
void score_markers_pairwise(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *group, const ScoreMarkersPairwiseOptions &options, const ScoreMarkersPairwiseBuffers< Stat_ > &output)
Definition score_markers_pairwise.hpp:368
void score_markers_pairwise_blocked(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *group, const Block_ *block, const ScoreMarkersPairwiseOptions &options, const ScoreMarkersPairwiseBuffers< Stat_ > &output)
Definition score_markers_pairwise.hpp:470
void parallelize(Function_ fun, Index_ tasks, int threads)
Buffers for score_markers_pairwise() and friends.
Definition score_markers_pairwise.hpp:82
Stat_ * delta_mean
Definition score_markers_pairwise.hpp:134
Stat_ * cohens_d
Definition score_markers_pairwise.hpp:112
std::vector< Stat_ * > detected
Definition score_markers_pairwise.hpp:95
Stat_ * delta_detected
Definition score_markers_pairwise.hpp:142
Stat_ * auc
Definition score_markers_pairwise.hpp:126
std::vector< Stat_ * > mean
Definition score_markers_pairwise.hpp:88
Options for score_markers_pairwise() and friends.
Definition score_markers_pairwise.hpp:28
scran_blocks::WeightPolicy block_weight_policy
Definition score_markers_pairwise.hpp:68
int num_threads
Definition score_markers_pairwise.hpp:39
bool compute_delta_mean
Definition score_markers_pairwise.hpp:57
double threshold
Definition score_markers_pairwise.hpp:33
bool compute_cohens_d
Definition score_markers_pairwise.hpp:45
bool compute_auc
Definition score_markers_pairwise.hpp:51
bool compute_delta_detected
Definition score_markers_pairwise.hpp:63
scran_blocks::VariableWeightParameters variable_block_weight_parameters
Definition score_markers_pairwise.hpp:74
Results for score_markers_pairwise() and friends.
Definition score_markers_pairwise.hpp:150
std::vector< Stat_ > delta_mean
Definition score_markers_pairwise.hpp:185
std::vector< std::vector< Stat_ > > detected
Definition score_markers_pairwise.hpp:161
std::vector< Stat_ > cohens_d
Definition score_markers_pairwise.hpp:169
std::vector< Stat_ > auc
Definition score_markers_pairwise.hpp:177
std::vector< Stat_ > delta_detected
Definition score_markers_pairwise.hpp:193
std::vector< std::vector< Stat_ > > mean
Definition score_markers_pairwise.hpp:155