11import numpy as np
22import pytest
33
4- from pandas import Float64Index , Index , Int64Index , Series , UInt64Index
4+ from pandas import Float64Index , Index , Int64Index , RangeIndex , Series , UInt64Index
55import pandas ._testing as tm
66
77
@@ -13,6 +13,54 @@ def index_large():
1313
1414
1515class TestGetLoc :
16+ @pytest .mark .parametrize ("method" , [None , "pad" , "backfill" , "nearest" ])
17+ def test_get_loc (self , method ):
18+ index = Index ([0 , 1 , 2 ])
19+ assert index .get_loc (1 , method = method ) == 1
20+
21+ if method :
22+ assert index .get_loc (1 , method = method , tolerance = 0 ) == 1
23+
24+ @pytest .mark .parametrize ("method" , [None , "pad" , "backfill" , "nearest" ])
25+ def test_get_loc_raises_bad_label (self , method ):
26+ index = Index ([0 , 1 , 2 ])
27+ if method :
28+ msg = "not supported between"
29+ else :
30+ msg = "invalid key"
31+
32+ with pytest .raises (TypeError , match = msg ):
33+ index .get_loc ([1 , 2 ], method = method )
34+
35+ @pytest .mark .parametrize (
36+ "method,loc" , [("pad" , 1 ), ("backfill" , 2 ), ("nearest" , 1 )]
37+ )
38+ def test_get_loc_tolerance (self , method , loc ):
39+ index = Index ([0 , 1 , 2 ])
40+ assert index .get_loc (1.1 , method ) == loc
41+ assert index .get_loc (1.1 , method , tolerance = 1 ) == loc
42+
43+ @pytest .mark .parametrize ("method" , ["pad" , "backfill" , "nearest" ])
44+ def test_get_loc_outside_tolerance_raises (self , method ):
45+ index = Index ([0 , 1 , 2 ])
46+ with pytest .raises (KeyError , match = "1.1" ):
47+ index .get_loc (1.1 , method , tolerance = 0.05 )
48+
49+ def test_get_loc_bad_tolerance_raises (self ):
50+ index = Index ([0 , 1 , 2 ])
51+ with pytest .raises (ValueError , match = "must be numeric" ):
52+ index .get_loc (1.1 , "nearest" , tolerance = "invalid" )
53+
54+ def test_get_loc_tolerance_no_method_raises (self ):
55+ index = Index ([0 , 1 , 2 ])
56+ with pytest .raises (ValueError , match = "tolerance .* valid if" ):
57+ index .get_loc (1.1 , tolerance = 1 )
58+
59+ def test_get_loc_raises_missized_tolerance (self ):
60+ index = Index ([0 , 1 , 2 ])
61+ with pytest .raises (ValueError , match = "tolerance size must match" ):
62+ index .get_loc (1.1 , "nearest" , tolerance = [1 , 1 ])
63+
1664 def test_get_loc_float64 (self ):
1765 idx = Float64Index ([0.0 , 1.0 , 2.0 ])
1866 for method in [None , "pad" , "backfill" , "nearest" ]:
@@ -82,6 +130,131 @@ def test_get_loc_missing_nan(self):
82130
83131
84132class TestGetIndexer :
133+ def test_get_indexer (self ):
134+ index1 = Index ([1 , 2 , 3 , 4 , 5 ])
135+ index2 = Index ([2 , 4 , 6 ])
136+
137+ r1 = index1 .get_indexer (index2 )
138+ e1 = np .array ([1 , 3 , - 1 ], dtype = np .intp )
139+ tm .assert_almost_equal (r1 , e1 )
140+
141+ @pytest .mark .parametrize ("reverse" , [True , False ])
142+ @pytest .mark .parametrize (
143+ "expected,method" ,
144+ [
145+ (np .array ([- 1 , 0 , 0 , 1 , 1 ], dtype = np .intp ), "pad" ),
146+ (np .array ([- 1 , 0 , 0 , 1 , 1 ], dtype = np .intp ), "ffill" ),
147+ (np .array ([0 , 0 , 1 , 1 , 2 ], dtype = np .intp ), "backfill" ),
148+ (np .array ([0 , 0 , 1 , 1 , 2 ], dtype = np .intp ), "bfill" ),
149+ ],
150+ )
151+ def test_get_indexer_methods (self , reverse , expected , method ):
152+ index1 = Index ([1 , 2 , 3 , 4 , 5 ])
153+ index2 = Index ([2 , 4 , 6 ])
154+
155+ if reverse :
156+ index1 = index1 [::- 1 ]
157+ expected = expected [::- 1 ]
158+
159+ result = index2 .get_indexer (index1 , method = method )
160+ tm .assert_almost_equal (result , expected )
161+
162+ def test_get_indexer_invalid (self ):
163+ # GH10411
164+ index = Index (np .arange (10 ))
165+
166+ with pytest .raises (ValueError , match = "tolerance argument" ):
167+ index .get_indexer ([1 , 0 ], tolerance = 1 )
168+
169+ with pytest .raises (ValueError , match = "limit argument" ):
170+ index .get_indexer ([1 , 0 ], limit = 1 )
171+
172+ @pytest .mark .parametrize (
173+ "method, tolerance, indexer, expected" ,
174+ [
175+ ("pad" , None , [0 , 5 , 9 ], [0 , 5 , 9 ]),
176+ ("backfill" , None , [0 , 5 , 9 ], [0 , 5 , 9 ]),
177+ ("nearest" , None , [0 , 5 , 9 ], [0 , 5 , 9 ]),
178+ ("pad" , 0 , [0 , 5 , 9 ], [0 , 5 , 9 ]),
179+ ("backfill" , 0 , [0 , 5 , 9 ], [0 , 5 , 9 ]),
180+ ("nearest" , 0 , [0 , 5 , 9 ], [0 , 5 , 9 ]),
181+ ("pad" , None , [0.2 , 1.8 , 8.5 ], [0 , 1 , 8 ]),
182+ ("backfill" , None , [0.2 , 1.8 , 8.5 ], [1 , 2 , 9 ]),
183+ ("nearest" , None , [0.2 , 1.8 , 8.5 ], [0 , 2 , 9 ]),
184+ ("pad" , 1 , [0.2 , 1.8 , 8.5 ], [0 , 1 , 8 ]),
185+ ("backfill" , 1 , [0.2 , 1.8 , 8.5 ], [1 , 2 , 9 ]),
186+ ("nearest" , 1 , [0.2 , 1.8 , 8.5 ], [0 , 2 , 9 ]),
187+ ("pad" , 0.2 , [0.2 , 1.8 , 8.5 ], [0 , - 1 , - 1 ]),
188+ ("backfill" , 0.2 , [0.2 , 1.8 , 8.5 ], [- 1 , 2 , - 1 ]),
189+ ("nearest" , 0.2 , [0.2 , 1.8 , 8.5 ], [0 , 2 , - 1 ]),
190+ ],
191+ )
192+ def test_get_indexer_nearest (self , method , tolerance , indexer , expected ):
193+ index = Index (np .arange (10 ))
194+
195+ actual = index .get_indexer (indexer , method = method , tolerance = tolerance )
196+ tm .assert_numpy_array_equal (actual , np .array (expected , dtype = np .intp ))
197+
198+ @pytest .mark .parametrize ("listtype" , [list , tuple , Series , np .array ])
199+ @pytest .mark .parametrize (
200+ "tolerance, expected" ,
201+ list (
202+ zip (
203+ [[0.3 , 0.3 , 0.1 ], [0.2 , 0.1 , 0.1 ], [0.1 , 0.5 , 0.5 ]],
204+ [[0 , 2 , - 1 ], [0 , - 1 , - 1 ], [- 1 , 2 , 9 ]],
205+ )
206+ ),
207+ )
208+ def test_get_indexer_nearest_listlike_tolerance (
209+ self , tolerance , expected , listtype
210+ ):
211+ index = Index (np .arange (10 ))
212+
213+ actual = index .get_indexer (
214+ [0.2 , 1.8 , 8.5 ], method = "nearest" , tolerance = listtype (tolerance )
215+ )
216+ tm .assert_numpy_array_equal (actual , np .array (expected , dtype = np .intp ))
217+
218+ def test_get_indexer_nearest_error (self ):
219+ index = Index (np .arange (10 ))
220+ with pytest .raises (ValueError , match = "limit argument" ):
221+ index .get_indexer ([1 , 0 ], method = "nearest" , limit = 1 )
222+
223+ with pytest .raises (ValueError , match = "tolerance size must match" ):
224+ index .get_indexer ([1 , 0 ], method = "nearest" , tolerance = [1 , 2 , 3 ])
225+
226+ @pytest .mark .parametrize (
227+ "method,expected" ,
228+ [("pad" , [8 , 7 , 0 ]), ("backfill" , [9 , 8 , 1 ]), ("nearest" , [9 , 7 , 0 ])],
229+ )
230+ def test_get_indexer_nearest_decreasing (self , method , expected ):
231+ index = Index (np .arange (10 ))[::- 1 ]
232+
233+ actual = index .get_indexer ([0 , 5 , 9 ], method = method )
234+ tm .assert_numpy_array_equal (actual , np .array ([9 , 4 , 0 ], dtype = np .intp ))
235+
236+ actual = index .get_indexer ([0.2 , 1.8 , 8.5 ], method = method )
237+ tm .assert_numpy_array_equal (actual , np .array (expected , dtype = np .intp ))
238+
239+ @pytest .mark .parametrize (
240+ "idx_class" , [Int64Index , RangeIndex , Float64Index , UInt64Index ]
241+ )
242+ @pytest .mark .parametrize ("method" , ["get_indexer" , "get_indexer_non_unique" ])
243+ def test_get_indexer_numeric_index_boolean_target (self , method , idx_class ):
244+ # GH 16877
245+
246+ numeric_index = idx_class (RangeIndex (4 ))
247+ other = Index ([True , False , True ])
248+
249+ result = getattr (numeric_index , method )(other )
250+ expected = np .array ([- 1 , - 1 , - 1 ], dtype = np .intp )
251+ if method == "get_indexer" :
252+ tm .assert_numpy_array_equal (result , expected )
253+ else :
254+ missing = np .arange (3 , dtype = np .intp )
255+ tm .assert_numpy_array_equal (result [0 ], expected )
256+ tm .assert_numpy_array_equal (result [1 ], missing )
257+
85258 @pytest .mark .parametrize ("method" , ["pad" , "backfill" , "nearest" ])
86259 def test_get_indexer_with_method_numeric_vs_bool (self , method ):
87260 left = Index ([1 , 2 , 3 ])
@@ -274,6 +447,62 @@ def test_contains_float64_not_nans(self):
274447 assert 1.0 in index
275448
276449
450+ class TestSliceLocs :
451+ @pytest .mark .parametrize ("dtype" , [int , float ])
452+ def test_slice_locs (self , dtype ):
453+ index = Index (np .array ([0 , 1 , 2 , 5 , 6 , 7 , 9 , 10 ], dtype = dtype ))
454+ n = len (index )
455+
456+ assert index .slice_locs (start = 2 ) == (2 , n )
457+ assert index .slice_locs (start = 3 ) == (3 , n )
458+ assert index .slice_locs (3 , 8 ) == (3 , 6 )
459+ assert index .slice_locs (5 , 10 ) == (3 , n )
460+ assert index .slice_locs (end = 8 ) == (0 , 6 )
461+ assert index .slice_locs (end = 9 ) == (0 , 7 )
462+
463+ # reversed
464+ index2 = index [::- 1 ]
465+ assert index2 .slice_locs (8 , 2 ) == (2 , 6 )
466+ assert index2 .slice_locs (7 , 3 ) == (2 , 5 )
467+
468+ @pytest .mark .parametrize ("dtype" , [int , float ])
469+ def test_slice_locs_float_locs (self , dtype ):
470+ index = Index (np .array ([0 , 1 , 2 , 5 , 6 , 7 , 9 , 10 ], dtype = dtype ))
471+ n = len (index )
472+ assert index .slice_locs (5.0 , 10.0 ) == (3 , n )
473+ assert index .slice_locs (4.5 , 10.5 ) == (3 , 8 )
474+
475+ index2 = index [::- 1 ]
476+ assert index2 .slice_locs (8.5 , 1.5 ) == (2 , 6 )
477+ assert index2 .slice_locs (10.5 , - 1 ) == (0 , n )
478+
479+ @pytest .mark .parametrize ("dtype" , [int , float ])
480+ def test_slice_locs_dup_numeric (self , dtype ):
481+ index = Index (np .array ([10 , 12 , 12 , 14 ], dtype = dtype ))
482+ assert index .slice_locs (12 , 12 ) == (1 , 3 )
483+ assert index .slice_locs (11 , 13 ) == (1 , 3 )
484+
485+ index2 = index [::- 1 ]
486+ assert index2 .slice_locs (12 , 12 ) == (1 , 3 )
487+ assert index2 .slice_locs (13 , 11 ) == (1 , 3 )
488+
489+ def test_slice_locs_na (self ):
490+ index = Index ([np .nan , 1 , 2 ])
491+ assert index .slice_locs (1 ) == (1 , 3 )
492+ assert index .slice_locs (np .nan ) == (0 , 3 )
493+
494+ index = Index ([0 , np .nan , np .nan , 1 , 2 ])
495+ assert index .slice_locs (np .nan ) == (1 , 5 )
496+
497+ def test_slice_locs_na_raises (self ):
498+ index = Index ([np .nan , 1 , 2 ])
499+ with pytest .raises (KeyError , match = "" ):
500+ index .slice_locs (start = 1.5 )
501+
502+ with pytest .raises (KeyError , match = "" ):
503+ index .slice_locs (end = 1.5 )
504+
505+
277506class TestGetSliceBounds :
278507 @pytest .mark .parametrize ("kind" , ["getitem" , "loc" , None ])
279508 @pytest .mark .parametrize ("side, expected" , [("left" , 4 ), ("right" , 5 )])
0 commit comments