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
4#include "scan_matrix.hpp"
5#include "cohens_d.hpp"
6#include "simple_diff.hpp"
8#include "average_group_stats.hpp"
9#include "create_combinations.hpp"
10
12#include "tatami/tatami.hpp"
13#include "sanisizer/sanisizer.hpp"
14
15#include <array>
16#include <map>
17#include <vector>
18
24namespace scran_markers {
25
34 double threshold = 0;
35
40 int num_threads = 1;
41
46 int cache_size = 100;
47
52 bool compute_cohens_d = true;
53
58 bool compute_auc = true;
59
64 bool compute_delta_mean = true;
65
71
76 bool compute_min = true;
77
82 bool compute_mean = true;
83
88 bool compute_median = true;
89
94 bool compute_max = true;
95
100 bool compute_min_rank = true;
101
105 scran_blocks::WeightPolicy block_weight_policy = scran_blocks::WeightPolicy::VARIABLE;
106
112};
113
119template<typename Stat_, typename Rank_>
126 std::vector<Stat_*> mean;
127
133 std::vector<Stat_*> detected;
134
142 std::vector<SummaryBuffers<Stat_, Rank_> > cohens_d;
143
151 std::vector<SummaryBuffers<Stat_, Rank_> > auc;
152
160 std::vector<SummaryBuffers<Stat_, Rank_> > delta_mean;
161
169 std::vector<SummaryBuffers<Stat_, Rank_> > delta_detected;
170};
171
177template<typename Stat_, typename Rank_>
183 std::vector<std::vector<Stat_> > mean;
184
189 std::vector<std::vector<Stat_> > detected;
190
198 std::vector<SummaryResults<Stat_, Rank_> > cohens_d;
199
207 std::vector<SummaryResults<Stat_, Rank_> > auc;
208
216 std::vector<SummaryResults<Stat_, Rank_> > delta_mean;
217
225 std::vector<SummaryResults<Stat_, Rank_> > delta_detected;
226};
227
231namespace internal {
232
233enum class CacheAction : unsigned char { SKIP, COMPUTE, CACHE };
234
235// Safely cap the cache size at the maximum possible number of comparisons (i.e., ngroups * (ngroups - 1) / 2).
236inline std::size_t cap_cache_size(std::size_t cache_size, std::size_t ngroups) {
237 if (ngroups < 2) {
238 return 0;
239 } else if (ngroups % 2 == 0) {
240 auto denom = ngroups / 2;
241 auto ratio = cache_size / denom;
242 if (ratio <= ngroups - 1) {
243 return cache_size;
244 } else {
245 return denom * (ngroups - 1);
246 }
247 } else {
248 auto denom = (ngroups - 1) / 2;
249 auto ratio = cache_size / denom;
250 if (ratio <= ngroups) {
251 return cache_size;
252 } else {
253 return denom * ngroups;
254 }
255 }
256}
257
258/*
259 * We compute effect sizes in a pairwise fashion with some nested loops, i.e.,
260 * iterating from g1 in [1, G) and then for g2 in [0, g1). When we compute the
261 * effect size for g1 vs g2, we sometimes get a free effect size for g2 vs g1,
262 * which we call the "reverse effect". However, we can't use the reverse effect
263 * size until we get around to summarizing effects for g2, hence the caching.
264 *
265 * This cache tries to store as many of the reverse effects as possible before
266 * it starts evicting. Evictions are based on the principle that it is better
267 * to store effects that will be re-used quickly, thus freeing up the cache for
268 * future stores. The 'speed' of reusability of each cache entry depends on the
269 * first group in the comparison corresponding to each cached effect size; the
270 * smaller the first group, the sooner it will be reached when iterating across
271 * groups in the ScoreMarkers function.
272 *
273 * So, the policy is to evict cache entries when the identity of the first
274 * group in the cached entry is larger than the identity of the first group for
275 * the incoming entry. Given that, if the cache is full, we have to throw away
276 * one of these effects anyway, I'd prefer to hold onto the one we're using
277 * soon, because at least it'll be freed up rapidly.
278 */
279template<typename Index_, typename Stat_>
280class EffectsCacher {
281public:
282 EffectsCacher(Index_ ngenes, std::size_t ngroups, std::size_t cache_size) :
283 my_ngenes(ngenes),
284 my_ngroups(ngroups),
285 my_cache_size(cap_cache_size(cache_size, ngroups)),
286 my_actions(sanisizer::cast<decltype(my_actions.size())>(ngroups)),
287 my_common_cache(sanisizer::product<decltype(my_common_cache.size())>(ngenes, my_cache_size)),
288 my_staging_cache(sanisizer::cast<decltype(my_staging_cache.size())>(ngroups))
289 {
290 my_unused_pool.reserve(my_cache_size);
291 auto ptr = my_common_cache.data();
292 for (decltype(my_cache_size) c = 0; c < my_cache_size; ++c, ptr += ngenes) {
293 my_unused_pool.push_back(ptr);
294 }
295 }
296
297private:
298 Index_ my_ngenes;
299 std::size_t my_ngroups;
300 std::size_t my_cache_size;
301
302 std::vector<CacheAction> my_actions;
303
304 // 'common_cache' contains allocation so that we don't have to do
305 // a lot of fiddling with move constructors, swaps, etc.
306 std::vector<Stat_> my_common_cache;
307
308 // 'staging_cache' contains the set of cached effects in the other
309 // direction, i.e., all other groups compared to the current group. This is
310 // only used to avoid repeated look-ups in 'cached' while filling the
311 // effect size vectors; they will ultimately be transferred to cached after
312 // the processing for the current group is complete.
313 std::vector<Stat_*> my_staging_cache;
314
315 // 'unused_pool' contains the currently-unused set of pointers to free
316 // subarrays in 'my_common_cache'
317 std::vector<Stat_*> my_unused_pool;
318
319 // 'cached' contains the cached effect size vectors from previous groups. Note
320 // that the use of a map is deliberate as we need the sorting.
321 std::map<std::pair<std::size_t, std::size_t>, Stat_*> my_cached;
322
323public:
324 void clear() {
325 my_cached.clear();
326 }
327
328public:
329 void fill_effects_from_cache(std::size_t group, std::vector<double>& full_effects) {
330 // During calculation of effects, the current group (i.e., 'group') is
331 // the first group in the comparison and 'other' is the second group.
332 // However, remember that we want to cache the reverse effects, so in
333 // the cached entry, 'group' is second and 'other' is first.
334 for (decltype(my_ngroups) other = 0; other < my_ngroups; ++other) {
335 if (other == group) {
336 my_actions[other] = CacheAction::SKIP;
337 continue;
338 }
339
340 if (my_cache_size == 0) {
341 my_actions[other] = CacheAction::COMPUTE;
342 continue;
343 }
344
345 // If 'other' is later than 'group', it's a candidate to be cached,
346 // as it will be used when this method is called with 'group = other'.
347 // Note that the ACTUAL caching decision is made in the refinement step below.
348 if (other > group) {
349 my_actions[other] = CacheAction::CACHE;
350 continue;
351 }
352
353 // Need to recompute cache entries that were previously evicted. We
354 // do so if the cache is empty or the first group of the first cached
355 // entry has a higher index than the current group (and thus the
356 // desired comparison's effects cannot possibly exist in the cache).
357 if (my_cached.empty()) {
358 my_actions[other] = CacheAction::COMPUTE;
359 continue;
360 }
361
362 const auto& front = my_cached.begin()->first;
363 if (front.first > group || front.second > other) {
364 // Technically, the second clause should be (front.first == group && front.second > other).
365 // However, less-thans should be impossible as they should have been used up during processing
366 // of previous 'group' values. Thus, equality is already implied if the first condition fails.
367 my_actions[other] = CacheAction::COMPUTE;
368 continue;
369 }
370
371 // If we got past the previous clause, this implies that the first cache entry
372 // contains the effect sizes for the desired comparison (i.e., 'group - other').
373 // We thus transfer the cached vector to the full_set.
374 my_actions[other] = CacheAction::SKIP;
375 auto curcache = my_cached.begin()->second;
376 for (decltype(my_ngenes) i = 0; i < my_ngenes; ++i) {
377 full_effects[sanisizer::nd_offset<std::size_t>(other, my_ngroups, i)] = curcache[i];
378 }
379
380 my_unused_pool.push_back(curcache);
381 my_cached.erase(my_cached.begin());
382 }
383
384 // Refining our choice of cacheable entries by doing a dummy run and
385 // seeing whether eviction actually happens. If it doesn't, we won't
386 // bother caching, because that would be a waste of memory accesses.
387 for (decltype(my_ngroups) other = 0; other < my_ngroups; ++other) {
388 if (my_actions[other] != CacheAction::CACHE) {
389 continue;
390 }
391
392 std::pair<std::size_t, std::size_t> key(other, group);
393 if (my_cached.size() < my_cache_size) {
394 auto ptr = my_unused_pool.back();
395 my_cached[key] = ptr;
396 my_staging_cache[other] = ptr;
397 my_unused_pool.pop_back();
398 continue;
399 }
400
401 // Looking at the last cache entry. If the first group of this
402 // entry is larger than the first group of the incoming entry, we
403 // evict it, as the incoming entry has faster reusability.
404 auto it = my_cached.end();
405 --it;
406 if ((it->first).first > other) {
407 auto ptr = it->second;
408 my_cached[key] = ptr;
409 my_staging_cache[other] = ptr;
410 my_cached.erase(it);
411 } else {
412 // Otherwise, if we're not going to do any evictions, we
413 // indicate that we shouldn't even bother computing the
414 // reverse, because we're won't cache the incoming entry.
415 my_actions[other] = CacheAction::COMPUTE;
416 }
417 }
418 }
419
420public:
421 CacheAction get_action(std::size_t other) const {
422 return my_actions[other];
423 }
424
425 Stat_* get_cache_location(std::size_t other) const {
426 return my_staging_cache[other];
427 }
428};
429
430template<typename Index_, typename Stat_, typename Rank_>
431void process_simple_summary_effects(
432 Index_ ngenes,
433 std::size_t ngroups,
434 std::size_t nblocks,
435 std::size_t ncombos,
436 const std::vector<Stat_>& combo_means,
437 const std::vector<Stat_>& combo_vars,
438 const std::vector<Stat_>& combo_detected,
439 const ScoreMarkersSummaryBuffers<Stat_, Rank_>& output,
440 const std::vector<Stat_>& combo_weights,
441 double threshold,
442 std::size_t cache_size,
443 int num_threads)
444{
445 // First, computing the pooled averages to get that out of the way.
446 {
447 std::vector<Stat_> total_weights_per_group;
448 const Stat_* total_weights_ptr = combo_weights.data();
449 if (nblocks > 1) {
450 total_weights_per_group = compute_total_weight_per_group(ngroups, nblocks, combo_weights.data());
451 total_weights_ptr = total_weights_per_group.data();
452 }
453
454 tatami::parallelize([&](int, Index_ start, Index_ length) -> void {
455 for (Index_ gene = start, end = start + length; gene < end; ++gene) {
456 auto in_offset = sanisizer::product_unsafe<std::size_t>(gene, ncombos);
457 const auto* tmp_means = combo_means.data() + in_offset;
458 const auto* tmp_detected = combo_detected.data() + in_offset;
459 average_group_stats(gene, ngroups, nblocks, tmp_means, tmp_detected, combo_weights.data(), total_weights_ptr, output.mean, output.detected);
460 }
461 }, ngenes, num_threads);
462 }
463
464 PrecomputedPairwiseWeights<Stat_> preweights(ngroups, nblocks, combo_weights.data());
465 EffectsCacher<Index_, Stat_> cache(ngenes, ngroups, cache_size);
466 std::vector<Stat_> full_effects(sanisizer::product<typename std::vector<Stat_>::size_type>(ngroups, ngenes));
467 auto effect_buffers = sanisizer::create<std::vector<std::vector<Stat_> > >(num_threads);
468 for (auto& ef : effect_buffers) {
469 ef.resize(ngroups);
470 }
471
472 if (output.cohens_d.size()) {
473 cache.clear();
474 for (decltype(ngroups) group = 0; group < ngroups; ++group) {
475 cache.fill_effects_from_cache(group, full_effects);
476
477 tatami::parallelize([&](int t, Index_ start, Index_ length) -> void {
478 auto& effect_buffer = effect_buffers[t];
479
480 for (Index_ gene = start, end = start + length; gene < end; ++gene) {
481 auto in_offset = sanisizer::product_unsafe<std::size_t>(gene, ncombos);
482 auto my_means = combo_means.data() + in_offset;
483 auto my_variances = combo_vars.data() + in_offset;
484 auto store_ptr = full_effects.data() + sanisizer::product_unsafe<std::size_t>(gene, ngroups);
485
486 for (decltype(ngroups) other = 0; other < ngroups; ++other) {
487 auto cache_action = cache.get_action(other);
488 if (cache_action == internal::CacheAction::COMPUTE) {
489 store_ptr[other] = compute_pairwise_cohens_d_one_sided(group, other, my_means, my_variances, ngroups, nblocks, preweights, threshold);
490 } else if (cache_action == internal::CacheAction::CACHE) {
491 auto tmp = compute_pairwise_cohens_d_two_sided(group, other, my_means, my_variances, ngroups, nblocks, preweights, threshold);
492 store_ptr[other] = tmp.first;
493 cache.get_cache_location(other)[gene] = tmp.second;
494 }
495 }
496 summarize_comparisons(ngroups, store_ptr, group, gene, output.cohens_d[group], effect_buffer);
497 }
498 }, ngenes, num_threads);
499
500 auto mr = output.cohens_d[group].min_rank;
501 if (mr) {
502 compute_min_rank_for_group(ngenes, ngroups, group, full_effects.data(), mr, num_threads);
503 }
504 }
505 }
506
507 if (output.delta_mean.size()) {
508 cache.clear();
509 for (decltype(ngroups) group = 0; group < ngroups; ++group) {
510 cache.fill_effects_from_cache(group, full_effects);
511
512 tatami::parallelize([&](int t, Index_ start, Index_ length) -> void {
513 auto& effect_buffer = effect_buffers[t];
514
515 for (Index_ gene = start, end = start + length; gene < end; ++gene) {
516 auto my_means = combo_means.data() + sanisizer::product_unsafe<std::size_t>(gene, ncombos);
517 auto store_ptr = full_effects.data() + sanisizer::product_unsafe<std::size_t>(gene, ngroups);
518
519 for (decltype(ngroups) other = 0; other < ngroups; ++other) {
520 auto cache_action = cache.get_action(other);
521 if (cache_action != internal::CacheAction::SKIP) {
522 auto val = compute_pairwise_simple_diff(group, other, my_means, ngroups, nblocks, preweights);
523 store_ptr[other] = val;
524 if (cache_action == CacheAction::CACHE) {
525 cache.get_cache_location(other)[gene] = -val;
526 }
527 }
528 }
529 summarize_comparisons(ngroups, store_ptr, group, gene, output.delta_mean[group], effect_buffer);
530 }
531 }, ngenes, num_threads);
532
533 auto mr = output.delta_mean[group].min_rank;
534 if (mr) {
535 compute_min_rank_for_group(ngenes, ngroups, group, full_effects.data(), mr, num_threads);
536 }
537 }
538 }
539
540 if (output.delta_detected.size()) {
541 cache.clear();
542 for (decltype(ngroups) group = 0; group < ngroups; ++group) {
543 cache.fill_effects_from_cache(group, full_effects);
544
545 tatami::parallelize([&](int t, Index_ start, Index_ length) -> void {
546 auto& effect_buffer = effect_buffers[t];
547
548 for (Index_ gene = start, end = start + length; gene < end; ++gene) {
549 auto my_detected = combo_detected.data() + sanisizer::product_unsafe<std::size_t>(gene, ncombos);
550 auto store_ptr = full_effects.data() + sanisizer::product_unsafe<std::size_t>(gene, ngroups);
551
552 for (decltype(ngroups) other = 0; other < ngroups; ++other) {
553 auto cache_action = cache.get_action(other);
554 if (cache_action != CacheAction::SKIP) {
555 auto val = compute_pairwise_simple_diff(group, other, my_detected, ngroups, nblocks, preweights);
556 store_ptr[other] = val;
557 if (cache_action == CacheAction::CACHE) {
558 cache.get_cache_location(other)[gene] = -val;
559 }
560 }
561 }
562 summarize_comparisons(ngroups, store_ptr, group, gene, output.delta_detected[group], effect_buffer);
563 }
564 }, ngenes, num_threads);
565
566 auto mr = output.delta_detected[group].min_rank;
567 if (mr) {
568 compute_min_rank_for_group(ngenes, ngroups, group, full_effects.data(), mr, num_threads);
569 }
570 }
571 }
572}
573
574template<typename Index_, typename Stat_, typename Rank_>
575ScoreMarkersSummaryBuffers<Stat_, Rank_> fill_summary_results(Index_ ngenes, std::size_t ngroups, ScoreMarkersSummaryResults<Stat_, Rank_>& store, const ScoreMarkersSummaryOptions& options) {
576 ScoreMarkersSummaryBuffers<Stat_, Rank_> output;
577
578 internal::fill_average_results(ngenes, ngroups, store.mean, store.detected, output.mean, output.detected);
579
580 if (options.compute_cohens_d) {
581 output.cohens_d = internal::fill_summary_results(
582 ngenes,
583 ngroups,
584 store.cohens_d,
585 options.compute_min,
586 options.compute_mean,
587 options.compute_median,
588 options.compute_max,
589 options.compute_min_rank
590 );
591 }
592
593 if (options.compute_auc) {
594 output.auc = internal::fill_summary_results(
595 ngenes,
596 ngroups,
597 store.auc,
598 options.compute_min,
599 options.compute_mean,
600 options.compute_median,
601 options.compute_max,
602 options.compute_min_rank
603 );
604 }
605
606 if (options.compute_delta_mean) {
607 output.delta_mean = internal::fill_summary_results(
608 ngenes,
609 ngroups,
610 store.delta_mean,
611 options.compute_min,
612 options.compute_mean,
613 options.compute_median,
614 options.compute_max,
615 options.compute_min_rank
616 );
617 }
618
619 if (options.compute_delta_detected) {
620 output.delta_detected = internal::fill_summary_results(
621 ngenes,
622 ngroups,
623 store.delta_detected,
624 options.compute_min,
625 options.compute_mean,
626 options.compute_median,
627 options.compute_max,
628 options.compute_min_rank
629 );
630 }
631
632 return output;
633}
634
635}
672template<typename Value_, typename Index_, typename Group_, typename Stat_, typename Rank_>
674 const tatami::Matrix<Value_, Index_>& matrix,
675 const Group_* group,
676 const ScoreMarkersSummaryOptions& options,
678{
679 auto NC = matrix.ncol();
680 auto group_sizes = tatami_stats::tabulate_groups(group, NC);
681 auto ngenes = matrix.nrow();
682 auto ngroups = group_sizes.size();
683
684 // In most cases this doesn't really matter, but we do it for consistency with the 1-block case,
685 // and to account for variable weighting where non-zero block sizes get zero weight.
686 auto group_weights = scran_blocks::compute_weights<Stat_>(group_sizes, options.block_weight_policy, options.variable_block_weight_parameters);
687
688 auto payload_size = sanisizer::product<typename std::vector<Stat_>::size_type>(ngenes, ngroups);
689 std::vector<Stat_> group_means(payload_size), group_vars(payload_size), group_detected(payload_size);
690
691 bool do_auc = !output.auc.empty();
692 std::vector<Stat_> tmp_auc;
693 Stat_* auc_ptr = NULL;
694 if (do_auc) {
695 tmp_auc.resize(sanisizer::product<decltype(tmp_auc.size())>(ngroups, ngroups, ngenes));
696 auc_ptr = tmp_auc.data();
697 }
698
699 if (do_auc || matrix.prefer_rows()) {
700 internal::scan_matrix_by_row<true>(
701 matrix,
702 ngroups,
703 group,
704 1,
705 static_cast<int*>(NULL),
706 ngroups,
707 NULL,
708 group_means,
709 group_vars,
710 group_detected,
711 auc_ptr,
712 group_sizes,
713 group_weights,
714 options.threshold,
715 options.num_threads
716 );
717
718 } else {
719 internal::scan_matrix_by_column(
720 matrix,
721 ngroups,
722 group,
723 group_means,
724 group_vars,
725 group_detected,
726 group_sizes,
727 options.num_threads
728 );
729 }
730
731 internal::process_simple_summary_effects(
732 matrix.nrow(),
733 ngroups,
734 1,
735 ngroups,
736 group_means,
737 group_vars,
738 group_detected,
739 output,
740 group_weights,
741 options.threshold,
742 options.cache_size,
743 options.num_threads
744 );
745
746 if (do_auc) {
747 internal::summarize_comparisons(ngenes, ngroups, auc_ptr, output.auc, options.num_threads);
748 internal::compute_min_rank_pairwise(ngenes, ngroups, auc_ptr, output.auc, options.num_threads);
749 }
750}
751
779template<typename Value_, typename Index_, typename Group_, typename Block_, typename Stat_, typename Rank_>
781 const tatami::Matrix<Value_, Index_>& matrix,
782 const Group_* group,
783 const Block_* block,
784 const ScoreMarkersSummaryOptions& options,
786{
787 auto NC = matrix.ncol();
788 auto ngenes = matrix.nrow();
789 auto ngroups = output.mean.size();
790 auto nblocks = tatami_stats::total_groups(block, NC);
791
792 auto combinations = internal::create_combinations(ngroups, group, block, NC);
793 auto combo_sizes = internal::tabulate_combinations<Index_>(ngroups, nblocks, combinations);
794 auto ncombos = combo_sizes.size();
795 auto combo_weights = scran_blocks::compute_weights<Stat_>(combo_sizes, options.block_weight_policy, options.variable_block_weight_parameters);
796
797 auto payload_size = sanisizer::product<typename std::vector<Stat_>::size_type>(ngenes, ncombos);
798 std::vector<Stat_> combo_means(payload_size), combo_vars(payload_size), combo_detected(payload_size);
799
800 bool do_auc = !output.auc.empty();
801 std::vector<Stat_> tmp_auc;
802 Stat_* auc_ptr = NULL;
803 if (do_auc) {
804 tmp_auc.resize(sanisizer::product<decltype(tmp_auc.size())>(ngroups, ngroups, ngenes));
805 auc_ptr = tmp_auc.data();
806 }
807
808 if (do_auc || matrix.prefer_rows()) {
809 internal::scan_matrix_by_row<false>(
810 matrix,
811 ngroups,
812 group,
813 nblocks,
814 block,
815 ncombos,
816 combinations.data(),
817 combo_means,
818 combo_vars,
819 combo_detected,
820 auc_ptr,
821 combo_sizes,
822 combo_weights,
823 options.threshold,
824 options.num_threads
825 );
826
827 } else {
828 internal::scan_matrix_by_column(
829 matrix,
830 ncombos,
831 combinations.data(),
832 combo_means,
833 combo_vars,
834 combo_detected,
835 combo_sizes,
836 options.num_threads
837 );
838 }
839
840 internal::process_simple_summary_effects(
841 matrix.nrow(),
842 ngroups,
843 nblocks,
844 ncombos,
845 combo_means,
846 combo_vars,
847 combo_detected,
848 output,
849 combo_weights,
850 options.threshold,
851 options.cache_size,
852 options.num_threads
853 );
854
855 if (do_auc) {
856 internal::summarize_comparisons(ngenes, ngroups, auc_ptr, output.auc, options.num_threads);
857 internal::compute_min_rank_pairwise(ngenes, ngroups, auc_ptr, output.auc, options.num_threads);
858 }
859}
860
877template<typename Stat_ = double, typename Rank_ = int, typename Value_, typename Index_, typename Group_>
879 const tatami::Matrix<Value_, Index_>& matrix,
880 const Group_* group,
881 const ScoreMarkersSummaryOptions& options)
882{
883 auto ngroups = tatami_stats::total_groups(group, matrix.ncol());
885 auto buffers = internal::fill_summary_results(matrix.nrow(), ngroups, output, options);
886 score_markers_summary(matrix, group, options, buffers);
887 return output;
888}
889
909template<typename Stat_ = double, typename Rank_ = int, typename Value_, typename Index_, typename Group_, typename Block_>
911 const tatami::Matrix<Value_, Index_>& matrix,
912 const Group_* group,
913 const Block_* block,
914 const ScoreMarkersSummaryOptions& options)
915{
916 auto ngroups = tatami_stats::total_groups(group, matrix.ncol());
918 auto buffers = internal::fill_summary_results(matrix.nrow(), ngroups, output, options);
919 score_markers_summary_blocked(matrix, group, block, options, buffers);
920 return output;
921}
922
923}
924
925#endif
virtual Index_ ncol() const=0
virtual Index_ nrow() const=0
virtual bool prefer_rows() const=0
void compute_weights(std::size_t num_blocks, const Size_ *sizes, WeightPolicy policy, const VariableWeightParameters &variable, Weight_ *weights)
Marker detection for single-cell data.
Definition score_markers_pairwise.hpp:25
void score_markers_summary(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *group, const ScoreMarkersSummaryOptions &options, const ScoreMarkersSummaryBuffers< Stat_, Rank_ > &output)
Definition score_markers_summary.hpp:673
void score_markers_summary_blocked(const tatami::Matrix< Value_, Index_ > &matrix, const Group_ *group, const Block_ *block, const ScoreMarkersSummaryOptions &options, const ScoreMarkersSummaryBuffers< Stat_, Rank_ > &output)
Definition score_markers_summary.hpp:780
void parallelize(Function_ fun, Index_ tasks, int threads)
Buffers for score_markers_summary() and friends.
Definition score_markers_summary.hpp:120
std::vector< Stat_ * > detected
Definition score_markers_summary.hpp:133
std::vector< SummaryBuffers< Stat_, Rank_ > > delta_detected
Definition score_markers_summary.hpp:169
std::vector< Stat_ * > mean
Definition score_markers_summary.hpp:126
std::vector< SummaryBuffers< Stat_, Rank_ > > delta_mean
Definition score_markers_summary.hpp:160
std::vector< SummaryBuffers< Stat_, Rank_ > > cohens_d
Definition score_markers_summary.hpp:142
std::vector< SummaryBuffers< Stat_, Rank_ > > auc
Definition score_markers_summary.hpp:151
Options for score_markers_summary() and friends.
Definition score_markers_summary.hpp:29
bool compute_max
Definition score_markers_summary.hpp:94
bool compute_delta_detected
Definition score_markers_summary.hpp:70
int cache_size
Definition score_markers_summary.hpp:46
bool compute_auc
Definition score_markers_summary.hpp:58
bool compute_min
Definition score_markers_summary.hpp:76
bool compute_median
Definition score_markers_summary.hpp:88
bool compute_mean
Definition score_markers_summary.hpp:82
double threshold
Definition score_markers_summary.hpp:34
scran_blocks::WeightPolicy block_weight_policy
Definition score_markers_summary.hpp:105
bool compute_cohens_d
Definition score_markers_summary.hpp:52
bool compute_min_rank
Definition score_markers_summary.hpp:100
int num_threads
Definition score_markers_summary.hpp:40
bool compute_delta_mean
Definition score_markers_summary.hpp:64
scran_blocks::VariableWeightParameters variable_block_weight_parameters
Definition score_markers_summary.hpp:111
Results for score_markers_summary() and friends.
Definition score_markers_summary.hpp:178
std::vector< SummaryResults< Stat_, Rank_ > > cohens_d
Definition score_markers_summary.hpp:198
std::vector< std::vector< Stat_ > > mean
Definition score_markers_summary.hpp:183
std::vector< SummaryResults< Stat_, Rank_ > > auc
Definition score_markers_summary.hpp:207
std::vector< SummaryResults< Stat_, Rank_ > > delta_detected
Definition score_markers_summary.hpp:225
std::vector< std::vector< Stat_ > > detected
Definition score_markers_summary.hpp:189
std::vector< SummaryResults< Stat_, Rank_ > > delta_mean
Definition score_markers_summary.hpp:216
Utilities for effect summarization.