123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551 |
- import numpy as np
- import pytest
- import pandas as pd
- from pandas import (
- Index,
- Series,
- )
- import pandas._testing as tm
- from pandas.tests.indexes.common import NumericBase
- class TestFloatNumericIndex(NumericBase):
- _index_cls = Index
- @pytest.fixture(params=[np.float64, np.float32])
- def dtype(self, request):
- return request.param
- @pytest.fixture
- def simple_index(self, dtype):
- values = np.arange(5, dtype=dtype)
- return self._index_cls(values)
- @pytest.fixture(
- params=[
- [1.5, 2, 3, 4, 5],
- [0.0, 2.5, 5.0, 7.5, 10.0],
- [5, 4, 3, 2, 1.5],
- [10.0, 7.5, 5.0, 2.5, 0.0],
- ],
- ids=["mixed", "float", "mixed_dec", "float_dec"],
- )
- def index(self, request, dtype):
- return self._index_cls(request.param, dtype=dtype)
- @pytest.fixture
- def mixed_index(self, dtype):
- return self._index_cls([1.5, 2, 3, 4, 5], dtype=dtype)
- @pytest.fixture
- def float_index(self, dtype):
- return self._index_cls([0.0, 2.5, 5.0, 7.5, 10.0], dtype=dtype)
- def test_repr_roundtrip(self, index):
- tm.assert_index_equal(eval(repr(index)), index, exact=True)
- def check_coerce(self, a, b, is_float_index=True):
- assert a.equals(b)
- tm.assert_index_equal(a, b, exact=False)
- if is_float_index:
- assert isinstance(b, self._index_cls)
- else:
- assert type(b) is Index
- def test_constructor_from_list_no_dtype(self):
- index = self._index_cls([1.5, 2.5, 3.5])
- assert index.dtype == np.float64
- def test_constructor(self, dtype):
- index_cls = self._index_cls
- # explicit construction
- index = index_cls([1, 2, 3, 4, 5], dtype=dtype)
- assert isinstance(index, index_cls)
- assert index.dtype == dtype
- expected = np.array([1, 2, 3, 4, 5], dtype=dtype)
- tm.assert_numpy_array_equal(index.values, expected)
- index = index_cls(np.array([1, 2, 3, 4, 5]), dtype=dtype)
- assert isinstance(index, index_cls)
- assert index.dtype == dtype
- index = index_cls([1.0, 2, 3, 4, 5], dtype=dtype)
- assert isinstance(index, index_cls)
- assert index.dtype == dtype
- index = index_cls(np.array([1.0, 2, 3, 4, 5]), dtype=dtype)
- assert isinstance(index, index_cls)
- assert index.dtype == dtype
- index = index_cls([1.0, 2, 3, 4, 5], dtype=dtype)
- assert isinstance(index, index_cls)
- assert index.dtype == dtype
- index = index_cls(np.array([1.0, 2, 3, 4, 5]), dtype=dtype)
- assert isinstance(index, index_cls)
- assert index.dtype == dtype
- # nan handling
- result = index_cls([np.nan, np.nan], dtype=dtype)
- assert pd.isna(result.values).all()
- result = index_cls(np.array([np.nan]), dtype=dtype)
- assert pd.isna(result.values).all()
- def test_constructor_invalid(self):
- index_cls = self._index_cls
- cls_name = index_cls.__name__
- # invalid
- msg = (
- rf"{cls_name}\(\.\.\.\) must be called with a collection of "
- r"some kind, 0\.0 was passed"
- )
- with pytest.raises(TypeError, match=msg):
- index_cls(0.0)
- def test_constructor_coerce(self, mixed_index, float_index):
- self.check_coerce(mixed_index, Index([1.5, 2, 3, 4, 5]))
- self.check_coerce(float_index, Index(np.arange(5) * 2.5))
- result = Index(np.array(np.arange(5) * 2.5, dtype=object))
- assert result.dtype == object # as of 2.0 to match Series
- self.check_coerce(float_index, result.astype("float64"))
- def test_constructor_explicit(self, mixed_index, float_index):
- # these don't auto convert
- self.check_coerce(
- float_index, Index((np.arange(5) * 2.5), dtype=object), is_float_index=False
- )
- self.check_coerce(
- mixed_index, Index([1.5, 2, 3, 4, 5], dtype=object), is_float_index=False
- )
- def test_type_coercion_fail(self, any_int_numpy_dtype):
- # see gh-15832
- msg = "Trying to coerce float values to integers"
- with pytest.raises(ValueError, match=msg):
- Index([1, 2, 3.5], dtype=any_int_numpy_dtype)
- def test_equals_numeric(self):
- index_cls = self._index_cls
- idx = index_cls([1.0, 2.0])
- assert idx.equals(idx)
- assert idx.identical(idx)
- idx2 = index_cls([1.0, 2.0])
- assert idx.equals(idx2)
- idx = index_cls([1.0, np.nan])
- assert idx.equals(idx)
- assert idx.identical(idx)
- idx2 = index_cls([1.0, np.nan])
- assert idx.equals(idx2)
- @pytest.mark.parametrize(
- "other",
- (
- Index([1, 2], dtype=np.int64),
- Index([1.0, 2.0], dtype=object),
- Index([1, 2], dtype=object),
- ),
- )
- def test_equals_numeric_other_index_type(self, other):
- idx = self._index_cls([1.0, 2.0])
- assert idx.equals(other)
- assert other.equals(idx)
- @pytest.mark.parametrize(
- "vals",
- [
- pd.date_range("2016-01-01", periods=3),
- pd.timedelta_range("1 Day", periods=3),
- ],
- )
- def test_lookups_datetimelike_values(self, vals, dtype):
- # If we have datetime64 or timedelta64 values, make sure they are
- # wrapped correctly GH#31163
- ser = Series(vals, index=range(3, 6))
- ser.index = ser.index.astype(dtype)
- expected = vals[1]
- result = ser[4.0]
- assert isinstance(result, type(expected)) and result == expected
- result = ser[4]
- assert isinstance(result, type(expected)) and result == expected
- result = ser.loc[4.0]
- assert isinstance(result, type(expected)) and result == expected
- result = ser.loc[4]
- assert isinstance(result, type(expected)) and result == expected
- result = ser.at[4.0]
- assert isinstance(result, type(expected)) and result == expected
- # GH#31329 .at[4] should cast to 4.0, matching .loc behavior
- result = ser.at[4]
- assert isinstance(result, type(expected)) and result == expected
- result = ser.iloc[1]
- assert isinstance(result, type(expected)) and result == expected
- result = ser.iat[1]
- assert isinstance(result, type(expected)) and result == expected
- def test_doesnt_contain_all_the_things(self):
- idx = self._index_cls([np.nan])
- assert not idx.isin([0]).item()
- assert not idx.isin([1]).item()
- assert idx.isin([np.nan]).item()
- def test_nan_multiple_containment(self):
- index_cls = self._index_cls
- idx = index_cls([1.0, np.nan])
- tm.assert_numpy_array_equal(idx.isin([1.0]), np.array([True, False]))
- tm.assert_numpy_array_equal(idx.isin([2.0, np.pi]), np.array([False, False]))
- tm.assert_numpy_array_equal(idx.isin([np.nan]), np.array([False, True]))
- tm.assert_numpy_array_equal(idx.isin([1.0, np.nan]), np.array([True, True]))
- idx = index_cls([1.0, 2.0])
- tm.assert_numpy_array_equal(idx.isin([np.nan]), np.array([False, False]))
- def test_fillna_float64(self):
- index_cls = self._index_cls
- # GH 11343
- idx = Index([1.0, np.nan, 3.0], dtype=float, name="x")
- # can't downcast
- exp = Index([1.0, 0.1, 3.0], name="x")
- tm.assert_index_equal(idx.fillna(0.1), exp, exact=True)
- # downcast
- exp = index_cls([1.0, 2.0, 3.0], name="x")
- tm.assert_index_equal(idx.fillna(2), exp)
- # object
- exp = Index([1.0, "obj", 3.0], name="x")
- tm.assert_index_equal(idx.fillna("obj"), exp, exact=True)
- class NumericInt(NumericBase):
- _index_cls = Index
- def test_is_monotonic(self):
- index_cls = self._index_cls
- index = index_cls([1, 2, 3, 4])
- assert index.is_monotonic_increasing is True
- assert index.is_monotonic_increasing is True
- assert index._is_strictly_monotonic_increasing is True
- assert index.is_monotonic_decreasing is False
- assert index._is_strictly_monotonic_decreasing is False
- index = index_cls([4, 3, 2, 1])
- assert index.is_monotonic_increasing is False
- assert index._is_strictly_monotonic_increasing is False
- assert index._is_strictly_monotonic_decreasing is True
- index = index_cls([1])
- assert index.is_monotonic_increasing is True
- assert index.is_monotonic_increasing is True
- assert index.is_monotonic_decreasing is True
- assert index._is_strictly_monotonic_increasing is True
- assert index._is_strictly_monotonic_decreasing is True
- def test_is_strictly_monotonic(self):
- index_cls = self._index_cls
- index = index_cls([1, 1, 2, 3])
- assert index.is_monotonic_increasing is True
- assert index._is_strictly_monotonic_increasing is False
- index = index_cls([3, 2, 1, 1])
- assert index.is_monotonic_decreasing is True
- assert index._is_strictly_monotonic_decreasing is False
- index = index_cls([1, 1])
- assert index.is_monotonic_increasing
- assert index.is_monotonic_decreasing
- assert not index._is_strictly_monotonic_increasing
- assert not index._is_strictly_monotonic_decreasing
- def test_logical_compat(self, simple_index):
- idx = simple_index
- assert idx.all() == idx.values.all()
- assert idx.any() == idx.values.any()
- def test_identical(self, simple_index, dtype):
- index = simple_index
- idx = Index(index.copy())
- assert idx.identical(index)
- same_values_different_type = Index(idx, dtype=object)
- assert not idx.identical(same_values_different_type)
- idx = index.astype(dtype=object)
- idx = idx.rename("foo")
- same_values = Index(idx, dtype=object)
- assert same_values.identical(idx)
- assert not idx.identical(index)
- assert Index(same_values, name="foo", dtype=object).identical(idx)
- assert not index.astype(dtype=object).identical(index.astype(dtype=dtype))
- def test_cant_or_shouldnt_cast(self, dtype):
- msg = r"invalid literal for int\(\) with base 10: 'foo'"
- # can't
- data = ["foo", "bar", "baz"]
- with pytest.raises(ValueError, match=msg):
- self._index_cls(data, dtype=dtype)
- def test_view_index(self, simple_index):
- index = simple_index
- index.view(Index)
- def test_prevent_casting(self, simple_index):
- index = simple_index
- result = index.astype("O")
- assert result.dtype == np.object_
- class TestIntNumericIndex(NumericInt):
- @pytest.fixture(params=[np.int64, np.int32, np.int16, np.int8])
- def dtype(self, request):
- return request.param
- @pytest.fixture
- def simple_index(self, dtype):
- return self._index_cls(range(0, 20, 2), dtype=dtype)
- @pytest.fixture(
- params=[range(0, 20, 2), range(19, -1, -1)], ids=["index_inc", "index_dec"]
- )
- def index(self, request, dtype):
- return self._index_cls(request.param, dtype=dtype)
- def test_constructor_from_list_no_dtype(self):
- index = self._index_cls([1, 2, 3])
- assert index.dtype == np.int64
- def test_constructor(self, dtype):
- index_cls = self._index_cls
- # scalar raise Exception
- msg = (
- rf"{index_cls.__name__}\(\.\.\.\) must be called with a collection of some "
- "kind, 5 was passed"
- )
- with pytest.raises(TypeError, match=msg):
- index_cls(5)
- # copy
- # pass list, coerce fine
- index = index_cls([-5, 0, 1, 2], dtype=dtype)
- arr = index.values
- new_index = index_cls(arr, copy=True)
- tm.assert_index_equal(new_index, index, exact=True)
- val = arr[0] + 3000
- # this should not change index
- arr[0] = val
- assert new_index[0] != val
- if dtype == np.int64:
- # pass list, coerce fine
- index = index_cls([-5, 0, 1, 2], dtype=dtype)
- expected = Index([-5, 0, 1, 2], dtype=dtype)
- tm.assert_index_equal(index, expected)
- # from iterable
- index = index_cls(iter([-5, 0, 1, 2]), dtype=dtype)
- expected = index_cls([-5, 0, 1, 2], dtype=dtype)
- tm.assert_index_equal(index, expected, exact=True)
- # interpret list-like
- expected = index_cls([5, 0], dtype=dtype)
- for cls in [Index, index_cls]:
- for idx in [
- cls([5, 0], dtype=dtype),
- cls(np.array([5, 0]), dtype=dtype),
- cls(Series([5, 0]), dtype=dtype),
- ]:
- tm.assert_index_equal(idx, expected)
- def test_constructor_corner(self, dtype):
- index_cls = self._index_cls
- arr = np.array([1, 2, 3, 4], dtype=object)
- index = index_cls(arr, dtype=dtype)
- assert index.values.dtype == index.dtype
- if dtype == np.int64:
- without_dtype = Index(arr)
- # as of 2.0 we do not infer a dtype when we get an object-dtype
- # ndarray of numbers, matching Series behavior
- assert without_dtype.dtype == object
- tm.assert_index_equal(index, without_dtype.astype(np.int64))
- # preventing casting
- arr = np.array([1, "2", 3, "4"], dtype=object)
- msg = "Trying to coerce float values to integers"
- with pytest.raises(ValueError, match=msg):
- index_cls(arr, dtype=dtype)
- def test_constructor_coercion_signed_to_unsigned(
- self,
- any_unsigned_int_numpy_dtype,
- ):
- # see gh-15832
- msg = "Trying to coerce negative values to unsigned integers"
- with pytest.raises(OverflowError, match=msg):
- Index([-1], dtype=any_unsigned_int_numpy_dtype)
- def test_constructor_np_signed(self, any_signed_int_numpy_dtype):
- # GH#47475
- scalar = np.dtype(any_signed_int_numpy_dtype).type(1)
- result = Index([scalar])
- expected = Index([1], dtype=any_signed_int_numpy_dtype)
- tm.assert_index_equal(result, expected, exact=True)
- def test_constructor_np_unsigned(self, any_unsigned_int_numpy_dtype):
- # GH#47475
- scalar = np.dtype(any_unsigned_int_numpy_dtype).type(1)
- result = Index([scalar])
- expected = Index([1], dtype=any_unsigned_int_numpy_dtype)
- tm.assert_index_equal(result, expected, exact=True)
- def test_coerce_list(self):
- # coerce things
- arr = Index([1, 2, 3, 4])
- assert isinstance(arr, self._index_cls)
- # but not if explicit dtype passed
- arr = Index([1, 2, 3, 4], dtype=object)
- assert type(arr) is Index
- class TestFloat16Index:
- # float 16 indexes not supported
- # GH 49535
- _index_cls = Index
- def test_constructor(self):
- index_cls = self._index_cls
- dtype = np.float16
- msg = "float16 indexes are not supported"
- # explicit construction
- with pytest.raises(NotImplementedError, match=msg):
- index_cls([1, 2, 3, 4, 5], dtype=dtype)
- with pytest.raises(NotImplementedError, match=msg):
- index_cls(np.array([1, 2, 3, 4, 5]), dtype=dtype)
- with pytest.raises(NotImplementedError, match=msg):
- index_cls([1.0, 2, 3, 4, 5], dtype=dtype)
- with pytest.raises(NotImplementedError, match=msg):
- index_cls(np.array([1.0, 2, 3, 4, 5]), dtype=dtype)
- with pytest.raises(NotImplementedError, match=msg):
- index_cls([1.0, 2, 3, 4, 5], dtype=dtype)
- with pytest.raises(NotImplementedError, match=msg):
- index_cls(np.array([1.0, 2, 3, 4, 5]), dtype=dtype)
- # nan handling
- with pytest.raises(NotImplementedError, match=msg):
- index_cls([np.nan, np.nan], dtype=dtype)
- with pytest.raises(NotImplementedError, match=msg):
- index_cls(np.array([np.nan]), dtype=dtype)
- class TestUIntNumericIndex(NumericInt):
- @pytest.fixture(params=[np.uint64])
- def dtype(self, request):
- return request.param
- @pytest.fixture
- def simple_index(self, dtype):
- # compat with shared Int64/Float64 tests
- return self._index_cls(np.arange(5, dtype=dtype))
- @pytest.fixture(
- params=[
- [2**63, 2**63 + 10, 2**63 + 15, 2**63 + 20, 2**63 + 25],
- [2**63 + 25, 2**63 + 20, 2**63 + 15, 2**63 + 10, 2**63],
- ],
- ids=["index_inc", "index_dec"],
- )
- def index(self, request):
- return self._index_cls(request.param, dtype=np.uint64)
- @pytest.mark.parametrize(
- "box",
- [list, lambda x: np.array(x, dtype=object), lambda x: Index(x, dtype=object)],
- )
- def test_uint_index_does_not_convert_to_float64(box):
- # https://github.com/pandas-dev/pandas/issues/28279
- # https://github.com/pandas-dev/pandas/issues/28023
- series = Series(
- [0, 1, 2, 3, 4, 5],
- index=[
- 7606741985629028552,
- 17876870360202815256,
- 17876870360202815256,
- 13106359306506049338,
- 8991270399732411471,
- 8991270399732411472,
- ],
- )
- result = series.loc[box([7606741985629028552, 17876870360202815256])]
- expected = Index(
- [7606741985629028552, 17876870360202815256, 17876870360202815256],
- dtype="uint64",
- )
- tm.assert_index_equal(result.index, expected)
- tm.assert_equal(result, series.iloc[:3])
- def test_float64_index_equals():
- # https://github.com/pandas-dev/pandas/issues/35217
- float_index = Index([1.0, 2, 3])
- string_index = Index(["1", "2", "3"])
- result = float_index.equals(string_index)
- assert result is False
- result = string_index.equals(float_index)
- assert result is False
- def test_map_dtype_inference_unsigned_to_signed():
- # GH#44609 cases where we don't retain dtype
- idx = Index([1, 2, 3], dtype=np.uint64)
- result = idx.map(lambda x: -x)
- expected = Index([-1, -2, -3], dtype=np.int64)
- tm.assert_index_equal(result, expected)
- def test_map_dtype_inference_overflows():
- # GH#44609 case where we have to upcast
- idx = Index(np.array([1, 2, 3], dtype=np.int8))
- result = idx.map(lambda x: x * 1000)
- # TODO: we could plausibly try to infer down to int16 here
- expected = Index([1000, 2000, 3000], dtype=np.int64)
- tm.assert_index_equal(result, expected)
|