Skip to content

Commit

Permalink
nanmedian wrong for particular ordering of NaN and non-NaN elements.
Browse files Browse the repository at this point in the history
Closes #22.
  • Loading branch information
kwgoodman committed May 5, 2011
1 parent a4194d3 commit 0fd01aa
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 95 deletions.
76 changes: 38 additions & 38 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -64,25 +64,25 @@ Bottleneck comes with a benchmark suite. To run the benchmark::

no NaN no NaN no NaN NaN NaN NaN
(10,10) (100,100) (1000,1000) (10,10) (100,100) (1000,1000)
median 5.25 2.20 2.27 5.88 4.06 2.87
nanmedian 128.35 28.31 4.35 152.00 71.91 6.46
nansum 12.04 6.18 1.71 12.24 7.20 1.71
nanmax 12.17 6.16 1.68 12.88 10.07 1.70
nanmean 24.67 13.85 2.99 25.86 29.22 4.97
nanstd 30.77 9.73 2.69 31.87 17.86 3.70
nanargmax 11.48 5.78 2.65 11.42 8.82 2.85
ss 5.27 3.31 1.25 5.27 3.30 1.25
rankdata 22.14 13.03 8.62 22.16 14.67 9.62
partsort 1.42 2.20 2.48 1.57 5.05 3.70
argpartsort 0.78 2.20 1.67 0.67 3.45 1.60
move_sum 11.91 8.64 14.25 11.78 8.73 13.79
move_nansum 29.90 19.47 28.85 30.40 25.27 29.40
move_mean 11.18 4.43 14.37 11.03 8.63 13.97
move_nanmean 35.93 12.11 29.77 37.45 14.67 30.69
move_std 18.38 3.42 23.01 24.21 20.98 29.72
move_nanstd 37.21 6.31 34.89 43.67 7.14 36.14
move_max 4.35 3.73 9.32 4.79 5.87 11.73
move_nanmax 22.96 6.40 19.58 27.06 15.19 26.97
median 5.22 2.18 2.20 5.98 4.02 2.86
nanmedian 115.05 27.65 4.33 148.55 68.91 6.44
nansum 12.92 6.28 1.70 12.84 7.06 1.73
nanmax 12.73 6.15 1.68 12.93 10.21 1.70
nanmean 24.28 13.73 3.00 25.40 28.95 4.98
nanstd 30.64 9.82 2.73 31.87 17.48 3.76
nanargmax 10.82 5.92 2.68 11.36 8.93 2.89
ss 5.26 3.36 1.25 5.30 3.30 1.25
rankdata 23.20 13.54 9.10 22.95 15.19 10.32
partsort 1.43 2.20 2.48 1.52 5.18 3.71
argpartsort 0.78 2.22 1.65 0.68 3.59 1.59
move_sum 12.24 8.38 14.15 12.10 8.58 13.73
move_nansum 29.84 20.39 28.79 30.51 25.29 29.04
move_mean 11.43 4.41 14.27 11.25 8.59 13.83
move_nanmean 35.99 12.01 29.60 37.25 14.63 30.52
move_std 18.15 3.42 23.08 24.11 21.19 29.73
move_nanstd 37.08 6.33 35.05 43.68 7.18 36.23
move_max 4.33 3.74 9.46 4.90 5.83 11.75
move_nanmax 23.49 6.44 19.58 27.26 15.29 26.92

Reference functions:
median np.median
Expand Down Expand Up @@ -150,25 +150,25 @@ Benchmarks for the low-level Cython functions::

no NaN no NaN no NaN NaN NaN NaN
(10,10) (100,100) (1000,1000) (10,10) (100,100) (1000,1000)
median 6.58 2.24 2.28 7.39 4.25 2.89
nanmedian 159.56 28.57 4.35 184.05 74.48 6.42
nansum 20.07 6.70 1.70 20.09 7.93 1.71
nanmax 18.39 6.44 1.68 19.83 10.83 1.69
nanmean 37.21 14.46 3.00 38.79 30.73 4.98
nanstd 42.23 9.96 2.68 44.62 18.35 3.69
nanargmax 17.15 6.00 2.67 17.45 9.42 2.87
ss 8.88 3.64 1.25 8.91 3.60 1.24
rankdata 23.42 12.99 8.51 23.68 14.60 9.53
partsort 2.03 2.22 2.48 2.37 5.25 3.71
argpartsort 1.12 2.22 1.67 0.92 3.57 1.59
move_sum 16.26 8.97 14.19 16.05 9.21 13.45
move_nansum 39.62 21.51 29.08 40.93 26.15 28.98
move_mean 14.49 4.49 14.31 14.58 9.08 13.84
move_nanmean 44.82 12.25 29.59 46.38 14.92 30.18
move_std 20.66 3.44 22.94 28.44 21.70 29.65
move_nanstd 41.16 6.35 34.94 49.21 7.21 36.04
move_max 5.30 3.80 9.34 6.20 6.01 11.81
move_nanmax 27.02 6.53 19.63 32.31 15.23 27.03
median 5.86 2.23 2.27 7.54 4.23 2.88
nanmedian 139.97 27.79 4.31 191.21 68.61 6.36
nansum 19.92 6.72 1.70 19.35 7.89 1.72
nanmax 19.09 6.49 1.68 20.17 11.07 1.70
nanmean 35.65 14.48 2.98 37.41 30.76 4.96
nanstd 41.62 10.02 2.70 43.75 17.98 3.71
nanargmax 16.91 6.23 2.69 17.61 9.58 2.88
ss 8.66 3.53 1.25 8.72 3.56 1.25
rankdata 23.58 13.08 8.69 23.63 14.55 9.68
partsort 1.99 2.22 2.48 2.24 5.36 3.70
argpartsort 0.95 2.22 1.66 0.86 3.69 1.59
move_sum 18.47 8.84 14.20 18.20 9.25 13.71
move_nansum 45.80 21.58 28.88 48.13 27.28 29.28
move_mean 16.33 4.51 14.30 16.40 9.16 13.87
move_nanmean 52.45 12.23 29.48 54.01 14.96 30.43
move_std 23.02 3.44 23.05 32.55 22.25 29.83
move_nanstd 47.08 6.35 34.96 57.24 7.18 36.13
move_max 5.75 3.77 9.29 6.72 6.01 11.74
move_nanmax 30.40 6.54 19.65 36.18 15.62 27.03

