Skip to content

Commit bac68d6

Browse files
committed
BUG: .astype() of a Float64Index to a Int64Index
closes #12881 closes #12866 xref #12309 Author: Jeff Reback <[email protected]> Closes #12899 from jreback/astype and squashes the following commits: 3c1800b [Jeff Reback] BUG: .astype() of a Float64Index to a Int64Index
1 parent 4c84f2d commit bac68d6

File tree

5 files changed

+51
-50
lines changed

5 files changed

+51
-50
lines changed

doc/source/whatsnew/v0.18.1.txt

+2-1
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,8 @@ Bug Fixes
271271
- Bug in ``float_format`` option with option not being validated as a callable. (:issue:`12706`)
272272
- Bug in ``GroupBy.filter`` when ``dropna=False`` and no groups fulfilled the criteria (:issue:`12768`)
273273
- Bug in ``__name__`` of ``.cum*`` functions (:issue:`12021`)
274-
274+
- Bug in ``.astype()`` of a ``Float64Inde/Int64Index`` to an ``Int64Index`` (:issue:`12881`)
275+
- Bug in roundtripping an integer based index in ``.to_json()/.read_json()`` when ``orient='index'`` (the default) (:issue:`12866`)
275276

276277
- Bug in ``.drop()`` with a non-unique ``MultiIndex``. (:issue:`12701`)
277278
- Bug in ``.concat`` of datetime tz-aware and naive DataFrames (:issue:`12467`)

pandas/indexes/numeric.py

+12-13
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77
from pandas.indexes.base import Index, InvalidIndexError
88
from pandas.util.decorators import Appender, cache_readonly
99
import pandas.core.common as com
10-
from pandas.core.common import is_dtype_equal, isnull
10+
from pandas.core.common import (is_dtype_equal, isnull, pandas_dtype,
11+
is_float_dtype, is_object_dtype,
12+
is_integer_dtype)
1113
import pandas.indexes.base as ibase
1214

1315

@@ -101,12 +103,7 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
101103
cls._string_data_error(data)
102104

