Skip to content

Commit 094e5e4

Browse files
committed
BUG: support PeriodIndex as DataFrame columns and deal with other PeriodIndex support issues in Series/DataFrame constructors, close #1211
1 parent 2cda234 commit 094e5e4

File tree

5 files changed

+63
-1
lines changed

5 files changed

+63
-1
lines changed

pandas/core/index.py

+2
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ class Index(np.ndarray):
6161
_inner_indexer = lib.inner_join_indexer_object
6262
_outer_indexer = lib.outer_join_indexer_object
6363

64+
_box_scalars = False
65+
6466
name = None
6567
asi8 = None
6668

pandas/core/internals.py

+2-1
Original file line numberDiff line numberDiff line change
@@ -1062,7 +1062,8 @@ def _shape_compat(x):
10621062
else:
10631063
return x.shape
10641064

1065-
items = [x for x in ref_items if x in dct]
1065+
# index may box values
1066+
items = ref_items[[x in dct for x in ref_items]]
10661067

10671068
first = dct[items[0]]
10681069
shape = (len(dct),) + _shape_compat(first)

pandas/core/series.py

+2
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,8 @@ def __new__(cls, data=None, index=None, dtype=None, name=None,
286286
# coerce back to datetime objects for lookup
287287
data = lib.fast_multiget(data, index.astype('O'),
288288
default=np.nan)
289+
elif isinstance(index, PeriodIndex):
290+
data = [data.get(i, nan) for i in index]
289291
else:
290292
data = lib.fast_multiget(data, index, default=np.nan)
291293
except TypeError:

pandas/tseries/period.py

+22
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ def _to_quarterly(year, month, freq='Q-DEC'):
6262

6363
class Period(object):
6464

65+
__slots__ = ['freq', 'ordinal']
66+
6567
def __init__(self, value=None, freq=None, ordinal=None,
6668
year=None, month=1, quarter=None, day=1,
6769
hour=0, minute=0, second=0):
@@ -507,6 +509,7 @@ class PeriodIndex(Int64Index):
507509
If periods is none, generated index will extend to first conforming
508510
period on or just past end argument
509511
"""
512+
_box_scalars = True
510513

511514
def __new__(cls, data=None,
512515
freq=None, start=None, end=None, periods=None,
@@ -592,6 +595,25 @@ def __new__(cls, data=None,
592595

593596
return subarr
594597

598+
def __contains__(self, key):
599+
if not isinstance(key, Period) or key.freq != self.freq:
600+
if isinstance(key, basestring):
601+
try:
602+
self.get_loc(key)
603+
return True
604+
except Exception:
605+
return False
606+
return False
607+
return key.ordinal in self._engine
608+
609+
def astype(self, dtype):
610+
dtype = np.dtype(dtype)
611+
if dtype == np.object_:
612+
result = np.empty(len(self), dtype=dtype)
613+
result[:] = [x for x in self]
614+
return result
615+
return np.ndarray.astype(self.values, dtype)
616+
595617
def __iter__(self):
596618
for val in self.values:
597619
yield Period(ordinal=val, freq=self.freq)

pandas/tseries/tests/test_period.py

+35
Original file line numberDiff line numberDiff line change
@@ -946,6 +946,39 @@ def _get_with_delta(delta, freq='A-DEC'):
946946
exp_index = _get_with_delta(delta)
947947
self.assert_(result.index.equals(exp_index))
948948

949+
def test_as_frame_columns(self):
950+
rng = period_range('1/1/2000', periods=5)
951+
df = DataFrame(randn(10, 5), columns=rng)
952+
953+
ts = df[rng[0]]
954+
assert_series_equal(ts, df.ix[:, 0])
955+
956+
# GH # 1211
957+
repr(df)
958+
959+
ts = df['1/1/2000']
960+
assert_series_equal(ts, df.ix[:, 0])
961+
962+
def test_nested_dict_frame_constructor(self):
963+
rng = period_range('1/1/2000', periods=5)
964+
df = DataFrame(randn(10, 5), columns=rng)
965+
966+
data = {}
967+
for col in df.columns:
968+
for row in df.index:
969+
data.setdefault(col, {})[row] = df.get_value(row, col)
970+
971+
result = DataFrame(data, columns=rng)
972+
tm.assert_frame_equal(result, df)
973+
974+
data = {}
975+
for col in df.columns:
976+
for row in df.index:
977+
data.setdefault(row, {})[col] = df.get_value(row, col)
978+
979+
result = DataFrame(data, index=rng).T
980+
tm.assert_frame_equal(result, df)
981+
949982
def test_frame_to_time_stamp(self):
950983
K = 5
951984
index = PeriodIndex(freq='A', start='1/1/2001', end='12/1/2009')
@@ -1425,9 +1458,11 @@ def _check_field(self, periodindex, fieldname):
14251458
for x, val in zip(periodindex, field_idx):
14261459
assert_equal(getattr(x, fieldname), val)
14271460

1461+
14281462
def _permute(obj):
14291463
return obj.take(np.random.permutation(len(obj)))
14301464

1465+
14311466
class TestMethods(TestCase):
14321467
"Base test class for MaskedArrays."
14331468

0 commit comments

Comments
 (0)