489 lines
19 KiB
Python
489 lines
19 KiB
Python
import pytest
|
|
|
|
import numpy as np
|
|
import pandas as pd
|
|
import pandas.util.testing as tm
|
|
import pandas.core.indexes.period as period
|
|
from pandas.compat import lrange, PY3, text_type, lmap
|
|
from pandas import (Period, PeriodIndex, period_range, offsets, date_range,
|
|
Series, Index)
|
|
|
|
|
|
class TestPeriodIndex(object):
|
|
|
|
def setup_method(self, method):
|
|
pass
|
|
|
|
def test_construction_base_constructor(self):
|
|
# GH 13664
|
|
arr = [pd.Period('2011-01', freq='M'), pd.NaT,
|
|
pd.Period('2011-03', freq='M')]
|
|
tm.assert_index_equal(pd.Index(arr), pd.PeriodIndex(arr))
|
|
tm.assert_index_equal(pd.Index(np.array(arr)),
|
|
pd.PeriodIndex(np.array(arr)))
|
|
|
|
arr = [np.nan, pd.NaT, pd.Period('2011-03', freq='M')]
|
|
tm.assert_index_equal(pd.Index(arr), pd.PeriodIndex(arr))
|
|
tm.assert_index_equal(pd.Index(np.array(arr)),
|
|
pd.PeriodIndex(np.array(arr)))
|
|
|
|
arr = [pd.Period('2011-01', freq='M'), pd.NaT,
|
|
pd.Period('2011-03', freq='D')]
|
|
tm.assert_index_equal(pd.Index(arr), pd.Index(arr, dtype=object))
|
|
|
|
tm.assert_index_equal(pd.Index(np.array(arr)),
|
|
pd.Index(np.array(arr), dtype=object))
|
|
|
|
def test_constructor_use_start_freq(self):
|
|
# GH #1118
|
|
p = Period('4/2/2012', freq='B')
|
|
index = PeriodIndex(start=p, periods=10)
|
|
expected = PeriodIndex(start='4/2/2012', periods=10, freq='B')
|
|
tm.assert_index_equal(index, expected)
|
|
|
|
def test_constructor_field_arrays(self):
|
|
# GH #1264
|
|
|
|
years = np.arange(1990, 2010).repeat(4)[2:-2]
|
|
quarters = np.tile(np.arange(1, 5), 20)[2:-2]
|
|
|
|
index = PeriodIndex(year=years, quarter=quarters, freq='Q-DEC')
|
|
expected = period_range('1990Q3', '2009Q2', freq='Q-DEC')
|
|
tm.assert_index_equal(index, expected)
|
|
|
|
index2 = PeriodIndex(year=years, quarter=quarters, freq='2Q-DEC')
|
|
tm.assert_numpy_array_equal(index.asi8, index2.asi8)
|
|
|
|
index = PeriodIndex(year=years, quarter=quarters)
|
|
tm.assert_index_equal(index, expected)
|
|
|
|
years = [2007, 2007, 2007]
|
|
months = [1, 2]
|
|
pytest.raises(ValueError, PeriodIndex, year=years, month=months,
|
|
freq='M')
|
|
pytest.raises(ValueError, PeriodIndex, year=years, month=months,
|
|
freq='2M')
|
|
pytest.raises(ValueError, PeriodIndex, year=years, month=months,
|
|
freq='M', start=Period('2007-01', freq='M'))
|
|
|
|
years = [2007, 2007, 2007]
|
|
months = [1, 2, 3]
|
|
idx = PeriodIndex(year=years, month=months, freq='M')
|
|
exp = period_range('2007-01', periods=3, freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
def test_constructor_U(self):
|
|
# U was used as undefined period
|
|
pytest.raises(ValueError, period_range, '2007-1-1', periods=500,
|
|
freq='X')
|
|
|
|
def test_constructor_nano(self):
|
|
idx = period_range(start=Period(ordinal=1, freq='N'),
|
|
end=Period(ordinal=4, freq='N'), freq='N')
|
|
exp = PeriodIndex([Period(ordinal=1, freq='N'),
|
|
Period(ordinal=2, freq='N'),
|
|
Period(ordinal=3, freq='N'),
|
|
Period(ordinal=4, freq='N')], freq='N')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
def test_constructor_arrays_negative_year(self):
|
|
years = np.arange(1960, 2000, dtype=np.int64).repeat(4)
|
|
quarters = np.tile(np.array([1, 2, 3, 4], dtype=np.int64), 40)
|
|
|
|
pindex = PeriodIndex(year=years, quarter=quarters)
|
|
|
|
tm.assert_index_equal(pindex.year, pd.Index(years))
|
|
tm.assert_index_equal(pindex.quarter, pd.Index(quarters))
|
|
|
|
def test_constructor_invalid_quarters(self):
|
|
pytest.raises(ValueError, PeriodIndex, year=lrange(2000, 2004),
|
|
quarter=lrange(4), freq='Q-DEC')
|
|
|
|
def test_constructor_corner(self):
|
|
pytest.raises(ValueError, PeriodIndex, periods=10, freq='A')
|
|
|
|
start = Period('2007', freq='A-JUN')
|
|
end = Period('2010', freq='A-DEC')
|
|
pytest.raises(ValueError, PeriodIndex, start=start, end=end)
|
|
pytest.raises(ValueError, PeriodIndex, start=start)
|
|
pytest.raises(ValueError, PeriodIndex, end=end)
|
|
|
|
result = period_range('2007-01', periods=10.5, freq='M')
|
|
exp = period_range('2007-01', periods=10, freq='M')
|
|
tm.assert_index_equal(result, exp)
|
|
|
|
def test_constructor_fromarraylike(self):
|
|
idx = period_range('2007-01', periods=20, freq='M')
|
|
|
|
# values is an array of Period, thus can retrieve freq
|
|
tm.assert_index_equal(PeriodIndex(idx.values), idx)
|
|
tm.assert_index_equal(PeriodIndex(list(idx.values)), idx)
|
|
|
|
pytest.raises(ValueError, PeriodIndex, idx._ndarray_values)
|
|
pytest.raises(ValueError, PeriodIndex, list(idx._ndarray_values))
|
|
pytest.raises(TypeError, PeriodIndex,
|
|
data=Period('2007', freq='A'))
|
|
|
|
result = PeriodIndex(iter(idx))
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
result = PeriodIndex(idx)
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
result = PeriodIndex(idx, freq='M')
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
result = PeriodIndex(idx, freq=offsets.MonthEnd())
|
|
tm.assert_index_equal(result, idx)
|
|
assert result.freq == 'M'
|
|
|
|
result = PeriodIndex(idx, freq='2M')
|
|
tm.assert_index_equal(result, idx.asfreq('2M'))
|
|
assert result.freq == '2M'
|
|
|
|
result = PeriodIndex(idx, freq=offsets.MonthEnd(2))
|
|
tm.assert_index_equal(result, idx.asfreq('2M'))
|
|
assert result.freq == '2M'
|
|
|
|
result = PeriodIndex(idx, freq='D')
|
|
exp = idx.asfreq('D', 'e')
|
|
tm.assert_index_equal(result, exp)
|
|
|
|
def test_constructor_datetime64arr(self):
|
|
vals = np.arange(100000, 100000 + 10000, 100, dtype=np.int64)
|
|
vals = vals.view(np.dtype('M8[us]'))
|
|
|
|
pytest.raises(ValueError, PeriodIndex, vals, freq='D')
|
|
|
|
def test_constructor_dtype(self):
|
|
# passing a dtype with a tz should localize
|
|
idx = PeriodIndex(['2013-01', '2013-03'], dtype='period[M]')
|
|
exp = PeriodIndex(['2013-01', '2013-03'], freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
assert idx.dtype == 'period[M]'
|
|
|
|
idx = PeriodIndex(['2013-01-05', '2013-03-05'], dtype='period[3D]')
|
|
exp = PeriodIndex(['2013-01-05', '2013-03-05'], freq='3D')
|
|
tm.assert_index_equal(idx, exp)
|
|
assert idx.dtype == 'period[3D]'
|
|
|
|
# if we already have a freq and its not the same, then asfreq
|
|
# (not changed)
|
|
idx = PeriodIndex(['2013-01-01', '2013-01-02'], freq='D')
|
|
|
|
res = PeriodIndex(idx, dtype='period[M]')
|
|
exp = PeriodIndex(['2013-01', '2013-01'], freq='M')
|
|
tm.assert_index_equal(res, exp)
|
|
assert res.dtype == 'period[M]'
|
|
|
|
res = PeriodIndex(idx, freq='M')
|
|
tm.assert_index_equal(res, exp)
|
|
assert res.dtype == 'period[M]'
|
|
|
|
msg = 'specified freq and dtype are different'
|
|
with tm.assert_raises_regex(period.IncompatibleFrequency, msg):
|
|
PeriodIndex(['2011-01'], freq='M', dtype='period[D]')
|
|
|
|
def test_constructor_empty(self):
|
|
idx = pd.PeriodIndex([], freq='M')
|
|
assert isinstance(idx, PeriodIndex)
|
|
assert len(idx) == 0
|
|
assert idx.freq == 'M'
|
|
|
|
with tm.assert_raises_regex(ValueError, 'freq not specified'):
|
|
pd.PeriodIndex([])
|
|
|
|
def test_constructor_pi_nat(self):
|
|
idx = PeriodIndex([Period('2011-01', freq='M'), pd.NaT,
|
|
Period('2011-01', freq='M')])
|
|
exp = PeriodIndex(['2011-01', 'NaT', '2011-01'], freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
idx = PeriodIndex(np.array([Period('2011-01', freq='M'), pd.NaT,
|
|
Period('2011-01', freq='M')]))
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
idx = PeriodIndex([pd.NaT, pd.NaT, Period('2011-01', freq='M'),
|
|
Period('2011-01', freq='M')])
|
|
exp = PeriodIndex(['NaT', 'NaT', '2011-01', '2011-01'], freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
idx = PeriodIndex(np.array([pd.NaT, pd.NaT,
|
|
Period('2011-01', freq='M'),
|
|
Period('2011-01', freq='M')]))
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
idx = PeriodIndex([pd.NaT, pd.NaT, '2011-01', '2011-01'], freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
with tm.assert_raises_regex(ValueError, 'freq not specified'):
|
|
PeriodIndex([pd.NaT, pd.NaT])
|
|
|
|
with tm.assert_raises_regex(ValueError, 'freq not specified'):
|
|
PeriodIndex(np.array([pd.NaT, pd.NaT]))
|
|
|
|
with tm.assert_raises_regex(ValueError, 'freq not specified'):
|
|
PeriodIndex(['NaT', 'NaT'])
|
|
|
|
with tm.assert_raises_regex(ValueError, 'freq not specified'):
|
|
PeriodIndex(np.array(['NaT', 'NaT']))
|
|
|
|
def test_constructor_incompat_freq(self):
|
|
msg = "Input has different freq=D from PeriodIndex\\(freq=M\\)"
|
|
|
|
with tm.assert_raises_regex(period.IncompatibleFrequency, msg):
|
|
PeriodIndex([Period('2011-01', freq='M'), pd.NaT,
|
|
Period('2011-01', freq='D')])
|
|
|
|
with tm.assert_raises_regex(period.IncompatibleFrequency, msg):
|
|
PeriodIndex(np.array([Period('2011-01', freq='M'), pd.NaT,
|
|
Period('2011-01', freq='D')]))
|
|
|
|
# first element is pd.NaT
|
|
with tm.assert_raises_regex(period.IncompatibleFrequency, msg):
|
|
PeriodIndex([pd.NaT, Period('2011-01', freq='M'),
|
|
Period('2011-01', freq='D')])
|
|
|
|
with tm.assert_raises_regex(period.IncompatibleFrequency, msg):
|
|
PeriodIndex(np.array([pd.NaT, Period('2011-01', freq='M'),
|
|
Period('2011-01', freq='D')]))
|
|
|
|
def test_constructor_mixed(self):
|
|
idx = PeriodIndex(['2011-01', pd.NaT, Period('2011-01', freq='M')])
|
|
exp = PeriodIndex(['2011-01', 'NaT', '2011-01'], freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
idx = PeriodIndex(['NaT', pd.NaT, Period('2011-01', freq='M')])
|
|
exp = PeriodIndex(['NaT', 'NaT', '2011-01'], freq='M')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
idx = PeriodIndex([Period('2011-01-01', freq='D'), pd.NaT,
|
|
'2012-01-01'])
|
|
exp = PeriodIndex(['2011-01-01', 'NaT', '2012-01-01'], freq='D')
|
|
tm.assert_index_equal(idx, exp)
|
|
|
|
def test_constructor_simple_new(self):
|
|
idx = period_range('2007-01', name='p', periods=2, freq='M')
|
|
result = idx._simple_new(idx, 'p', freq=idx.freq)
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
result = idx._simple_new(idx.astype('i8'), 'p', freq=idx.freq)
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
result = idx._simple_new([pd.Period('2007-01', freq='M'),
|
|
pd.Period('2007-02', freq='M')],
|
|
'p', freq=idx.freq)
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
result = idx._simple_new(np.array([pd.Period('2007-01', freq='M'),
|
|
pd.Period('2007-02', freq='M')]),
|
|
'p', freq=idx.freq)
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
def test_constructor_simple_new_empty(self):
|
|
# GH13079
|
|
idx = PeriodIndex([], freq='M', name='p')
|
|
result = idx._simple_new(idx, name='p', freq='M')
|
|
tm.assert_index_equal(result, idx)
|
|
|
|
@pytest.mark.parametrize('floats', [[1.1, 2.1], np.array([1.1, 2.1])])
|
|
def test_constructor_floats(self, floats):
|
|
# GH#13079
|
|
with pytest.raises(TypeError):
|
|
pd.PeriodIndex._simple_new(floats, freq='M')
|
|
|
|
with pytest.raises(TypeError):
|
|
pd.PeriodIndex(floats, freq='M')
|
|
|
|
def test_constructor_nat(self):
|
|
pytest.raises(ValueError, period_range, start='NaT',
|
|
end='2011-01-01', freq='M')
|
|
pytest.raises(ValueError, period_range, start='2011-01-01',
|
|
end='NaT', freq='M')
|
|
|
|
def test_constructor_year_and_quarter(self):
|
|
year = pd.Series([2001, 2002, 2003])
|
|
quarter = year - 2000
|
|
idx = PeriodIndex(year=year, quarter=quarter)
|
|
strs = ['%dQ%d' % t for t in zip(quarter, year)]
|
|
lops = list(map(Period, strs))
|
|
p = PeriodIndex(lops)
|
|
tm.assert_index_equal(p, idx)
|
|
|
|
def test_constructor_freq_mult(self):
|
|
# GH #7811
|
|
for func in [PeriodIndex, period_range]:
|
|
# must be the same, but for sure...
|
|
pidx = func(start='2014-01', freq='2M', periods=4)
|
|
expected = PeriodIndex(['2014-01', '2014-03',
|
|
'2014-05', '2014-07'], freq='2M')
|
|
tm.assert_index_equal(pidx, expected)
|
|
|
|
pidx = func(start='2014-01-02', end='2014-01-15', freq='3D')
|
|
expected = PeriodIndex(['2014-01-02', '2014-01-05',
|
|
'2014-01-08', '2014-01-11',
|
|
'2014-01-14'], freq='3D')
|
|
tm.assert_index_equal(pidx, expected)
|
|
|
|
pidx = func(end='2014-01-01 17:00', freq='4H', periods=3)
|
|
expected = PeriodIndex(['2014-01-01 09:00', '2014-01-01 13:00',
|
|
'2014-01-01 17:00'], freq='4H')
|
|
tm.assert_index_equal(pidx, expected)
|
|
|
|
msg = ('Frequency must be positive, because it'
|
|
' represents span: -1M')
|
|
with tm.assert_raises_regex(ValueError, msg):
|
|
PeriodIndex(['2011-01'], freq='-1M')
|
|
|
|
msg = ('Frequency must be positive, because it' ' represents span: 0M')
|
|
with tm.assert_raises_regex(ValueError, msg):
|
|
PeriodIndex(['2011-01'], freq='0M')
|
|
|
|
msg = ('Frequency must be positive, because it' ' represents span: 0M')
|
|
with tm.assert_raises_regex(ValueError, msg):
|
|
period_range('2011-01', periods=3, freq='0M')
|
|
|
|
@pytest.mark.parametrize('freq', ['A', 'M', 'D', 'T', 'S'])
|
|
@pytest.mark.parametrize('mult', [1, 2, 3, 4, 5])
|
|
def test_constructor_freq_mult_dti_compat(self, mult, freq):
|
|
freqstr = str(mult) + freq
|
|
pidx = PeriodIndex(start='2014-04-01', freq=freqstr, periods=10)
|
|
expected = date_range(start='2014-04-01', freq=freqstr,
|
|
periods=10).to_period(freqstr)
|
|
tm.assert_index_equal(pidx, expected)
|
|
|
|
def test_constructor_freq_combined(self):
|
|
for freq in ['1D1H', '1H1D']:
|
|
pidx = PeriodIndex(['2016-01-01', '2016-01-02'], freq=freq)
|
|
expected = PeriodIndex(['2016-01-01 00:00', '2016-01-02 00:00'],
|
|
freq='25H')
|
|
for freq, func in zip(['1D1H', '1H1D'], [PeriodIndex, period_range]):
|
|
pidx = func(start='2016-01-01', periods=2, freq=freq)
|
|
expected = PeriodIndex(['2016-01-01 00:00', '2016-01-02 01:00'],
|
|
freq='25H')
|
|
tm.assert_index_equal(pidx, expected)
|
|
|
|
def test_constructor(self):
|
|
pi = PeriodIndex(freq='A', start='1/1/2001', end='12/1/2009')
|
|
assert len(pi) == 9
|
|
|
|
pi = PeriodIndex(freq='Q', start='1/1/2001', end='12/1/2009')
|
|
assert len(pi) == 4 * 9
|
|
|
|
pi = PeriodIndex(freq='M', start='1/1/2001', end='12/1/2009')
|
|
assert len(pi) == 12 * 9
|
|
|
|
pi = PeriodIndex(freq='D', start='1/1/2001', end='12/31/2009')
|
|
assert len(pi) == 365 * 9 + 2
|
|
|
|
pi = PeriodIndex(freq='B', start='1/1/2001', end='12/31/2009')
|
|
assert len(pi) == 261 * 9
|
|
|
|
pi = PeriodIndex(freq='H', start='1/1/2001', end='12/31/2001 23:00')
|
|
assert len(pi) == 365 * 24
|
|
|
|
pi = PeriodIndex(freq='Min', start='1/1/2001', end='1/1/2001 23:59')
|
|
assert len(pi) == 24 * 60
|
|
|
|
pi = PeriodIndex(freq='S', start='1/1/2001', end='1/1/2001 23:59:59')
|
|
assert len(pi) == 24 * 60 * 60
|
|
|
|
start = Period('02-Apr-2005', 'B')
|
|
i1 = PeriodIndex(start=start, periods=20)
|
|
assert len(i1) == 20
|
|
assert i1.freq == start.freq
|
|
assert i1[0] == start
|
|
|
|
end_intv = Period('2006-12-31', 'W')
|
|
i1 = PeriodIndex(end=end_intv, periods=10)
|
|
assert len(i1) == 10
|
|
assert i1.freq == end_intv.freq
|
|
assert i1[-1] == end_intv
|
|
|
|
end_intv = Period('2006-12-31', '1w')
|
|
i2 = PeriodIndex(end=end_intv, periods=10)
|
|
assert len(i1) == len(i2)
|
|
assert (i1 == i2).all()
|
|
assert i1.freq == i2.freq
|
|
|
|
end_intv = Period('2006-12-31', ('w', 1))
|
|
i2 = PeriodIndex(end=end_intv, periods=10)
|
|
assert len(i1) == len(i2)
|
|
assert (i1 == i2).all()
|
|
assert i1.freq == i2.freq
|
|
|
|
end_intv = Period('2005-05-01', 'B')
|
|
i1 = PeriodIndex(start=start, end=end_intv)
|
|
|
|
# infer freq from first element
|
|
i2 = PeriodIndex([end_intv, Period('2005-05-05', 'B')])
|
|
assert len(i2) == 2
|
|
assert i2[0] == end_intv
|
|
|
|
i2 = PeriodIndex(np.array([end_intv, Period('2005-05-05', 'B')]))
|
|
assert len(i2) == 2
|
|
assert i2[0] == end_intv
|
|
|
|
# Mixed freq should fail
|
|
vals = [end_intv, Period('2006-12-31', 'w')]
|
|
pytest.raises(ValueError, PeriodIndex, vals)
|
|
vals = np.array(vals)
|
|
pytest.raises(ValueError, PeriodIndex, vals)
|
|
|
|
def test_constructor_error(self):
|
|
start = Period('02-Apr-2005', 'B')
|
|
end_intv = Period('2006-12-31', ('w', 1))
|
|
|
|
msg = 'start and end must have same freq'
|
|
with tm.assert_raises_regex(ValueError, msg):
|
|
PeriodIndex(start=start, end=end_intv)
|
|
|
|
msg = ('Of the three parameters: start, end, and periods, '
|
|
'exactly two must be specified')
|
|
with tm.assert_raises_regex(ValueError, msg):
|
|
PeriodIndex(start=start)
|
|
|
|
@pytest.mark.parametrize('freq', ['M', 'Q', 'A', 'D', 'B',
|
|
'T', 'S', 'L', 'U', 'N', 'H'])
|
|
def test_recreate_from_data(self, freq):
|
|
org = PeriodIndex(start='2001/04/01', freq=freq, periods=1)
|
|
idx = PeriodIndex(org.values, freq=freq)
|
|
tm.assert_index_equal(idx, org)
|
|
|
|
def test_map_with_string_constructor(self):
|
|
raw = [2005, 2007, 2009]
|
|
index = PeriodIndex(raw, freq='A')
|
|
types = str,
|
|
|
|
if PY3:
|
|
# unicode
|
|
types += text_type,
|
|
|
|
for t in types:
|
|
expected = Index(lmap(t, raw))
|
|
res = index.map(t)
|
|
|
|
# should return an Index
|
|
assert isinstance(res, Index)
|
|
|
|
# preserve element types
|
|
assert all(isinstance(resi, t) for resi in res)
|
|
|
|
# lastly, values should compare equal
|
|
tm.assert_index_equal(res, expected)
|
|
|
|
|
|
class TestSeriesPeriod(object):
|
|
|
|
def setup_method(self, method):
|
|
self.series = Series(period_range('2000-01-01', periods=10, freq='D'))
|
|
|
|
def test_constructor_cant_cast_period(self):
|
|
with pytest.raises(TypeError):
|
|
Series(period_range('2000-01-01', periods=10, freq='D'),
|
|
dtype=float)
|
|
|
|
def test_constructor_cast_object(self):
|
|
s = Series(period_range('1/1/2000', periods=10), dtype=object)
|
|
exp = Series(period_range('1/1/2000', periods=10))
|
|
tm.assert_series_equal(s, exp)
|