103105
elif issubclass(data.dtype.type, np.integer):
104-
# don't force the upcast as we may be dealing
105-
# with a platform int
106-
if (dtype is None or
107-
not issubclass(np.dtype(dtype).type, np.integer)):
108-
dtype = np.int64
109-
106+
dtype = np.int64
110107
subarr = np.array(data, dtype=dtype, copy=copy)
111108
else:
112109
subarr = np.array(data, dtype=np.int64, copy=copy)
@@ -219,12 +216,9 @@ def __new__(cls, data=None, dtype=None, copy=False, name=None,
219216
dtype = np.dtype(dtype)
220217

221218
# allow integer / object dtypes to be passed, but coerce to float64
222-
if dtype.kind in ['i', 'O']:
219+
if dtype.kind in ['i', 'O', 'f']:
223220
dtype = np.float64
224221

225-
elif dtype.kind in ['f']:
226-
pass
227-
228222
else:
229223
raise TypeError("cannot support {0} dtype in "
230224
"Float64Index".format(dtype))
@@ -245,11 +239,16 @@ def inferred_type(self):
245239
return 'floating'
246240

247241
def astype(self, dtype):
248-
if np.dtype(dtype) not in (np.object, np.float64):
242+
dtype = pandas_dtype(dtype)
243+
if is_float_dtype(dtype) or is_integer_dtype(dtype):
244+
values = self._values.astype(dtype)
245+
elif is_object_dtype(dtype):
246+
values = self._values
247+
else:
249248
raise TypeError('Setting %s dtype to anything other than '
250249
'float64 or object is not supported' %
251250
self.__class__)
252-
return Index(self._values, name=self.name, dtype=dtype)
251+
return Index(values, name=self.name, dtype=dtype)
253252

254253
def _convert_scalar_indexer(self, key, kind=None):
255254
"""

pandas/io/tests/test_json/test_pandas.py

+9-15
Original file line numberDiff line numberDiff line change
@@ -576,10 +576,7 @@ def test_reconstruction_index(self):
576576
df = DataFrame([[1, 2, 3], [4, 5, 6]])
577577
result = read_json(df.to_json())
578578

579-
self.assertEqual(result.index.dtype, np.float64)
580-
self.assertEqual(result.columns.dtype, np.float64)
581-
assert_frame_equal(result, df, check_index_type=False,
582-
check_column_type=False)
579+
assert_frame_equal(result, df)
583580

584581
df = DataFrame({'a': [1, 2, 3], 'b': [4, 5, 6]}, index=['A', 'B', 'C'])
585582
result = read_json(df.to_json())
@@ -776,23 +773,20 @@ def test_timedelta(self):
776773

777774
s = Series([timedelta(23), timedelta(seconds=5)])
778775
self.assertEqual(s.dtype, 'timedelta64[ns]')
779-
# index will be float dtype
780-
assert_series_equal(s, pd.read_json(s.to_json(), typ='series')
781-
.apply(converter),
782-
check_index_type=False)
776+
777+
result = pd.read_json(s.to_json(), typ='series').apply(converter)
778+
assert_series_equal(result, s)
783779

784780
s = Series([timedelta(23), timedelta(seconds=5)],
785-
index=pd.Index([0, 1], dtype=float))
781+
index=pd.Index([0, 1]))
786782
self.assertEqual(s.dtype, 'timedelta64[ns]')
787-
assert_series_equal(s, pd.read_json(
788-
s.to_json(), typ='series').apply(converter))
783+
result = pd.read_json(s.to_json(), typ='series').apply(converter)
784+
assert_series_equal(result, s)
789785

790786
frame = DataFrame([timedelta(23), timedelta(seconds=5)])
791787
self.assertEqual(frame[0].dtype, 'timedelta64[ns]')
792788
assert_frame_equal(frame, pd.read_json(frame.to_json())
793-
.apply(converter),
794-
check_index_type=False,
795-
check_column_type=False)
789+
.apply(converter))
796790

797791
frame = DataFrame({'a': [timedelta(days=23), timedelta(seconds=5)],
798792
'b': [1, 2],
@@ -801,7 +795,7 @@ def test_timedelta(self):
801795
result = pd.read_json(frame.to_json(date_unit='ns'))
802796
result['a'] = pd.to_timedelta(result.a, unit='ns')
803797
result['c'] = pd.to_datetime(result.c)
804-
assert_frame_equal(frame, result, check_index_type=False)
798+
assert_frame_equal(frame, result)
805799

806800
def test_mixed_timedelta_datetime(self):
807801
frame = DataFrame({'a': [timedelta(23), pd.Timestamp('20130101')]},

pandas/tests/indexes/test_numeric.py

+28
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,34 @@ def test_astype(self):
231231
self.assertTrue(i.equals(result))
232232
self.check_is_index(result)
233233

234+
# GH 12881
235+
# a float astype int
236+
for dtype in ['int16', 'int32', 'int64']:
237+
i = Float64Index([0, 1, 2])
238+
result = i.astype(dtype)
239+
expected = Int64Index([0, 1, 2])
240+
tm.assert_index_equal(result, expected)
241+
242+
i = Float64Index([0, 1.1, 2])
243+
result = i.astype(dtype)
244+
expected = Int64Index([0, 1, 2])
245+
tm.assert_index_equal(result, expected)
246+
247+
for dtype in ['float32', 'float64']:
248+
i = Float64Index([0, 1, 2])
249+
result = i.astype(dtype)
250+
expected = i
251+
tm.assert_index_equal(result, expected)
252+
253+
i = Float64Index([0, 1.1, 2])
254+
result = i.astype(dtype)
255+
expected = Index(i.values.astype(dtype))
256+
tm.assert_index_equal(result, expected)
257+
258+
# invalid
259+
for dtype in ['M8[ns]', 'm8[ns]']:
260+
self.assertRaises(TypeError, lambda: i.astype(dtype))
261+
234262
def test_equals(self):
235263

236264
i = Float64Index([1.0, 2.0])

pandas/tests/test_common.py

-21
Original file line numberDiff line numberDiff line change
@@ -652,27 +652,6 @@ def test_ensure_int32():
652652
assert (result.dtype == np.int32)
653653

654654

655-
def test_ensure_platform_int():
656-
657-
# verify that when we create certain types of indices
658-
# they remain the correct type under platform conversions
659-
from pandas.core.index import Int64Index
660-
661-
# int64
662-
x = Int64Index([1, 2, 3], dtype='int64')
663-
assert (x.dtype == np.int64)
664-
665-
pi = com._ensure_platform_int(x)
666-
assert (pi.dtype == np.int_)
667-
668-
# int32
669-
x = Int64Index([1, 2, 3], dtype='int32')
670-
assert (x.dtype == np.int32)
671-
672-
pi = com._ensure_platform_int(x)
673-
assert (pi.dtype == np.int_)
674-
675-
676655
def test_is_re():
677656
passes = re.compile('ad'),
678657
fails = 'x', 2, 3, object()

0 commit comments

Comments
 (0)