scran_markers
Marker detection for single-cell data
Loading...
Searching...
No Matches
score_markers_summary.hpp
Go to the documentation of this file.
1#ifndef SCRAN_SCORE_MARKERS_HPP
2#define SCRAN_SCORE_MARKERS_HPP
3
5#include "tatami/tatami.hpp"
6#include "sanisizer/sanisizer.hpp"
7#include "topicks/topicks.hpp"
8#include "quickstats/quickstats.hpp"
9
10#include <array>
11#include <map>
12#include <vector>
13#include <optional>
14
15#include "scan_matrix.hpp"
16#include "cohens_d.hpp"
17#include "simple_diff.hpp"
18#include "block_averages.hpp"
20#include "average_group_stats.hpp"
21#include "create_combinations.hpp"
22#include "utils.hpp"
23
29namespace scran_markers {
30
40 double threshold = 0;
41
46 int num_threads = 1;
47
52 bool compute_group_mean = true;
53
59
64 bool compute_cohens_d = true;
65
70 bool compute_auc = true;
71
76 bool compute_delta_mean = true;
77
83
89
95
101
107
113 std::optional<std::vector<double> > compute_summary_quantiles;
114
120
126 std::size_t min_rank_limit = 500;
127
134
140 BlockAveragePolicy block_average_policy = BlockAveragePolicy::MEAN;
141
154 scran_blocks::WeightPolicy block_weight_policy = scran_blocks::WeightPolicy::VARIABLE;
155
162
167 double block_quantile = 0.5;
168};
169
175template<typename Stat_, typename Rank_>
184 std::vector<Stat_*> mean;
185
193 std::vector<Stat_*> detected;
194
202 std::vector<SummaryBuffers<Stat_, Rank_> > cohens_d;
203
211 std::vector<SummaryBuffers<Stat_, Rank_> > auc;
212
220 std::vector<SummaryBuffers<Stat_, Rank_> > delta_mean;
221
229 std::vector<SummaryBuffers<Stat_, Rank_> > delta_detected;
230};
231
235namespace internal {
236
237// Inner vector is optional as we might not need it if SummaryBuffers::min_rank=NULL for a group.
238template<typename Stat_, typename Index_>
239using MinrankTopQueues = std::vector<std::optional<std::vector<topicks::TopQueue<Stat_, Index_> > > >;
240
241template<typename Stat_, typename Index_, typename Rank_>
242void preallocate_minrank_queues(
243 const std::size_t num_groups,
244 MinrankTopQueues<Stat_, Index_>& queue,
245 const std::vector<SummaryBuffers<Stat_, Rank_> >& summaries,
246 const Index_ limit,
247 const bool keep_ties
248) {
250 qopt.keep_ties = keep_ties;
251 qopt.check_nan = true;
252
253 sanisizer::resize(queue, num_groups);
254 for (I<decltype(num_groups)> g1 = 0; g1 < num_groups; ++g1) {
255 if (summaries[g1].min_rank == NULL) {
256 continue;
257 }
258 queue[g1].emplace();
259
260 auto& g_queue = *(queue[g1]);
261 sanisizer::reserve(g_queue, num_groups);
262 for (I<decltype(num_groups)> g2 = 0; g2 < num_groups; ++g2) {
263 g_queue.emplace_back(limit, true, qopt);
264 }
265 }
266}
267
268template<typename Stat_, typename Index_, typename Rank_>
269void compute_summary_stats_per_gene(
270 const Index_ gene,
271 const std::size_t num_groups,
272 const Stat_* const pairwise_buffer_ptr,
273 std::vector<Stat_>& summary_buffer,
274 MaybeMultipleQuantiles<Stat_>& summary_qcalcs,
275 MinrankTopQueues<Stat_, Index_>& minrank_queues,
276 const std::vector<SummaryBuffers<Stat_, Rank_> >& summaries
277) {
278 for (I<decltype(num_groups)> gr = 0; gr < num_groups; ++gr) {
279 auto& cursummary = summaries[gr];
280 const auto in_offset = sanisizer::product_unsafe<std::size_t>(num_groups, gr);
281 summarize_comparisons(num_groups, pairwise_buffer_ptr + in_offset, gr, gene, cursummary, summary_qcalcs, summary_buffer);
282
283 if (cursummary.min_rank) {
284 auto& gr_queue = *(minrank_queues[gr]);
285 for (I<decltype(num_groups)> gr2 = 0; gr2 < num_groups; ++gr2) {
286 if (gr != gr2) {
287 gr_queue[gr2].emplace(pairwise_buffer_ptr[in_offset + gr2], gene);
288 }
289 }
290 }
291 }
292}
293
294template<typename Stat_, typename Index_, typename Rank_>
295void report_minrank_from_queues(
296 const Index_ num_genes,
297 const std::size_t num_groups,
298 std::vector<std::optional<MinrankTopQueues<Stat_, Index_> > >& all_queues,
299 const std::vector<SummaryBuffers<Stat_, Rank_> >& summaries,
300 const int num_threads,
301 const bool keep_ties
302) {
303 if (all_queues.empty()) {
304 // If no queues were populated with ranks, this means that the matrix had no rows at all.
305 // If that's the case, there's no point iterating through the groups.
306 // We don't need to fill the min_rank array because num_genes == 0.
307 // Thus, we can just return immediately.
308 return;
309 }
310
311 tatami::parallelize([&](const int, const std::size_t start, const std::size_t length) -> void {
312 std::vector<Index_> tie_buffer;
313
314 for (I<decltype(num_groups)> gr = start, grend = start + length; gr < grend; ++gr) {
315 const auto mr_out = summaries[gr].min_rank;
316 if (mr_out == NULL) {
317 continue;
318 }
319
320 // Using the maximum possible rank (i.e., 'num_genes') as the default.
321 const auto maxrank_placeholder = sanisizer::cast<Rank_>(num_genes);
322 std::fill_n(mr_out, num_genes, maxrank_placeholder);
323
324 auto& first_mr_queue = *(all_queues.front());
325 for (I<decltype(num_groups)> gr2 = 0; gr2 < num_groups; ++gr2) {
326 if (gr == gr2) {
327 continue;
328 }
329
330 // Moving contents into a thread-local variable to minimize false sharing,
331 // at least while we repeatedly update the queue within this thread.
332 auto current_out = std::move((*(first_mr_queue[gr]))[gr2]);
333
334 const auto num_queues = all_queues.size();
335 for (I<decltype(num_queues)> q = 1; q < num_queues; ++q) {
336 auto& current_mr_queue = *(all_queues[q]);
337 auto current_in = std::move((*(current_mr_queue[gr]))[gr2]); // moving it to minimize false sharing.
338 while (!current_in.empty()) {
339 current_out.push(current_in.top());
340 current_in.pop();
341 }
342 }
343
344 // Cast to Rank_ is safe as current_out.size() <= num_genes,
345 // and we already checked that num_genes can fit into Rank_ in report_minrank_from_current_outs().
346 if (!keep_ties) {
347 while (!current_out.empty()) {
348 auto& mr = mr_out[current_out.top().second];
349 mr = std::min(mr, static_cast<Rank_>(current_out.size()));
350 current_out.pop();
351 }
352 } else {
353 while (!current_out.empty()) {
354 tie_buffer.clear();
355 const auto curtop = current_out.top();
356 current_out.pop();
357
358 while (!current_out.empty() && current_out.top().first == curtop.first) {
359 tie_buffer.push_back(current_out.top().second);
360 current_out.pop();
361 }
362
363 // Increment is safe as we already reduced the size at least once.
364 const Rank_ tied_rank = current_out.size() + 1;
365
366 mr_out[curtop.second] = std::min(mr_out[curtop.second], tied_rank);
367 for (const auto t : tie_buffer) {
368 mr_out[t] = std::min(mr_out[t], tied_rank);
369 }
370 }
371 }
372 }
373 }
374 }, num_groups, num_threads);
375}
376
377template<typename Index_, typename Stat_, typename Rank_>
378void process_simple_summary_effects(
379 const Index_ num_genes,
380 const std::size_t num_groups,
381 const std::size_t num_blocks,
382 const std::size_t num_combos,
383 const std::vector<Stat_>& combo_means,
384 const std::vector<Stat_>& combo_vars,
385 const std::vector<Stat_>& combo_detected,
386 const double threshold,
387 const BlockAverageInfo<Stat_>& average_info,
388 const std::optional<std::vector<double> >& summary_quantiles,
389 const Index_ minrank_limit,
390 const bool minrank_keep_ties,
391 const ScoreMarkersSummaryBuffers<Stat_, Rank_>& output,
392 const int num_threads
393) {
394 std::optional<std::vector<std::optional<MinrankTopQueues<Stat_, Index_> > > > cohens_d_minrank_all_queues, delta_mean_minrank_all_queues, delta_detected_minrank_all_queues;
395 if (output.cohens_d.size()) {
396 cohens_d_minrank_all_queues.emplace(sanisizer::cast<I<decltype(cohens_d_minrank_all_queues->size())> >(num_threads));
397 }
398 if (output.delta_mean.size()) {
399 delta_mean_minrank_all_queues.emplace(sanisizer::cast<I<decltype(delta_mean_minrank_all_queues->size())> >(num_threads));
400 }
401 if (output.delta_detected.size()) {
402 delta_detected_minrank_all_queues.emplace(sanisizer::cast<I<decltype(delta_detected_minrank_all_queues->size())> >(num_threads));
403 }
404
405 std::optional<std::vector<Stat_> > total_weights_per_group;
406 const Stat_* total_weights_ptr = NULL;
407 if (average_info.use_mean()) {
408 if (!output.mean.empty() || !output.detected.empty()) {
409 if (num_blocks > 1) {
410 total_weights_per_group = compute_total_weight_per_group(num_groups, num_blocks, average_info.combo_weights().data());
411 total_weights_ptr = total_weights_per_group->data();
412 } else {
413 total_weights_ptr = average_info.combo_weights().data();
414 }
415 }
416 }
417
418 std::optional<PrecomputedPairwiseWeights<Stat_> > preweights;
419 if (average_info.use_mean()) {
420 if (!output.cohens_d.empty() || !output.delta_mean.empty() || !output.delta_detected.empty()) {
421 preweights = PrecomputedPairwiseWeights<Stat_>(num_groups, num_blocks, average_info.combo_weights().data());
422 }
423 }
424
425 const auto num_groups2 = sanisizer::product<typename std::vector<Stat_>::size_type>(num_groups, num_groups);
426 const auto nused = tatami::parallelize([&](const int t, const Index_ start, const Index_ length) -> void {
427 std::vector<Stat_> pairwise_buffer(num_groups2);
428 std::vector<Stat_> summary_buffer(num_groups);
429 auto summary_qcalcs = setup_multiple_quantiles<Stat_>(summary_quantiles, num_groups);
430
431 std::optional<std::vector<Stat_> > qbuffer, qrevbuffer;
432 std::optional<quickstats::SingleQuantileVariableNumber<Stat_> > qcalc;
433 if (!average_info.use_mean()) {
434 qbuffer.emplace();
435 qrevbuffer.emplace();
436 qcalc.emplace(num_blocks, average_info.quantile());
437 }
438
439 std::optional<MinrankTopQueues<Stat_, Index_> > cohens_d_minrank_queue, delta_mean_minrank_queue, delta_detected_minrank_queue;
440 if (output.cohens_d.size()) {
441 cohens_d_minrank_queue.emplace();
442 preallocate_minrank_queues(num_groups, *cohens_d_minrank_queue, output.cohens_d, minrank_limit, minrank_keep_ties);
443 }
444 if (output.delta_mean.size()) {
445 delta_mean_minrank_queue.emplace();
446 preallocate_minrank_queues(num_groups, *delta_mean_minrank_queue, output.delta_mean, minrank_limit, minrank_keep_ties);
447 }
448 if (output.delta_detected.size()) {
449 delta_detected_minrank_queue.emplace();
450 preallocate_minrank_queues(num_groups, *delta_detected_minrank_queue, output.delta_detected, minrank_limit, minrank_keep_ties);
451 }
452
453 for (Index_ gene = start, end = start + length; gene < end; ++gene) {
454 const auto in_offset = sanisizer::product_unsafe<std::size_t>(gene, num_combos);
455
456 if (!output.mean.empty()) {
457 const auto tmp_means = combo_means.data() + in_offset;
458 if (average_info.use_mean()) {
459 average_group_stats_blockmean(gene, num_groups, num_blocks, tmp_means, average_info.combo_weights().data(), total_weights_ptr, output.mean);
460 } else {
461 average_group_stats_blockquantile(gene, num_groups, num_blocks, tmp_means, *qbuffer, *qcalc, output.mean);
462 }
463 }
464
465 if (!output.detected.empty()) {
466 const auto tmp_detected = combo_detected.data() + in_offset;
467 if (average_info.use_mean()) {
468 average_group_stats_blockmean(gene, num_groups, num_blocks, tmp_detected, average_info.combo_weights().data(), total_weights_ptr, output.detected);
469 } else {
470 average_group_stats_blockquantile(gene, num_groups, num_blocks, tmp_detected, *qbuffer, *qcalc, output.detected);
471 }
472 }
473
474 if (output.cohens_d.size()) {
475 const auto tmp_means = combo_means.data() + in_offset;
476 const auto tmp_variances = combo_vars.data() + in_offset;
477 if (average_info.use_mean()) {
478 compute_pairwise_cohens_d_blockmean(tmp_means, tmp_variances, num_groups, num_blocks, threshold, *preweights, pairwise_buffer.data());
479 } else {
480 compute_pairwise_cohens_d_blockquantile(tmp_means, tmp_variances, num_groups, num_blocks, threshold, *qbuffer, *qrevbuffer, *qcalc, pairwise_buffer.data());
481 }
482 compute_summary_stats_per_gene(gene, num_groups, pairwise_buffer.data(), summary_buffer, summary_qcalcs, *cohens_d_minrank_queue, output.cohens_d);
483 }
484
485 if (output.delta_mean.size()) {
486 const auto tmp_means = combo_means.data() + in_offset;
487 if (average_info.use_mean()) {
488 compute_pairwise_simple_diff_blockmean(tmp_means, num_groups, num_blocks, *preweights, pairwise_buffer.data());
489 } else {
490 compute_pairwise_simple_diff_blockquantile(tmp_means, num_groups, num_blocks, *qbuffer, *qcalc, pairwise_buffer.data());
491 }
492 compute_summary_stats_per_gene(gene, num_groups, pairwise_buffer.data(), summary_buffer, summary_qcalcs, *delta_mean_minrank_queue, output.delta_mean);
493 }
494
495 if (output.delta_detected.size()) {
496 const auto tmp_det = combo_detected.data() + in_offset;
497 if (average_info.use_mean()) {
498 compute_pairwise_simple_diff_blockmean(tmp_det, num_groups, num_blocks, *preweights, pairwise_buffer.data());
499 } else {
500 compute_pairwise_simple_diff_blockquantile(tmp_det, num_groups, num_blocks, *qbuffer, *qcalc, pairwise_buffer.data());
501 }
502 compute_summary_stats_per_gene(gene, num_groups, pairwise_buffer.data(), summary_buffer, summary_qcalcs, *delta_detected_minrank_queue, output.delta_detected);
503 }
504 }
505
506 // Only flushing it to the output buffer at the very end to minimize false sharing.
507 if (output.cohens_d.size()) {
508 (*cohens_d_minrank_all_queues)[t] = std::move(cohens_d_minrank_queue);
509 }
510 if (output.delta_mean.size()) {
511 (*delta_mean_minrank_all_queues)[t] = std::move(delta_mean_minrank_queue);
512 }
513 if (output.delta_detected.size()) {
514 (*delta_detected_minrank_all_queues)[t] = std::move(delta_detected_minrank_queue);
515 }
516 }, num_genes, num_threads);
517
518 if (output.cohens_d.size()) {
519 cohens_d_minrank_all_queues->resize(nused);
520 report_minrank_from_queues(num_genes, num_groups, *cohens_d_minrank_all_queues, output.cohens_d, num_threads, minrank_keep_ties);
521 }
522 if (output.delta_mean.size()) {
523 delta_mean_minrank_all_queues->resize(nused);
524 report_minrank_from_queues(num_genes, num_groups, *delta_mean_minrank_all_queues, output.delta_mean, num_threads, minrank_keep_ties);
525 }
526 if (output.delta_detected.size()) {
527 delta_detected_minrank_all_queues->resize(nused);
528 report_minrank_from_queues(num_genes, num_groups, *delta_detected_minrank_all_queues, output.delta_detected, num_threads, minrank_keep_ties);
529 }
530}
531
532template<
533 bool single_block_,
534 typename Value_,
535 typename Index_,
536 typename Group_,
537 typename Block_,
538 typename Stat_,
539 typename Rank_
540>
542 const tatami::Matrix<Value_, Index_>& matrix,
543 const Group_* const group,
544 const std::size_t num_groups,
545 const Block_* const block,
546 const std::size_t num_blocks,
547 const std::size_t* const combo,
548 const std::size_t num_combos,
549 const std::vector<Index_>& combo_sizes,
550 const ScoreMarkersSummaryOptions& options,
551 const ScoreMarkersSummaryBuffers<Stat_, Rank_>& output
552) {
553 const auto num_genes = matrix.nrow();
554 const auto payload_size = sanisizer::product<typename std::vector<Stat_>::size_type>(num_genes, num_combos);
555 std::vector<Stat_> combo_means, combo_vars, combo_detected;
556 if (!output.mean.empty() || !output.cohens_d.empty() || !output.delta_mean.empty()) {
557 combo_means.resize(payload_size);
558 }
559 if (!output.cohens_d.empty()) {
560 combo_vars.resize(payload_size);
561 }
562 if (!output.detected.empty() || !output.delta_detected.empty()) {
563 combo_detected.resize(payload_size);
564 }
565
566 // For a single block, this usually doesn't really matter, but we do it for consistency with the multi-block case,
567 // and to account for variable weighting where non-zero block sizes get zero weight.
568 BlockAverageInfo<Stat_> average_info;
569 if (options.block_average_policy == BlockAveragePolicy::MEAN) {
570 average_info = BlockAverageInfo<Stat_>(
572 combo_sizes,
573 options.block_weight_policy,
574 options.variable_block_weight_parameters
575 )
576 );
577 } else {
578 average_info = BlockAverageInfo<Stat_>(options.block_quantile);
579 }
580
581 const Index_ minrank_limit = sanisizer::cap<Index_>(options.min_rank_limit);
582 internal::validate_quantiles(options.compute_summary_quantiles);
583
584 if (!output.auc.empty()) {
585 auto auc_minrank_all_queues = sanisizer::create<std::vector<std::optional<MinrankTopQueues<Stat_, Index_> > > >(options.num_threads);
586
587 struct AucResultWorkspace {
588 AucResultWorkspace(const std::size_t num_groups, const std::optional<std::vector<double> >& summary_quantiles) :
589 pairwise_buffer(sanisizer::product<typename std::vector<Stat_>::size_type>(num_groups, num_groups)),
590 summary_buffer(sanisizer::cast<typename std::vector<Stat_>::size_type>(num_groups)),
591 summary_qcalcs(setup_multiple_quantiles<Stat_>(summary_quantiles, num_groups))
592 {};
593
594 public:
595 std::vector<Stat_> pairwise_buffer;
596 std::vector<Stat_> summary_buffer;
597 MaybeMultipleQuantiles<Stat_> summary_qcalcs;
598 MinrankTopQueues<Stat_, Index_> queue;
599 };
600
601 const auto num_used = scan_matrix_by_row_custom_auc<single_block_>(
602 matrix,
603 group,
604 num_groups,
605 block,
606 num_blocks,
607 combo,
608 num_combos,
609 combo_sizes,
610 average_info,
611 combo_means,
612 combo_vars,
613 combo_detected,
614 /* do_auc = */ true,
615 /* auc_result_initialize = */ [&](const int) -> AucResultWorkspace {
616 AucResultWorkspace res_work(num_groups, options.compute_summary_quantiles);
617 preallocate_minrank_queues(num_groups, res_work.queue, output.auc, minrank_limit, options.min_rank_preserve_ties);
618 return res_work;
619 },
620 /* auc_result_process = */ [&](const Index_ gene, AucScanWorkspace<Value_, Group_, Stat_, Index_>& auc_work, AucResultWorkspace& res_work) -> void {
621 process_auc_for_rows(auc_work, num_groups, num_blocks, options.threshold, res_work.pairwise_buffer.data());
622 compute_summary_stats_per_gene(gene, num_groups, res_work.pairwise_buffer.data(), res_work.summary_buffer, res_work.summary_qcalcs, res_work.queue, output.auc);
623 },
624 /* auc_result_finalize = */ [&](const int t, AucResultWorkspace& res_work) -> void {
625 auc_minrank_all_queues[t] = std::move(res_work.queue);
626 },
627 options.num_threads
628 );
629
630 auc_minrank_all_queues.resize(num_used);
631 report_minrank_from_queues(num_genes, num_groups, auc_minrank_all_queues, output.auc, options.num_threads, options.min_rank_preserve_ties);
632
633 } else if (matrix.prefer_rows()) {
634 scan_matrix_by_row_full_auc<single_block_>(
635 matrix,
636 group,
637 num_groups,
638 block,
639 num_blocks,
640 combo,
641 num_combos,
642 combo_sizes,
643 average_info,
644 combo_means,
645 combo_vars,
646 combo_detected,
647 static_cast<Stat_*>(NULL),
648 options.threshold,
649 options.num_threads
650 );
651
652 } else {
653 scan_matrix_by_column(
654 matrix,
655 [&]{
656 if constexpr(single_block_) {
657 return group;
658 } else {
659 return combo;
660 }
661 }(),
662 [&]{
663 if constexpr(single_block_) {
664 return num_groups;
665 } else {
666 return num_combos;
667 }
668 }(),
669 combo_sizes,
670 combo_means,
671 combo_vars,
672 combo_detected,
673 options.num_threads
674 );
675 }
676
677 process_simple_summary_effects(
678 matrix.nrow(),
679 num_groups,
680 num_blocks,
681 num_combos,
682 combo_means,
683 combo_vars,
684 combo_detected,
685 options.threshold,
686 average_info,
687 options.compute_summary_quantiles,
688 minrank_limit,
689 options.min_rank_preserve_ties,
690 output,
691 options.num_threads
692 );
693}
694
695}
735template<typename Value_, typename Index_, typename Group_, typename Stat_, typename Rank_>
737 const tatami::Matrix<Value_, Index_>& matrix,
738 const Group_* const group,
739 const std::size_t num_groups,
740 const ScoreMarkersSummaryOptions& options,
742) {
743 const auto group_sizes = tabulate_groups(matrix.ncol(), group, num_groups);
744 internal::score_markers_summary<true>(
745 matrix,
746 group,
747 num_groups,
748 static_cast<int*>(NULL),
749 1,
750 static_cast<std::size_t*>(NULL),
751 num_groups,
752 group_sizes,
753 options,
754 output
755 );
756}
757
788template<typename Value_, typename Index_, typename Group_, typename Block_, typename Stat_, typename Rank_>
790 const tatami::Matrix<Value_, Index_>& matrix,
791 const Group_* const group,
792 const std::size_t num_groups,
793 const Block_* const block,
794 const std::size_t num_blocks,
795 const ScoreMarkersSummaryOptions& options,
797) {
798 const auto combo_out = create_combinations(matrix.ncol(), group, num_groups, block, num_blocks);
799 internal::score_markers_summary<false>(
800 matrix,
801 group,
802 num_groups,
803 block,
804 num_blocks,
805 combo_out.combinations.data(),
806 combo_out.num_combinations,
807 combo_out.frequencies,
808 options,
809 output
810 );
811}
812
818template<typename Stat_, typename Rank_>
824 std::vector<std::vector<Stat_> > mean;
825
830 std::vector<std::vector<Stat_> > detected;
831
839 std::vector<SummaryResults<Stat_, Rank_> > cohens_d;
840
848 std::vector<SummaryResults<Stat_, Rank_> > auc;
849
857 std::vector<SummaryResults<Stat_, Rank_> > delta_mean;
858
866 std::vector<SummaryResults<Stat_, Rank_> > delta_detected;
867};
868
872template<typename Index_, typename Stat_, typename Rank_>
873ScoreMarkersSummaryBuffers<Stat_, Rank_> preallocate_summary_results(
874 const Index_ num_genes,
875 const std::size_t num_groups,
877 const ScoreMarkersSummaryOptions& options
878) {
880
881 if (options.compute_group_mean) {
882 internal::preallocate_average_results(num_genes, num_groups, store.mean, output.mean);
883 }
884
885 if (options.compute_group_detected) {
886 internal::preallocate_average_results(num_genes, num_groups, store.detected, output.detected);
887 }
888
889 if (options.compute_cohens_d) {
890 output.cohens_d = internal::fill_summary_results(
891 num_genes,
892 num_groups,
893 store.cohens_d,
894 options.compute_summary_min,
895 options.compute_summary_mean,
897 options.compute_summary_max,
900 );
901 }
902
903 if (options.compute_auc) {
904 output.auc = internal::fill_summary_results(
905 num_genes,
906 num_groups,
907 store.auc,
908 options.compute_summary_min,
909 options.compute_summary_mean,
911 options.compute_summary_max,
914 );
915 }
916
917 if (options.compute_delta_mean) {
918 output.delta_mean = internal::fill_summary_results(
919 num_genes,
920 num_groups,
921 store.delta_mean,
922 options.compute_summary_min,
923 options.compute_summary_mean,
925 options.compute_summary_max,
928 );
929 }
930
931 if (options.compute_delta_detected) {
932 output.delta_detected = internal::fill_summary_results(
933 num_genes,
934 num_groups,
935 store.delta_detected,
936 options.compute_summary_min,
937 options.compute_summary_mean,
939 options.compute_summary_max,
942 );
943 }
944
945 return output;
946}
969template<typename Stat_ = double, typename Rank_ = int, typename Value_, typename Index_, typename Group_>
971 const tatami::Matrix<Value_, Index_>& matrix,
972 const Group_* const group,
973 const std::size_t num_groups,
974 const ScoreMarkersSummaryOptions& options
975) {
977 const auto buffers = preallocate_summary_results(matrix.nrow(), num_groups, output, options);
978 score_markers_summary(matrix, group, num_groups, options, buffers);
979 return output;
980}
981
1004template<typename Stat_ = double, typename Rank_ = int, typename Value_, typename Index_, typename Group_, typename Block_>
1006 const tatami::Matrix<Value_, Index_>& matrix,
1007 const Group_* const group,
1008 const std::size_t num_groups,
1009 const Block_* const block,
1010 const std::size_t num_blocks,
1011 const ScoreMarkersSummaryOptions& options
1012) {
1014 const auto buffers = preallocate_summary_results(matrix.nrow(), num_groups, output, options);
1015 score_markers_summary_blocked(matrix, group, num_groups, block, num_blocks, options, buffers);
1016 return output;
1017}
1018
1019}
1020
1021#endif
Averaging statistics over blocks.
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
virtual bool prefer_rows() const=0
void compute_weights(const std::size_t num_blocks, const Size_ *const sizes, const WeightPolicy policy, const VariableWeightParameters &variable, Weight_ *const weights)
Marker detection for single-cell data.
Definition score_markers_pairwise.hpp:26
void score_markers_summary_blocked(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *const group, const std::size_t num_groups, const Block_ *const block, const std::size_t num_blocks, const ScoreMarkersSummaryOptions &options, const ScoreMarkersSummaryBuffers< Stat_, Rank_ > &output)
Definition score_markers_summary.hpp:789
BlockAveragePolicy
Definition block_averages.hpp:27
void score_markers_summary(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *const group, const std::size_t num_groups, const ScoreMarkersSummaryOptions &options, const ScoreMarkersSummaryBuffers< Stat_, Rank_ > &output)
Definition score_markers_summary.hpp:736
int parallelize(Function_ fun, const Index_ tasks, const int workers)
Buffers for score_markers_summary() and friends.
Definition score_markers_summary.hpp:176
std::vector< Stat_ * > detected
Definition score_markers_summary.hpp:193
std::vector< SummaryBuffers< Stat_, Rank_ > > delta_detected
Definition score_markers_summary.hpp:229
std::vector< Stat_ * > mean
Definition score_markers_summary.hpp:184
std::vector< SummaryBuffers< Stat_, Rank_ > > delta_mean
Definition score_markers_summary.hpp:220
std::vector< SummaryBuffers< Stat_, Rank_ > > cohens_d
Definition score_markers_summary.hpp:202
std::vector< SummaryBuffers< Stat_, Rank_ > > auc
Definition score_markers_summary.hpp:211
Options for score_markers_summary() and friends.
Definition score_markers_summary.hpp:34
bool compute_group_detected
Definition score_markers_summary.hpp:58
bool compute_delta_detected
Definition score_markers_summary.hpp:82
double block_quantile
Definition score_markers_summary.hpp:167
bool compute_auc
Definition score_markers_summary.hpp:70
bool compute_group_mean
Definition score_markers_summary.hpp:52
std::optional< std::vector< double > > compute_summary_quantiles
Definition score_markers_summary.hpp:113
bool compute_summary_max
Definition score_markers_summary.hpp:106
double threshold
Definition score_markers_summary.hpp:40
bool min_rank_preserve_ties
Definition score_markers_summary.hpp:133
scran_blocks::WeightPolicy block_weight_policy
Definition score_markers_summary.hpp:154
bool compute_summary_mean
Definition score_markers_summary.hpp:94
BlockAveragePolicy block_average_policy
Definition score_markers_summary.hpp:140
bool compute_cohens_d
Definition score_markers_summary.hpp:64
bool compute_summary_min
Definition score_markers_summary.hpp:88
bool compute_summary_min_rank
Definition score_markers_summary.hpp:119
int num_threads
Definition score_markers_summary.hpp:46
bool compute_delta_mean
Definition score_markers_summary.hpp:76
scran_blocks::VariableWeightParameters variable_block_weight_parameters
Definition score_markers_summary.hpp:161
bool compute_summary_median
Definition score_markers_summary.hpp:100
std::size_t min_rank_limit
Definition score_markers_summary.hpp:126
Results for score_markers_summary() and friends.
Definition score_markers_summary.hpp:819
std::vector< SummaryResults< Stat_, Rank_ > > cohens_d
Definition score_markers_summary.hpp:839
std::vector< std::vector< Stat_ > > mean
Definition score_markers_summary.hpp:824
std::vector< SummaryResults< Stat_, Rank_ > > auc
Definition score_markers_summary.hpp:848
std::vector< SummaryResults< Stat_, Rank_ > > delta_detected
Definition score_markers_summary.hpp:866
std::vector< std::vector< Stat_ > > detected
Definition score_markers_summary.hpp:830
std::vector< SummaryResults< Stat_, Rank_ > > delta_mean
Definition score_markers_summary.hpp:857
Pointers to arrays to hold the summary statistics.
Definition summarize_comparisons.hpp:33
Utilities for effect summarization.