ENH: support CategoricalIndex (GH7629)
closes #7629
xref #8613 
xref #8074 
- [x] docs / whatsnew
- [x] ~~auto-create a `CategoricalIndex` when grouping by a `Categorical` (this doesn't ATM)~~
- [x] adding a value not in the Index, e.g. `df2.loc['d'] = 5` should do what? (currently will coerce to an `Index`)
- [x] `pd.concat([df2,df])` should STILL have a `CategoricalIndex` (yep)?
- [x] implement `min/max`
- [x] fix groupby on cat column
- [x] add `Categorical` wrapper methods
- [x] make repr evalable / fix
- [x] contains should be on values not categories

A `CategoricalIndex` is essentially a drop-in replacement for `Index`, that works nicely for non-unique values. It uses a `Categorical` to represent itself. The behavior is very similar to using a duplicated Index (for say indexing).

Groupby works naturally (and returns another `CategoricalIndex`). The only real departure is that `.sort_index()` works like you would expected (which is a good thing:). Clearly this will provide idempotency for `set/reset` index w.r.t. Categoricals, and thus memory savings by its representation.

This doesn't change the API at all. IOW, this is not turned on by default, you have to either use `set/reset`, assign an index, or pass a `Categorical` to `Index`.

```
In [1]: df = DataFrame({'A' : np.arange(6,dtype='int64'),
   ...:                         'B' : Series(list('aabbca')).astype('category',categories=list('cab')) })

In [2]: df
Out[2]: 
   A  B
0  0  a
1  1  a
2  2  b
3  3  b
4  4  c
5  5  a

In [3]: df.dtypes
Out[3]: 
A       int64
B    category
dtype: object

In [5]: df.B.cat.categories
Out[5]: Index([u'c', u'a', u'b'], dtype='object')

In [6]: df2 = df.set_index('B')
In [7]: df2
Out[7]: 
   A
B   
a  0
a  1
b  2
b  3
c  4
a  5

In [8]: df2.index
Out[8]: CategoricalIndex([u'a', u'a', u'b', u'b', u'c', u'a'], dtype='category')

In [9]: df2.index.categories
Out[9]: Index([u'c', u'a', u'b'], dtype='object')

In [10]: df2.index.codes     
Out[10]: array([1, 1, 2, 2, 0, 1], dtype=int8)

In [11]: df2.loc['a']
Out[11]: 
   A
B   
a  0
a  1
a  5

In [12]: df2.loc['a'].index 
Out[12]: CategoricalIndex([u'a', u'a', u'a'], dtype='category')

In [13]: df2.loc['a'].index.categories
Out[13]: Index([u'c', u'a', u'b'], dtype='object')

In [14]: df2.sort_index() 
Out[14]: 
   A
B   
c  4
a  0
a  1
a  5
b  2
b  3

In [15]: df2.groupby(level=0).sum()
Out[15]: 
   A
B   
a  6
b  5
c  4

In [16]: df2.groupby(level=0).sum().index
Out[16]: CategoricalIndex([u'a', u'b', u'c'], dtype='category')
```
