rust-ndarray / ndarray-stats

Statistical routines for ndarray
https://docs.rs/ndarray-stats
Apache License 2.0
201 stars 25 forks source link

Bulk quantiles #26

Closed LukeMathWalker closed 5 years ago

LukeMathWalker commented 5 years ago

Using the ordering guarantees we have on the output of quantile_mut/sorted_get_mut, it provides a method optimized to compute multiple quantiles at once (by scanning an increasingly smaller subset of the original array, thanks to the computation of the previous quantile).

Breaking changes:

jturner314 commented 5 years ago

I started reviewing this PR. This is great work. I created LukeMathWalker/ndarray-stats#1 with a few changes.

I had a couple of thoughts:

Edit: It would be good to rebase this branch off the latest master to resolve merge conflicts and incorporate #28.

LukeMathWalker commented 5 years ago

I have merged your PR - all useful additions/style changes!

I can't confirm the average complexity you estimated for your alternative implementation, but it intuitively looks faster and log(q) < n is true for all relevant cases I'd say. I'll give it a go in a separate branch and then we can run some benchmarks :+1:

Re:IndexMap - I think it's a matter of preference, I usually find it error-prone to match input/output indexes, the way NumPy forces you to work sometimes, an IndexMap looks more ergonomic to me . The solid pro I can see in returning an Option<Array<A, D>> is that you can do cross-quantile computation more easily, that is significant.

LukeMathWalker commented 5 years ago

@jturner314 I have implemented the algorithm you have described - it's definitely more efficient than the one I came up with before. Please give it a look and let me know what you think.

jturner314 commented 5 years ago

I haven't finished reviewing this PR, but I've created LukeMathWalker/ndarray-stats#5 with some changes. I've added a couple of benchmarks and worked on improving performance of get_many_from_sorted_mut_unchecked (plus a few additional things). Eliminating allocations from _get_many_from_sorted_mut_unchecked improved performance on small arrays by 30-45%. (For larger arrays, the difference is less noticeable.)

jturner314 commented 5 years ago

I finished reviewing this PR and added some more changes to LukeMathWalker/ndarray-stats#5. The primary additional changes are:

  1. The bulk quantiles methods now return an Array instead of an IndexMap. Option<Array<A, D>> is easier to work with than Option<IndexMap<N64, Array<A, D::Smaller>>>. It also needs only one heap allocation and should have better performance for most operations.

  2. I've added the interpolation strategy as an explicit parameter to the quantile methods. See the commit message for a list of the advantages.

  3. I've changed get_many_from_sorted_mut and the bulk quantiles methods to take the indices as an array instead of a slice. This is a little more versatile because arrays can have arbitrary strides. It also seems more consistent with the rest of the API.

With change (1), we can now change qs back to f64 instead of N64 if desired. I think this would probably be a good idea just because most things work with f64 instead of N64.

What do you think?

LukeMathWalker commented 5 years ago

I think it makes sense to take interpolate as a parameter - in a recent conversation with @xd009642 it turned out that it would be nice to expose EquiSpaced as a strategy, but given that it requires some array-independent parameters (e.g. number of bins), it was troublesome to get it to work with the existing arrangement. Nothing to say on the other two changes.

I'd keep N64 - I think that we should leverage the expressiveness of the type system to communicate constraints, if it doesn't add complexity or hinders readability of our API/the code using it.

LukeMathWalker commented 5 years ago

I have merged master and aligned return types (Result instead of Option).

LukeMathWalker commented 5 years ago

I have used InvalidQuantile in the end - let me know what you think @jturner314.

jturner314 commented 5 years ago

Yay! :tada: Great job on these PRs @LukeMathWalker!

LukeMathWalker commented 5 years ago

Thanks for your help @jturner314 - you always manage to make them much better :pray: