diff --git a/doc/source/whatsnew/v0.19.1.txt b/doc/source/whatsnew/v0.19.1.txt index 5180b9a092f6c..1a86ecae2faf3 100644 --- a/doc/source/whatsnew/v0.19.1.txt +++ b/doc/source/whatsnew/v0.19.1.txt @@ -48,3 +48,6 @@ Bug Fixes - Bug in ``MultiIndex.set_levels`` where illegal level values were still set after raising an error (:issue:`13754`) - Bug in ``DataFrame.to_json`` where ``lines=True`` and a value contained a ``}`` character (:issue:`14391`) - Bug in ``df.groupby`` causing an ``AttributeError`` when grouping a single index frame by a column and the index level (:issue`14327`) +- Bug in ``pd.to_numeric`` where it would not downcast a 0 to a uint8 (:issue:`14404`) +- Bug in ``pd.to_numeric`` where it would not downcast a 0 properly. (:issue:`14401`) +- Bug in ``pd.to_numeric`` where a 0 was not unsigned on a downcast = 'unsigned' argument (:issue:`14401`) diff --git a/pandas/tools/tests/test_util.py b/pandas/tools/tests/test_util.py index 8c16308d79a31..54cfd1dacb87e 100644 --- a/pandas/tools/tests/test_util.py +++ b/pandas/tools/tests/test_util.py @@ -401,6 +401,62 @@ def test_downcast(self): res = pd.to_numeric(data, downcast=downcast) tm.assert_numpy_array_equal(res, expected) + # check that the smallest and largest values in each integer type pass to each type. + integer_dtype_min_max = { + 'int8': [np.iinfo(np.int8).min, np.iinfo(np.int8).max], + 'int16': [np.iinfo(np.int16).min, np.iinfo(np.int16).max], + 'int32': [np.iinfo(np.int32).min, np.iinfo(np.int32).max], + 'int64': [np.iinfo(np.int64).min, np.iinfo(np.int64).max] + } + + for dtype, min_max in integer_dtype_min_max.items(): + series = pd.to_numeric(pd.Series(min_max), downcast = 'integer') + tm.assert_equal(series.dtype, dtype) + + + unsigned_dtype_min_max = { + 'uint8': [np.iinfo(np.uint8).min, np.iinfo(np.uint8).max], + 'uint16': [np.iinfo(np.uint16).min, np.iinfo(np.uint16).max], + 'uint32': [np.iinfo(np.uint32).min, np.iinfo(np.uint32).max], + # 'uint64': [np.iinfo(np.uint64).min, np.iinfo(np.uint64).max] + } + + for dtype, min_max in unsigned_dtype_min_max.items(): + series = pd.to_numeric(pd.Series(min_max), downcast = 'unsigned') + tm.assert_equal(series.dtype, dtype) + + #check to see if the minimum number to shift integer types actually shifts + + integer_dtype_min_max_plus = { + 'int16': [np.iinfo(np.int8).min, np.iinfo(np.int8).max + 1], + 'int32': [np.iinfo(np.int16).min, np.iinfo(np.int16).max + 1], + 'int64': [np.iinfo(np.int32).min, np.iinfo(np.int32).max + 1], + } + + for dtype, min_max in integer_dtype_min_max_plus.items(): + series = pd.to_numeric(pd.Series(min_max), downcast = 'integer') + tm.assert_equal(series.dtype, dtype) + + integer_dtype_min_max_minus = { + 'int16': [np.iinfo(np.int8).min - 1, np.iinfo(np.int16).max], + 'int32': [np.iinfo(np.int16).min - 1, np.iinfo(np.int32).max], + 'int64': [np.iinfo(np.int32).min - 1, np.iinfo(np.int64).max] + } + + for dtype, min_max in integer_dtype_min_max_minus.items(): + series = pd.to_numeric(pd.Series(min_max), downcast = 'integer') + tm.assert_equal(series.dtype, dtype) + + unsigned_dtype_min_max_plus = { + 'uint16': [np.iinfo(np.uint8).min, np.iinfo(np.uint8).max + 1], + 'uint32': [np.iinfo(np.uint16).min, np.iinfo(np.uint16).max + 1], + # 'uint64': [np.iinfo(np.uint32).min, np.iinfo(np.uint32).max + 1], + } + + for dtype, min_max in unsigned_dtype_min_max_plus.items(): + series = pd.to_numeric(pd.Series(min_max), downcast = 'unsigned') + tm.assert_equal(series.dtype, dtype) + if __name__ == '__main__': nose.runmodule(argv=[__file__, '-vvs', '-x', '--pdb', '--pdb-failure'], exit=False) diff --git a/pandas/tools/util.py b/pandas/tools/util.py index fec56328c1721..b50bf9dc448bc 100644 --- a/pandas/tools/util.py +++ b/pandas/tools/util.py @@ -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']