Speedups, bugfixes, and fleshing out current AbstractDataFrame API

@tshort The third commit is the one of interest, where I shuffled around code between DataFrame and AbstractDataFrame, and fleshed out a transient interface
`eachcol` iterates through tuples of `(colname, col)`, so not the same even for `DataFrame` -- not sure what naming would make the distinction more clear. I'll look into the performance difference to see if that argument (for adding `columns` rather than replacing `df.columns` with `for (_, col) in eachcol(df)`) can be discounted, but using eachol there still makes me a little uneasy as `_` is just a naming convention rather than a guarantee that the variable won't be used, so still some clutter and cognitive overhead.