pydata/pandas — pull request #3045 by y-p (2013-03-14 02:08:35+00:00)
Title: Access row/col data via attributes

- Supercedes #1904
- Namespaces rows/cols as `df.r.
`, `df.c.`
- get/set, multindex in both axes
- Designates df. (75310383) for future removal.
- No perf hit on attribute lookup, if you don't use it (raised in #1904).

Open issues:
- .r and .c (which i like), don't generalize to dim>2. Use a numbered scheme instead? (a0, a1,etc')
- no panel support. No reason, I just never use them.
- Setting columns has a caveat, need your numpy-fu help here (see bottom).

Demo:
```python
In [1]: import pandas as pd
...: from pandas.util.testing import makeCustomDataframe as mkdf
...:
...: pd.options.display.notebook_repr_html=False

In [2]: df=mkdf(4,2,r_idx_nlevels=1)

In [3]: df
Out[3]:
C0 C_l0_g0 C_l0_g1
R0
R_l0_g0 R0C0 R0C1
R_l0_g1 R1C0 R1C1
R_l0_g2 R2C0 R2C1
R_l0_g3 R3C0 R3C1

In [4]: df.r.R_l0_g1 # tab-complete
Out[4]:
C0
C_l0_g0 R1C0
C_l0_g1 R1C1
Name: R_l0_g1, dtype: object

In [5]: df.r.R_l0_g1 = df.r.R_l0_g0

In [6]: df
Out[6]:
C0 C_l0_g0 C_l0_g1
R0
R_l0_g0 R0C0 R0C1
R_l0_g1 R0C0 R0C1
R_l0_g2 R2C0 R2C1
R_l0_g3 R3C0 R3C1

In [7]: df.c.C_l0_g1 # # tab-complete
Out[7]:
R0
R_l0_g0 R0C1
R_l0_g1 R0C1
R_l0_g2 R2C1
R_l0_g3 R3C1
Name: C_l0_g1, dtype: object

In [8]: df.c.C_l0_g1 = df.c.C_l0_g0

In [9]: df
Out[9]:
C0 C_l0_g0 C_l0_g1
R0
R_l0_g0 R0C0 R0C0
R_l0_g1 R0C0 R0C0
R_l0_g2 R2C0 R2C0
R_l0_g3 R3C0 R3C0
```

**Multindex example (note recursive syntax):**
```python
In [1]: import pandas as pd
...: from pandas.util.testing import makeCustomDataframe as mkdf
...:
...: pd.options.display.notebook_repr_html=False

In [2]: df=mkdf(4,2,r_idx_nlevels=2,c_idx_nlevels=2)

In [3]: df
Out[3]:
C0 C_l0_g0 C_l0_g1
C1 C_l1_g0 C_l1_g1
R0 R1
R_l0_g0 R_l1_g0 R0C0 R0C1
R_l0_g1 R_l1_g1 R1C0 R1C1
R_l0_g2 R_l1_g2 R2C0 R2C1
R_l0_g3 R_l1_g3 R3C0 R3C1

In [4]: df.r.R_l0_g1.r.R_l1_g1 # tab-complete. twice
Out[4]:
C0 C1
C_l0_g0 C_l1_g0 R1C0
C_l0_g1 C_l1_g1 R1C1
Name: R_l1_g1, dtype: object

In [5]: df.c.C_l0_g0.c.C_l1_g0 # tab-complete. twice
Out[5]:
R0 R1
R_l0_g0 R_l1_g0 R0C0
R_l0_g1 R_l1_g1 R1C0
R_l0_g2 R_l1_g2 R2C0
R_l0_g3 R_l1_g3 R3C0
Name: C_l1_g0, dtype: object

In [6]: df=mkdf(4,2,r_idx_nlevels=2,c_idx_nlevels=2)

In [7]: df.c.C_l0_g0.c.C_l1_g0=df.c.C_l0_g1.c.C_l1_g1

In [8]: df
Out[8]:
C0 C_l0_g0 C_l0_g1
C1 C_l1_g0 C_l1_g1
R0 R1
R_l0_g0 R_l1_g0 R0C1 R0C1
R_l0_g1 R_l1_g1 R1C1 R1C1
R_l0_g2 R_l1_g2 R2C1 R2C1
R_l0_g3 R_l1_g3 R3C1 R3C1
```

Suggest a fix for this? I'm sure I'm just lacking in numpy-fu here.

```python
In [7]: df.r.R_l0_g0.r.R_l1_g0 = df.r.R_l0_g1.r.R_l1_g1 # this works
In [8]: df.r.R_l0_g0.r.R_l1_g0 = df.r.R_l0_g1 # this works
In [3]: df.c.C_l0_g0.c.C_l1_g0=df.c.C_l0_g1.c.C_l1_g1 # this works
In [5]: df.c.C_l0_g0.c.C_l1_g0=df.c.C_l0_g1 # this doesn't
```