Skip to content

Commit def6f6d

Browse files
authored
REF: numeric index test_indexing (#33387)
1 parent 87a1cc2 commit def6f6d

File tree

2 files changed

+241
-205
lines changed

2 files changed

+241
-205
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
import numpy as np
2+
import pytest
3+
4+
from pandas import Float64Index, Int64Index, Series, UInt64Index
5+
import pandas._testing as tm
6+
7+
8+
@pytest.fixture
9+
def index_large():
10+
# large values used in UInt64Index tests where no compat needed with Int64/Float64
11+
large = [2 ** 63, 2 ** 63 + 10, 2 ** 63 + 15, 2 ** 63 + 20, 2 ** 63 + 25]
12+
return UInt64Index(large)
13+
14+
15+
class TestGetLoc:
16+
def test_get_loc_float64(self):
17+
idx = Float64Index([0.0, 1.0, 2.0])
18+
for method in [None, "pad", "backfill", "nearest"]:
19+
assert idx.get_loc(1, method) == 1
20+
if method is not None:
21+
assert idx.get_loc(1, method, tolerance=0) == 1
22+
23+
for method, loc in [("pad", 1), ("backfill", 2), ("nearest", 1)]:
24+
assert idx.get_loc(1.1, method) == loc
25+
assert idx.get_loc(1.1, method, tolerance=0.9) == loc
26+
27+
with pytest.raises(KeyError, match="^'foo'$"):
28+
idx.get_loc("foo")
29+
with pytest.raises(KeyError, match=r"^1\.5$"):
30+
idx.get_loc(1.5)
31+
with pytest.raises(KeyError, match=r"^1\.5$"):
32+
idx.get_loc(1.5, method="pad", tolerance=0.1)
33+
with pytest.raises(KeyError, match="^True$"):
34+
idx.get_loc(True)
35+
with pytest.raises(KeyError, match="^False$"):
36+
idx.get_loc(False)
37+
38+
with pytest.raises(ValueError, match="must be numeric"):
39+
idx.get_loc(1.4, method="nearest", tolerance="foo")
40+
41+
with pytest.raises(ValueError, match="must contain numeric elements"):
42+
idx.get_loc(1.4, method="nearest", tolerance=np.array(["foo"]))
43+
44+
with pytest.raises(
45+
ValueError, match="tolerance size must match target index size"
46+
):
47+
idx.get_loc(1.4, method="nearest", tolerance=np.array([1, 2]))
48+
49+
def test_get_loc_na(self):
50+
idx = Float64Index([np.nan, 1, 2])
51+
assert idx.get_loc(1) == 1
52+
assert idx.get_loc(np.nan) == 0
53+
54+
idx = Float64Index([np.nan, 1, np.nan])
55+
assert idx.get_loc(1) == 1
56+
57+
# FIXME: dont leave commented-out
58+
# representable by slice [0:2:2]
59+
# pytest.raises(KeyError, idx.slice_locs, np.nan)
60+
sliced = idx.slice_locs(np.nan)
61+
assert isinstance(sliced, tuple)
62+
assert sliced == (0, 3)
63+
64+
# not representable by slice
65+
idx = Float64Index([np.nan, 1, np.nan, np.nan])
66+
assert idx.get_loc(1) == 1
67+
msg = "'Cannot get left slice bound for non-unique label: nan"
68+
with pytest.raises(KeyError, match=msg):
69+
idx.slice_locs(np.nan)
70+
71+
def test_get_loc_missing_nan(self):
72+
# GH#8569
73+
idx = Float64Index([1, 2])
74+
assert idx.get_loc(1) == 0
75+
with pytest.raises(KeyError, match=r"^3$"):
76+
idx.get_loc(3)
77+
with pytest.raises(KeyError, match="^nan$"):
78+
idx.get_loc(np.nan)
79+
with pytest.raises(TypeError, match=r"'\[nan\]' is an invalid key"):
80+
# listlike/non-hashable raises TypeError
81+
idx.get_loc([np.nan])
82+
83+
84+
class TestGetIndexer:
85+
def test_get_indexer_float64(self):
86+
idx = Float64Index([0.0, 1.0, 2.0])
87+
tm.assert_numpy_array_equal(
88+
idx.get_indexer(idx), np.array([0, 1, 2], dtype=np.intp)
89+
)
90+
91+
target = [-0.1, 0.5, 1.1]
92+
tm.assert_numpy_array_equal(
93+
idx.get_indexer(target, "pad"), np.array([-1, 0, 1], dtype=np.intp)
94+
)
95+
tm.assert_numpy_array_equal(
96+
idx.get_indexer(target, "backfill"), np.array([0, 1, 2], dtype=np.intp)
97+
)
98+
tm.assert_numpy_array_equal(
99+
idx.get_indexer(target, "nearest"), np.array([0, 1, 1], dtype=np.intp)
100+
)
101+
102+
def test_get_indexer_nan(self):
103+
# GH#7820
104+
result = Float64Index([1, 2, np.nan]).get_indexer([np.nan])
105+
expected = np.array([2], dtype=np.intp)
106+
tm.assert_numpy_array_equal(result, expected)
107+
108+
def test_get_indexer_int64(self):
109+
index = Int64Index(range(0, 20, 2))
110+
target = Int64Index(np.arange(10))
111+
indexer = index.get_indexer(target)
112+
expected = np.array([0, -1, 1, -1, 2, -1, 3, -1, 4, -1], dtype=np.intp)
113+
tm.assert_numpy_array_equal(indexer, expected)
114+
115+
target = Int64Index(np.arange(10))
116+
indexer = index.get_indexer(target, method="pad")
117+
expected = np.array([0, 0, 1, 1, 2, 2, 3, 3, 4, 4], dtype=np.intp)
118+
tm.assert_numpy_array_equal(indexer, expected)
119+
120+
target = Int64Index(np.arange(10))
121+
indexer = index.get_indexer(target, method="backfill")
122+
expected = np.array([0, 1, 1, 2, 2, 3, 3, 4, 4, 5], dtype=np.intp)
123+
tm.assert_numpy_array_equal(indexer, expected)
124+
125+
def test_get_indexer_uint64(self, index_large):
126+
target = UInt64Index(np.arange(10).astype("uint64") * 5 + 2 ** 63)
127+
indexer = index_large.get_indexer(target)
128+
expected = np.array([0, -1, 1, 2, 3, 4, -1, -1, -1, -1], dtype=np.intp)
129+
tm.assert_numpy_array_equal(indexer, expected)
130+
131+
target = UInt64Index(np.arange(10).astype("uint64") * 5 + 2 ** 63)
132+
indexer = index_large.get_indexer(target, method="pad")
133+
expected = np.array([0, 0, 1, 2, 3, 4, 4, 4, 4, 4], dtype=np.intp)
134+
tm.assert_numpy_array_equal(indexer, expected)
135+
136+
target = UInt64Index(np.arange(10).astype("uint64") * 5 + 2 ** 63)
137+
indexer = index_large.get_indexer(target, method="backfill")
138+
expected = np.array([0, 1, 1, 2, 3, 4, -1, -1, -1, -1], dtype=np.intp)
139+
tm.assert_numpy_array_equal(indexer, expected)
140+
141+
142+
class TestWhere:
143+
@pytest.mark.parametrize(
144+
"index",
145+
[
146+
Float64Index(np.arange(5, dtype="float64")),
147+
Int64Index(range(0, 20, 2)),
148+
UInt64Index(np.arange(5, dtype="uint64")),
149+
],
150+
)
151+
@pytest.mark.parametrize("klass", [list, tuple, np.array, Series])
152+
def test_where(self, klass, index):
153+
cond = [True] * len(index)
154+
expected = index
155+
result = index.where(klass(cond))
156+
157+
cond = [False] + [True] * (len(index) - 1)
158+
expected = Float64Index([index._na_value] + index[1:].tolist())
159+
result = index.where(klass(cond))
160+
tm.assert_index_equal(result, expected)
161+
162+
163+
class TestTake:
164+
@pytest.mark.parametrize("klass", [Float64Index, Int64Index, UInt64Index])
165+
def test_take_preserve_name(self, klass):
166+
index = klass([1, 2, 3, 4], name="foo")
167+
taken = index.take([3, 0, 1])
168+
assert index.name == taken.name
169+
170+
def test_take_fill_value_float64(self):
171+
# GH 12631
172+
idx = Float64Index([1.0, 2.0, 3.0], name="xxx")
173+
result = idx.take(np.array([1, 0, -1]))
174+
expected = Float64Index([2.0, 1.0, 3.0], name="xxx")
175+
tm.assert_index_equal(result, expected)
176+
177+
# fill_value
178+
result = idx.take(np.array([1, 0, -1]), fill_value=True)
179+
expected = Float64Index([2.0, 1.0, np.nan], name="xxx")
180+
tm.assert_index_equal(result, expected)
181+
182+
# allow_fill=False
183+
result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
184+
expected = Float64Index([2.0, 1.0, 3.0], name="xxx")
185+
tm.assert_index_equal(result, expected)
186+
187+
msg = (
188+
"When allow_fill=True and fill_value is not None, "
189+
"all indices must be >= -1"
190+
)
191+
with pytest.raises(ValueError, match=msg):
192+
idx.take(np.array([1, 0, -2]), fill_value=True)
193+
with pytest.raises(ValueError, match=msg):
194+
idx.take(np.array([1, 0, -5]), fill_value=True)
195+
196+
msg = "index -5 is out of bounds for (axis 0 with )?size 3"
197+
with pytest.raises(IndexError, match=msg):
198+
idx.take(np.array([1, -5]))
199+
200+
@pytest.mark.parametrize("klass", [Int64Index, UInt64Index])
201+
def test_take_fill_value_ints(self, klass):
202+
# see gh-12631
203+
idx = klass([1, 2, 3], name="xxx")
204+
result = idx.take(np.array([1, 0, -1]))
205+
expected = klass([2, 1, 3], name="xxx")
206+
tm.assert_index_equal(result, expected)
207+
208+
name = klass.__name__
209+
msg = f"Unable to fill values because {name} cannot contain NA"
210+
211+
# fill_value=True
212+
with pytest.raises(ValueError, match=msg):
213+
idx.take(np.array([1, 0, -1]), fill_value=True)
214+
215+
# allow_fill=False
216+
result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
217+
expected = klass([2, 1, 3], name="xxx")
218+
tm.assert_index_equal(result, expected)
219+
220+
with pytest.raises(ValueError, match=msg):
221+
idx.take(np.array([1, 0, -2]), fill_value=True)
222+
with pytest.raises(ValueError, match=msg):
223+
idx.take(np.array([1, 0, -5]), fill_value=True)
224+
225+
msg = "index -5 is out of bounds for (axis 0 with )?size 3"
226+
with pytest.raises(IndexError, match=msg):
227+
idx.take(np.array([1, -5]))
228+
229+
230+
class TestContains:
231+
def test_contains_float64_nans(self):
232+
index = Float64Index([1.0, 2.0, np.nan])
233+
assert np.nan in index
234+
235+
def test_contains_float64_not_nans(self):
236+
index = Float64Index([1.0, 2.0, np.nan])
237+
assert 1.0 in index

0 commit comments

Comments
 (0)