BUG: Fix copy s.t. it always copies index/columns.
Fixes #4202 (and maybe some others too).

Only copies index/columns with `deep=True` on `BlockManager`. Plus some 
tests...yay!

@hayd copying will work now :)
 this works for everything but SparseSeries and SparsePanel at this point...still trying to figure them out.
 re identical 

u might try something like

if a is b or a.base is b.base: ( maybe do a share memory check too)
   return True

return a.identizal(b)

so the actual identity  case is a lot faster
 Problem is that bases gets changed with view.  I.e.:

```
In [2]: i = Index(range(10)
   ...: )

In [3]: i.base
Out[3]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

In [4]: i.view().base
Out[4]: Int64Index([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64)

In [5]: i.view().view().base is i
Out[5]: True
```

so slight tweak on base.
 @jreback @cpcloud here's what I'm thinking for index, adding an `is_` method:

``` python
    def is_(self, other):
        """returns True if and only if the indices actually are the same underlying array.
         Generally survives through views. Doesn't care about metadata."""
        if self is other:
            return True
        s_base, o_base = self.base, other.base
        return self is o_base or other is s_base or s_base is o_base
```

(base calls aren't cached, which is why it needs to be setup this way)
 blah, this doesn't quite work either :-/ multiple levels of view screw up `.base`.
 It's going to take some thinking to decide on how best to efficiently handle flexible metadata for `Index`. I was thinking of setting an `_id` attribute that gets copied on views but changed when slicing, copying or setting attributes. then the `is_` check would just be comparing the equality of two ids (probably hashes of id + type name).
 Got this working (and faster) with the `is_` method from #4909. @cpcloud you want to take a look at either this or #4909 to see whether you think this is fast enough for groupby?
 i'll vbench it and report back :)
 if it's not good enough, we can shave off about 600-800ns per iteration by skipping the function call and using `self.index._id is other.index._id`
 Is this the right behavior?

```
ind = Index(range(10))
df = DataFrame(range(10), ind)
assert df.index is ind
assert (df + 1).index is ind
```
 @jtratner yep
 @jreback @cpcloud does this look okay to merge?
 ok
 yep
