Repository: dask/dask

Issue:
Series / DataFrame view method not implemented.
When attempting to convert a column from one dtype to another using `astype`, there is a `FutureWarning` raised by Dask and Pandas regarding the move to using `view`.

Pandas suggests replacing the `astype` method with `view`, however `view` appears not to be implemented in `dask.dataframe.core`.

This is the `FutureWarning` from Pandas:

> FutureWarning: casting datetime64[ns] values to int64 with .astype(...) is deprecated and will raise in a future version. Use .view(...) instead.
df['TIMESTAMP_astype'] = df['TIMESTAMP'].astype('int64')


Setup:
```
import pandas as pd
import dask.dataframe as dd

data = {
    'TIMESTAMP': [
        '2021-11-27 00:05:02.175274',
        '2021-11-27 00:05:05.205596',
        '2021-11-27 00:05:29.212572',
        '2021-11-27 00:05:25.708343',
        '2021-11-27 00:05:47.714958',
    ]
}

df = pd.DataFrame(data)
df['TIMESTAMP'] = pd.to_datetime(df['TIMESTAMP'])

ddf = dd.from_pandas(df, npartitions=1)
ddf['TIMESTAMP'] = dd.to_datetime(ddf['TIMESTAMP'])
```

Pandas code:
```
df['TIMESTAMP_astype'] = df['TIMESTAMP'].astype('int64')  # works - throws FutureWarning
df['TIMESTAMP_view'] = df['TIMESTAMP'].view('int64')  # works

assert (df['TIMESTAMP_astype'] == df['TIMESTAMP_view']).all()  # True
```

Dask code:
```
ddf['TIMESTAMP_astype'] = ddf['TIMESTAMP'].astype('int64')  # works - throws FutureWarning
ddf['TIMESTAMP_view'] = ddf['TIMESTAMP'].view('int64')  # error - below
```

Not implemented `view` in `dask.dataframe.core`:
> AttributeError: 'Series' object has no attribute 'view'


Discussion:
Thanks for raising this @ocqco . It looks like this deprecation was added in [pandas 1.3.0](https://pandas.pydata.org/docs/whatsnew/v1.3.0.html#other-deprecations). I also see some heartache downstream related to this in holoviews: https://github.com/holoviz/holoviews/issues/5146.

I don't *think* it would be hugely difficult to add a `view` method to dask.dataframe.

Resolving patch:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -3839,6 +3839,11 @@ def is_monotonic_decreasing(self):
             token="monotonic_decreasing",
         )
 
+    @derived_from(pd.Series)
+    def view(self, dtype):
+        meta = self._meta.view(dtype)
+        return self.map_partitions(M.view, dtype, meta=meta)
+
 
 class Index(Series):
     _partition_type = pd.Index


Test patch:
diff --git a/dask/dataframe/tests/test_dataframe.py b/dask/dataframe/tests/test_dataframe.py
--- a/dask/dataframe/tests/test_dataframe.py
+++ b/dask/dataframe/tests/test_dataframe.py
@@ -4765,6 +4765,27 @@ def test_nunique(dropna, axis):
     )
 
 
+def test_view():
+    data = {
+        "x": pd.Series(range(5), dtype="int8"),
+        "y": pd.Series(
+            [
+                "2021-11-27 00:05:02.175274",
+                "2021-11-27 00:05:05.205596",
+                "2021-11-27 00:05:29.212572",
+                "2021-11-27 00:05:25.708343",
+                "2021-11-27 00:05:47.714958",
+            ],
+            dtype="datetime64[ns]",
+        ),
+    }
+
+    df = pd.DataFrame(data)
+    ddf = dd.from_pandas(df, npartitions=2)
+    assert_eq(ddf["x"].view("uint8"), df["x"].view("uint8"))
+    assert_eq(ddf["y"].view("int64"), df["y"].view("int64"))
+
+
 def test_simple_map_partitions():
     data = {"col_0": [9, -3, 0, -1, 5], "col_1": [-2, -7, 6, 8, -5]}
     df = pd.DataFrame(data)