Skip to content

Commit

Permalink
BUG: to_numeric downcast = 'unsigned' would not un-sign a 0 value
Browse files Browse the repository at this point in the history
closes #14504
closes #14401
  • Loading branch information
Nicholas Ver Halen authored and jreback committed Nov 17, 2016
1 parent 7e66937 commit b5864b0
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 2 deletions.
1 change: 1 addition & 0 deletions doc/source/whatsnew/v0.19.2.txt
Expand Up @@ -33,6 +33,7 @@ Bug Fixes


- Bug in ``pd.cut`` with negative values and a single bin (:issue:`14652`)
- Bug in ``pd.to_numeric`` where a 0 was not unsigned on a ``downcast='unsigned'`` argument (:issue:`14401`)



Expand Down
38 changes: 37 additions & 1 deletion pandas/tools/tests/test_util.py
Expand Up @@ -4,9 +4,10 @@
import nose

import numpy as np
from numpy import iinfo

import pandas as pd
from pandas import date_range, Index
from pandas import (date_range, Index, _np_version_under1p9)
import pandas.util.testing as tm
from pandas.tools.util import cartesian_product, to_numeric

Expand Down Expand Up @@ -401,6 +402,41 @@ def test_downcast(self):
res = pd.to_numeric(data, downcast=downcast)
tm.assert_numpy_array_equal(res, expected)

def test_downcast_limits(self):
# Test the limits of each downcast. Bug: #14401.
# Check to make sure numpy is new enough to run this test.
if _np_version_under1p9:
raise nose.SkipTest("Numpy version is under 1.9")

i = 'integer'
u = 'unsigned'
dtype_downcast_min_max = [
('int8', i, [iinfo(np.int8).min, iinfo(np.int8).max]),
('int16', i, [iinfo(np.int16).min, iinfo(np.int16).max]),
('int32', i, [iinfo(np.int32).min, iinfo(np.int32).max]),
('int64', i, [iinfo(np.int64).min, iinfo(np.int64).max]),
('uint8', u, [iinfo(np.uint8).min, iinfo(np.uint8).max]),
('uint16', u, [iinfo(np.uint16).min, iinfo(np.uint16).max]),
('uint32', u, [iinfo(np.uint32).min, iinfo(np.uint32).max]),
# Test will be skipped until there is more uint64 support.
# ('uint64', u, [iinfo(uint64).min, iinfo(uint64).max]),
('int16', i, [iinfo(np.int8).min, iinfo(np.int8).max + 1]),
('int32', i, [iinfo(np.int16).min, iinfo(np.int16).max + 1]),
('int64', i, [iinfo(np.int32).min, iinfo(np.int32).max + 1]),
('int16', i, [iinfo(np.int8).min - 1, iinfo(np.int16).max]),
('int32', i, [iinfo(np.int16).min - 1, iinfo(np.int32).max]),
('int64', i, [iinfo(np.int32).min - 1, iinfo(np.int64).max]),
('uint16', u, [iinfo(np.uint8).min, iinfo(np.uint8).max + 1]),
('uint32', u, [iinfo(np.uint16).min, iinfo(np.uint16).max + 1]),
# Test will be skipped until there is more uint64 support.
# ('uint64', u, [iinfo(np.uint32).min, iinfo(np.uint32).max + 1]),
]

for dtype, downcast, min_max in dtype_downcast_min_max:
series = pd.to_numeric(pd.Series(min_max), downcast=downcast)
tm.assert_equal(series.dtype, dtype)


if __name__ == '__main__':
nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'],
exit=False)
2 changes: 1 addition & 1 deletion pandas/tools/util.py
Expand Up @@ -205,7 +205,7 @@ def to_numeric(arg, errors='raise', downcast=None):

if downcast in ('integer', 'signed'):
typecodes = np.typecodes['Integer']
elif downcast == 'unsigned' and np.min(values) > 0:
elif downcast == 'unsigned' and np.min(values) >= 0:
typecodes = np.typecodes['UnsignedInteger']
elif downcast == 'float':
typecodes = np.typecodes['Float']
Expand Down

0 comments on commit b5864b0

Please sign in to comment.