From 428896d59a1748278efea0acb44fb40f9508170f Mon Sep 17 00:00:00 2001 From: Chris Billington Date: Thu, 9 Feb 2012 11:39:50 +1000 Subject: [PATCH] Modifications to column-hierarchical behaviour as per "'Mixed depth' hierarchical column labels'" discussion on pystatsmodels. If column label tuples contain only empty strings at the lower levels, allows the DataFrame to be indexed with only the higher levels. So for example if a column has the hierarchical label ('a','',''), and there are no other columns with 'a' at their top level, then this change allows the column to be pulled out with df['a'], rather than df['a','','']. It also names the resulting series 'a'. The use case for this is when some columns have a deeper hierarchy than others, and you want to treat the shallower columns as if the lower levels of the hierarchy weren't there. --- pandas/core/frame.py | 5 +++++ pandas/core/generic.py | 16 +++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/pandas/core/frame.py b/pandas/core/frame.py index bb490a92d..1854cec34 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1429,6 +1429,11 @@ def _getitem_multilevel(self, key): new_values = self.values[:, loc] result = DataFrame(new_values, index=self.index, columns=result_columns) + if len(result.columns) == 1: + top = result.columns[0] + if (type(top) == str and top == '' or + type(top) == tuple and top[0] == ''): + result = Series(result[''], index=self.index, name=key) return result else: return self._get_item_cache(key) diff --git a/pandas/core/generic.py b/pandas/core/generic.py index 16ac9d78d..86f3ccbcb 100644 --- a/pandas/core/generic.py +++ b/pandas/core/generic.py @@ -302,7 +302,21 @@ def __delitem__(self, key): """ Delete item """ - self._data.delete(key) + deleted = False + if key not in self.columns: + # If column labels are tuples, allow shorthand to delete + # all columns whose first len(key) elements match key: + if not isinstance(key,tuple): + key = (key,) + for col in self.columns: + if isinstance(col,tuple) and col[:len(key)] == key: + del self[col] + deleted = True + if not deleted: + # If the above loop ran and didn't delete anything because + # there was no match, this call should raise the appropriate + # exception: + self._data.delete(key) try: del self._item_cache[key]