-
Notifications
You must be signed in to change notification settings - Fork 28
Bulk quantiles #26
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
LukeMathWalker
merged 84 commits into
rust-ndarray:master
from
LukeMathWalker:bulk-quantiles
Apr 6, 2019
Merged
Bulk quantiles #26
Changes from 76 commits
Commits
Show all changes
84 commits
Select commit
Hold shift + click to select a range
06b82be
Promoted module to directory
LukeMathWalker 47c1696
Moved interpolate to separate file
LukeMathWalker 8f1e7cd
Re-implemented quantile_axis_mut to get closer to something we can us…
LukeMathWalker c81f6be
Use a set instead of a vec to avoid repeating computations
LukeMathWalker 7aee452
Use bulk method for single quantile
LukeMathWalker 745e45b
Implement bulk method to get sorted
LukeMathWalker 74eda81
Refactored quantiles_axis_mut to use sorted_get_many_mut
LukeMathWalker 93531de
Avoid recomputing index value
LukeMathWalker c00620d
Add quantiles_mut to 1d trait
LukeMathWalker a7111e9
Return hashmaps from bulk methods
LukeMathWalker 36284d2
Fixed tests
LukeMathWalker fc56ca4
Use IndexSet to preserve insertion order
LukeMathWalker 67a4477
Fix indentation
LukeMathWalker ac0ca03
IndexMap provides a more intuitive behaviour
LukeMathWalker a4c1508
Remove prints
LukeMathWalker aa3a157
Renamed methods
LukeMathWalker 2ea9233
Docs for get_many_from_sorted_mut
LukeMathWalker 12a7944
Added docs for private free function
LukeMathWalker ac93a1e
Docs for quantiles_mut
LukeMathWalker c408c67
Fixed several typos in docs
LukeMathWalker c471955
More robust test
LukeMathWalker 1411f15
Added test for quantiles
LukeMathWalker 48f2bf0
Test quantiles_axis_mut
LukeMathWalker c27feb1
Add comments
LukeMathWalker 00e14f7
Return options when the lane we are computing against is empty
LukeMathWalker 846c336
Fixed docs
LukeMathWalker ab8d701
Fixed tests
LukeMathWalker 8b38345
Move *index* functions out of Interpolate trait
jturner314 5771514
Reduce indentation in quantiles_axis_mut
jturner314 e0eb686
Reduce indentation in quantile_axis_skipnan_mut
jturner314 6c51145
Use .into_scalar() method
jturner314 30c3466
Improve docs of partition_mut
jturner314 dca9c7b
Reformat quantiles_axis_mut
jturner314 92f08a4
Cargo fmt
LukeMathWalker 35d2094
Fmt
LukeMathWalker 1021507
Formatting
LukeMathWalker c2ed805
Log version works
LukeMathWalker 9dc5eef
Refactor
LukeMathWalker c49ad04
Fix indexes
LukeMathWalker cf7b362
Working implementation
LukeMathWalker cb1d9f8
Shorter syntax
LukeMathWalker 75d7d55
Formatting
LukeMathWalker ca951cf
Better docs
LukeMathWalker 45e84cd
Comments
LukeMathWalker 46a6834
Typo
LukeMathWalker 01e794c
Don't lose pieces after rebase
LukeMathWalker 0c70bbb
Fmt
LukeMathWalker 1ba922a
Reduce code duplication
LukeMathWalker d5ab45c
Fmt
LukeMathWalker 1d8c671
Merge branch 'master' into bulk-quantiles
LukeMathWalker 7b4e0de
Clarify docs of get_many_from_sorted_mut_unchecked
jturner314 64ed72b
Add get_many_from_sorted_mut benchmark
jturner314 2c90309
Add get_from_sorted_mut benchmark
jturner314 3a4ea2e
Simplify get_many_from_sorted_mut_unchecked
jturner314 e5c9474
Eliminate allocations from _get_many_from_sorted_mut_unchecked
jturner314 24ee710
Call slice_axis_mut instead of slice_mut
jturner314 8739c3b
Replace iter::repeat with vec!
jturner314 88d896f
Fix typo in comment
jturner314 29d507b
Remove unnecessary type annotation
jturner314 d0879c8
Simplify quantiles tests
jturner314 54c11be
Check keys in test_sorted_get_many_mut
jturner314 847fcd5
Simplify sort tests
jturner314 c6f762a
Improve sort and quantiles docs
jturner314 1685095
Make Interpolate::interpolate operate elementwise
jturner314 e965e85
Make quantiles_* return Array instead of IndexMap
jturner314 cfc408f
Add interpolate parameter to quantile*
jturner314 b5d8a08
Make get_many_from_sorted_mut take array of indexes
jturner314 00a21c0
Make quantiles* take array instead of slice
jturner314 8f9f0b6
Remove unnecessary IndexSet
jturner314 a4e8c5d
Merge pull request #5 from jturner314/bulk-quantiles
LukeMathWalker beec7ae
Merge master
LukeMathWalker 5ff4430
Return EmptyInput instead of None
LukeMathWalker ca9f3db
Fix tests
LukeMathWalker 7ca6b7f
Match output type for argmin/max_skipnan
LukeMathWalker 22cbfbb
Fix tests
LukeMathWalker 56906cf
Fmt
LukeMathWalker 950cd44
Update src/lib.rs
jturner314 37b3b19
Add quantile error
LukeMathWalker 1f37d44
Renamed InvalidFraction to InvalidQuantile
LukeMathWalker 1e9ba18
Return QuantileError
LukeMathWalker caad47d
Fix tests
LukeMathWalker fab842c
Fix docs
LukeMathWalker a32d9a8
Fmt
LukeMathWalker a315f70
Simplify and deduplicate
LukeMathWalker File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
extern crate criterion; | ||
extern crate ndarray; | ||
extern crate ndarray_stats; | ||
extern crate rand; | ||
|
||
use criterion::{ | ||
black_box, criterion_group, criterion_main, AxisScale, BatchSize, Criterion, | ||
ParameterizedBenchmark, PlotConfiguration, | ||
}; | ||
use ndarray::prelude::*; | ||
use ndarray_stats::Sort1dExt; | ||
use rand::prelude::*; | ||
|
||
fn get_from_sorted_mut(c: &mut Criterion) { | ||
let lens = vec![10, 100, 1000, 10000]; | ||
let benchmark = ParameterizedBenchmark::new( | ||
"get_from_sorted_mut", | ||
|bencher, &len| { | ||
let mut rng = StdRng::seed_from_u64(42); | ||
let mut data: Vec<_> = (0..len).collect(); | ||
data.shuffle(&mut rng); | ||
let indices: Vec<_> = (0..len).step_by(len / 10).collect(); | ||
bencher.iter_batched( | ||
|| Array1::from(data.clone()), | ||
|mut arr| { | ||
for &i in &indices { | ||
black_box(arr.get_from_sorted_mut(i)); | ||
} | ||
}, | ||
BatchSize::SmallInput, | ||
) | ||
}, | ||
lens, | ||
) | ||
.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic)); | ||
c.bench("get_from_sorted_mut", benchmark); | ||
} | ||
|
||
fn get_many_from_sorted_mut(c: &mut Criterion) { | ||
let lens = vec![10, 100, 1000, 10000]; | ||
let benchmark = ParameterizedBenchmark::new( | ||
"get_many_from_sorted_mut", | ||
|bencher, &len| { | ||
let mut rng = StdRng::seed_from_u64(42); | ||
let mut data: Vec<_> = (0..len).collect(); | ||
data.shuffle(&mut rng); | ||
let indices: Vec<_> = (0..len).step_by(len / 10).collect(); | ||
bencher.iter_batched( | ||
|| Array1::from(data.clone()), | ||
|mut arr| { | ||
black_box(arr.get_many_from_sorted_mut(&indices)); | ||
}, | ||
BatchSize::SmallInput, | ||
) | ||
}, | ||
lens, | ||
) | ||
.plot_config(PlotConfiguration::default().summary_scale(AxisScale::Logarithmic)); | ||
c.bench("get_many_from_sorted_mut", benchmark); | ||
} | ||
|
||
criterion_group! { | ||
name = benches; | ||
config = Criterion::default(); | ||
targets = get_from_sorted_mut, get_many_from_sorted_mut | ||
} | ||
criterion_main!(benches); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
//! Interpolation strategies. | ||
use noisy_float::types::N64; | ||
use num_traits::{Float, FromPrimitive, NumOps, ToPrimitive}; | ||
|
||
fn float_quantile_index(q: N64, len: usize) -> N64 { | ||
q * ((len - 1) as f64) | ||
} | ||
|
||
/// Returns the fraction that the quantile is between the lower and higher indices. | ||
/// | ||
/// This ranges from 0, where the quantile exactly corresponds the lower index, | ||
/// to 1, where the quantile exactly corresponds to the higher index. | ||
fn float_quantile_index_fraction(q: N64, len: usize) -> N64 { | ||
float_quantile_index(q, len).fract() | ||
} | ||
|
||
/// Returns the index of the value on the lower side of the quantile. | ||
pub(crate) fn lower_index(q: N64, len: usize) -> usize { | ||
float_quantile_index(q, len).floor().to_usize().unwrap() | ||
} | ||
|
||
/// Returns the index of the value on the higher side of the quantile. | ||
pub(crate) fn higher_index(q: N64, len: usize) -> usize { | ||
float_quantile_index(q, len).ceil().to_usize().unwrap() | ||
} | ||
|
||
/// Used to provide an interpolation strategy to [`quantile_axis_mut`]. | ||
/// | ||
/// [`quantile_axis_mut`]: ../trait.QuantileExt.html#tymethod.quantile_axis_mut | ||
pub trait Interpolate<T> { | ||
/// Returns `true` iff the lower value is needed to compute the | ||
/// interpolated value. | ||
#[doc(hidden)] | ||
fn needs_lower(q: N64, len: usize) -> bool; | ||
|
||
/// Returns `true` iff the higher value is needed to compute the | ||
/// interpolated value. | ||
#[doc(hidden)] | ||
fn needs_higher(q: N64, len: usize) -> bool; | ||
|
||
/// Computes the interpolated value. | ||
/// | ||
/// **Panics** if `None` is provided for the lower value when it's needed | ||
/// or if `None` is provided for the higher value when it's needed. | ||
#[doc(hidden)] | ||
fn interpolate(lower: Option<T>, higher: Option<T>, q: N64, len: usize) -> T; | ||
} | ||
|
||
/// Select the higher value. | ||
pub struct Higher; | ||
/// Select the lower value. | ||
pub struct Lower; | ||
/// Select the nearest value. | ||
pub struct Nearest; | ||
/// Select the midpoint of the two values (`(lower + higher) / 2`). | ||
pub struct Midpoint; | ||
/// Linearly interpolate between the two values | ||
/// (`lower + (higher - lower) * fraction`, where `fraction` is the | ||
/// fractional part of the index surrounded by `lower` and `higher`). | ||
pub struct Linear; | ||
|
||
impl<T> Interpolate<T> for Higher { | ||
fn needs_lower(_q: N64, _len: usize) -> bool { | ||
false | ||
} | ||
fn needs_higher(_q: N64, _len: usize) -> bool { | ||
true | ||
} | ||
fn interpolate(_lower: Option<T>, higher: Option<T>, _q: N64, _len: usize) -> T { | ||
higher.unwrap() | ||
} | ||
} | ||
|
||
impl<T> Interpolate<T> for Lower { | ||
fn needs_lower(_q: N64, _len: usize) -> bool { | ||
true | ||
} | ||
fn needs_higher(_q: N64, _len: usize) -> bool { | ||
false | ||
} | ||
fn interpolate(lower: Option<T>, _higher: Option<T>, _q: N64, _len: usize) -> T { | ||
lower.unwrap() | ||
} | ||
} | ||
|
||
impl<T> Interpolate<T> for Nearest { | ||
fn needs_lower(q: N64, len: usize) -> bool { | ||
float_quantile_index_fraction(q, len) < 0.5 | ||
} | ||
fn needs_higher(q: N64, len: usize) -> bool { | ||
!<Self as Interpolate<T>>::needs_lower(q, len) | ||
} | ||
fn interpolate(lower: Option<T>, higher: Option<T>, q: N64, len: usize) -> T { | ||
if <Self as Interpolate<T>>::needs_lower(q, len) { | ||
lower.unwrap() | ||
} else { | ||
higher.unwrap() | ||
} | ||
} | ||
} | ||
|
||
impl<T> Interpolate<T> for Midpoint | ||
where | ||
T: NumOps + Clone + FromPrimitive, | ||
{ | ||
fn needs_lower(_q: N64, _len: usize) -> bool { | ||
true | ||
} | ||
fn needs_higher(_q: N64, _len: usize) -> bool { | ||
true | ||
} | ||
fn interpolate(lower: Option<T>, higher: Option<T>, _q: N64, _len: usize) -> T { | ||
let denom = T::from_u8(2).unwrap(); | ||
let lower = lower.unwrap(); | ||
let higher = higher.unwrap(); | ||
lower.clone() + (higher.clone() - lower.clone()) / denom.clone() | ||
} | ||
} | ||
|
||
impl<T> Interpolate<T> for Linear | ||
where | ||
T: NumOps + Clone + FromPrimitive + ToPrimitive, | ||
{ | ||
fn needs_lower(_q: N64, _len: usize) -> bool { | ||
true | ||
} | ||
fn needs_higher(_q: N64, _len: usize) -> bool { | ||
true | ||
} | ||
fn interpolate(lower: Option<T>, higher: Option<T>, q: N64, len: usize) -> T { | ||
let fraction = float_quantile_index_fraction(q, len).to_f64().unwrap(); | ||
let lower = lower.unwrap(); | ||
let higher = higher.unwrap(); | ||
let lower_f64 = lower.to_f64().unwrap(); | ||
let higher_f64 = higher.to_f64().unwrap(); | ||
lower.clone() + T::from_f64(fraction * (higher_f64 - lower_f64)).unwrap() | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.