scran
C++ library for basic single-cell RNA-seq analyses
Loading...
Searching...
No Matches
PairwiseEffects.hpp
Go to the documentation of this file.
1#ifndef SCRAN_PAIRWISE_EFFECTS_HPP
2#define SCRAN_PAIRWISE_EFFECTS_HPP
3
4#include "../utils/macros.hpp"
5
6#include "MatrixCalculator.hpp"
7#include "cohens_d.hpp"
8#include "simple_diff.hpp"
9
10#include "../utils/vector_to_pointers.hpp"
11#include "../utils/blocking.hpp"
12#include "../utils/average_vectors.hpp"
13
14#include "tatami/tatami.hpp"
15
22namespace scran {
23
90public:
94 struct Defaults {
98 static constexpr double threshold = 0;
99
103 static constexpr int num_threads = 1;
104
108 static constexpr bool compute_cohen = true;
109
113 static constexpr bool compute_auc = true;
114
118 static constexpr bool compute_lfc = true;
119
123 static constexpr bool compute_delta_detected = true;
124
128 static constexpr WeightPolicy block_weight_policy = WeightPolicy::VARIABLE;
129
134 };
135
136private:
137 double threshold = Defaults::threshold;
138 int nthreads = Defaults::num_threads;
139 bool do_cohen = Defaults::compute_cohen;
140 bool do_auc = Defaults::compute_auc;
141 bool do_lfc = Defaults::compute_lfc;
142 bool do_delta_detected = Defaults::compute_delta_detected;
143
144 WeightPolicy block_weight_policy = Defaults::block_weight_policy;
146
147public:
155 threshold = t;
156 return *this;
157 }
158
164 nthreads = n;
165 return *this;
166 }
167
177 do_cohen = c;
178 return *this;
179 }
180
190 do_auc = c;
191 return *this;
192 }
193
203 do_lfc = c;
204 return *this;
205 }
206
216 do_delta_detected = c;
217 return *this;
218 }
219
226 block_weight_policy = w;
227 return *this;
228 }
229
240
241public:
270 template<typename Data_, typename Index_, typename Group_, typename Stat_>
271 void run(
272 const tatami::Matrix<Data_, Index_>* p,
273 const Group_* group,
274 std::vector<Stat_*> means,
275 std::vector<Stat_*> detected,
276 Stat_* cohen,
277 Stat_* auc,
278 Stat_* lfc,
279 Stat_* delta_detected)
280 const {
281 int ngroups = means.size();
282 differential_analysis::MatrixCalculator runner(nthreads, threshold, block_weight_policy, variable_block_weight_parameters);
283 Overlord overlord(auc);
284 auto state = runner.run(p, group, ngroups, overlord);
285 process_simple_effects(p->nrow(), ngroups, 1, state, means, detected, cohen, lfc, delta_detected);
286 }
287
320 template<typename Data_, typename Index_, typename Group_, typename Block_, typename Stat_>
322 const tatami::Matrix<Data_, Index_>* p,
323 const Group_* group,
324 const Block_* block,
325 std::vector<Stat_*> means,
326 std::vector<Stat_*> detected,
327 Stat_* cohen,
328 Stat_* auc,
329 Stat_* lfc,
330 Stat_* delta_detected)
331 const {
332 if (block == NULL) {
333 run(p, group, std::move(means), std::move(detected), cohen, auc, lfc, delta_detected);
334
335 } else {
336 auto ngenes = p->nrow();
337 int ngroups = means.size();
338 int nblocks = count_ids(p->ncol(), block);
339
340 int ncombos = ngroups * nblocks;
341 std::vector<std::vector<Stat_> > means_store(ncombos), detected_store(ncombos);
342 std::vector<Stat_*> means2(ncombos), detected2(ncombos);
343 for (int c = 0; c < ncombos; ++c) {
344 means_store[c].resize(ngenes);
345 detected_store[c].resize(ngenes);
346 means2[c] = means_store[c].data();
347 detected2[c] = detected_store[c].data();
348 }
349
350 differential_analysis::MatrixCalculator runner(nthreads, threshold, block_weight_policy, variable_block_weight_parameters);
351 Overlord overlord(auc);
352 auto state = runner.run_blocked(p, group, ngroups, block, nblocks, overlord);
353 process_simple_effects(p->nrow(), ngroups, nblocks, state, means2, detected2, cohen, lfc, delta_detected);
354
355 // Averaging the remaining statistics.
356 std::vector<double> weights(nblocks);
357 std::vector<Stat_*> mstats(nblocks), dstats(nblocks);
358
359 for (int gr = 0; gr < ngroups; ++gr) {
360 for (int b = 0; b < nblocks; ++b) {
361 size_t offset = gr * static_cast<size_t>(nblocks) + b;
362 weights[b] = state.level_weight[offset];
363 mstats[b] = means2[offset];
364 dstats[b] = detected2[offset];
365 }
366
367 average_vectors_weighted(ngenes, mstats, weights.data(), means[gr]);
368 average_vectors_weighted(ngenes, dstats, weights.data(), detected[gr]);
369 }
370 }
371 }
372
373private:
374 template<typename Stat_>
375 struct Overlord {
376 Overlord(Stat_* auc_) : auc(auc_) {}
377
378 bool needs_auc() const {
379 return auc != NULL;
380 }
381
382 Stat_* auc;
383
384 Stat_* prepare_auc_buffer(size_t gene, size_t ngroups) {
385 return auc + gene * ngroups * ngroups;
386 }
387 };
388
389 template<typename Stat_>
390 void process_simple_effects(
391 size_t ngenes, // using size_t consistently here, to avoid integer overflow bugs when computing products.
392 size_t ngroups,
393 size_t nblocks,
394 const differential_analysis::MatrixCalculator::State& state,
395 std::vector<Stat_*>& means,
396 std::vector<Stat_*>& detected,
397 Stat_* cohen,
398 Stat_* lfc,
399 Stat_* delta_detected)
400 const {
401 const auto& level_size = state.level_size;
402 size_t nlevels = level_size.size();
403
404 tatami::parallelize([&](size_t, size_t start, size_t length) -> void {
405 auto in_offset = nlevels * start;
406 const auto* tmp_means = state.means.data() + in_offset;
407 const auto* tmp_variances = state.variances.data() + in_offset;
408 const auto* tmp_detected = state.detected.data() + in_offset;
409
410 size_t squared = ngroups * ngroups;
411 size_t out_offset = start * squared;
412 for (size_t gene = start, end = start + length; gene < end; ++gene, out_offset += squared) {
413 for (size_t l = 0; l < nlevels; ++l) {
414 means[l][gene] = tmp_means[l];
415 detected[l][gene] = tmp_detected[l];
416 }
417
418 if (cohen != NULL) {
419 differential_analysis::compute_pairwise_cohens_d(tmp_means, tmp_variances, state.level_weight, ngroups, nblocks, threshold, cohen + out_offset);
420 }
421
422 if (delta_detected != NULL) {
423 differential_analysis::compute_pairwise_simple_diff(tmp_detected, state.level_weight, ngroups, nblocks, delta_detected + out_offset);
424 }
425
426 if (lfc != NULL) {
427 differential_analysis::compute_pairwise_simple_diff(tmp_means, state.level_weight, ngroups, nblocks, lfc + out_offset);
428 }
429
430 tmp_means += nlevels;
431 tmp_variances += nlevels;
432 tmp_detected += nlevels;
433 }
434 }, ngenes, nthreads);
435 }
436
437public:
449 template<typename Stat_>
450 struct Results {
454 Results(size_t ngenes, size_t ngroups, bool do_cohen, bool do_auc, bool do_lfc, bool do_delta) :
455 means(ngroups, std::vector<Stat_>(ngenes)),
456 detected(ngroups, std::vector<Stat_>(ngenes))
457 {
458 size_t nelements = ngenes * ngroups * ngroups;
459 if (do_cohen) {
460 cohen.resize(nelements);
461 }
462 if (do_auc) {
463 auc.resize(nelements);
464 }
465 if (do_lfc) {
466 lfc.resize(nelements);
467 }
468 if (do_delta) {
469 delta_detected.resize(nelements);
470 }
471 }
480 std::vector<Stat_> cohen;
481
486 std::vector<Stat_> auc;
487
492 std::vector<Stat_> lfc;
493
498 std::vector<Stat_> delta_detected;
499
505 std::vector<std::vector<Stat_> > means;
506
512 std::vector<std::vector<Stat_> > detected;
513 };
514
529 template<typename Stat_ = double, typename Data_ = double, typename Index_ = int, typename Group_ = int>
530 Results<Stat_> run(const tatami::Matrix<Data_, Index_>* p, const Group_* group) {
531 size_t ngroups = count_ids(p->ncol(), group);
532 Results<Stat_> res(p->nrow(), ngroups, do_cohen, do_auc, do_lfc, do_delta_detected);
533 run(
534 p,
535 group,
538 harvest_pointer(res.cohen, do_cohen),
539 harvest_pointer(res.auc, do_auc),
540 harvest_pointer(res.lfc, do_lfc),
541 harvest_pointer(res.delta_detected, do_delta_detected)
542 );
543 return res;
544 }
545
563 template<typename Stat_ = double, typename Data_ = double, typename Index_ = int, typename Group_ = int, typename Block_ = int>
564 Results<Stat_> run_blocked(const tatami::Matrix<Data_, Index_>* p, const Group_* group, const Block_* block) {
565 size_t ngroups = count_ids(p->ncol(), group);
566 Results<Stat_> res(p->nrow(), ngroups, do_cohen, do_auc, do_lfc, do_delta_detected);
568 p,
569 group,
570 block,
573 harvest_pointer(res.cohen, do_cohen),
574 harvest_pointer(res.auc, do_auc),
575 harvest_pointer(res.lfc, do_lfc),
576 harvest_pointer(res.delta_detected, do_delta_detected)
577 );
578 return res;
579 }
580
581private:
582 template<typename Ptr>
583 static std::vector<Ptr> fetch_first(const std::vector<std::vector<Ptr> >& input) {
584 std::vector<Ptr> output;
585 output.reserve(input.size());
586 for (const auto& i : input) {
587 output.push_back(i.front());
588 }
589 return output;
590 }
591
592 template<typename Stat>
593 static Stat* harvest_pointer(std::vector<Stat>& source, bool use) {
594 if (use) {
595 return source.data();
596 } else {
597 return static_cast<Stat*>(NULL);
598 }
599 }
600};
601
602}
603
604#endif
Compute pairwise effect size between groups of cells.
Definition PairwiseEffects.hpp:89
PairwiseEffects & set_compute_auc(bool c=Defaults::compute_auc)
Definition PairwiseEffects.hpp:189
PairwiseEffects & set_variable_block_weight_parameters(VariableBlockWeightParameters v=Defaults::variable_block_weight_parameters)
Definition PairwiseEffects.hpp:236
Results< Stat_ > run_blocked(const tatami::Matrix< Data_, Index_ > *p, const Group_ *group, const Block_ *block)
Definition PairwiseEffects.hpp:564
PairwiseEffects & set_threshold(double t=Defaults::threshold)
Definition PairwiseEffects.hpp:154
Results< Stat_ > run(const tatami::Matrix< Data_, Index_ > *p, const Group_ *group)
Definition PairwiseEffects.hpp:530
void run(const tatami::Matrix< Data_, Index_ > *p, const Group_ *group, std::vector< Stat_ * > means, std::vector< Stat_ * > detected, Stat_ *cohen, Stat_ *auc, Stat_ *lfc, Stat_ *delta_detected) const
Definition PairwiseEffects.hpp:271
PairwiseEffects & set_compute_lfc(bool c=Defaults::compute_lfc)
Definition PairwiseEffects.hpp:202
PairwiseEffects & set_compute_cohen(bool c=Defaults::compute_cohen)
Definition PairwiseEffects.hpp:176
PairwiseEffects & set_num_threads(int n=Defaults::num_threads)
Definition PairwiseEffects.hpp:163
PairwiseEffects & set_compute_delta_detected(bool c=Defaults::compute_delta_detected)
Definition PairwiseEffects.hpp:215
PairwiseEffects & set_block_weight_policy(WeightPolicy w=Defaults::block_weight_policy)
Definition PairwiseEffects.hpp:225
void run_blocked(const tatami::Matrix< Data_, Index_ > *p, const Group_ *group, const Block_ *block, std::vector< Stat_ * > means, std::vector< Stat_ * > detected, Stat_ *cohen, Stat_ *auc, Stat_ *lfc, Stat_ *delta_detected) const
Definition PairwiseEffects.hpp:321
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 PairwiseEffects.hpp:94
static constexpr int num_threads
Definition PairwiseEffects.hpp:103
static constexpr double threshold
Definition PairwiseEffects.hpp:98
static constexpr bool compute_cohen
Definition PairwiseEffects.hpp:108
static constexpr bool compute_auc
Definition PairwiseEffects.hpp:113
static constexpr WeightPolicy block_weight_policy
Definition PairwiseEffects.hpp:128
static constexpr VariableBlockWeightParameters variable_block_weight_parameters
Definition PairwiseEffects.hpp:133
static constexpr bool compute_lfc
Definition PairwiseEffects.hpp:118
static constexpr bool compute_delta_detected
Definition PairwiseEffects.hpp:123
Pairwise effect size results.
Definition PairwiseEffects.hpp:450
std::vector< Stat_ > auc
Definition PairwiseEffects.hpp:486
std::vector< Stat_ > delta_detected
Definition PairwiseEffects.hpp:498
std::vector< std::vector< Stat_ > > detected
Definition PairwiseEffects.hpp:512
std::vector< std::vector< Stat_ > > means
Definition PairwiseEffects.hpp:505
std::vector< Stat_ > cohen
Definition PairwiseEffects.hpp:480
std::vector< Stat_ > lfc
Definition PairwiseEffects.hpp:492
Parameters for variable_block_weight().
Definition blocking.hpp:87