test_interpolate.py 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823
  1. import numpy as np
  2. import pytest
  3. import pandas.util._test_decorators as td
  4. import pandas as pd
  5. from pandas import (
  6. Index,
  7. MultiIndex,
  8. Series,
  9. date_range,
  10. isna,
  11. )
  12. import pandas._testing as tm
  13. @pytest.fixture(
  14. params=[
  15. "linear",
  16. "index",
  17. "values",
  18. "nearest",
  19. "slinear",
  20. "zero",
  21. "quadratic",
  22. "cubic",
  23. "barycentric",
  24. "krogh",
  25. "polynomial",
  26. "spline",
  27. "piecewise_polynomial",
  28. "from_derivatives",
  29. "pchip",
  30. "akima",
  31. "cubicspline",
  32. ]
  33. )
  34. def nontemporal_method(request):
  35. """Fixture that returns an (method name, required kwargs) pair.
  36. This fixture does not include method 'time' as a parameterization; that
  37. method requires a Series with a DatetimeIndex, and is generally tested
  38. separately from these non-temporal methods.
  39. """
  40. method = request.param
  41. kwargs = {"order": 1} if method in ("spline", "polynomial") else {}
  42. return method, kwargs
  43. @pytest.fixture(
  44. params=[
  45. "linear",
  46. "slinear",
  47. "zero",
  48. "quadratic",
  49. "cubic",
  50. "barycentric",
  51. "krogh",
  52. "polynomial",
  53. "spline",
  54. "piecewise_polynomial",
  55. "from_derivatives",
  56. "pchip",
  57. "akima",
  58. "cubicspline",
  59. ]
  60. )
  61. def interp_methods_ind(request):
  62. """Fixture that returns a (method name, required kwargs) pair to
  63. be tested for various Index types.
  64. This fixture does not include methods - 'time', 'index', 'nearest',
  65. 'values' as a parameterization
  66. """
  67. method = request.param
  68. kwargs = {"order": 1} if method in ("spline", "polynomial") else {}
  69. return method, kwargs
  70. class TestSeriesInterpolateData:
  71. @pytest.mark.xfail(reason="EA.fillna does not handle 'linear' method")
  72. def test_interpolate_period_values(self):
  73. orig = Series(date_range("2012-01-01", periods=5))
  74. ser = orig.copy()
  75. ser[2] = pd.NaT
  76. # period cast
  77. ser_per = ser.dt.to_period("D")
  78. res_per = ser_per.interpolate()
  79. expected_per = orig.dt.to_period("D")
  80. tm.assert_series_equal(res_per, expected_per)
  81. def test_interpolate(self, datetime_series):
  82. ts = Series(np.arange(len(datetime_series), dtype=float), datetime_series.index)
  83. ts_copy = ts.copy()
  84. ts_copy[5:10] = np.NaN
  85. linear_interp = ts_copy.interpolate(method="linear")
  86. tm.assert_series_equal(linear_interp, ts)
  87. ord_ts = Series(
  88. [d.toordinal() for d in datetime_series.index], index=datetime_series.index
  89. ).astype(float)
  90. ord_ts_copy = ord_ts.copy()
  91. ord_ts_copy[5:10] = np.NaN
  92. time_interp = ord_ts_copy.interpolate(method="time")
  93. tm.assert_series_equal(time_interp, ord_ts)
  94. def test_interpolate_time_raises_for_non_timeseries(self):
  95. # When method='time' is used on a non-TimeSeries that contains a null
  96. # value, a ValueError should be raised.
  97. non_ts = Series([0, 1, 2, np.NaN])
  98. msg = "time-weighted interpolation only works on Series.* with a DatetimeIndex"
  99. with pytest.raises(ValueError, match=msg):
  100. non_ts.interpolate(method="time")
  101. @td.skip_if_no_scipy
  102. def test_interpolate_cubicspline(self):
  103. ser = Series([10, 11, 12, 13])
  104. expected = Series(
  105. [11.00, 11.25, 11.50, 11.75, 12.00, 12.25, 12.50, 12.75, 13.00],
  106. index=Index([1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]),
  107. )
  108. # interpolate at new_index
  109. new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
  110. float
  111. )
  112. result = ser.reindex(new_index).interpolate(method="cubicspline")[1:3]
  113. tm.assert_series_equal(result, expected)
  114. @td.skip_if_no_scipy
  115. def test_interpolate_pchip(self):
  116. ser = Series(np.sort(np.random.uniform(size=100)))
  117. # interpolate at new_index
  118. new_index = ser.index.union(
  119. Index([49.25, 49.5, 49.75, 50.25, 50.5, 50.75])
  120. ).astype(float)
  121. interp_s = ser.reindex(new_index).interpolate(method="pchip")
  122. # does not blow up, GH5977
  123. interp_s[49:51]
  124. @td.skip_if_no_scipy
  125. def test_interpolate_akima(self):
  126. ser = Series([10, 11, 12, 13])
  127. # interpolate at new_index where `der` is zero
  128. expected = Series(
  129. [11.00, 11.25, 11.50, 11.75, 12.00, 12.25, 12.50, 12.75, 13.00],
  130. index=Index([1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]),
  131. )
  132. new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
  133. float
  134. )
  135. interp_s = ser.reindex(new_index).interpolate(method="akima")
  136. tm.assert_series_equal(interp_s[1:3], expected)
  137. # interpolate at new_index where `der` is a non-zero int
  138. expected = Series(
  139. [11.0, 1.0, 1.0, 1.0, 12.0, 1.0, 1.0, 1.0, 13.0],
  140. index=Index([1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]),
  141. )
  142. new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
  143. float
  144. )
  145. interp_s = ser.reindex(new_index).interpolate(method="akima", der=1)
  146. tm.assert_series_equal(interp_s[1:3], expected)
  147. @td.skip_if_no_scipy
  148. def test_interpolate_piecewise_polynomial(self):
  149. ser = Series([10, 11, 12, 13])
  150. expected = Series(
  151. [11.00, 11.25, 11.50, 11.75, 12.00, 12.25, 12.50, 12.75, 13.00],
  152. index=Index([1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]),
  153. )
  154. # interpolate at new_index
  155. new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
  156. float
  157. )
  158. interp_s = ser.reindex(new_index).interpolate(method="piecewise_polynomial")
  159. tm.assert_series_equal(interp_s[1:3], expected)
  160. @td.skip_if_no_scipy
  161. def test_interpolate_from_derivatives(self):
  162. ser = Series([10, 11, 12, 13])
  163. expected = Series(
  164. [11.00, 11.25, 11.50, 11.75, 12.00, 12.25, 12.50, 12.75, 13.00],
  165. index=Index([1.0, 1.25, 1.5, 1.75, 2.0, 2.25, 2.5, 2.75, 3.0]),
  166. )
  167. # interpolate at new_index
  168. new_index = ser.index.union(Index([1.25, 1.5, 1.75, 2.25, 2.5, 2.75])).astype(
  169. float
  170. )
  171. interp_s = ser.reindex(new_index).interpolate(method="from_derivatives")
  172. tm.assert_series_equal(interp_s[1:3], expected)
  173. @pytest.mark.parametrize(
  174. "kwargs",
  175. [
  176. {},
  177. pytest.param(
  178. {"method": "polynomial", "order": 1}, marks=td.skip_if_no_scipy
  179. ),
  180. ],
  181. )
  182. def test_interpolate_corners(self, kwargs):
  183. s = Series([np.nan, np.nan])
  184. tm.assert_series_equal(s.interpolate(**kwargs), s)
  185. s = Series([], dtype=object).interpolate()
  186. tm.assert_series_equal(s.interpolate(**kwargs), s)
  187. def test_interpolate_index_values(self):
  188. s = Series(np.nan, index=np.sort(np.random.rand(30)))
  189. s[::3] = np.random.randn(10)
  190. vals = s.index.values.astype(float)
  191. result = s.interpolate(method="index")
  192. expected = s.copy()
  193. bad = isna(expected.values)
  194. good = ~bad
  195. expected = Series(
  196. np.interp(vals[bad], vals[good], s.values[good]), index=s.index[bad]
  197. )
  198. tm.assert_series_equal(result[bad], expected)
  199. # 'values' is synonymous with 'index' for the method kwarg
  200. other_result = s.interpolate(method="values")
  201. tm.assert_series_equal(other_result, result)
  202. tm.assert_series_equal(other_result[bad], expected)
  203. def test_interpolate_non_ts(self):
  204. s = Series([1, 3, np.nan, np.nan, np.nan, 11])
  205. msg = (
  206. "time-weighted interpolation only works on Series or DataFrames "
  207. "with a DatetimeIndex"
  208. )
  209. with pytest.raises(ValueError, match=msg):
  210. s.interpolate(method="time")
  211. @pytest.mark.parametrize(
  212. "kwargs",
  213. [
  214. {},
  215. pytest.param(
  216. {"method": "polynomial", "order": 1}, marks=td.skip_if_no_scipy
  217. ),
  218. ],
  219. )
  220. def test_nan_interpolate(self, kwargs):
  221. s = Series([0, 1, np.nan, 3])
  222. result = s.interpolate(**kwargs)
  223. expected = Series([0.0, 1.0, 2.0, 3.0])
  224. tm.assert_series_equal(result, expected)
  225. def test_nan_irregular_index(self):
  226. s = Series([1, 2, np.nan, 4], index=[1, 3, 5, 9])
  227. result = s.interpolate()
  228. expected = Series([1.0, 2.0, 3.0, 4.0], index=[1, 3, 5, 9])
  229. tm.assert_series_equal(result, expected)
  230. def test_nan_str_index(self):
  231. s = Series([0, 1, 2, np.nan], index=list("abcd"))
  232. result = s.interpolate()
  233. expected = Series([0.0, 1.0, 2.0, 2.0], index=list("abcd"))
  234. tm.assert_series_equal(result, expected)
  235. @td.skip_if_no_scipy
  236. def test_interp_quad(self):
  237. sq = Series([1, 4, np.nan, 16], index=[1, 2, 3, 4])
  238. result = sq.interpolate(method="quadratic")
  239. expected = Series([1.0, 4.0, 9.0, 16.0], index=[1, 2, 3, 4])
  240. tm.assert_series_equal(result, expected)
  241. @td.skip_if_no_scipy
  242. def test_interp_scipy_basic(self):
  243. s = Series([1, 3, np.nan, 12, np.nan, 25])
  244. # slinear
  245. expected = Series([1.0, 3.0, 7.5, 12.0, 18.5, 25.0])
  246. result = s.interpolate(method="slinear")
  247. tm.assert_series_equal(result, expected)
  248. result = s.interpolate(method="slinear", downcast="infer")
  249. tm.assert_series_equal(result, expected)
  250. # nearest
  251. expected = Series([1, 3, 3, 12, 12, 25])
  252. result = s.interpolate(method="nearest")
  253. tm.assert_series_equal(result, expected.astype("float"))
  254. result = s.interpolate(method="nearest", downcast="infer")
  255. tm.assert_series_equal(result, expected)
  256. # zero
  257. expected = Series([1, 3, 3, 12, 12, 25])
  258. result = s.interpolate(method="zero")
  259. tm.assert_series_equal(result, expected.astype("float"))
  260. result = s.interpolate(method="zero", downcast="infer")
  261. tm.assert_series_equal(result, expected)
  262. # quadratic
  263. # GH #15662.
  264. expected = Series([1, 3.0, 6.823529, 12.0, 18.058824, 25.0])
  265. result = s.interpolate(method="quadratic")
  266. tm.assert_series_equal(result, expected)
  267. result = s.interpolate(method="quadratic", downcast="infer")
  268. tm.assert_series_equal(result, expected)
  269. # cubic
  270. expected = Series([1.0, 3.0, 6.8, 12.0, 18.2, 25.0])
  271. result = s.interpolate(method="cubic")
  272. tm.assert_series_equal(result, expected)
  273. def test_interp_limit(self):
  274. s = Series([1, 3, np.nan, np.nan, np.nan, 11])
  275. expected = Series([1.0, 3.0, 5.0, 7.0, np.nan, 11.0])
  276. result = s.interpolate(method="linear", limit=2)
  277. tm.assert_series_equal(result, expected)
  278. @pytest.mark.parametrize("limit", [-1, 0])
  279. def test_interpolate_invalid_nonpositive_limit(self, nontemporal_method, limit):
  280. # GH 9217: make sure limit is greater than zero.
  281. s = Series([1, 2, np.nan, 4])
  282. method, kwargs = nontemporal_method
  283. with pytest.raises(ValueError, match="Limit must be greater than 0"):
  284. s.interpolate(limit=limit, method=method, **kwargs)
  285. def test_interpolate_invalid_float_limit(self, nontemporal_method):
  286. # GH 9217: make sure limit is an integer.
  287. s = Series([1, 2, np.nan, 4])
  288. method, kwargs = nontemporal_method
  289. limit = 2.0
  290. with pytest.raises(ValueError, match="Limit must be an integer"):
  291. s.interpolate(limit=limit, method=method, **kwargs)
  292. @pytest.mark.parametrize("invalid_method", [None, "nonexistent_method"])
  293. def test_interp_invalid_method(self, invalid_method):
  294. s = Series([1, 3, np.nan, 12, np.nan, 25])
  295. msg = f"method must be one of.* Got '{invalid_method}' instead"
  296. with pytest.raises(ValueError, match=msg):
  297. s.interpolate(method=invalid_method)
  298. # When an invalid method and invalid limit (such as -1) are
  299. # provided, the error message reflects the invalid method.
  300. with pytest.raises(ValueError, match=msg):
  301. s.interpolate(method=invalid_method, limit=-1)
  302. def test_interp_invalid_method_and_value(self):
  303. # GH#36624
  304. ser = Series([1, 3, np.nan, 12, np.nan, 25])
  305. msg = "Cannot pass both fill_value and method"
  306. with pytest.raises(ValueError, match=msg):
  307. ser.interpolate(fill_value=3, method="pad")
  308. def test_interp_limit_forward(self):
  309. s = Series([1, 3, np.nan, np.nan, np.nan, 11])
  310. # Provide 'forward' (the default) explicitly here.
  311. expected = Series([1.0, 3.0, 5.0, 7.0, np.nan, 11.0])
  312. result = s.interpolate(method="linear", limit=2, limit_direction="forward")
  313. tm.assert_series_equal(result, expected)
  314. result = s.interpolate(method="linear", limit=2, limit_direction="FORWARD")
  315. tm.assert_series_equal(result, expected)
  316. def test_interp_unlimited(self):
  317. # these test are for issue #16282 default Limit=None is unlimited
  318. s = Series([np.nan, 1.0, 3.0, np.nan, np.nan, np.nan, 11.0, np.nan])
  319. expected = Series([1.0, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 11.0])
  320. result = s.interpolate(method="linear", limit_direction="both")
  321. tm.assert_series_equal(result, expected)
  322. expected = Series([np.nan, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, 11.0])
  323. result = s.interpolate(method="linear", limit_direction="forward")
  324. tm.assert_series_equal(result, expected)
  325. expected = Series([1.0, 1.0, 3.0, 5.0, 7.0, 9.0, 11.0, np.nan])
  326. result = s.interpolate(method="linear", limit_direction="backward")
  327. tm.assert_series_equal(result, expected)
  328. def test_interp_limit_bad_direction(self):
  329. s = Series([1, 3, np.nan, np.nan, np.nan, 11])
  330. msg = (
  331. r"Invalid limit_direction: expecting one of \['forward', "
  332. r"'backward', 'both'\], got 'abc'"
  333. )
  334. with pytest.raises(ValueError, match=msg):
  335. s.interpolate(method="linear", limit=2, limit_direction="abc")
  336. # raises an error even if no limit is specified.
  337. with pytest.raises(ValueError, match=msg):
  338. s.interpolate(method="linear", limit_direction="abc")
  339. # limit_area introduced GH #16284
  340. def test_interp_limit_area(self):
  341. # These tests are for issue #9218 -- fill NaNs in both directions.
  342. s = Series([np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan])
  343. expected = Series([np.nan, np.nan, 3.0, 4.0, 5.0, 6.0, 7.0, np.nan, np.nan])
  344. result = s.interpolate(method="linear", limit_area="inside")
  345. tm.assert_series_equal(result, expected)
  346. expected = Series(
  347. [np.nan, np.nan, 3.0, 4.0, np.nan, np.nan, 7.0, np.nan, np.nan]
  348. )
  349. result = s.interpolate(method="linear", limit_area="inside", limit=1)
  350. tm.assert_series_equal(result, expected)
  351. expected = Series([np.nan, np.nan, 3.0, 4.0, np.nan, 6.0, 7.0, np.nan, np.nan])
  352. result = s.interpolate(
  353. method="linear", limit_area="inside", limit_direction="both", limit=1
  354. )
  355. tm.assert_series_equal(result, expected)
  356. expected = Series([np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 7.0, 7.0, 7.0])
  357. result = s.interpolate(method="linear", limit_area="outside")
  358. tm.assert_series_equal(result, expected)
  359. expected = Series(
  360. [np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 7.0, 7.0, np.nan]
  361. )
  362. result = s.interpolate(method="linear", limit_area="outside", limit=1)
  363. tm.assert_series_equal(result, expected)
  364. expected = Series([np.nan, 3.0, 3.0, np.nan, np.nan, np.nan, 7.0, 7.0, np.nan])
  365. result = s.interpolate(
  366. method="linear", limit_area="outside", limit_direction="both", limit=1
  367. )
  368. tm.assert_series_equal(result, expected)
  369. expected = Series([3.0, 3.0, 3.0, np.nan, np.nan, np.nan, 7.0, np.nan, np.nan])
  370. result = s.interpolate(
  371. method="linear", limit_area="outside", limit_direction="backward"
  372. )
  373. tm.assert_series_equal(result, expected)
  374. # raises an error even if limit type is wrong.
  375. msg = r"Invalid limit_area: expecting one of \['inside', 'outside'\], got abc"
  376. with pytest.raises(ValueError, match=msg):
  377. s.interpolate(method="linear", limit_area="abc")
  378. @pytest.mark.parametrize(
  379. "method, limit_direction, expected",
  380. [
  381. ("pad", "backward", "forward"),
  382. ("ffill", "backward", "forward"),
  383. ("backfill", "forward", "backward"),
  384. ("bfill", "forward", "backward"),
  385. ("pad", "both", "forward"),
  386. ("ffill", "both", "forward"),
  387. ("backfill", "both", "backward"),
  388. ("bfill", "both", "backward"),
  389. ],
  390. )
  391. def test_interp_limit_direction_raises(self, method, limit_direction, expected):
  392. # https://github.com/pandas-dev/pandas/pull/34746
  393. s = Series([1, 2, 3])
  394. msg = f"`limit_direction` must be '{expected}' for method `{method}`"
  395. with pytest.raises(ValueError, match=msg):
  396. s.interpolate(method=method, limit_direction=limit_direction)
  397. @pytest.mark.parametrize(
  398. "data, expected_data, kwargs",
  399. (
  400. (
  401. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  402. [np.nan, np.nan, 3.0, 3.0, 3.0, 3.0, 7.0, np.nan, np.nan],
  403. {"method": "pad", "limit_area": "inside"},
  404. ),
  405. (
  406. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  407. [np.nan, np.nan, 3.0, 3.0, np.nan, np.nan, 7.0, np.nan, np.nan],
  408. {"method": "pad", "limit_area": "inside", "limit": 1},
  409. ),
  410. (
  411. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  412. [np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 7.0, 7.0, 7.0],
  413. {"method": "pad", "limit_area": "outside"},
  414. ),
  415. (
  416. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  417. [np.nan, np.nan, 3.0, np.nan, np.nan, np.nan, 7.0, 7.0, np.nan],
  418. {"method": "pad", "limit_area": "outside", "limit": 1},
  419. ),
  420. (
  421. [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
  422. [np.nan, np.nan, np.nan, np.nan, np.nan, np.nan, np.nan],
  423. {"method": "pad", "limit_area": "outside", "limit": 1},
  424. ),
  425. (
  426. range(5),
  427. range(5),
  428. {"method": "pad", "limit_area": "outside", "limit": 1},
  429. ),
  430. ),
  431. )
  432. def test_interp_limit_area_with_pad(self, data, expected_data, kwargs):
  433. # GH26796
  434. s = Series(data)
  435. expected = Series(expected_data)
  436. result = s.interpolate(**kwargs)
  437. tm.assert_series_equal(result, expected)
  438. @pytest.mark.parametrize(
  439. "data, expected_data, kwargs",
  440. (
  441. (
  442. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  443. [np.nan, np.nan, 3.0, 7.0, 7.0, 7.0, 7.0, np.nan, np.nan],
  444. {"method": "bfill", "limit_area": "inside"},
  445. ),
  446. (
  447. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  448. [np.nan, np.nan, 3.0, np.nan, np.nan, 7.0, 7.0, np.nan, np.nan],
  449. {"method": "bfill", "limit_area": "inside", "limit": 1},
  450. ),
  451. (
  452. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  453. [3.0, 3.0, 3.0, np.nan, np.nan, np.nan, 7.0, np.nan, np.nan],
  454. {"method": "bfill", "limit_area": "outside"},
  455. ),
  456. (
  457. [np.nan, np.nan, 3, np.nan, np.nan, np.nan, 7, np.nan, np.nan],
  458. [np.nan, 3.0, 3.0, np.nan, np.nan, np.nan, 7.0, np.nan, np.nan],
  459. {"method": "bfill", "limit_area": "outside", "limit": 1},
  460. ),
  461. ),
  462. )
  463. def test_interp_limit_area_with_backfill(self, data, expected_data, kwargs):
  464. # GH26796
  465. s = Series(data)
  466. expected = Series(expected_data)
  467. result = s.interpolate(**kwargs)
  468. tm.assert_series_equal(result, expected)
  469. def test_interp_limit_direction(self):
  470. # These tests are for issue #9218 -- fill NaNs in both directions.
  471. s = Series([1, 3, np.nan, np.nan, np.nan, 11])
  472. expected = Series([1.0, 3.0, np.nan, 7.0, 9.0, 11.0])
  473. result = s.interpolate(method="linear", limit=2, limit_direction="backward")
  474. tm.assert_series_equal(result, expected)
  475. expected = Series([1.0, 3.0, 5.0, np.nan, 9.0, 11.0])
  476. result = s.interpolate(method="linear", limit=1, limit_direction="both")
  477. tm.assert_series_equal(result, expected)
  478. # Check that this works on a longer series of nans.
  479. s = Series([1, 3, np.nan, np.nan, np.nan, 7, 9, np.nan, np.nan, 12, np.nan])
  480. expected = Series([1.0, 3.0, 4.0, 5.0, 6.0, 7.0, 9.0, 10.0, 11.0, 12.0, 12.0])
  481. result = s.interpolate(method="linear", limit=2, limit_direction="both")
  482. tm.assert_series_equal(result, expected)
  483. expected = Series(
  484. [1.0, 3.0, 4.0, np.nan, 6.0, 7.0, 9.0, 10.0, 11.0, 12.0, 12.0]
  485. )
  486. result = s.interpolate(method="linear", limit=1, limit_direction="both")
  487. tm.assert_series_equal(result, expected)
  488. def test_interp_limit_to_ends(self):
  489. # These test are for issue #10420 -- flow back to beginning.
  490. s = Series([np.nan, np.nan, 5, 7, 9, np.nan])
  491. expected = Series([5.0, 5.0, 5.0, 7.0, 9.0, np.nan])
  492. result = s.interpolate(method="linear", limit=2, limit_direction="backward")
  493. tm.assert_series_equal(result, expected)
  494. expected = Series([5.0, 5.0, 5.0, 7.0, 9.0, 9.0])
  495. result = s.interpolate(method="linear", limit=2, limit_direction="both")
  496. tm.assert_series_equal(result, expected)
  497. def test_interp_limit_before_ends(self):
  498. # These test are for issue #11115 -- limit ends properly.
  499. s = Series([np.nan, np.nan, 5, 7, np.nan, np.nan])
  500. expected = Series([np.nan, np.nan, 5.0, 7.0, 7.0, np.nan])
  501. result = s.interpolate(method="linear", limit=1, limit_direction="forward")
  502. tm.assert_series_equal(result, expected)
  503. expected = Series([np.nan, 5.0, 5.0, 7.0, np.nan, np.nan])
  504. result = s.interpolate(method="linear", limit=1, limit_direction="backward")
  505. tm.assert_series_equal(result, expected)
  506. expected = Series([np.nan, 5.0, 5.0, 7.0, 7.0, np.nan])
  507. result = s.interpolate(method="linear", limit=1, limit_direction="both")
  508. tm.assert_series_equal(result, expected)
  509. @td.skip_if_no_scipy
  510. def test_interp_all_good(self):
  511. s = Series([1, 2, 3])
  512. result = s.interpolate(method="polynomial", order=1)
  513. tm.assert_series_equal(result, s)
  514. # non-scipy
  515. result = s.interpolate()
  516. tm.assert_series_equal(result, s)
  517. @pytest.mark.parametrize(
  518. "check_scipy", [False, pytest.param(True, marks=td.skip_if_no_scipy)]
  519. )
  520. def test_interp_multiIndex(self, check_scipy):
  521. idx = MultiIndex.from_tuples([(0, "a"), (1, "b"), (2, "c")])
  522. s = Series([1, 2, np.nan], index=idx)
  523. expected = s.copy()
  524. expected.loc[2] = 2
  525. result = s.interpolate()
  526. tm.assert_series_equal(result, expected)
  527. msg = "Only `method=linear` interpolation is supported on MultiIndexes"
  528. if check_scipy:
  529. with pytest.raises(ValueError, match=msg):
  530. s.interpolate(method="polynomial", order=1)
  531. @td.skip_if_no_scipy
  532. def test_interp_nonmono_raise(self):
  533. s = Series([1, np.nan, 3], index=[0, 2, 1])
  534. msg = "krogh interpolation requires that the index be monotonic"
  535. with pytest.raises(ValueError, match=msg):
  536. s.interpolate(method="krogh")
  537. @td.skip_if_no_scipy
  538. @pytest.mark.parametrize("method", ["nearest", "pad"])
  539. def test_interp_datetime64(self, method, tz_naive_fixture):
  540. df = Series(
  541. [1, np.nan, 3], index=date_range("1/1/2000", periods=3, tz=tz_naive_fixture)
  542. )
  543. result = df.interpolate(method=method)
  544. expected = Series(
  545. [1.0, 1.0, 3.0],
  546. index=date_range("1/1/2000", periods=3, tz=tz_naive_fixture),
  547. )
  548. tm.assert_series_equal(result, expected)
  549. def test_interp_pad_datetime64tz_values(self):
  550. # GH#27628 missing.interpolate_2d should handle datetimetz values
  551. dti = date_range("2015-04-05", periods=3, tz="US/Central")
  552. ser = Series(dti)
  553. ser[1] = pd.NaT
  554. result = ser.interpolate(method="pad")
  555. expected = Series(dti)
  556. expected[1] = expected[0]
  557. tm.assert_series_equal(result, expected)
  558. def test_interp_limit_no_nans(self):
  559. # GH 7173
  560. s = Series([1.0, 2.0, 3.0])
  561. result = s.interpolate(limit=1)
  562. expected = s
  563. tm.assert_series_equal(result, expected)
  564. @td.skip_if_no_scipy
  565. @pytest.mark.parametrize("method", ["polynomial", "spline"])
  566. def test_no_order(self, method):
  567. # see GH-10633, GH-24014
  568. s = Series([0, 1, np.nan, 3])
  569. msg = "You must specify the order of the spline or polynomial"
  570. with pytest.raises(ValueError, match=msg):
  571. s.interpolate(method=method)
  572. @td.skip_if_no_scipy
  573. @pytest.mark.parametrize("order", [-1, -1.0, 0, 0.0, np.nan])
  574. def test_interpolate_spline_invalid_order(self, order):
  575. s = Series([0, 1, np.nan, 3])
  576. msg = "order needs to be specified and greater than 0"
  577. with pytest.raises(ValueError, match=msg):
  578. s.interpolate(method="spline", order=order)
  579. @td.skip_if_no_scipy
  580. def test_spline(self):
  581. s = Series([1, 2, np.nan, 4, 5, np.nan, 7])
  582. result = s.interpolate(method="spline", order=1)
  583. expected = Series([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])
  584. tm.assert_series_equal(result, expected)
  585. @td.skip_if_no_scipy
  586. def test_spline_extrapolate(self):
  587. s = Series([1, 2, 3, 4, np.nan, 6, np.nan])
  588. result3 = s.interpolate(method="spline", order=1, ext=3)
  589. expected3 = Series([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 6.0])
  590. tm.assert_series_equal(result3, expected3)
  591. result1 = s.interpolate(method="spline", order=1, ext=0)
  592. expected1 = Series([1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0])
  593. tm.assert_series_equal(result1, expected1)
  594. @td.skip_if_no_scipy
  595. def test_spline_smooth(self):
  596. s = Series([1, 2, np.nan, 4, 5.1, np.nan, 7])
  597. assert (
  598. s.interpolate(method="spline", order=3, s=0)[5]
  599. != s.interpolate(method="spline", order=3)[5]
  600. )
  601. @td.skip_if_no_scipy
  602. def test_spline_interpolation(self):
  603. # Explicit cast to float to avoid implicit cast when setting np.nan
  604. s = Series(np.arange(10) ** 2, dtype="float")
  605. s[np.random.randint(0, 9, 3)] = np.nan
  606. result1 = s.interpolate(method="spline", order=1)
  607. expected1 = s.interpolate(method="spline", order=1)
  608. tm.assert_series_equal(result1, expected1)
  609. def test_interp_timedelta64(self):
  610. # GH 6424
  611. df = Series([1, np.nan, 3], index=pd.to_timedelta([1, 2, 3]))
  612. result = df.interpolate(method="time")
  613. expected = Series([1.0, 2.0, 3.0], index=pd.to_timedelta([1, 2, 3]))
  614. tm.assert_series_equal(result, expected)
  615. # test for non uniform spacing
  616. df = Series([1, np.nan, 3], index=pd.to_timedelta([1, 2, 4]))
  617. result = df.interpolate(method="time")
  618. expected = Series([1.0, 1.666667, 3.0], index=pd.to_timedelta([1, 2, 4]))
  619. tm.assert_series_equal(result, expected)
  620. def test_series_interpolate_method_values(self):
  621. # GH#1646
  622. rng = date_range("1/1/2000", "1/20/2000", freq="D")
  623. ts = Series(np.random.randn(len(rng)), index=rng)
  624. ts[::2] = np.nan
  625. result = ts.interpolate(method="values")
  626. exp = ts.interpolate()
  627. tm.assert_series_equal(result, exp)
  628. def test_series_interpolate_intraday(self):
  629. # #1698
  630. index = date_range("1/1/2012", periods=4, freq="12D")
  631. ts = Series([0, 12, 24, 36], index)
  632. new_index = index.append(index + pd.DateOffset(days=1)).sort_values()
  633. exp = ts.reindex(new_index).interpolate(method="time")
  634. index = date_range("1/1/2012", periods=4, freq="12H")
  635. ts = Series([0, 12, 24, 36], index)
  636. new_index = index.append(index + pd.DateOffset(hours=1)).sort_values()
  637. result = ts.reindex(new_index).interpolate(method="time")
  638. tm.assert_numpy_array_equal(result.values, exp.values)
  639. @pytest.mark.parametrize(
  640. "ind",
  641. [
  642. ["a", "b", "c", "d"],
  643. pd.period_range(start="2019-01-01", periods=4),
  644. pd.interval_range(start=0, end=4),
  645. ],
  646. )
  647. def test_interp_non_timedelta_index(self, interp_methods_ind, ind):
  648. # gh 21662
  649. df = pd.DataFrame([0, 1, np.nan, 3], index=ind)
  650. method, kwargs = interp_methods_ind
  651. if method == "pchip":
  652. pytest.importorskip("scipy")
  653. if method == "linear":
  654. result = df[0].interpolate(**kwargs)
  655. expected = Series([0.0, 1.0, 2.0, 3.0], name=0, index=ind)
  656. tm.assert_series_equal(result, expected)
  657. else:
  658. expected_error = (
  659. "Index column must be numeric or datetime type when "
  660. f"using {method} method other than linear. "
  661. "Try setting a numeric or datetime index column before "
  662. "interpolating."
  663. )
  664. with pytest.raises(ValueError, match=expected_error):
  665. df[0].interpolate(method=method, **kwargs)
  666. @td.skip_if_no_scipy
  667. def test_interpolate_timedelta_index(self, request, interp_methods_ind):
  668. """
  669. Tests for non numerical index types - object, period, timedelta
  670. Note that all methods except time, index, nearest and values
  671. are tested here.
  672. """
  673. # gh 21662
  674. ind = pd.timedelta_range(start=1, periods=4)
  675. df = pd.DataFrame([0, 1, np.nan, 3], index=ind)
  676. method, kwargs = interp_methods_ind
  677. if method in {"cubic", "zero"}:
  678. request.node.add_marker(
  679. pytest.mark.xfail(
  680. reason=f"{method} interpolation is not supported for TimedeltaIndex"
  681. )
  682. )
  683. result = df[0].interpolate(method=method, **kwargs)
  684. expected = Series([0.0, 1.0, 2.0, 3.0], name=0, index=ind)
  685. tm.assert_series_equal(result, expected)
  686. @pytest.mark.parametrize(
  687. "ascending, expected_values",
  688. [(True, [1, 2, 3, 9, 10]), (False, [10, 9, 3, 2, 1])],
  689. )
  690. def test_interpolate_unsorted_index(self, ascending, expected_values):
  691. # GH 21037
  692. ts = Series(data=[10, 9, np.nan, 2, 1], index=[10, 9, 3, 2, 1])
  693. result = ts.sort_index(ascending=ascending).interpolate(method="index")
  694. expected = Series(data=expected_values, index=expected_values, dtype=float)
  695. tm.assert_series_equal(result, expected)