Repository: dask/dask

Issue:
dask.dataframe.DataFrame.rename not allowed
Is it really not allowed to rename columns of Dask DataFrame's?

The code to reproduce it:

```python
import pandas as pd
import dask.dataframe as dd
df1 = pd.DataFrame(data={'a':[1,2,3],'b':[10,20,30]})
dd1 = dd.from_pandas(df1, npartitions=3)
dd1.rename(index=str, columns={'a':'A'})
```
gives
> Traceback (most recent call last):
>   File "<stdin>", line 1, in <module>
>   File "/path/to/Python-3.6.3/lib/python3.6/site-packages/dask/dataframe/core.py", line 2565, in rename
>     raise ValueError("Cannot rename index.")
> ValueError: Cannot rename index.

The corresponding line in the core.py says:
```python
        if index is not None:
            raise ValueError("Cannot rename index.")
```
However, even Dask's own documentation examples allow `index=str`:
http://dask.pydata.org/en/latest/dataframe-api.html#dask.dataframe.DataFrame.rename

Discussion:

Patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
index 5c55ab9b4..54f256c24 100644
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -2565,7 +2565,7 @@ class DataFrame(_Frame):
         df2 = self._meta.assign(**_extract_meta(kwargs))
         return elemwise(methods.assign, self, *pairs, meta=df2)
 
-    @derived_from(pd.DataFrame)
+    @derived_from(pd.DataFrame, ua_args=['index'])
     def rename(self, index=None, columns=None):
         if index is not None:
             raise ValueError("Cannot rename index.")
@@ -3536,7 +3536,17 @@ def apply_and_enforce(func, args, kwargs, meta):
     if isinstance(df, (pd.DataFrame, pd.Series, pd.Index)):
         if len(df) == 0:
             return meta
-        c = meta.columns if isinstance(df, pd.DataFrame) else meta.name
+
+        if isinstance(df, pd.DataFrame):
+            # Need nan_to_num otherwise nan comparison gives False
+            if not np.array_equal(np.nan_to_num(meta.columns),
+                                  np.nan_to_num(df.columns)):
+                raise ValueError("The columns in the computed data do not match"
+                                 " the columns in the provided metadata")
+            else:
+                c = meta.columns
+        else:
+            c = meta.name
         return _rename(c, df)
     return df
 
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index df2d77421..6bc853540 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -14,6 +14,7 @@ Dataframe
 +++++++++
 
 - Add to/read_json (:pr:`3494`) `Martin Durant`_
+- Adds ``index`` to unsupported arguments for ``DataFrame.rename`` method (:pr:`3522`) `James Bourbeau`_
 
 Bag
 +++


Test patch:
diff --git a/dask/dataframe/io/tests/test_io.py b/dask/dataframe/io/tests/test_io.py
index adee19cb3..0c8e582ee 100644
--- a/dask/dataframe/io/tests/test_io.py
+++ b/dask/dataframe/io/tests/test_io.py
@@ -514,6 +514,29 @@ def test_from_delayed():
     assert str(e.value).startswith('Metadata mismatch found in `from_delayed`')
 
 
+def test_from_delayed_misordered_meta():
+    df = pd.DataFrame(
+        columns=['(1)', '(2)', 'date', 'ent', 'val'],
+        data=[range(i * 5, i * 5 + 5) for i in range(3)],
+        index=range(3)
+    )
+
+    # meta with different order for columns
+    misordered_meta = pd.DataFrame(
+        columns=['date', 'ent', 'val', '(1)', '(2)'],
+        data=[range(5)]
+    )
+
+    ddf = dd.from_delayed([delayed(lambda: df)()], meta=misordered_meta)
+
+    with pytest.raises(ValueError) as info:
+        #produces dataframe which does not match meta
+        ddf.reset_index().compute()
+    msg = "The columns in the computed data do not match the columns in the" \
+          " provided metadata"
+    assert msg in str(info.value)
+
+
 def test_from_delayed_sorted():
     a = pd.DataFrame({'x': [1, 2]}, index=[1, 10])
     b = pd.DataFrame({'x': [4, 1]}, index=[100, 200])