test_period.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353
  1. import numpy as np
  2. import pytest
  3. from pandas._libs.tslibs.period import IncompatibleFrequency
  4. from pandas import (
  5. Index,
  6. NaT,
  7. Period,
  8. PeriodIndex,
  9. Series,
  10. date_range,
  11. offsets,
  12. period_range,
  13. )
  14. import pandas._testing as tm
  15. from pandas.tests.indexes.datetimelike import DatetimeLike
  16. class TestPeriodIndex(DatetimeLike):
  17. _index_cls = PeriodIndex
  18. @pytest.fixture
  19. def simple_index(self) -> Index:
  20. return period_range("20130101", periods=5, freq="D")
  21. @pytest.fixture(
  22. params=[
  23. tm.makePeriodIndex(10),
  24. period_range("20130101", periods=10, freq="D")[::-1],
  25. ],
  26. ids=["index_inc", "index_dec"],
  27. )
  28. def index(self, request):
  29. return request.param
  30. def test_where(self):
  31. # This is handled in test_indexing
  32. pass
  33. def test_make_time_series(self):
  34. index = period_range(freq="A", start="1/1/2001", end="12/1/2009")
  35. series = Series(1, index=index)
  36. assert isinstance(series, Series)
  37. def test_view_asi8(self):
  38. idx = PeriodIndex([], freq="M")
  39. exp = np.array([], dtype=np.int64)
  40. tm.assert_numpy_array_equal(idx.view("i8"), exp)
  41. tm.assert_numpy_array_equal(idx.asi8, exp)
  42. idx = PeriodIndex(["2011-01", NaT], freq="M")
  43. exp = np.array([492, -9223372036854775808], dtype=np.int64)
  44. tm.assert_numpy_array_equal(idx.view("i8"), exp)
  45. tm.assert_numpy_array_equal(idx.asi8, exp)
  46. exp = np.array([14975, -9223372036854775808], dtype=np.int64)
  47. idx = PeriodIndex(["2011-01-01", NaT], freq="D")
  48. tm.assert_numpy_array_equal(idx.view("i8"), exp)
  49. tm.assert_numpy_array_equal(idx.asi8, exp)
  50. def test_values(self):
  51. idx = PeriodIndex([], freq="M")
  52. exp = np.array([], dtype=object)
  53. tm.assert_numpy_array_equal(idx.values, exp)
  54. tm.assert_numpy_array_equal(idx.to_numpy(), exp)
  55. exp = np.array([], dtype=np.int64)
  56. tm.assert_numpy_array_equal(idx.asi8, exp)
  57. idx = PeriodIndex(["2011-01", NaT], freq="M")
  58. exp = np.array([Period("2011-01", freq="M"), NaT], dtype=object)
  59. tm.assert_numpy_array_equal(idx.values, exp)
  60. tm.assert_numpy_array_equal(idx.to_numpy(), exp)
  61. exp = np.array([492, -9223372036854775808], dtype=np.int64)
  62. tm.assert_numpy_array_equal(idx.asi8, exp)
  63. idx = PeriodIndex(["2011-01-01", NaT], freq="D")
  64. exp = np.array([Period("2011-01-01", freq="D"), NaT], dtype=object)
  65. tm.assert_numpy_array_equal(idx.values, exp)
  66. tm.assert_numpy_array_equal(idx.to_numpy(), exp)
  67. exp = np.array([14975, -9223372036854775808], dtype=np.int64)
  68. tm.assert_numpy_array_equal(idx.asi8, exp)
  69. def test_period_index_length(self):
  70. pi = period_range(freq="A", start="1/1/2001", end="12/1/2009")
  71. assert len(pi) == 9
  72. pi = period_range(freq="Q", start="1/1/2001", end="12/1/2009")
  73. assert len(pi) == 4 * 9
  74. pi = period_range(freq="M", start="1/1/2001", end="12/1/2009")
  75. assert len(pi) == 12 * 9
  76. start = Period("02-Apr-2005", "B")
  77. i1 = period_range(start=start, periods=20)
  78. assert len(i1) == 20
  79. assert i1.freq == start.freq
  80. assert i1[0] == start
  81. end_intv = Period("2006-12-31", "W")
  82. i1 = period_range(end=end_intv, periods=10)
  83. assert len(i1) == 10
  84. assert i1.freq == end_intv.freq
  85. assert i1[-1] == end_intv
  86. end_intv = Period("2006-12-31", "1w")
  87. i2 = period_range(end=end_intv, periods=10)
  88. assert len(i1) == len(i2)
  89. assert (i1 == i2).all()
  90. assert i1.freq == i2.freq
  91. msg = "start and end must have same freq"
  92. with pytest.raises(ValueError, match=msg):
  93. period_range(start=start, end=end_intv)
  94. end_intv = Period("2005-05-01", "B")
  95. i1 = period_range(start=start, end=end_intv)
  96. msg = (
  97. "Of the three parameters: start, end, and periods, exactly two "
  98. "must be specified"
  99. )
  100. with pytest.raises(ValueError, match=msg):
  101. period_range(start=start)
  102. # infer freq from first element
  103. i2 = PeriodIndex([end_intv, Period("2005-05-05", "B")])
  104. assert len(i2) == 2
  105. assert i2[0] == end_intv
  106. i2 = PeriodIndex(np.array([end_intv, Period("2005-05-05", "B")]))
  107. assert len(i2) == 2
  108. assert i2[0] == end_intv
  109. # Mixed freq should fail
  110. vals = [end_intv, Period("2006-12-31", "w")]
  111. msg = r"Input has different freq=W-SUN from PeriodIndex\(freq=B\)"
  112. with pytest.raises(IncompatibleFrequency, match=msg):
  113. PeriodIndex(vals)
  114. vals = np.array(vals)
  115. with pytest.raises(ValueError, match=msg):
  116. PeriodIndex(vals)
  117. def test_fields(self):
  118. # year, month, day, hour, minute
  119. # second, weekofyear, week, dayofweek, weekday, dayofyear, quarter
  120. # qyear
  121. pi = period_range(freq="A", start="1/1/2001", end="12/1/2005")
  122. self._check_all_fields(pi)
  123. pi = period_range(freq="Q", start="1/1/2001", end="12/1/2002")
  124. self._check_all_fields(pi)
  125. pi = period_range(freq="M", start="1/1/2001", end="1/1/2002")
  126. self._check_all_fields(pi)
  127. pi = period_range(freq="D", start="12/1/2001", end="6/1/2001")
  128. self._check_all_fields(pi)
  129. pi = period_range(freq="B", start="12/1/2001", end="6/1/2001")
  130. self._check_all_fields(pi)
  131. pi = period_range(freq="H", start="12/31/2001", end="1/1/2002 23:00")
  132. self._check_all_fields(pi)
  133. pi = period_range(freq="Min", start="12/31/2001", end="1/1/2002 00:20")
  134. self._check_all_fields(pi)
  135. pi = period_range(
  136. freq="S", start="12/31/2001 00:00:00", end="12/31/2001 00:05:00"
  137. )
  138. self._check_all_fields(pi)
  139. end_intv = Period("2006-12-31", "W")
  140. i1 = period_range(end=end_intv, periods=10)
  141. self._check_all_fields(i1)
  142. def _check_all_fields(self, periodindex):
  143. fields = [
  144. "year",
  145. "month",
  146. "day",
  147. "hour",
  148. "minute",
  149. "second",
  150. "weekofyear",
  151. "week",
  152. "dayofweek",
  153. "day_of_week",
  154. "dayofyear",
  155. "day_of_year",
  156. "quarter",
  157. "qyear",
  158. "days_in_month",
  159. ]
  160. periods = list(periodindex)
  161. ser = Series(periodindex)
  162. for field in fields:
  163. field_idx = getattr(periodindex, field)
  164. assert len(periodindex) == len(field_idx)
  165. for x, val in zip(periods, field_idx):
  166. assert getattr(x, field) == val
  167. if len(ser) == 0:
  168. continue
  169. field_s = getattr(ser.dt, field)
  170. assert len(periodindex) == len(field_s)
  171. for x, val in zip(periods, field_s):
  172. assert getattr(x, field) == val
  173. def test_is_(self):
  174. create_index = lambda: period_range(freq="A", start="1/1/2001", end="12/1/2009")
  175. index = create_index()
  176. assert index.is_(index)
  177. assert not index.is_(create_index())
  178. assert index.is_(index.view())
  179. assert index.is_(index.view().view().view().view().view())
  180. assert index.view().is_(index)
  181. ind2 = index.view()
  182. index.name = "Apple"
  183. assert ind2.is_(index)
  184. assert not index.is_(index[:])
  185. assert not index.is_(index.asfreq("M"))
  186. assert not index.is_(index.asfreq("A"))
  187. assert not index.is_(index - 2)
  188. assert not index.is_(index - 0)
  189. def test_index_unique(self):
  190. idx = PeriodIndex([2000, 2007, 2007, 2009, 2009], freq="A-JUN")
  191. expected = PeriodIndex([2000, 2007, 2009], freq="A-JUN")
  192. tm.assert_index_equal(idx.unique(), expected)
  193. assert idx.nunique() == 3
  194. def test_shift(self):
  195. # This is tested in test_arithmetic
  196. pass
  197. def test_negative_ordinals(self):
  198. Period(ordinal=-1000, freq="A")
  199. Period(ordinal=0, freq="A")
  200. idx1 = PeriodIndex(ordinal=[-1, 0, 1], freq="A")
  201. idx2 = PeriodIndex(ordinal=np.array([-1, 0, 1]), freq="A")
  202. tm.assert_index_equal(idx1, idx2)
  203. def test_pindex_fieldaccessor_nat(self):
  204. idx = PeriodIndex(
  205. ["2011-01", "2011-02", "NaT", "2012-03", "2012-04"], freq="D", name="name"
  206. )
  207. exp = Index([2011, 2011, -1, 2012, 2012], dtype=np.int64, name="name")
  208. tm.assert_index_equal(idx.year, exp)
  209. exp = Index([1, 2, -1, 3, 4], dtype=np.int64, name="name")
  210. tm.assert_index_equal(idx.month, exp)
  211. def test_pindex_multiples(self):
  212. expected = PeriodIndex(
  213. ["2011-01", "2011-03", "2011-05", "2011-07", "2011-09", "2011-11"],
  214. freq="2M",
  215. )
  216. pi = period_range(start="1/1/11", end="12/31/11", freq="2M")
  217. tm.assert_index_equal(pi, expected)
  218. assert pi.freq == offsets.MonthEnd(2)
  219. assert pi.freqstr == "2M"
  220. pi = period_range(start="1/1/11", periods=6, freq="2M")
  221. tm.assert_index_equal(pi, expected)
  222. assert pi.freq == offsets.MonthEnd(2)
  223. assert pi.freqstr == "2M"
  224. def test_iteration(self):
  225. index = period_range(start="1/1/10", periods=4, freq="B")
  226. result = list(index)
  227. assert isinstance(result[0], Period)
  228. assert result[0].freq == index.freq
  229. def test_with_multi_index(self):
  230. # #1705
  231. index = date_range("1/1/2012", periods=4, freq="12H")
  232. index_as_arrays = [index.to_period(freq="D"), index.hour]
  233. s = Series([0, 1, 2, 3], index_as_arrays)
  234. assert isinstance(s.index.levels[0], PeriodIndex)
  235. assert isinstance(s.index.values[0][0], Period)
  236. def test_map(self):
  237. # test_map_dictlike generally tests
  238. index = PeriodIndex([2005, 2007, 2009], freq="A")
  239. result = index.map(lambda x: x.ordinal)
  240. exp = Index([x.ordinal for x in index])
  241. tm.assert_index_equal(result, exp)
  242. def test_format_empty(self):
  243. # GH35712
  244. empty_idx = self._index_cls([], freq="A")
  245. assert empty_idx.format() == []
  246. assert empty_idx.format(name=True) == [""]
  247. def test_maybe_convert_timedelta():
  248. pi = PeriodIndex(["2000", "2001"], freq="D")
  249. offset = offsets.Day(2)
  250. assert pi._maybe_convert_timedelta(offset) == 2
  251. assert pi._maybe_convert_timedelta(2) == 2
  252. offset = offsets.BusinessDay()
  253. msg = r"Input has different freq=B from PeriodIndex\(freq=D\)"
  254. with pytest.raises(ValueError, match=msg):
  255. pi._maybe_convert_timedelta(offset)
  256. @pytest.mark.parametrize("array", [True, False])
  257. def test_dunder_array(array):
  258. obj = PeriodIndex(["2000-01-01", "2001-01-01"], freq="D")
  259. if array:
  260. obj = obj._data
  261. expected = np.array([obj[0], obj[1]], dtype=object)
  262. result = np.array(obj)
  263. tm.assert_numpy_array_equal(result, expected)
  264. result = np.asarray(obj)
  265. tm.assert_numpy_array_equal(result, expected)
  266. expected = obj.asi8
  267. for dtype in ["i8", "int64", np.int64]:
  268. result = np.array(obj, dtype=dtype)
  269. tm.assert_numpy_array_equal(result, expected)
  270. result = np.asarray(obj, dtype=dtype)
  271. tm.assert_numpy_array_equal(result, expected)
  272. for dtype in ["float64", "int32", "uint64"]:
  273. msg = "argument must be"
  274. with pytest.raises(TypeError, match=msg):
  275. np.array(obj, dtype=dtype)
  276. with pytest.raises(TypeError, match=msg):
  277. np.array(obj, dtype=getattr(np, dtype))