PageRenderTime 48ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/pandas/tests/indexes/timedeltas/test_indexing.py

https://github.com/pydata/pandas
Python | 360 lines | 278 code | 68 blank | 14 comment | 26 complexity | b43fdb4edeb16a9e526eefd323f6318d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. from datetime import (
  2. datetime,
  3. timedelta,
  4. )
  5. import re
  6. import numpy as np
  7. import pytest
  8. from pandas import (
  9. Index,
  10. NaT,
  11. Timedelta,
  12. TimedeltaIndex,
  13. Timestamp,
  14. notna,
  15. offsets,
  16. timedelta_range,
  17. to_timedelta,
  18. )
  19. import pandas._testing as tm
  20. class TestGetItem:
  21. def test_getitem_slice_keeps_name(self):
  22. # GH#4226
  23. tdi = timedelta_range("1d", "5d", freq="H", name="timebucket")
  24. assert tdi[1:].name == tdi.name
  25. def test_getitem(self):
  26. idx1 = timedelta_range("1 day", "31 day", freq="D", name="idx")
  27. for idx in [idx1]:
  28. result = idx[0]
  29. assert result == Timedelta("1 day")
  30. result = idx[0:5]
  31. expected = timedelta_range("1 day", "5 day", freq="D", name="idx")
  32. tm.assert_index_equal(result, expected)
  33. assert result.freq == expected.freq
  34. result = idx[0:10:2]
  35. expected = timedelta_range("1 day", "9 day", freq="2D", name="idx")
  36. tm.assert_index_equal(result, expected)
  37. assert result.freq == expected.freq
  38. result = idx[-20:-5:3]
  39. expected = timedelta_range("12 day", "24 day", freq="3D", name="idx")
  40. tm.assert_index_equal(result, expected)
  41. assert result.freq == expected.freq
  42. result = idx[4::-1]
  43. expected = TimedeltaIndex(
  44. ["5 day", "4 day", "3 day", "2 day", "1 day"], freq="-1D", name="idx"
  45. )
  46. tm.assert_index_equal(result, expected)
  47. assert result.freq == expected.freq
  48. @pytest.mark.parametrize(
  49. "key",
  50. [
  51. Timestamp("1970-01-01"),
  52. Timestamp("1970-01-02"),
  53. datetime(1970, 1, 1),
  54. Timestamp("1970-01-03").to_datetime64(),
  55. # non-matching NA values
  56. np.datetime64("NaT"),
  57. ],
  58. )
  59. def test_timestamp_invalid_key(self, key):
  60. # GH#20464
  61. tdi = timedelta_range(0, periods=10)
  62. with pytest.raises(KeyError, match=re.escape(repr(key))):
  63. tdi.get_loc(key)
  64. class TestGetLoc:
  65. @pytest.mark.filterwarnings("ignore:Passing method:FutureWarning")
  66. def test_get_loc(self):
  67. idx = to_timedelta(["0 days", "1 days", "2 days"])
  68. for method in [None, "pad", "backfill", "nearest"]:
  69. assert idx.get_loc(idx[1], method) == 1
  70. assert idx.get_loc(idx[1].to_pytimedelta(), method) == 1
  71. assert idx.get_loc(str(idx[1]), method) == 1
  72. assert idx.get_loc(idx[1], "pad", tolerance=Timedelta(0)) == 1
  73. assert idx.get_loc(idx[1], "pad", tolerance=np.timedelta64(0, "s")) == 1
  74. assert idx.get_loc(idx[1], "pad", tolerance=timedelta(0)) == 1
  75. with pytest.raises(ValueError, match="unit abbreviation w/o a number"):
  76. idx.get_loc(idx[1], method="nearest", tolerance="foo")
  77. with pytest.raises(ValueError, match="tolerance size must match"):
  78. idx.get_loc(
  79. idx[1],
  80. method="nearest",
  81. tolerance=[
  82. Timedelta(0).to_timedelta64(),
  83. Timedelta(0).to_timedelta64(),
  84. ],
  85. )
  86. for method, loc in [("pad", 1), ("backfill", 2), ("nearest", 1)]:
  87. assert idx.get_loc("1 day 1 hour", method) == loc
  88. # GH 16909
  89. assert idx.get_loc(idx[1].to_timedelta64()) == 1
  90. # GH 16896
  91. assert idx.get_loc("0 days") == 0
  92. def test_get_loc_nat(self):
  93. tidx = TimedeltaIndex(["1 days 01:00:00", "NaT", "2 days 01:00:00"])
  94. assert tidx.get_loc(NaT) == 1
  95. assert tidx.get_loc(None) == 1
  96. assert tidx.get_loc(float("nan")) == 1
  97. assert tidx.get_loc(np.nan) == 1
  98. class TestGetIndexer:
  99. def test_get_indexer(self):
  100. idx = to_timedelta(["0 days", "1 days", "2 days"])
  101. tm.assert_numpy_array_equal(
  102. idx.get_indexer(idx), np.array([0, 1, 2], dtype=np.intp)
  103. )
  104. target = to_timedelta(["-1 hour", "12 hours", "1 day 1 hour"])
  105. tm.assert_numpy_array_equal(
  106. idx.get_indexer(target, "pad"), np.array([-1, 0, 1], dtype=np.intp)
  107. )
  108. tm.assert_numpy_array_equal(
  109. idx.get_indexer(target, "backfill"), np.array([0, 1, 2], dtype=np.intp)
  110. )
  111. tm.assert_numpy_array_equal(
  112. idx.get_indexer(target, "nearest"), np.array([0, 1, 1], dtype=np.intp)
  113. )
  114. res = idx.get_indexer(target, "nearest", tolerance=Timedelta("1 hour"))
  115. tm.assert_numpy_array_equal(res, np.array([0, -1, 1], dtype=np.intp))
  116. class TestWhere:
  117. def test_where_doesnt_retain_freq(self):
  118. tdi = timedelta_range("1 day", periods=3, freq="D", name="idx")
  119. cond = [True, True, False]
  120. expected = TimedeltaIndex([tdi[0], tdi[1], tdi[0]], freq=None, name="idx")
  121. result = tdi.where(cond, tdi[::-1])
  122. tm.assert_index_equal(result, expected)
  123. def test_where_invalid_dtypes(self, fixed_now_ts):
  124. tdi = timedelta_range("1 day", periods=3, freq="D", name="idx")
  125. tail = tdi[2:].tolist()
  126. i2 = Index([NaT, NaT] + tail)
  127. mask = notna(i2)
  128. expected = Index([NaT.value, NaT.value] + tail, dtype=object, name="idx")
  129. assert isinstance(expected[0], int)
  130. result = tdi.where(mask, i2.asi8)
  131. tm.assert_index_equal(result, expected)
  132. ts = i2 + fixed_now_ts
  133. expected = Index([ts[0], ts[1]] + tail, dtype=object, name="idx")
  134. result = tdi.where(mask, ts)
  135. tm.assert_index_equal(result, expected)
  136. per = (i2 + fixed_now_ts).to_period("D")
  137. expected = Index([per[0], per[1]] + tail, dtype=object, name="idx")
  138. result = tdi.where(mask, per)
  139. tm.assert_index_equal(result, expected)
  140. ts = fixed_now_ts
  141. expected = Index([ts, ts] + tail, dtype=object, name="idx")
  142. result = tdi.where(mask, ts)
  143. tm.assert_index_equal(result, expected)
  144. def test_where_mismatched_nat(self):
  145. tdi = timedelta_range("1 day", periods=3, freq="D", name="idx")
  146. cond = np.array([True, False, False])
  147. dtnat = np.datetime64("NaT", "ns")
  148. expected = Index([tdi[0], dtnat, dtnat], dtype=object, name="idx")
  149. assert expected[2] is dtnat
  150. result = tdi.where(cond, dtnat)
  151. tm.assert_index_equal(result, expected)
  152. class TestTake:
  153. def test_take(self):
  154. # GH 10295
  155. idx1 = timedelta_range("1 day", "31 day", freq="D", name="idx")
  156. for idx in [idx1]:
  157. result = idx.take([0])
  158. assert result == Timedelta("1 day")
  159. result = idx.take([-1])
  160. assert result == Timedelta("31 day")
  161. result = idx.take([0, 1, 2])
  162. expected = timedelta_range("1 day", "3 day", freq="D", name="idx")
  163. tm.assert_index_equal(result, expected)
  164. assert result.freq == expected.freq
  165. result = idx.take([0, 2, 4])
  166. expected = timedelta_range("1 day", "5 day", freq="2D", name="idx")
  167. tm.assert_index_equal(result, expected)
  168. assert result.freq == expected.freq
  169. result = idx.take([7, 4, 1])
  170. expected = timedelta_range("8 day", "2 day", freq="-3D", name="idx")
  171. tm.assert_index_equal(result, expected)
  172. assert result.freq == expected.freq
  173. result = idx.take([3, 2, 5])
  174. expected = TimedeltaIndex(["4 day", "3 day", "6 day"], name="idx")
  175. tm.assert_index_equal(result, expected)
  176. assert result.freq is None
  177. result = idx.take([-3, 2, 5])
  178. expected = TimedeltaIndex(["29 day", "3 day", "6 day"], name="idx")
  179. tm.assert_index_equal(result, expected)
  180. assert result.freq is None
  181. def test_take_invalid_kwargs(self):
  182. idx = timedelta_range("1 day", "31 day", freq="D", name="idx")
  183. indices = [1, 6, 5, 9, 10, 13, 15, 3]
  184. msg = r"take\(\) got an unexpected keyword argument 'foo'"
  185. with pytest.raises(TypeError, match=msg):
  186. idx.take(indices, foo=2)
  187. msg = "the 'out' parameter is not supported"
  188. with pytest.raises(ValueError, match=msg):
  189. idx.take(indices, out=indices)
  190. msg = "the 'mode' parameter is not supported"
  191. with pytest.raises(ValueError, match=msg):
  192. idx.take(indices, mode="clip")
  193. def test_take_equiv_getitem(self):
  194. tds = ["1day 02:00:00", "1 day 04:00:00", "1 day 10:00:00"]
  195. idx = timedelta_range(start="1d", end="2d", freq="H", name="idx")
  196. expected = TimedeltaIndex(tds, freq=None, name="idx")
  197. taken1 = idx.take([2, 4, 10])
  198. taken2 = idx[[2, 4, 10]]
  199. for taken in [taken1, taken2]:
  200. tm.assert_index_equal(taken, expected)
  201. assert isinstance(taken, TimedeltaIndex)
  202. assert taken.freq is None
  203. assert taken.name == expected.name
  204. def test_take_fill_value(self):
  205. # GH 12631
  206. idx = TimedeltaIndex(["1 days", "2 days", "3 days"], name="xxx")
  207. result = idx.take(np.array([1, 0, -1]))
  208. expected = TimedeltaIndex(["2 days", "1 days", "3 days"], name="xxx")
  209. tm.assert_index_equal(result, expected)
  210. # fill_value
  211. result = idx.take(np.array([1, 0, -1]), fill_value=True)
  212. expected = TimedeltaIndex(["2 days", "1 days", "NaT"], name="xxx")
  213. tm.assert_index_equal(result, expected)
  214. # allow_fill=False
  215. result = idx.take(np.array([1, 0, -1]), allow_fill=False, fill_value=True)
  216. expected = TimedeltaIndex(["2 days", "1 days", "3 days"], name="xxx")
  217. tm.assert_index_equal(result, expected)
  218. msg = (
  219. "When allow_fill=True and fill_value is not None, "
  220. "all indices must be >= -1"
  221. )
  222. with pytest.raises(ValueError, match=msg):
  223. idx.take(np.array([1, 0, -2]), fill_value=True)
  224. with pytest.raises(ValueError, match=msg):
  225. idx.take(np.array([1, 0, -5]), fill_value=True)
  226. msg = "index -5 is out of bounds for (axis 0 with )?size 3"
  227. with pytest.raises(IndexError, match=msg):
  228. idx.take(np.array([1, -5]))
  229. class TestMaybeCastSliceBound:
  230. @pytest.fixture(params=["increasing", "decreasing", None])
  231. def monotonic(self, request):
  232. return request.param
  233. @pytest.fixture
  234. def tdi(self, monotonic):
  235. tdi = timedelta_range("1 Day", periods=10)
  236. if monotonic == "decreasing":
  237. tdi = tdi[::-1]
  238. elif monotonic is None:
  239. taker = np.arange(10, dtype=np.intp)
  240. np.random.shuffle(taker)
  241. tdi = tdi.take(taker)
  242. return tdi
  243. def test_maybe_cast_slice_bound_invalid_str(self, tdi):
  244. # test the low-level _maybe_cast_slice_bound and that we get the
  245. # expected exception+message all the way up the stack
  246. msg = (
  247. "cannot do slice indexing on TimedeltaIndex with these "
  248. r"indexers \[foo\] of type str"
  249. )
  250. with pytest.raises(TypeError, match=msg):
  251. tdi._maybe_cast_slice_bound("foo", side="left")
  252. with pytest.raises(TypeError, match=msg):
  253. tdi.get_slice_bound("foo", side="left")
  254. with pytest.raises(TypeError, match=msg):
  255. tdi.slice_locs("foo", None, None)
  256. def test_slice_invalid_str_with_timedeltaindex(
  257. self, tdi, frame_or_series, indexer_sl
  258. ):
  259. obj = frame_or_series(range(10), index=tdi)
  260. msg = (
  261. "cannot do slice indexing on TimedeltaIndex with these "
  262. r"indexers \[foo\] of type str"
  263. )
  264. with pytest.raises(TypeError, match=msg):
  265. indexer_sl(obj)["foo":]
  266. with pytest.raises(TypeError, match=msg):
  267. indexer_sl(obj)["foo":-1]
  268. with pytest.raises(TypeError, match=msg):
  269. indexer_sl(obj)[:"foo"]
  270. with pytest.raises(TypeError, match=msg):
  271. indexer_sl(obj)[tdi[0] : "foo"]
  272. class TestContains:
  273. def test_contains_nonunique(self):
  274. # GH#9512
  275. for vals in (
  276. [0, 1, 0],
  277. [0, 0, -1],
  278. [0, -1, -1],
  279. ["00:01:00", "00:01:00", "00:02:00"],
  280. ["00:01:00", "00:01:00", "00:00:01"],
  281. ):
  282. idx = TimedeltaIndex(vals)
  283. assert idx[0] in idx
  284. def test_contains(self):
  285. # Checking for any NaT-like objects
  286. # GH#13603
  287. td = to_timedelta(range(5), unit="d") + offsets.Hour(1)
  288. for v in [NaT, None, float("nan"), np.nan]:
  289. assert not (v in td)
  290. td = to_timedelta([NaT])
  291. for v in [NaT, None, float("nan"), np.nan]:
  292. assert v in td