69
69
# --- HYNDMAN and FAN METHODS
70
70
# Discrete methods
71
71
inverted_cdf = dict (
72
- get_virtual_index = lambda n , quantiles : _inverted_cdf (n , quantiles ),
73
- fix_gamma = lambda gamma , _ : gamma , # should never be called
72
+ get_virtual_index = lambda n , quantiles : (n * quantiles ) - 1 ,
73
+ fix_gamma = lambda g , _ : _get_gamma_mask (
74
+ shape = g .shape ,
75
+ default_value = 1. ,
76
+ conditioned_value = 0.0 ,
77
+ where = g == 0 ),
78
+ discrete_shortcut = lambda n , quantiles : _inverted_cdf (n , quantiles ),
74
79
),
75
80
averaged_inverted_cdf = dict (
76
81
get_virtual_index = lambda n , quantiles : (n * quantiles ) - 1 ,
77
- fix_gamma = lambda gamma , _ : _get_gamma_mask (
78
- shape = gamma .shape ,
82
+ fix_gamma = lambda g , _ : _get_gamma_mask (
83
+ shape = g .shape ,
79
84
default_value = 1. ,
80
85
conditioned_value = 0.5 ,
81
- where = gamma == 0 ),
86
+ where = g == 0 ),
87
+ discrete_shortcut = None ,
82
88
),
83
89
closest_observation = dict (
84
- get_virtual_index = lambda n , quantiles : _closest_observation (n ,
85
- quantiles ),
86
- fix_gamma = lambda gamma , _ : gamma , # should never be called
90
+ get_virtual_index = lambda n , quantiles : (n * quantiles ) - 1 - 0.5 ,
91
+ fix_gamma = lambda g , index : _get_gamma_mask (
92
+ shape = g .shape ,
93
+ default_value = 1. ,
94
+ conditioned_value = 0.0 ,
95
+ where = (g == 0 ) & (np .floor (index ) % 2 == 0 )),
96
+ discrete_shortcut = (lambda n , quantiles :
97
+ _closest_observation (n , quantiles )),
87
98
),
88
99
# Continuous methods
89
100
interpolated_inverted_cdf = dict (
90
101
get_virtual_index = lambda n , quantiles :
91
102
_compute_virtual_index (n , quantiles , 0 , 1 ),
92
- fix_gamma = lambda gamma , _ : gamma ,
103
+ fix_gamma = lambda g , _ : g ,
104
+ discrete_shortcut = None ,
93
105
),
94
106
hazen = dict (
95
107
get_virtual_index = lambda n , quantiles :
96
108
_compute_virtual_index (n , quantiles , 0.5 , 0.5 ),
97
- fix_gamma = lambda gamma , _ : gamma ,
109
+ fix_gamma = lambda g , _ : g ,
110
+ discrete_shortcut = None ,
98
111
),
99
112
weibull = dict (
100
113
get_virtual_index = lambda n , quantiles :
101
114
_compute_virtual_index (n , quantiles , 0 , 0 ),
102
- fix_gamma = lambda gamma , _ : gamma ,
115
+ fix_gamma = lambda g , _ : g ,
116
+ discrete_shortcut = None ,
103
117
),
104
118
# Default method.
105
119
# To avoid some rounding issues, `(n-1) * quantiles` is preferred to
106
120
# `_compute_virtual_index(n, quantiles, 1, 1)`.
107
121
# They are mathematically equivalent.
108
122
linear = dict (
109
123
get_virtual_index = lambda n , quantiles : (n - 1 ) * quantiles ,
110
- fix_gamma = lambda gamma , _ : gamma ,
124
+ fix_gamma = lambda g , _ : g ,
125
+ discrete_shortcut = None ,
111
126
),
112
127
median_unbiased = dict (
113
128
get_virtual_index = lambda n , quantiles :
114
129
_compute_virtual_index (n , quantiles , 1 / 3.0 , 1 / 3.0 ),
115
- fix_gamma = lambda gamma , _ : gamma ,
130
+ fix_gamma = lambda g , _ : g ,
131
+ discrete_shortcut = None ,
116
132
),
117
133
normal_unbiased = dict (
118
134
get_virtual_index = lambda n , quantiles :
119
135
_compute_virtual_index (n , quantiles , 3 / 8.0 , 3 / 8.0 ),
120
- fix_gamma = lambda gamma , _ : gamma ,
136
+ fix_gamma = lambda g , _ : g ,
137
+ discrete_shortcut = None ,
121
138
),
122
139
# --- OTHER METHODS
123
140
lower = dict (
124
- get_virtual_index = lambda n , quantiles : np .floor (
141
+ get_virtual_index = lambda n , quantiles : (n - 1 ) * quantiles ,
142
+ fix_gamma = lambda g , _ : np .floor (g ),
143
+ discrete_shortcut = lambda n , quantiles : np .floor (
125
144
(n - 1 ) * quantiles ).astype (np .intp ),
126
- fix_gamma = lambda gamma , _ : gamma ,
127
- # should never be called, index dtype is int
128
145
),
129
146
higher = dict (
130
- get_virtual_index = lambda n , quantiles : np .ceil (
147
+ get_virtual_index = lambda n , quantiles : (n - 1 ) * quantiles ,
148
+ fix_gamma = lambda g , _ : np .ceil (g ),
149
+ discrete_shortcut = lambda n , quantiles : np .ceil (
131
150
(n - 1 ) * quantiles ).astype (np .intp ),
132
- fix_gamma = lambda gamma , _ : gamma ,
133
- # should never be called, index dtype is int
134
151
),
135
152
midpoint = dict (
136
153
get_virtual_index = lambda n , quantiles : 0.5 * (
137
154
np .floor ((n - 1 ) * quantiles )
138
155
+ np .ceil ((n - 1 ) * quantiles )),
139
- fix_gamma = lambda gamma , index : _get_gamma_mask (
140
- shape = gamma .shape ,
156
+ fix_gamma = lambda g , index : _get_gamma_mask (
157
+ shape = g .shape ,
141
158
default_value = 0.5 ,
142
159
conditioned_value = 0. ,
143
- where = index % 1 == 0 ),
160
+ where = (index % 1 == 0 ) & (g == 0 )),
161
+ discrete_shortcut = None ,
144
162
),
145
163
nearest = dict (
146
- get_virtual_index = lambda n , quantiles : np .around (
164
+ get_virtual_index = lambda n , quantiles : (n - 1 ) * quantiles ,
165
+ # fix_gamma here meant to match behavior of discrete_shortcut because
166
+ # np.around rounds to the nearest even integer.
167
+ fix_gamma = lambda g , index : _get_gamma_mask (
168
+ shape = g .shape ,
169
+ default_value = np .around (g ),
170
+ conditioned_value = np .around (index ) - np .around (index - g ),
171
+ where = g == 0.5 ),
172
+ discrete_shortcut = lambda n , quantiles : np .around (
147
173
(n - 1 ) * quantiles ).astype (np .intp ),
148
- fix_gamma = lambda gamma , _ : gamma ,
149
- # should never be called, index dtype is int
150
174
))
151
175
152
176
@@ -4765,7 +4789,7 @@ def _compute_virtual_index(n, quantiles, alpha: float, beta: float):
4765
4789
4766
4790
def _get_gamma (virtual_indexes , previous_indexes , method ):
4767
4791
"""
4768
- Compute gamma (a.k.a 'm' or 'weight' ) for the linear interpolation
4792
+ Compute gamma (a.k.a 'm') for the linear interpolation
4769
4793
of quantiles.
4770
4794
4771
4795
virtual_indexes : array_like
@@ -4780,8 +4804,10 @@ def _get_gamma(virtual_indexes, previous_indexes, method):
4780
4804
gamma is usually the fractional part of virtual_indexes but can be modified
4781
4805
by the interpolation method.
4782
4806
"""
4783
- gamma = np .asanyarray (virtual_indexes - previous_indexes )
4784
- gamma = method ["fix_gamma" ](gamma , virtual_indexes )
4807
+ # % 1 because index diff can be > 1 in weight space calculation
4808
+ # when virtual index lies within a value of large weight.
4809
+ g = np .asanyarray (virtual_indexes - previous_indexes ) % 1
4810
+ gamma = method ["fix_gamma" ](g , virtual_indexes )
4785
4811
return np .asanyarray (gamma )
4786
4812
4787
4813
@@ -4899,12 +4925,6 @@ def _get_indexes(arr, virtual_indexes, valid_values_count):
4899
4925
if indexes_below_bounds .any ():
4900
4926
previous_indexes [indexes_below_bounds ] = 0
4901
4927
next_indexes [indexes_below_bounds ] = 0
4902
- if np .issubdtype (arr .dtype , np .inexact ):
4903
- # After the sort, slices having NaNs will have for last element a NaN
4904
- virtual_indexes_nans =
10000
span> np .isnan (virtual_indexes ) # indexes have nans?
4905
- if virtual_indexes_nans .any ():
4906
- previous_indexes [virtual_indexes_nans ] = - 1
4907
- next_indexes [virtual_indexes_nans ] = - 1
4908
4928
previous_indexes = previous_indexes .astype (np .intp )
4909
4929
next_indexes = next_indexes .astype (np .intp )
4910
4930
return previous_indexes , next_indexes
@@ -5037,13 +5057,11 @@ def _get_weighted_quantile_values(arr1d, wgts1d):
5037
5057
np .interp (previous_w_indexes , w_index_bounds , real_indexes )
5038
5058
next_indexes = \
5039
5059
np .interp (next_w_indexes , w_index_bounds , real_indexes )
5040
- indexes = \
5041
- np .interp (weight_space_indexes , w_index_bounds , real_indexes )
5042
5060
5043
5061
# method-dependent gammas determine interpolation scheme between
5044
5062
# neighboring values, and are computed in weight space.
5045
- gamma = _get_gamma ( indexes , previous_indexes , method )
5046
-
5063
+ gamma = \
5064
+ _get_gamma ( weight_space_indexes , previous_w_indexes , method )
5047
5065
previous = take (arr1d , previous_indexes .astype (int ))
5048
5066
next = take (arr1d , next_indexes .astype (int ))
5049
5067
return _lerp (previous , next , gamma , out = out )
@@ -5064,7 +5082,14 @@ def _get_weighted_quantile_values(arr1d, wgts1d):
5064
5082
if axis != 0 : # moveaxis is slow, so only call it if necessary.
5065
5083
arr = np .moveaxis (arr , axis , destination = 0 )
5066
5084
5067
- virtual_indexes = method ["get_virtual_index" ](values_count , quantiles )
5085
+ if method ["discrete_shortcut" ]: # lumps indexing + gamma interplation
5086
+ # discrete methods result in dtype = np.intp
5087
+ virtual_indexes = \
5088
+ method ["discrete_shortcut" ](values_count , quantiles )
5089
+ else :
5090
+ virtual_indexes = \
5091
+ method ["get_virtual_index" ](values_count , quantiles )
5092
+
5068
5093
virtual_indexes = np .asanyarray (virtual_indexes )
5069
5094
5070
5095
result , slices_having_nans = \
0 commit comments