Repository: dask/dask
Pull request: Add dask.dataframe.series.view()
- [x] Closes #8439
- [x] Tests added / passed
- [x] Passes `pre-commit run --all-files`

Problem statement:
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'

Hints from issue 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.

Commit message: black reformat

Patch to review:
diff --git a/dask/dataframe/core.py b/dask/dataframe/core.py
index 3a1e517b541..5f2dcc100fa 100644
--- a/dask/dataframe/core.py
+++ b/dask/dataframe/core.py
@@ -3839,6 +3839,10 @@ def is_monotonic_decreasing(self):
             token="monotonic_decreasing",
         )
 
+    @derived_from(pd.Series)
+    def view(self, dtype):
+        return self.map_partitions(M.view, dtype, enforce_metadata=False)
+
 
 class Index(Series):
     _partition_type = pd.Index
diff --git a/dask/dataframe/tests/test_dataframe.py b/dask/dataframe/tests/test_dataframe.py
index 508e9483aa7..3ffb1942280 100644
--- a/dask/dataframe/tests/test_dataframe.py
+++ b/dask/dataframe/tests/test_dataframe.py
@@ -4765,6 +4765,12 @@ def test_nunique(dropna, axis):
     )
 
 
+def test_view():
+    s = pd.Series(range(10), dtype="int8")
+    ds = dd.from_pandas(s, npartitions=2)
+    assert_eq(ds.view("uint8"), s.view("uint8"))
+
+
 def test_simple_map_partitions():
     data = {"col_0": [9, -3, 0, -1, 5], "col_1": [-2, -7, 6, 8, -5]}
     df = pd.DataFrame(data)


Code review comments:
diff_hunk: @@ -3839,6 +3839,10 @@ def is_monotonic_decreasing(self):
             token="monotonic_decreasing",
         )
 
+    @derived_from(pd.Series)
+    def view(self, dtype):
+        return self.map_partitions(M.view, dtype, enforce_metadata=False)
path: dask/dataframe/core.py
text: @user1:
You may need to also update the `_meta` object for consistency