@@ -1244,6 +1244,153 @@ def backfill_2d(values, limit=None, mask=None):
1244
1244
return values
1245
1245
1246
1246
1247
+ def _clean_interp_method (method , order = None , ** kwargs ):
1248
+ valid = ['linear' , 'time' , 'values' , 'nearest' , 'zero' , 'slinear' ,
1249
+ 'quadratic' , 'cubic' , 'barycentric' , 'polynomial' ,
1250
+ 'krogh' , 'piecewise_polynomial' ,
1251
+ 'pchip' , 'spline' ]
1252
+ if method in ('spline' , 'polynomial' ) and order is None :
1253
+ raise ValueError ("You must specify the order of the spline or "
1254
+ "polynomial." )
1255
+ if method not in valid :
1256
+ raise ValueError ("method must be one of {0}."
1257
+ "Got '{1}' instead." .format (valid , method ))
1258
+ return method
1259
+
1260
+
1261
+ def interpolate_1d (xvalues , yvalues , method = 'linear' , limit = None ,
1262
+ fill_value = None , bounds_error = False , ** kwargs ):
1263
+ """
1264
+ Logic for the 1-d interpolation. The result should be 1-d, inputs
1265
+ xvalues and yvalues will each be 1-d arrays of the same length.
1266
+
1267
+ Bounds_error is currently hardcoded to False since non-scipy ones don't
1268
+ take it as an argumnet.
1269
+ """
1270
+ # Treat the original, non-scipy methods first.
1271
+
1272
+ invalid = isnull (yvalues )
1273
+ valid = ~ invalid
1274
+
1275
+ valid_y = yvalues [valid ]
1276
+ valid_x = xvalues [valid ]
1277
+ new_x = xvalues [invalid ]
1278
+
1279
+ if method == 'time' :
1280
+ if not getattr (xvalues , 'is_all_dates' , None ):
1281
+ # if not issubclass(xvalues.dtype.type, np.datetime64):
1282
+ raise ValueError ('time-weighted interpolation only works '
1283
+ 'on Series or DataFrames with a '
1284
+ 'DatetimeIndex' )
1285
+ method = 'values'
1286
+
1287
+ def _interp_limit (invalid , limit ):
1288
+ """mask off values that won't be filled since they exceed the limit"""
1289
+ all_nans = np .where (invalid )[0 ]
1290
+ violate = [invalid [x :x + limit + 1 ] for x in all_nans ]
1291
+ violate = np .array ([x .all () & (x .size > limit ) for x in violate ])
1292
+ return all_nans [violate ] + limit
1293
+
1294
+ xvalues = getattr (xvalues , 'values' , xvalues )
1295
+ yvalues = getattr (yvalues , 'values' , yvalues )
1296
+
1297
+ if limit :
1298
+ violate_limit = _interp_limit (invalid , limit )
1299
+ if valid .any ():
1300
+ firstIndex = valid .argmax ()
1301
+ valid = valid [firstIndex :]
1302
+ invalid = invalid [firstIndex :]
1303
+ result = yvalues .copy ()
1304
+ if valid .all ():
1305
+ return yvalues
1306
+ else :
1307
+ # have to call np.array(xvalues) since xvalues could be an Index
1308
+ # which cant be mutated
1309
+ result = np .empty_like (np .array (xvalues ), dtype = np .float64 )
1310
+ result .fill (np .nan )
1311
+ return result
1312
+
1313
+ if method in ['linear' , 'time' , 'values' ]:
1314
+ if method in ('values' , 'index' ):
1315
+ inds = np .asarray (xvalues )
1316
+ # hack for DatetimeIndex, #1646
1317
+ if issubclass (inds .dtype .type , np .datetime64 ):
1318
+ inds = inds .view (pa .int64 )
1319
+
1320
+ if inds .dtype == np .object_ :
1321
+ inds = lib .maybe_convert_objects (inds )
1322
+ else :
1323
+ inds = xvalues
1324
+
1325
+ inds = inds [firstIndex :]
1326
+
1327
+ result [firstIndex :][invalid ] = np .interp (inds [invalid ], inds [valid ],
1328
+ yvalues [firstIndex :][valid ])
1329
+
1330
+ if limit :
1331
+ result [violate_limit ] = np .nan
1332
+ return result
1333
+
1334
+ sp_methods = ['nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ,
1335
+ 'barycentric' , 'krogh' , 'spline' , 'polynomial' ,
1336
+ 'piecewise_polynomial' , 'pchip' ]
1337
+ if method in sp_methods :
1338
+ new_x = new_x [firstIndex :]
1339
+ xvalues = xvalues [firstIndex :]
1340
+
1341
+ result [firstIndex :][invalid ] = _interpolate_scipy_wrapper (valid_x ,
1342
+ valid_y , new_x , method = method , fill_value = fill_value ,
1343
+ bounds_error = bounds_error , ** kwargs )
1344
+ if limit :
1345
+ result [violate_limit ] = np .nan
1346
+ return result
1347
+
1348
+
1349
+ def _interpolate_scipy_wrapper (x , y , new_x , method , fill_value = None ,
1350
+ bounds_error = False , order = None , ** kwargs ):
1351
+ """
1352
+ passed off to scipy.interpolate.interp1d. method is scipy's kind.
1353
+ Returns an array interpolated at new_x. Add any new methods to
1354
+ the list in _clean_interp_method
1355
+ """
1356
+ try :
1357
+ from scipy import interpolate
1358
+ except ImportError :
1359
+ raise ImportError ('{0} interpolation requires Scipy' .format (method ))
1360
+
1361
+ new_x = np .asarray (new_x )
1362
+
1363
+ # ignores some kwargs that could be passed along.
1364
+ alt_methods = {
1365
+ 'barycentric' : interpolate .barycentric_interpolate ,
1366
+ 'krogh' : interpolate .krogh_interpolate ,
1367
+ 'piecewise_polynomial' : interpolate .piecewise_polynomial_interpolate ,
1368
+ }
1369
+
1370
+ try :
1371
+ alt_methods ['pchip' ] = interpolate .pchip_interpolate
1372
+ except AttributeError :
1373
+ if method == 'pchip' :
1374
+ raise ImportError ("Your version of scipy does not support "
1375
+ "PCHIP interpolation." )
1376
+
1377
+ interp1d_methods = ['nearest' , 'zero' , 'slinear' , 'quadratic' , 'cubic' ,
1378
+ 'polynomial' ]
1379
+ if method in interp1d_methods :
1380
+ if method == 'polynomial' :
1381
+ method = order
1382
+ terp = interpolate .interp1d (x , y , kind = method , fill_value = fill_value ,
1383
+ bounds_error = bounds_error )
1384
+ new_y = terp (new_x )
1385
+ elif method == 'spline' :
1386
+ terp = interpolate .UnivariateSpline (x , y , k = order )
1387
+ new_y = terp (new_x )
1388
+ else :
1389
+ method = alt_methods [method ]
1390
+ new_y = method (x , y , new_x )
1391
+ return new_y
1392
+
1393
+
1247
1394
def interpolate_2d (values , method = 'pad' , axis = 0 , limit = None , fill_value = None ):
1248
1395
""" perform an actual interpolation of values, values will be make 2-d if needed
1249
1396
fills inplace, returns the result """
0 commit comments