@@ -215,7 +215,7 @@ def interpolate_array_2d(
215
215
** kwargs ,
216
216
):
217
217
"""
218
- Wrapper to dispatch to either interpolate_2d or interpolate_2d_with_fill .
218
+ Wrapper to dispatch to either interpolate_2d or _interpolate_2d_with_fill .
219
219
"""
220
220
try :
221
221
m = clean_fill_method (method )
@@ -237,7 +237,7 @@ def interpolate_array_2d(
237
237
else :
238
238
assert index is not None # for mypy
239
239
240
- interp_values = interpolate_2d_with_fill (
240
+ interp_values = _interpolate_2d_with_fill (
241
241
data = data ,
242
242
index = index ,
243
243
axis = axis ,
@@ -251,7 +251,7 @@ def interpolate_array_2d(
251
251
return interp_values
252
252
253
253
254
- def interpolate_2d_with_fill (
254
+ def _interpolate_2d_with_fill (
255
255
data : np .ndarray , # floating dtype
256
256
index : Index ,
257
257
axis : int ,
@@ -263,11 +263,11 @@ def interpolate_2d_with_fill(
263
263
** kwargs ,
264
264
) -> np .ndarray :
265
265
"""
266
- Column-wise application of interpolate_1d .
266
+ Column-wise application of _interpolate_1d .
267
267
268
268
Notes
269
269
-----
270
- The signature does differs from interpolate_1d because it only
270
+ The signature does differs from _interpolate_1d because it only
271
271
includes what is needed for Block.interpolate.
272
272
"""
273
273
# validate the interp method
@@ -276,13 +276,44 @@ def interpolate_2d_with_fill(
276
276
if is_valid_na_for_dtype (fill_value , data .dtype ):
277
277
fill_value = na_value_for_dtype (data .dtype , compat = False )
278
278
279
+ if method == "time" :
280
+ if not needs_i8_conversion (index .dtype ):
281
+ raise ValueError (
282
+ "time-weighted interpolation only works "
283
+ "on Series or DataFrames with a "
284
+ "DatetimeIndex"
285
+ )
286
+ method = "values"
287
+
288
+ valid_limit_directions = ["forward" , "backward" , "both" ]
289
+ limit_direction = limit_direction .lower ()
290
+ if limit_direction not in valid_limit_directions :
291
+ raise ValueError (
292
+ "Invalid limit_direction: expecting one of "
293
+ f"{ valid_limit_directions } , got '{ limit_direction } '."
294
+ )
295
+
296
+ if limit_area is not None :
297
+ valid_limit_areas = ["inside" , "outside" ]
298
+ limit_area = limit_area .lower ()
299
+ if limit_area not in valid_limit_areas :
300
+ raise ValueError (
301
+ f"Invalid limit_area: expecting one of { valid_limit_areas } , got "
302
+ f"{ limit_area } ."
303
+ )
304
+
305
+ # default limit is unlimited GH #16282
306
+ limit = algos .validate_limit (nobs = None , limit = limit )
307
+
308
+ indices = _index_to_interp_indices (index , method )
309
+
279
310
def func (yvalues : np .ndarray ) -> np .ndarray :
280
311
# process 1-d slices in the axis direction, returning it
281
312
282
313
# should the axis argument be handled below in apply_along_axis?
283
- # i.e. not an arg to interpolate_1d
284
- return interpolate_1d (
285
- xvalues = index ,
314
+ # i.e. not an arg to _interpolate_1d
315
+ return _interpolate_1d (
316
+ indices = indices ,
286
317
yvalues = yvalues ,
287
318
method = method ,
288
319
limit = limit ,
@@ -297,8 +328,30 @@ def func(yvalues: np.ndarray) -> np.ndarray:
297
328
return np .apply_along_axis (func , axis , data )
298
329
299
330
300
- def interpolate_1d (
301
- xvalues : Index ,
331
+ def _index_to_interp_indices (index : Index , method : str ) -> np .ndarray :
332
+ """
333
+ Convert Index to ndarray of indices to pass to NumPy/SciPy.
334
+ """
335
+ xarr = index ._values
336
+ if needs_i8_conversion (xarr .dtype ):
337
+ # GH#1646 for dt64tz
338
+ xarr = xarr .view ("i8" )
339
+
340
+ if method == "linear" :
341
+ inds = xarr
342
+ inds = cast (np .ndarray , inds )
343
+ else :
344
+ inds = np .asarray (xarr )
345
+
346
+ if method in ("values" , "index" ):
347
+ if inds .dtype == np .object_ :
348
+ inds = lib .maybe_convert_objects (inds )
349
+
350
+ return inds
351
+
352
+
353
+ def _interpolate_1d (
354
+ indices : np .ndarray ,
302
355
yvalues : np .ndarray ,
303
356
method : str | None = "linear" ,
304
357
limit : int | None = None ,
@@ -311,51 +364,23 @@ def interpolate_1d(
311
364
):
312
365
"""
313
366
Logic for the 1-d interpolation. The result should be 1-d, inputs
314
- xvalues and yvalues will each be 1-d arrays of the same length.
367
+ indices and yvalues will each be 1-d arrays of the same length.
315
368
316
369
Bounds_error is currently hardcoded to False since non-scipy ones don't
317
370
take it as an argument.
318
371
"""
372
+
319
373
invalid = isna (yvalues )
320
374
valid = ~ invalid
321
375
322
376
if not valid .any ():
323
- result = np .empty (xvalues .shape , dtype = np .float64 )
377
+ result = np .empty (indices .shape , dtype = np .float64 )
324
378
result .fill (np .nan )
325
379
return result
326
380
327
381
if valid .all ():
328
382
return yvalues
329
383
330
- if method == "time" :
331
- if not needs_i8_conversion (xvalues .dtype ):
332
- raise ValueError (
333
- "time-weighted interpolation only works "
334
- "on Series or DataFrames with a "
335
- "DatetimeIndex"
336
- )
337
- method = "values"
338
-
339
- valid_limit_directions = ["forward" , "backward" , "both" ]
340
- limit_direction = limit_direction .lower ()
341
- if limit_direction not in valid_limit_directions :
342
- raise ValueError (
343
- "Invalid limit_direction: expecting one of "
344
- f"{ valid_limit_directions } , got '{ limit_direction } '."
345
- )
346
-
347
- if limit_area is not None :
348
- valid_limit_areas = ["inside" , "outside" ]
349
- limit_area = limit_area .lower ()
350
- if limit_area not in valid_limit_areas :
351
- raise ValueError (
352
- f"Invalid limit_area: expecting one of { valid_limit_areas } , got "
353
- f"{ limit_area } ."
354
- )
355
-
356
- # default limit is unlimited GH #16282
357
- limit = algos .validate_limit (nobs = None , limit = limit )
358
-
359
384
# These are sets of index pointers to invalid values... i.e. {0, 1, etc...
360
385
all_nans = set (np .flatnonzero (invalid ))
361
386
@@ -369,8 +394,6 @@ def interpolate_1d(
369
394
last_valid_index = len (yvalues )
370
395
end_nans = set (range (1 + last_valid_index , len (valid )))
371
396
372
- mid_nans = all_nans - start_nans - end_nans
373
-
374
397
# Like the sets above, preserve_nans contains indices of invalid values,
375
398
# but in this case, it is the final set of indices that need to be
376
399
# preserved as NaN after the interpolation.
@@ -396,44 +419,26 @@ def interpolate_1d(
396
419
preserve_nans |= start_nans | end_nans
397
420
elif limit_area == "outside" :
398
421
# preserve NaNs on the inside
422
+ mid_nans = all_nans - start_nans - end_nans
399
423
preserve_nans |= mid_nans
400
424
401
425
# sort preserve_nans and convert to list
402
426
preserve_nans = sorted (preserve_nans )
403
427
404
428
result = yvalues .copy ()
405
429
406
- # xarr to pass to NumPy/SciPy
407
- xarr = xvalues ._values
408
- if needs_i8_conversion (xarr .dtype ):
409
- # GH#1646 for dt64tz
410
- xarr = xarr .view ("i8" )
411
-
412
- if method == "linear" :
413
- inds = xarr
414
- else :
415
- inds = np .asarray (xarr )
416
-
417
- if method in ("values" , "index" ):
418
- if inds .dtype == np .object_ :
419
- inds = lib .maybe_convert_objects (inds )
420
-
421
430
if method in NP_METHODS :
422
431
# np.interp requires sorted X values, #21037
423
432
424
- # error: Argument 1 to "argsort" has incompatible type "Union[ExtensionArray,
425
- # Any]"; expected "Union[Union[int, float, complex, str, bytes, generic],
426
- # Sequence[Union[int, float, complex, str, bytes, generic]],
427
- # Sequence[Sequence[Any]], _SupportsArray]"
428
- indexer = np .argsort (inds [valid ]) # type: ignore[arg-type]
433
+ indexer = np .argsort (indices [valid ])
429
434
result [invalid ] = np .interp (
430
- inds [invalid ], inds [valid ][indexer ], yvalues [valid ][indexer ]
435
+ indices [invalid ], indices [valid ][indexer ], yvalues [valid ][indexer ]
431
436
)
432
437
else :
433
438
result [invalid ] = _interpolate_scipy_wrapper (
434
- inds [valid ],
439
+ indices [valid ],
435
440
yvalues [valid ],
436
- inds [invalid ],
441
+ indices [invalid ],
437
442
method = method ,
438
443
fill_value = fill_value ,
439
444
bounds_error = bounds_error ,
0 commit comments