scran
C++ library for basic single-cell RNA-seq analyses
Loading...
Searching...
No Matches
ScoreMarkers.hpp
Go to the documentation of this file.
1#ifndef SCRAN_SCORE_MARKERS_HPP
2#define SCRAN_SCORE_MARKERS_HPP
3
4#include "../utils/macros.hpp"
5
6#include "MatrixCalculator.hpp"
7#include "cohens_d.hpp"
8#include "simple_diff.hpp"
10
11#include "../utils/vector_to_pointers.hpp"
12#include "../utils/average_vectors.hpp"
13#include "../utils/blocking.hpp"
14
15#include "tatami/tatami.hpp"
16
17#include <array>
18#include <map>
19#include <vector>
20
27namespace scran {
28
32namespace differential_analysis {
33
34enum class CacheAction : unsigned char { SKIP, COMPUTE, CACHE };
35
36// This cache tries to store as many of the reverse effects as possible before
37// it starts evicting. Evictions are based on the principle that it is better
38// to store effects that will be re-used quickly, thus freeing up the cache for
39// future stores. The 'speed' of reusability of each cache entry depends on the
40// first group in the comparison corresponding to each cached effect size; the
41// smaller the first group, the sooner it will be reached when iterating across
42// groups in the ScoreMarkers function.
43//
44// So, the policy is to evict cache entries when the identity of the first
45// group in the cached entry is larger than the identity of the first group for
46// the incoming entry. Given that, if the cache is full, we have to throw away
47// one of these effects anyway, I'd prefer to hold onto the one we're using
48// soon, because at least it'll be freed up rapidly.
49template<typename Stat_>
50struct EffectsCacher {
51 EffectsCacher(size_t nge, int ngr, int cs) :
52 ngenes(nge),
53 ngroups(ngr),
54 cache_size(cs),
55 actions(ngroups),
56 staging_cache(ngroups)
57 {
58 vector_pool.reserve(cache_size);
59 }
60
61public:
62 size_t ngenes;
63 int ngroups;
64 int cache_size;
65
66 std::vector<CacheAction> actions;
67
68 // 'staging_cache' contains the set of cached effects in the other
69 // direction, i.e., all other groups compared to the current group. This is
70 // only used to avoid repeated look-ups in 'cached' while filling the
71 // effect size vectors; they will ultimately be transferred to cached after
72 // the processing for the current group is complete.
73 std::vector<std::vector<Stat_> > staging_cache;
74
75 // 'vector_pool' allows us to recycle effect size vectors to avoid reallocations.
76 std::vector<std::vector<Stat_> > vector_pool;
77
78 // 'cached' contains the cached effect size vectors from previous groups. Note
79 // that the use of a map is deliberate as we need the sorting.
80 std::map<std::pair<int, int>, std::vector<Stat_> > cached;
81
82public:
83 void clear() {
84 cached.clear();
85 }
86
87public:
88 void configure(int group, std::vector<double>& full_set) {
89 // During calculation of effects, the current group (i.e., 'group') is
90 // the first group in the comparison and 'other' is the second group.
91 // However, remember that we want to cache the reverse effects, so in
92 // the cached entry, 'group' is second and 'other' is first.
93 for (int other = 0; other < ngroups; ++other) {
94 if (other == group) {
95 actions[other] = CacheAction::SKIP;
96 continue;
97 }
98
99 if (cache_size == 0) {
100 actions[other] = CacheAction::COMPUTE;
101 continue;
102 }
103
104 // If 'other' is later than 'group', it's a candidate to be cached,
105 // as it will be reused when the current group becomes 'other'.
106 if (other > group) {
107 actions[other] = CacheAction::CACHE;
108 continue;
109 }
110
111 // Need to recompute cache entries that were previously evicted. We
112 // do so if the cache is empty or the first group of the first cached
113 // entry has a higher index than the current group (and thus the
114 // desired comparison's effects cannot possibly exist in the cache).
115 if (cached.empty()) {
116 actions[other] = CacheAction::COMPUTE;
117 continue;
118 }
119
120 const auto& front = cached.begin()->first;
121 if (front.first > group || front.second > other) {
122 // Technically, the second clause should be (front.first == group && front.second > other).
123 // However, less-thans should be impossible as they should have been used up during processing
124 // of previous 'group' values. Thus, equality is already implied if the first condition fails.
125 actions[other] = CacheAction::COMPUTE;
126 continue;
127 }
128
129 // If we got past the previous clause, this implies that the first cache entry
130 // contains the effect sizes for the desired comparison (i.e., 'group - other').
131 // We thus transfer the cached vector to the full_set.
132 actions[other] = CacheAction::SKIP;
133 auto& x = cached.begin()->second;
134 for (size_t i = 0, end = x.size(); i < end; ++i) {
135 full_set[other + i * ngroups] = x[i];
136 }
137
138 vector_pool.emplace_back(std::move(x)); // recycle memory to avoid heap reallocations.
139 cached.erase(cached.begin());
140 }
141
142 // Refining our choice of cacheable entries by doing a dummy run and
143 // seeing whether eviction actually happens. If it doesn't, we won't
144 // bother caching, because that would be a waste of memory accesses.
145 for (int other = 0; other < ngroups; ++other) {
146 if (actions[other] != CacheAction::CACHE) {
147 continue;
148 }
149
150 std::pair<int, int> key(other, group);
151 if (cached.size() < static_cast<size_t>(cache_size)) {
152 cached[key] = std::vector<Stat_>();
153 prepare_staging_cache(other);
154 continue;
155 }
156
157 // Looking at the last cache entry. If the first group of this
158 // entry is larger than the first group of the incoming entry, we
159 // evict it, as the incoming entry has faster reusability.
160 auto it = cached.end();
161 --it;
162 if ((it->first).first > other) {
163 auto& evicted = it->second;
164 if (evicted.size()) {
165 vector_pool.emplace_back(std::move(evicted));
166 }
167 cached.erase(it);
168 prepare_staging_cache(other);
169 cached[key] = std::vector<Stat_>();
170 } else {
171 // Otherwise, if we're not going to do any evictions, we
172 // indicate that we shouldn't even bother computing the
173 // reverse, because we're won't cache the incoming entry.
174 actions[other] = CacheAction::COMPUTE;
175 }
176 }
177 }
178
179 void transfer(int group) {
180 for (int other = 0; other < ngroups; ++other) {
181 if (actions[other] != CacheAction::CACHE) {
182 continue;
183 }
184
185 // All the to-be-staged logic is already implemented in 'configure()'.
186 auto& staged = staging_cache[other];
187 std::pair<int, int> key(other, group);
188 cached[key] = std::move(staged);
189 }
190 }
191
192private:
193 void prepare_staging_cache(int other) {
194 if (vector_pool.empty()) {
195 staging_cache[other].resize(ngenes);
196 } else {
197 // Recycling existing heap allocations.
198 staging_cache[other] = std::move(vector_pool.back());
199 vector_pool.pop_back();
200 }
201 }
202};
203
204}
232public:
237 typedef std::array<bool, differential_analysis::n_summaries> ComputeSummaries;
238
242 struct Defaults {
247 ComputeSummaries output { 0 };
248 for (int i = 0; i < differential_analysis::n_summaries; ++i) {
249 output[i] = true;
250 }
251 return output;
252 }
253
258 ComputeSummaries output { 0 };
259 for (int i = 0; i < differential_analysis::n_summaries; ++i) {
260 output[i] = false;
261 }
262 return output;
263 }
264
268 static constexpr double threshold = 0;
269
273 static constexpr int num_threads = 1;
274
278 static constexpr int cache_size = 100;
279
283 static constexpr WeightPolicy block_weight_policy = WeightPolicy::VARIABLE;
284
289 };
290
291private:
292 double threshold = Defaults::threshold;
293 WeightPolicy block_weight_policy = Defaults::block_weight_policy;
295
300
301 int cache_size = Defaults::cache_size;
302 int nthreads = Defaults::num_threads;
303
304public:
312 threshold = t;
313 return *this;
314 }
315
321 nthreads = n;
322 return *this;
323 }
324
332 cache_size = c;
333 return *this;
334 }
335
342 block_weight_policy = w;
343 return *this;
344 }
345
356
357public:
367 do_cohen = s;
368 return *this;
369 }
370
383 std::fill(do_cohen.begin(), do_cohen.end(), c);
384 return *this;
385 }
386
397 do_cohen[s] = c;
398 return *this;
399 }
400
410 do_auc = s;
411 return *this;
412 }
413
426 std::fill(do_auc.begin(), do_auc.end(), c);
427 return *this;
428 }
429
440 do_auc[s] = c;
441 return *this;
442 }
443
453 do_lfc = s;
454 return *this;
455 }
456
469 std::fill(do_lfc.begin(), do_lfc.end(), c);
470 return *this;
471 }
472
483 do_lfc[s] = c;
484 return *this;
485 }
486
496 do_delta_detected = s;
497 return *this;
498 }
499
512 std::fill(do_delta_detected.begin(), do_delta_detected.end(), c);
513 return *this;
514 }
515
526 do_delta_detected[s] = c;
527 return *this;
528 }
529
530private:
531 void set_everyone(differential_analysis::summary s, bool c) {
532 do_cohen[s] = c;
533 do_auc[s] = c;
534 do_lfc[s] = c;
535 do_delta_detected[s] = c;
536 return;
537 }
538
539public:
552 set_everyone(differential_analysis::MIN, s);
553 return *this;
554 }
555
568 set_everyone(differential_analysis::MEAN, s);
569 return *this;
570 }
571
584 set_everyone(differential_analysis::MEDIAN, s);
585 return *this;
586 }
587
600 set_everyone(differential_analysis::MAX, s);
601 return *this;
602 }
603
616 set_everyone(differential_analysis::MIN_RANK, s);
617 return *this;
618 }
619
620public:
649 template<typename Value_, typename Index_, typename Group_, typename Stat_>
650 void run(const tatami::Matrix<Value_, Index_>* p, const Group_* group,
651 std::vector<Stat_*> means,
652 std::vector<Stat_*> detected,
653 std::vector<std::vector<Stat_*> > cohen,
654 std::vector<std::vector<Stat_*> > auc,
655 std::vector<std::vector<Stat_*> > lfc,
656 std::vector<std::vector<Stat_*> > delta_detected)
657 const {
658 differential_analysis::MatrixCalculator runner(nthreads, threshold, block_weight_policy, variable_block_weight_parameters);
659
660 size_t ngenes = p->nrow();
661 size_t ngroups = means.size();
662 Overlord<Stat_> overlord(ngenes, ngroups, auc.empty());
663 auto state = runner.run(p, group, ngroups, overlord);
664
665 process_simple_effects(ngenes, ngroups, 1, state, means, detected, cohen, lfc, delta_detected);
666 summarize_auc(ngenes, ngroups, state, auc, overlord.auc_buffer);
667 }
668
701 template<typename Value_, typename Index_, typename Group_, typename Block_, typename Stat_>
702 void run_blocked(const tatami::Matrix<Value_, Index_>* p, const Group_* group, const Block_* block,
703 std::vector<Stat_*> means,
704 std::vector<Stat_*> detected,
705 std::vector<std::vector<Stat_*> > cohen,
706 std::vector<std::vector<Stat_*> > auc,
707 std::vector<std::vector<Stat_*> > lfc,
708 std::vector<std::vector<Stat_*> > delta_detected)
709 const {
710 if (block == NULL) {
711 run(
712 p,
713 group,
714 std::move(means),
715 std::move(detected),
716 std::move(cohen),
717 std::move(auc),
718 std::move(lfc),
719 std::move(delta_detected)
720 );
721 return;
722 }
723
724 differential_analysis::MatrixCalculator runner(nthreads, threshold, block_weight_policy, variable_block_weight_parameters);
725
726 size_t ngenes = p->nrow();
727 size_t ngroups = means.size();
728 size_t nblocks = count_ids(p->ncol(), block);
729 Overlord<Stat_> overlord(ngenes, ngroups, auc.empty());
730 auto state = runner.run_blocked(p, group, ngroups, block, nblocks, overlord);
731
732 int ncombos = ngroups * nblocks;
733 std::vector<std::vector<Stat_> > means_store(ncombos), detected_store(ncombos);
734 std::vector<Stat_*> means2(ncombos), detected2(ncombos);
735 for (int c = 0; c < ncombos; ++c) {
736 means_store[c].resize(ngenes);
737 detected_store[c].resize(ngenes);
738 means2[c] = means_store[c].data();
739 detected2[c] = detected_store[c].data();
740 }
741
742 process_simple_effects(ngenes, ngroups, nblocks, state, means2, detected2, cohen, lfc, delta_detected);
743 summarize_auc(ngenes, ngroups, state, auc, overlord.auc_buffer);
744
745 // Averaging the remaining statistics.
746 std::vector<double> weights(nblocks);
747 std::vector<Stat_*> mstats(nblocks), dstats(nblocks);
748
749 for (int gr = 0; gr < ngroups; ++gr) {
750 for (int b = 0; b < nblocks; ++b) {
751 size_t offset = gr * static_cast<size_t>(nblocks) + b;
752 weights[b] = state.level_weight[offset];
753 mstats[b] = means2[offset];
754 dstats[b] = detected2[offset];
755 }
756
757 average_vectors_weighted(ngenes, mstats, weights.data(), means[gr]);
758 average_vectors_weighted(ngenes, dstats, weights.data(), detected[gr]);
759 }
760 }
761
762private:
763 template<typename Stat_>
764 class Overlord {
765 public:
766 Overlord(size_t nr, size_t ng, bool skip_auc) : skipped(skip_auc), auc_buffer(skip_auc ? 0 : nr * ng * ng) {}
767
768 bool needs_auc() const {
769 return !skipped;
770 }
771
772 bool skipped;
773 std::vector<Stat_> auc_buffer;
774
775 Stat_* prepare_auc_buffer(size_t gene, size_t ngroups) {
776 return auc_buffer.data() + gene * ngroups * ngroups;
777 }
778 };
779
780 template<typename Stat_>
781 void process_simple_effects(
782 size_t ngenes, // using size_t consistently here, to eliminate integer overflow bugs when computing products.
783 size_t ngroups,
784 size_t nblocks,
785 const differential_analysis::MatrixCalculator::State& state,
786 std::vector<Stat_*>& means,
787 std::vector<Stat_*>& detected,
788 std::vector<std::vector<Stat_*> >& cohen,
789 std::vector<std::vector<Stat_*> >& lfc,
790 std::vector<std::vector<Stat_*> >& delta_detected)
791 const {
792 const auto& level_weight = state.level_weight;
793 auto nlevels = level_weight.size();
794 const auto* tmp_means = state.means.data();
795 const auto* tmp_variances = state.variances.data();
796 const auto* tmp_detected = state.detected.data();
797
798 // Transferring the block-wise statistics over.
799 {
800 auto my_means = tmp_means;
801 auto my_detected = tmp_detected;
802 for (size_t gene = 0; gene < ngenes; ++gene) {
803 for (size_t l = 0; l < nlevels; ++l, ++my_means, ++my_detected) {
804 means[l][gene] = *my_means;
805 detected[l][gene] = *my_detected;
806 }
807 }
808 }
809
810 // Looping over each group and computing the various summaries. We do this on
811 // a per-group basis to avoid having to store the full group-by-group matrix of
812 // effect sizes that we would otherwise need as input to SummarizeEffects.
813 differential_analysis::EffectsCacher<Stat_> cache(ngenes, ngroups, cache_size);
814 std::vector<double> full_set(ngroups * ngenes);
815
816 if (cohen.size()) {
817 cache.clear();
818 for (int group = 0; group < ngroups; ++group) {
819 cache.configure(group, full_set);
820
821 tatami::parallelize([&](size_t, size_t start, size_t length) -> void {
822 size_t in_offset = nlevels * start;
823 auto my_means = tmp_means + in_offset;
824 auto my_variances = tmp_variances + in_offset;
825
826 const auto& actions = cache.actions;
827 auto& staging_cache = cache.staging_cache;
828
829 auto cohen_ptr = full_set.data() + start * ngroups;
830 std::vector<double> effect_buffer(ngroups);
831
832 for (size_t gene = start, end = start + length; gene < end; ++gene, my_means += nlevels, my_variances += nlevels, cohen_ptr += ngroups) {
833 for (int other = 0; other < ngroups; ++other) {
834 if (actions[other] == differential_analysis::CacheAction::SKIP) {
835 continue;
836 }
837
838 if (actions[other] == differential_analysis::CacheAction::COMPUTE) {
839 cohen_ptr[other] = differential_analysis::compute_pairwise_cohens_d<false>(group, other, my_means, my_variances, level_weight, ngroups, nblocks, threshold);
840 continue;
841 }
842
843 auto tmp = differential_analysis::compute_pairwise_cohens_d<true>(group, other, my_means, my_variances, level_weight, ngroups, nblocks, threshold);
844 cohen_ptr[other] = tmp.first;
845 staging_cache[other][gene] = tmp.second;
846 }
847
848 differential_analysis::summarize_comparisons(ngroups, cohen_ptr, group, gene, cohen, effect_buffer);
849 }
850 }, ngenes, nthreads);
851
852 if (cohen[differential_analysis::summary::MIN_RANK].size()) {
853 differential_analysis::compute_min_rank(ngenes, ngroups, group, full_set.data(), cohen[differential_analysis::summary::MIN_RANK][group], nthreads);
854 }
855
856 cache.transfer(group);
857 }
858 }
859
860 if (lfc.size()) {
861 cache.clear();
862 for (int group = 0; group < ngroups; ++group) {
863 cache.configure(group, full_set);
864
865 tatami::parallelize([&](size_t, size_t start, size_t length) -> void {
866 auto my_means = tmp_means + nlevels * start;
867
868 const auto& actions = cache.actions;
869 auto& staging_cache = cache.staging_cache;
870
871 auto lfc_ptr = full_set.data() + start * ngroups;
872 std::vector<double> effect_buffer(ngroups);
873
874 for (size_t gene = start, end = start + length; gene < end; ++gene, my_means += nlevels, lfc_ptr += ngroups) {
875 for (int other = 0; other < ngroups; ++other) {
876 if (actions[other] == differential_analysis::CacheAction::SKIP) {
877 continue;
878 }
879
880 auto val = differential_analysis::compute_pairwise_simple_diff(group, other, my_means, level_weight, ngroups, nblocks);
881 lfc_ptr[other] = val;
882 if (actions[other] == differential_analysis::CacheAction::CACHE) {
883 staging_cache[other][gene] = -val;
884 }
885 }
886
887 differential_analysis::summarize_comparisons(ngroups, lfc_ptr, group, gene, lfc, effect_buffer);
888 }
889 }, ngenes, nthreads);
890
891 if (lfc[differential_analysis::summary::MIN_RANK].size()) {
892 differential_analysis::compute_min_rank(ngenes, ngroups, group, full_set.data(), lfc[differential_analysis::summary::MIN_RANK][group], nthreads);
893 }
894
895 cache.transfer(group);
896 }
897 }
898
899 if (delta_detected.size()) {
900 cache.clear();
901 for (int group = 0; group < ngroups; ++group) {
902 cache.configure(group, full_set);
903
904 tatami::parallelize([&](size_t, size_t start, size_t length) -> void {
905 auto my_detected = tmp_detected + nlevels * start;
906
907 const auto& actions = cache.actions;
908 auto& staging_cache = cache.staging_cache;
909
910 auto delta_detected_ptr = full_set.data() + start * ngroups;
911 std::vector<double> effect_buffer(ngroups);
912
913 for (size_t gene = start, end = start + length; gene < end; ++gene, my_detected += nlevels, delta_detected_ptr += ngroups) {
914 for (int other = 0; other < ngroups; ++other) {
915 if (actions[other] == differential_analysis::CacheAction::SKIP) {
916 continue;
917 }
918
919 auto val = differential_analysis::compute_pairwise_simple_diff(group, other, my_detected, level_weight, ngroups, nblocks);
920 delta_detected_ptr[other] = val;
921 if (actions[other] == differential_analysis::CacheAction::CACHE) {
922 staging_cache[other][gene] = -val;
923 }
924 }
925
926 differential_analysis::summarize_comparisons(ngroups, delta_detected_ptr, group, gene, delta_detected, effect_buffer);
927 }
928 }, ngenes, nthreads);
929
930 if (delta_detected[differential_analysis::summary::MIN_RANK].size()) {
931 differential_analysis::compute_min_rank(ngenes, ngroups, group, full_set.data(), delta_detected[differential_analysis::summary::MIN_RANK][group], nthreads);
932 }
933
934 cache.transfer(group);
935 }
936 }
937 }
938
939 template<typename Stat_>
940 void summarize_auc(
941 size_t ngenes,
942 size_t ngroups,
943 const differential_analysis::MatrixCalculator::State& state,
944 std::vector<std::vector<Stat_*> >& auc,
945 std::vector<Stat_>& auc_buffer)
946 const {
947 // If we need the min-rank AUCs, there's no choice but to hold everything in memory.
948 if (auc.size()) {
949 differential_analysis::summarize_comparisons(ngenes, ngroups, auc_buffer.data(), auc, nthreads);
950 if (auc[differential_analysis::summary::MIN_RANK].size()) {
951 differential_analysis::compute_min_rank(ngenes, ngroups, auc_buffer.data(), auc[differential_analysis::summary::MIN_RANK], nthreads);
952 }
953 }
954 }
955
956public:
965 template<typename Stat_>
966 struct Results {
970 Results() {}
971
972 Results(
973 size_t ngenes,
974 int ngroups,
975 const ComputeSummaries& do_cohen,
976 const ComputeSummaries& do_auc,
977 const ComputeSummaries& do_lfc,
978 const ComputeSummaries& do_delta_detected)
979 {
980 auto fill_inner = [&](int N, auto& type) {
981 type.reserve(N);
982 for (int n = 0; n < N; ++n) {
983 type.emplace_back(ngenes);
984 }
985 };
986
987 fill_inner(ngroups, means);
988 fill_inner(ngroups, detected);
989
990 auto fill_effect = [&](const ComputeSummaries& do_this, auto& effect) {
991 bool has_any = false;
992 for (size_t i = 0; i < do_this.size(); ++i) {
993 if (do_this[i]) {
994 has_any = true;
995 break;
996 }
997 }
998
999 if (has_any) {
1000 effect.resize(differential_analysis::n_summaries);
1001 if (do_this[differential_analysis::MIN]) {
1002 fill_inner(ngroups, effect[differential_analysis::MIN]);
1003 }
1004 if (do_this[differential_analysis::MEAN]) {
1005 fill_inner(ngroups, effect[differential_analysis::MEAN]);
1006 }
1007 if (do_this[differential_analysis::MEDIAN]) {
1008 fill_inner(ngroups, effect[differential_analysis::MEDIAN]);
1009 }
1010 if (do_this[differential_analysis::MAX]) {
1011 fill_inner(ngroups, effect[differential_analysis::MAX]);
1012 }
1013 if (do_this[differential_analysis::MIN_RANK]) {
1014 fill_inner(ngroups, effect[differential_analysis::MIN_RANK]);
1015 }
1016 }
1017 return;
1018 };
1019
1020 fill_effect(do_cohen, cohen);
1021 fill_effect(do_auc, auc);
1022 fill_effect(do_lfc, lfc);
1023 fill_effect(do_delta_detected, delta_detected);
1024 return;
1025 }
1036 std::vector<std::vector<std::vector<Stat_> > > cohen;
1037
1044 std::vector<std::vector<std::vector<Stat_> > > auc;
1045
1052 std::vector<std::vector<std::vector<Stat_> > > lfc;
1053
1060 std::vector<std::vector<std::vector<Stat_> > > delta_detected;
1061
1066 std::vector<std::vector<Stat_> > means;
1067
1072 std::vector<std::vector<Stat_> > detected;
1073 };
1074
1090 template<typename Stat_ = double, typename Value_, typename Index_, typename Group_>
1091 Results<Stat_> run(const tatami::Matrix<Value_, Index_>* p, const Group_* group) const {
1092 auto ngroups = count_ids(p->ncol(), group);
1093 Results<Stat_> res(p->nrow(), ngroups, do_cohen, do_auc, do_lfc, do_delta_detected);
1094 run(
1095 p,
1096 group,
1103 );
1104 return res;
1105 }
1106
1126 template<typename Stat_ = double, typename Value_, typename Index_, typename Group_, typename Block_>
1127 Results<Stat_> run_blocked(const tatami::Matrix<Value_, Index_>* p, const Group_* group, const Block_* block) const {
1128 auto ngroups = count_ids(p->ncol(), group);
1129 Results<Stat_> res(p->nrow(), ngroups, do_cohen, do_auc, do_lfc, do_delta_detected);
1131 p,
1132 group,
1133 block,
1140 );
1141 return res;
1142 }
1143};
1144
1145}
1146
1147#endif
Score each gene as a candidate marker for each group of cells.
Definition ScoreMarkers.hpp:231
ScoreMarkers & set_compute_delta_detected(bool c)
Definition ScoreMarkers.hpp:511
ScoreMarkers & set_compute_delta_detected(ComputeSummaries s=Defaults::compute_all_summaries())
Definition ScoreMarkers.hpp:495
ScoreMarkers & set_num_threads(int n=Defaults::num_threads)
Definition ScoreMarkers.hpp:320
Results< Stat_ > run(const tatami::Matrix< Value_, Index_ > *p, const Group_ *group) const
Definition ScoreMarkers.hpp:1091
ScoreMarkers & set_summary_min_rank(bool s)
Definition ScoreMarkers.hpp:615
ScoreMarkers & set_compute_delta_detected(differential_analysis::summary s, bool c)
Definition ScoreMarkers.hpp:525
ScoreMarkers & set_compute_lfc(bool c)
Definition ScoreMarkers.hpp:468
Results< Stat_ > run_blocked(const tatami::Matrix< Value_, Index_ > *p, const Group_ *group, const Block_ *block) const
Definition ScoreMarkers.hpp:1127
ScoreMarkers & set_cache_size(int c=Defaults::cache_size)
Definition ScoreMarkers.hpp:331
void run_blocked(const tatami::Matrix< Value_, Index_ > *p, const Group_ *group, const Block_ *block, std::vector< Stat_ * > means, std::vector< Stat_ * > detected, std::vector< std::vector< Stat_ * > > cohen, std::vector< std::vector< Stat_ * > > auc, std::vector< std::vector< Stat_ * > > lfc, std::vector< std::vector< Stat_ * > > delta_detected) const
Definition ScoreMarkers.hpp:702
ScoreMarkers & set_compute_auc(ComputeSummaries s=Defaults::compute_all_summaries())
Definition ScoreMarkers.hpp:409
std::array< bool, differential_analysis::n_summaries > ComputeSummaries
Definition ScoreMarkers.hpp:237
ScoreMarkers & set_compute_auc(differential_analysis::summary s, bool c)
Definition ScoreMarkers.hpp:439
ScoreMarkers & set_block_weight_policy(WeightPolicy w=Defaults::block_weight_policy)
Definition ScoreMarkers.hpp:341
ScoreMarkers & set_compute_lfc(differential_analysis::summary s, bool c)
Definition ScoreMarkers.hpp:482
ScoreMarkers & set_summary_min(bool s)
Definition ScoreMarkers.hpp:551
ScoreMarkers & set_threshold(double t=Defaults::threshold)
Definition ScoreMarkers.hpp:311
ScoreMarkers & set_compute_auc(bool c)
Definition ScoreMarkers.hpp:425
ScoreMarkers & set_compute_lfc(ComputeSummaries s=Defaults::compute_all_summaries())
Definition ScoreMarkers.hpp:452
ScoreMarkers & set_summary_max(bool s)
Definition ScoreMarkers.hpp:599
ScoreMarkers & set_summary_mean(bool s)
Definition ScoreMarkers.hpp:567
ScoreMarkers & set_variable_block_weight_parameters(VariableBlockWeightParameters v=Defaults::variable_block_weight_parameters)
Definition ScoreMarkers.hpp:352
void run(const tatami::Matrix< Value_, Index_ > *p, const Group_ *group, std::vector< Stat_ * > means, std::vector< Stat_ * > detected, std::vector< std::vector< Stat_ * > > cohen, std::vector< std::vector< Stat_ * > > auc, std::vector< std::vector< Stat_ * > > lfc, std::vector< std::vector< Stat_ * > > delta_detected) const
Definition ScoreMarkers.hpp:650
ScoreMarkers & set_compute_cohen(ComputeSummaries s=Defaults::compute_all_summaries())
Definition ScoreMarkers.hpp:366
ScoreMarkers & set_compute_cohen(bool c)
Definition ScoreMarkers.hpp:382
ScoreMarkers & set_summary_median(bool s)
Definition ScoreMarkers.hpp:583
ScoreMarkers & set_compute_cohen(differential_analysis::summary s, bool c)
Definition ScoreMarkers.hpp:396
summary
Definition summarize_comparisons.hpp:28
Functions for single-cell RNA-seq analyses.
Definition AggregateAcrossCells.hpp:18
size_t count_ids(size_t length, const Id_ *ids)
Definition blocking.hpp:29
void average_vectors_weighted(size_t n, std::vector< Stat_ * > in, const Weight_ *w, Output_ *out)
Definition average_vectors.hpp:158
std::vector< T * > vector_to_pointers(std::vector< std::vector< T > > &input)
Definition vector_to_pointers.hpp:26
WeightPolicy
Definition blocking.hpp:82
Default parameter settings.
Definition ScoreMarkers.hpp:242
static constexpr int cache_size
Definition ScoreMarkers.hpp:278
static constexpr VariableBlockWeightParameters variable_block_weight_parameters
Definition ScoreMarkers.hpp:288
static constexpr ComputeSummaries compute_all_summaries()
Definition ScoreMarkers.hpp:246
static constexpr ComputeSummaries compute_no_summaries()
Definition ScoreMarkers.hpp:257
static constexpr int num_threads
Definition ScoreMarkers.hpp:273
static constexpr WeightPolicy block_weight_policy
Definition ScoreMarkers.hpp:283
static constexpr double threshold
Definition ScoreMarkers.hpp:268
Results of the marker scoring.
Definition ScoreMarkers.hpp:966
std::vector< std::vector< std::vector< Stat_ > > > cohen
Definition ScoreMarkers.hpp:1036
std::vector< std::vector< std::vector< Stat_ > > > lfc
Definition ScoreMarkers.hpp:1052
std::vector< std::vector< std::vector< Stat_ > > > auc
Definition ScoreMarkers.hpp:1044
std::vector< std::vector< std::vector< Stat_ > > > delta_detected
Definition ScoreMarkers.hpp:1060
std::vector< std::vector< Stat_ > > means
Definition ScoreMarkers.hpp:1066
std::vector< std::vector< Stat_ > > detected
Definition ScoreMarkers.hpp:1072
Parameters for variable_block_weight().
Definition blocking.hpp:87
Utilities for effect summarization.