ENH: Make core/index exceptions more descriptive

* `assert_copy`: You can use `assert_copy` to check that two iterables
  produce copies that are not the same object. (uses `assert_almost_equal`
  under the hood).
* Fix assert_almost_equal to handle non-ndarrays (previously failed
  after iterable check)
* Fix test_mixed_panel to reflect true name behavior
ENH: Index inherits from FrozenNDArray + add FrozenList
ENH: Add FrozenList and FrozenNDArray types

* `FrozenNDArray` - thin wrapper around ndarray that disallows setting methods
  (will be used for levels on `MultiIndex`)
* `FrozenList` - thin wrapper around list that disallows setting methods
  (needed because of type checks elsewhere)

TST: Additional test cases for immutable containers

Index inherits from FrozenNDArray now and also returns a shallow copy
through deep copy (otherwise, could deepcopy and change metadata).
Assumption is that underlying array is still immutable-ish
BUG/ENH: Make names, levels and labels properties.

* `names` is now a property *and* is set up as an immutable tuple.
* `levels` are always (shallow) copied now and it is deprecated to set directly
* `labels` are set up as a property now, moving all the processing of
  labels out of `__new__` + shallow-copied.
* `levels` and `labels` are immutable.
* Add names tests, motivating example from #3742, reflect tuple-ish
  output from names, and level names check to reindex test.
* Add set_levels, set_labels, set_names and rename to index
* Deprecate setting labels and levels directly

Similar to other set_* methods...allows mutation if necessary but
otherwise returns same object.

Labels are now converted to `FrozenNDArray` and wrapped in a
`FrozenList`. Should mostly resolve #3714 because you have to work to
actually make assignments to an `Index`.

BUG: Give MultiIndex its own astype method

Fixes issue with set_value forgetting names.
ENH: Additional keyword arguments for Index.copy()

* Index derivatives can set `name` or `names` as well as
  `dtype` on copy. MultiIndex can set `levels`, `labels`, and `names`.
* Also, `__deepcopy__` just calls `copy(deep=True)`
* Now, BlockManager.copy() takes an additional argument `copy_axes` which
  copies axes as well. Defaults to False.
* `Series.copy()` takes an optional deep argument, which causes it to
  copy its index.
* `DataFrame.copy()` passes `copy_axes=True` when deepcopying.
* Add copy kwarg to MultiIndex `__new__`
DOC: Changes to Index and MultiIndex