Skip to content

Commit 4f80369

Browse files
committed
Fix bug in 'nearest' interpolation
Add whatsnew Fix bug: catch KeyError not ValueError Add return type to roll_quantile
1 parent f5fb6cb commit 4f80369

File tree

4 files changed

+30
-15
lines changed

4 files changed

+30
-15
lines changed

doc/source/whatsnew/v0.23.0.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,7 @@ Other Enhancements
449449
- Updated ``to_gbq`` and ``read_gbq`` signature and documentation to reflect changes from
450450
the Pandas-GBQ library version 0.4.0. Adds intersphinx mapping to Pandas-GBQ
451451
library. (:issue:`20564`)
452+
- :meth:`Rolling.quantile` and :meth:`Expanding.quantile` now accept ``interpolation`` keyword
452453

453454
.. _whatsnew_0230.api_breaking:
454455

pandas/_libs/window.pyx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1396,7 +1396,7 @@ def roll_quantile(ndarray[float64_t, cast=True] input, int64_t win,
13961396

13971397
try:
13981398
interpolation_type = interpolation_types[interpolation]
1399-
except ValueError:
1399+
except KeyError:
14001400
raise ValueError("Interpolation {} is not supported"
14011401
.format(interpolation))
14021402

@@ -1442,7 +1442,7 @@ def roll_quantile(ndarray[float64_t, cast=True] input, int64_t win,
14421442
# Single value in skip list
14431443
output[i] = skiplist.get(0)
14441444
else:
1445-
idx_with_fraction = quantile * <double> (nobs - 1)
1445+
idx_with_fraction = quantile * (nobs - 1)
14461446
idx = int(idx_with_fraction)
14471447

14481448
if interpolation_type == LINEAR:
@@ -1455,10 +1455,7 @@ def roll_quantile(ndarray[float64_t, cast=True] input, int64_t win,
14551455
elif interpolation_type == HIGHER:
14561456
output[i] = skiplist.get(idx + 1)
14571457
elif interpolation_type == NEAREST:
1458-
if idx_with_fraction - idx < 0.5:
1459-
output[i] = skiplist.get(idx)
1460-
else:
1461-
output[i] = skiplist.get(idx + 1)
1458+
output[i] = skiplist.get(round(idx_with_fraction))
14621459
elif interpolation_type == MIDPOINT:
14631460
vlow = skiplist.get(idx)
14641461
vhigh = skiplist.get(idx + 1)

pandas/core/window.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1287,7 +1287,8 @@ def kurt(self, **kwargs):
12871287
fractional part of the index surrounded by `i` and `j`.
12881288
* lower: `i`.
12891289
* higher: `j`.
1290-
* nearest: `i` or `j` whichever is nearest.
1290+
* nearest: `i` or `j` whichever is nearest. Implementation uses
1291+
round() built-in.
12911292
* midpoint: (`i` + `j`) / 2.
12921293
12931294
Returns
@@ -1305,6 +1306,7 @@ def kurt(self, **kwargs):
13051306
2 2.0
13061307
3 3.0
13071308
dtype: float64
1309+
13081310
>>> s.rolling(2).quantile(.4, interpolation='midpoint')
13091311
0 NaN
13101312
1 1.5
@@ -1316,7 +1318,7 @@ def kurt(self, **kwargs):
13161318
--------
13171319
pandas.Series.quantile
13181320
pandas.DataFrame.quantile
1319-
1321+
13201322
""")
13211323

13221324
def quantile(self, quantile, interpolation='linear', **kwargs):
@@ -1655,7 +1657,7 @@ def kurt(self, **kwargs):
16551657
@Substitution(name='rolling')
16561658
@Appender(_doc_template)
16571659
@Appender(_shared_docs['quantile'])
1658-
def quantile(self, quantile, interpolation='linear', **kwargs): # here
1660+
def quantile(self, quantile, interpolation='linear', **kwargs):
16591661
return super(Rolling, self).quantile(quantile=quantile,
16601662
interpolation=interpolation,
16611663
**kwargs)
@@ -1916,8 +1918,10 @@ def kurt(self, **kwargs):
19161918
@Substitution(name='expanding')
19171919
@Appender(_doc_template)
19181920
@Appender(_shared_docs['quantile'])
1919-
def quantile(self, quantile, **kwargs):
1920-
return super(Expanding, self).quantile(quantile=quantile, **kwargs)
1921+
def quantile(self, quantile, interpolation='linear', **kwargs,):
1922+
return super(Expanding, self).quantile(quantile=quantile,
1923+
interpolation=interpolation,
1924+
**kwargs)
19211925

19221926
@Substitution(name='expanding')
19231927
@Appender(_doc_template)

pandas/tests/test_window.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1168,7 +1168,7 @@ def test_rolling_quantile_np_percentile(self):
11681168

11691169
def test_rolling_quantile_series(self):
11701170
# #16211: Tests that rolling window's quantile default behavior
1171-
# is analogus to Series' quantile
1171+
# is analogous to Series' quantile
11721172
arr = np.arange(100)
11731173
s = Series(arr)
11741174
q1 = s.quantile(0.1)
@@ -1177,16 +1177,29 @@ def test_rolling_quantile_series(self):
11771177
tm.assert_almost_equal(q1, q2)
11781178

11791179
@pytest.mark.parametrize('quantile', [0.0, 0.1, 0.45, 0.5, 1])
1180+
@pytest.mark.parametrize('na_probability', [0.0, 0.3])
11801181
@pytest.mark.parametrize('interpolation', ['linear', 'lower', 'higher',
11811182
'nearest', 'midpoint'])
11821183
def test_rolling_quantile_interpolation_options(self, quantile,
1184+
na_probability,
11831185
interpolation):
1184-
# Tests that rolling window's quantile behavior is analogus to
1186+
# Tests that rolling window's quantile behavior is analogous to
11851187
# Series' quantile for each interpolation option
11861188
size = 100
1187-
s = Series(np.arange(size))
1189+
s = Series(np.random.rand(size))
1190+
1191+
# set NaN values
1192+
na_count = 0
1193+
na_total = int(size * na_probability)
1194+
while na_count < na_total:
1195+
index = np.random.randint(0, size)
1196+
if not np.isnan(s[index]):
1197+
s[index] = np.NaN
1198+
na_count += 1
1199+
11881200
q1 = s.quantile(quantile, interpolation)
1189-
q2 = s.rolling(size).quantile(quantile, interpolation).iloc[-1]
1201+
q2 = s.rolling(size, min_periods=1).quantile(
1202+
quantile, interpolation).iloc[-1]
11901203

11911204
tm.assert_almost_equal(q1, q2)
11921205

0 commit comments

Comments
 (0)