diff --git a/doc/source/whatsnew/v0.18.1.txt b/doc/source/whatsnew/v0.18.1.txt index b010fcc0f2d57..885934ceeef41 100644 --- a/doc/source/whatsnew/v0.18.1.txt +++ b/doc/source/whatsnew/v0.18.1.txt @@ -267,7 +267,8 @@ Bug Fixes - Bug in ``float_format`` option with option not being validated as a callable. (:issue:`12706`) - Bug in ``GroupBy.filter`` when ``dropna=False`` and no groups fulfilled the criteria (:issue:`12768`) - Bug in ``__name__`` of ``.cum*`` functions (:issue:`12021`) - +- Bug in ``.astype()`` of a ``Float64Inde/Int64Index`` to an ``Int64Index`` (:issue:`12881`) +- Bug in roundtripping an integer based index in ``.to_json()/.read_json()`` when ``orient='index'`` (the default) (:issue:`12866`) - Bug in ``.drop()`` with a non-unique ``MultiIndex``. (:issue:`12701`) - Bug in ``.concat`` of datetime tz-aware and naive DataFrames (:issue:`12467`) diff --git a/pandas/indexes/numeric.py b/pandas/indexes/numeric.py index 79a9d0a584a42..983ea731b11ac 100644 --- a/pandas/indexes/numeric.py +++ b/pandas/indexes/numeric.py @@ -7,7 +7,9 @@ from pandas.indexes.base import Index, InvalidIndexError from pandas.util.decorators import Appender, cache_readonly import pandas.core.common as com -from pandas.core.common import is_dtype_equal, isnull +from pandas.core.common import (is_dtype_equal, isnull, pandas_dtype, + is_float_dtype, is_object_dtype, + is_integer_dtype) import pandas.indexes.base as ibase @@ -101,12 +103,7 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, cls._string_data_error(data) elif issubclass(data.dtype.type, np.integer): - # don't force the upcast as we may be dealing - # with a platform int - if (dtype is None or - not issubclass(np.dtype(dtype).type, np.integer)): - dtype = np.int64 - + dtype = np.int64 subarr = np.array(data, dtype=dtype, copy=copy) else: subarr = np.array(data, dtype=np.int64, copy=copy) @@ -219,12 +216,9 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None, dtype = np.dtype(dtype) # allow integer / object dtypes to be passed, but coerce to float64 - if dtype.kind in ['i', 'O']: + if dtype.kind in ['i', 'O', 'f']: dtype = np.float64 - elif dtype.kind in ['f']: - pass - else: raise TypeError("cannot support {0} dtype in " "Float64Index".format(dtype)) @@ -245,11 +239,16 @@ def inferred_type(self): return 'floating' def astype(self, dtype): - if np.dtype(dtype) not in (np.object, np.float64): + dtype = pandas_dtype(dtype) + if is_float_dtype(dtype) or is_integer_dtype(dtype): + values = self._values.astype(dtype) + elif is_object_dtype(dtype): + values = self._values + else: raise TypeError('Setting %s dtype to anything other than ' 'float64 or object is not supported' % self.__class__) - return Index(self._values, name=self.name, dtype=dtype) + return Index(values, name=self.name, dtype=dtype) def _convert_scalar_indexer(self, key, kind=None): """ diff --git a/pandas/io/tests/test_json/test_pandas.py b/pandas/io/tests/test_json/test_pandas.py index 2889acef8180d..af897aeeee419 100644 --- a/pandas/io/tests/test_json/test_pandas.py +++ b/pandas/io/tests/test_json/test_pandas.py @@ -576,10 +576,7 @@ def test_reconstruction_index(self): df = DataFrame([[1, 2, 3], [4, 5, 6]]) result = read_json(df.to_json()) - self.assertEqual(result.index.dtype, np.float64) - self.assertEqual(result.columns.dtype, np.float64) - assert_frame_equal(result, df, check_index_type=False, - check_column_type=False) + assert_frame_equal(result, df) df = DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}, index=['A', 'B', 'C']) result = read_json(df.to_json()) @@ -776,23 +773,20 @@ def test_timedelta(self): s = Series([timedelta(23), timedelta(seconds=5)]) self.assertEqual(s.dtype, 'timedelta64[ns]') - # index will be float dtype - assert_series_equal(s, pd.read_json(s.to_json(), typ='series') - .apply(converter), - check_index_type=False) + + result = pd.read_json(s.to_json(), typ='series').apply(converter) + assert_series_equal(result, s) s = Series([timedelta(23), timedelta(seconds=5)], - index=pd.Index([0, 1], dtype=float)) + index=pd.Index([0, 1])) self.assertEqual(s.dtype, 'timedelta64[ns]') - assert_series_equal(s, pd.read_json( - s.to_json(), typ='series').apply(converter)) + result = pd.read_json(s.to_json(), typ='series').apply(converter) + assert_series_equal(result, s) frame = DataFrame([timedelta(23), timedelta(seconds=5)]) self.assertEqual(frame[0].dtype, 'timedelta64[ns]') assert_frame_equal(frame, pd.read_json(frame.to_json()) - .apply(converter), - check_index_type=False, - check_column_type=False) + .apply(converter)) frame = DataFrame({'a': [timedelta(days=23), timedelta(seconds=5)], 'b': [1, 2], @@ -801,7 +795,7 @@ def test_timedelta(self): result = pd.read_json(frame.to_json(date_unit='ns')) result['a'] = pd.to_timedelta(result.a, unit='ns') result['c'] = pd.to_datetime(result.c) - assert_frame_equal(frame, result, check_index_type=False) + assert_frame_equal(frame, result) def test_mixed_timedelta_datetime(self): frame = DataFrame({'a': [timedelta(23), pd.Timestamp('20130101')]}, diff --git a/pandas/tests/indexes/test_numeric.py b/pandas/tests/indexes/test_numeric.py index 56e19c8b1d7d9..06923e364bc63 100644 --- a/pandas/tests/indexes/test_numeric.py +++ b/pandas/tests/indexes/test_numeric.py @@ -231,6 +231,34 @@ def test_astype(self): self.assertTrue(i.equals(result)) self.check_is_index(result) + # GH 12881 + # a float astype int + for dtype in ['int16', 'int32', 'int64']: + i = Float64Index([0, 1, 2]) + result = i.astype(dtype) + expected = Int64Index([0, 1, 2]) + tm.assert_index_equal(result, expected) + + i = Float64Index([0, 1.1, 2]) + result = i.astype(dtype) + expected = Int64Index([0, 1, 2]) + tm.assert_index_equal(result, expected) + + for dtype in ['float32', 'float64']: + i = Float64Index([0, 1, 2]) + result = i.astype(dtype) + expected = i + tm.assert_index_equal(result, expected) + + i = Float64Index([0, 1.1, 2]) + result = i.astype(dtype) + expected = Index(i.values.astype(dtype)) + tm.assert_index_equal(result, expected) + + # invalid + for dtype in ['M8[ns]', 'm8[ns]']: + self.assertRaises(TypeError, lambda: i.astype(dtype)) + def test_equals(self): i = Float64Index([1.0, 2.0]) diff --git a/pandas/tests/test_common.py b/pandas/tests/test_common.py index 905816081f0c5..9fe0d3c569ae0 100644 --- a/pandas/tests/test_common.py +++ b/pandas/tests/test_common.py @@ -652,27 +652,6 @@ def test_ensure_int32(): assert (result.dtype == np.int32) -def test_ensure_platform_int(): - - # verify that when we create certain types of indices - # they remain the correct type under platform conversions - from pandas.core.index import Int64Index - - # int64 - x = Int64Index([1, 2, 3], dtype='int64') - assert (x.dtype == np.int64) - - pi = com._ensure_platform_int(x) - assert (pi.dtype == np.int_) - - # int32 - x = Int64Index([1, 2, 3], dtype='int32') - assert (x.dtype == np.int32) - - pi = com._ensure_platform_int(x) - assert (pi.dtype == np.int_) - - def test_is_re(): passes = re.compile('ad'), fails = 'x', 2, 3, object()