
Overview
Pretty much as it says in the title. This library implements some utilities to compute simple statistics like quantiles and variances. Nothing too exotic or difficult, just annoying to re-implement for each application. Most of this code was migrated from tatami_stats or libscran for more general use.
Check out the reference documentation for more details.
Medians
Pretty much as it says - works for dense and sparse vectors:
std::vector<double> x{ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. };
std::vector<double> x_nonzero{ 1., 2., 3. };
Output_ median(const std::size_t num_total, Input_ *const ptr, const MedianOptions< Output_ > &options)
Definition median.hpp:47
Note that this will shuffle the input array.
Single quantiles
The SingleQuantileFixedNumber class will compute a pre-specified quantile from a fixed number of elements:
std::vector<double> x{ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. };
auto fq20 = qfixed(x.data());
std::vector<double> x_nonzero{ 1., 2., 3. };
auto fq20_sparse = qfixed(x_nonzero.size(), x_nonzero.data());
Calculate a single quantile from a fixed number of elements.
Definition SingleQuantile.hpp:69
The SingleQuantileVariableNumber class will compute a pre-specified quantile from a variable number of elements, up to a maximum:
std::vector<double> y{ 1., 2., 3., 4., 5., 6. };
auto vq20 = qvar(y.size(), y.data());
std::vector<double> y_nonzero{ 1., 2., 3. };
auto vq20_sparse = qvar(6, y_nonzero.size(), y_nonzero.data());
Calculate a quantile from a variable number of elements.
Definition SingleQuantile.hpp:228
Multiple quantiles
To compute multiple quantiles at once, we can construct a MultipleQuantilesFixedNumber instance. This is more efficient than creating and invoking multiple SingleQuantileFixedNumber instances.
std::vector<double> quantiles{ 0.1, 0.2, 0.4, 0.8 };
std::vector<double> x{ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. };
std::vector<double> res(quantiles.size());
qfixed(
x.data(),
[&](std::size_t q, double val) -> void {
res[q] = val;
}
);
std::vector<double> x_nonzero{ 1., 2., 3. };
qfixed(
x_nonzero.size(),
x_nonzero.data(),
[&](int q, double val) -> void {
res[q] = val;
}
);
Calculate multiple quantiles from a fixed number of elements.
Definition MultipleQuantiles.hpp:33
Similarly, the MultipleQuantilesVariableNumber class computes multiple quantiles from a variable number of elements, up to a maximum:
std::vector<double> y{ 1., 2., 3., 4., 5., 6. };
qvar(
y.size(),
y.data(),
[&](int q, double val) -> void {
res[q] = val;
}
);
std::vector<double> y_nonzero{ 1., 2., 3. };
qvar(
6,
y_nonzero.size(),
y_nonzero.data(),
[&](int q, double val) -> void {
res[q] = val;
}
);
Calculate multiple quantiles from a variable number of elements.
Definition MultipleQuantiles.hpp:382
Pairwise summation
We can perform pairwise summation to, well, compute the sum of an array. This mitigates loss of precision due to floating-point round-off error compared to naive std::accumulate().
std::vector<double> x{ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. };
Output_ pairwise_sum(const std::size_t num_total, const Input_ *const ptr, PairwiseSumWorkspace< Output_ > &work, const PairwiseSumOptions &options)
Definition pairwise_sum.hpp:215
Re-usable workspace for pairwise_sum() and pairwise_sum_abstract().
Definition pairwise_sum.hpp:24
We can also customize the source of the input data to perform accumulations over an abstract array:
auto mean = sum / x.size();
x.size(),
[&](const std::size_t idx) -> auto {
const double delta = x[idx] - mean;
return delta * delta;
}
work,
{}
);
Output_ pairwise_sum_abstract(const std::size_t num_total, Input_ input, PairwiseSumWorkspace< Output_ > &work, const PairwiseSumOptions &options)
Definition pairwise_sum.hpp:102
Residual sum of squares
The rss() function will compute both the mean and the residual sum of squares (RSS) of an array:
std::vector<double> x{ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. };
rssout.mean;
rssout.rss;
std::vector<double> y{ 1., 2., 3. };
sprssout.mean;
sprssout.rss;
RssResult< Output_ > rss(const std::size_t num_total, const std::size_t num_non_zero, const Input_ *const ptr, RssWorkspace< Output_ > &work, const RssOptions< Output_ > &options)
Definition rss.hpp:98
In some situations, we might want to update the RSS as new values become available. This can be done using the update_rss() function:
double curmean = 0, currss = 0;
for (std::size_t i = 0; i < 5; ++i) {
}
for (std::size_t i = 5; i < 10; ++i) {
}
void update_rss_with_zeros(Output_ &mean, Output_ &rss, const Count_ num_zeros, const Count_ num_total)
Definition rss.hpp:263
void update_rss(Output_ &mean, Output_ &rss, const Input_ value, const Count_ num_total)
Definition rss.hpp:210
We can trivially convert each RSS into a variance estimate by dividing each variance with the number of observations (minus 1, for the sample variance). Note, some extra care may be required to handle zero denominators at low numbers of observations.
We can also use recenter_rss() to adjust the RSS for a different value of the mean. This is typically used to combine RSS values from multiple subarrays into a single RSS value for the entire array.
Median absolute deviation
Given the median, the mad() function will compute the median absolute deviation. Note that this will replace the input array with the absolute deviations.
std::vector<double> x{ 1., 2., 3., 4., 5., 6., 7., 8., 9., 10. };
Output_ mad(const std::size_t num_total, Input_ *const ptr, const Input_ median, const MadOptions< Output_ > &options)
Definition mad.hpp:61
For infinite medians, we can optionally define the difference between infinities of the same sign as zero. This is occasionally helpful for providing a sane result when infinities are generated by mathematical transformations, e.g., log(0).
constexpr auto inf = std::numeric_limits<double>::infinity();
std::vector<double> x{ inf, 0, inf, inf, 0, inf, 0, 2, inf, inf };
Options for mad() and mad_with_infinities().
Definition mad.hpp:22
bool difference_between_infinities_is_zero
Definition mad.hpp:34
As usual, the same functions are also available for sparse vectors.
Building projects
CMake with FetchContent
If you're using CMake, you just need to add something like this to your CMakeLists.txt:
include(FetchContent)
FetchContent_Declare(
quickstats
GIT_REPOSITORY https://github.com/LTLA/quickstats
GIT_TAG master # replace with a pinned version
)
FetchContent_MakeAvailable(quickstats)
Then you can link to quickstats to make the headers available during compilation:
# For executables:
target_link_libraries(myexe quickstats)
# For libaries
target_link_libraries(mylib INTERFACE quickstats)
CMake with find_package()
You can install the library by cloning a suitable version of this repository and running the following commands:
mkdir build && cd build
cmake .. -DQUICKSTATS_TESTS=OFF
cmake --build . --target install
Then you can use find_package() as usual:
find_package(ltla_quickstats CONFIG REQUIRED)
target_link_libraries(mylib INTERFACE ltla::quickstats)
Manual
If you're not using CMake, the simple approach is to just copy the files in the include/ subdirectory - either directly or with Git submodules - and include their path during compilation with, e.g., GCC's -I.