Reference functions:
median np.median
Expand Down
4 changes: 4 additions & 0 deletions RELEASE.rst
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ Bottleneck 0.5.0
**Breaks from 0.4.3**

- nanmax and nanmin now follow Numpy 1.6 (not 1.5.1) when input is all NaN

**Bug fixes**

- #22 nanmedian wrong for particular ordering of NaN and non-NaN elements

Older versions
==============
Expand Down
93 changes: 36 additions & 57 deletions bottleneck/src/template/func/nanmedian.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,28 +14,21 @@
loop[1] = """\
if nINDEX0 == 0:
return np.FLOAT(NAN)
k = nAXIS
l = 0
r = k - 1
while l < r:
i = l
j = r
while b[i] == b[i]:
i += 1
if i == nAXIS:
j = nAXIS - 1
flag = 1
for i in range(nINDEX0):
if b[i] != b[i]:
while b[j] != b[j]:
if j <= 0:
break
j -= 1
if i >= j:
flag = 0
break
while b[j] != b[j]:
j -= 1
if i <= j:
tmp = b[i]
b[i] = b[j]
b[j] = tmp
i += 1
j -= 1
if i > j: break
l = i
r = j
n = j + 1
n = i + flag
k = n >> 1
l = 0
r = n - 1
Expand Down Expand Up @@ -75,29 +68,22 @@
if nINDEX1 == 0:
PyArray_FillWithScalar(y, NAN)
return y
for iINDEX0 in range(nINDEX0):
k = nAXIS
l = 0
r = k - 1
while l < r:
i = l
j = r
while b[INDEXREPLACE|i|] == b[INDEXREPLACE|i|]:
i += 1
if i == nAXIS:
for iINDEX0 in range(nINDEX0):
j = nAXIS - 1
flag = 1
for i in range(nINDEX1):
if b[INDEXREPLACE|i|] != b[INDEXREPLACE|i|]:
while b[INDEXREPLACE|j|] != b[INDEXREPLACE|j|]:
if j <= 0:
break
j -= 1
if i >= j:
flag = 0
break
while b[INDEXREPLACE|j|] != b[INDEXREPLACE|j|]:
j -= 1
if i <= j:
tmp = b[INDEXREPLACE|i|]
b[INDEXREPLACE|i|] = b[INDEXREPLACE|j|]
b[INDEXREPLACE|j|] = tmp
i += 1
j -= 1
if i > j: break
l = i
r = j
n = j + 1
n = i + flag
k = n >> 1
l = 0
r = n - 1
Expand Down Expand Up @@ -139,28 +125,21 @@
return y
for iINDEX0 in range(nINDEX0):
for iINDEX1 in range(nINDEX1):
k = nAXIS
l = 0
r = k - 1
while l < r:
i = l
j = r
while b[INDEXREPLACE|i|] == b[INDEXREPLACE|i|]:
i += 1
if i == nAXIS:
j = nAXIS - 1
flag = 1
for i in range(nINDEX2):
if b[INDEXREPLACE|i|] != b[INDEXREPLACE|i|]:
while b[INDEXREPLACE|j|] != b[INDEXREPLACE|j|]:
if j <= 0:
break
j -= 1
if i >= j:
flag = 0
break
while b[INDEXREPLACE|j|] != b[INDEXREPLACE|j|]:
j -= 1
if i <= j:
tmp = b[INDEXREPLACE|i|]
b[INDEXREPLACE|i|] = b[INDEXREPLACE|j|]
b[INDEXREPLACE|j|] = tmp
i += 1
j -= 1
if i > j: break
l = i
r = j
n = j + 1
n = i + flag
k = n >> 1
l = 0
r = n - 1
Expand Down Expand Up @@ -210,8 +189,8 @@
@cython.wraparound(False)
def NAME_NDIMd_DTYPE_axisAXIS(np.ndarray[np.DTYPE_t, ndim=NDIM] a):
"Median of NDIMd array with dtype=DTYPE along axis=AXIS."
cdef int allnan = 1
cdef np.npy_intp i, j = 0, l, r, k, n
cdef int allnan = 1, flag = 0
cdef np.npy_intp i = 0, j = 0, l, r, k, n
cdef np.DTYPE_t x, tmp, amax, ai
cdef np.ndarray[np.DTYPE_t, ndim=NDIM] b = PyArray_Copy(a)
"""
Expand Down
7 changes: 7 additions & 0 deletions bottleneck/tests/func_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ def arrays(dtypes=bn.dtypes, nans=True):
a.flat[i] = np.inf
yield a
yield -a
if nans:
# nanmedian regression tests
a = np.array([1, nan, nan, 2])
yield a
a = np.vstack((a, a))
yield a
yield a.reshape(1,2,4)

def unit_maker(func, func0, decimal=np.inf, nans=True):
"Test that bn.xxx gives the same output as np.xxx."
Expand Down

0 comments on commit 0fd01aa

Please sign in to comment.