WIP/API: add magic 'X' for selection
- [ ] could close #13133
- [ ] tests added / passed
- [ ] passes `git diff upstream/master | flake8 --diff`
- [ ] whatsnew entry

This is very WIP, but wanted to put it up and show the general direction.  This adds essentially a modified version of `pandas_ply` that produces plain callables that can be passed to the existing `[]`/`assign` methods.  Short demo below.

One thing that's tricky is figuring out when an expression is "complete."  `pandas_ply` and `dplython` don't have to do this because they use a special method to instantiate the selection, but I'd prefer not to do this if possible, so this doesn't touch any pandas internals.  There's one example below (`X.c.str.upper()`) that shows where the current heuristic is failing.

cc @shoyer, @jreback, @joshuahhh @dodger487, welcome any thoughts

```
df = pd.DataFrame({'a':[1,2,3], 'b':[1.5, 2.5, 3.4],
                   'c':['abc', 'def', 'efg'],
                   'd':pd.to_datetime(['2014-01-01', '2014-01-02', '2014-01-03'])})

from pandas import X

df[X.a > 1]
Out[3]: 
   a    b    c          d
1  2  2.5  def 2014-01-02
2  3  3.4  efg 2014-01-03

df[X.d.dt.day == 2]
Out[4]: 
   a    b    c          d
1  2  2.5  def 2014-01-02

df.assign(e=X.a+1)
Out[5]: 
   a    b    c          d  e
0  1  1.5  abc 2014-01-01  2
1  2  2.5  def 2014-01-02  3
2  3  3.4  efg 2014-01-03  4

df.assign(e=X.b.pipe(np.exp))
Out[6]: 
   a    b    c          d          e
0  1  1.5  abc 2014-01-01   4.481689
1  2  2.5  def 2014-01-02  12.182494
2  3  3.4  efg 2014-01-03  29.964100

# this should work, but doesn't
df.assign(e=X.c.str.upper())
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-7-65b030f82188> in <module>()
----> 1 df.assign(e=X.c.str.upper())

# this can't work, but need to give a good error msg
df.assign(e=np.log(X.a))
---------------------------------------------------------------------------
TypeError: 
pandas `X` is a deferred object that cannot be passed into
functions. The object was attempted to be converted to a numpy array which is invalid.
To pass a deferred Series into a function, use the .pipe
function, for example, X.a.pipe(np.log), instead np.log(df.a)
```
