Repository: dask/dask

Issue:
groupBy on index of Series fails
<!-- Please include a self-contained copy-pastable example that generates the issue if possible.

Please be concise with code posted. See guidelines below on how to provide a good bug report:

- Craft Minimal Bug Reports http://matthewrocklin.com/blog/work/2018/02/28/minimal-bug-reports
- Minimal Complete Verifiable Examples https://stackoverflow.com/help/mcve

Bug reports that follow these guidelines are easier to diagnose, and so are often handled much more quickly.
-->

**Minimal Complete Verifiable Example**:

```python
import numpy as np
import pandas as pd
import dask.dataframe as dd

df = pd.DataFrame(np.asarray([[0,3,2],[0,2,8],[1,3,8]]), columns=["A","B","C"]).set_index("A")

# expected
print(df["B"].groupby("A").cumsum())

# In dask
ddf = dd.from_pandas(df, npartitions=1)
print(ddf["B"].groupby("A").cumsum().compute())
```

Instead of returning the same result as plain pandas, the above snippet crashes with the following traceback:
```
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
/tmp/ipykernel_4276/396749366.py in <module>
      1 # real
      2 ddf = dd.from_pandas(df, npartitions=1)
----> 3 ddf["B"].groupby("A").cumsum().compute()

.../python3.9/site-packages/dask/dataframe/groupby.py in cumsum(self, axis)
   1339             return self.obj.cumsum(axis=axis)
   1340         else:
-> 1341             return self._cum_agg("cumsum", chunk=M.cumsum, aggregate=M.add, initial=0)
   1342 
   1343     @derived_from(pd.core.groupby.GroupBy)

.../python3.9/site-packages/dask/dataframe/groupby.py in _cum_agg(self, token, chunk, aggregate, initial)
   1230 
   1231         cumpart_ext = cumpart_raw_frame.assign(
-> 1232             **{
   1233                 i: self.obj[i]
   1234                 if np.isscalar(i) and i in self.obj.columns

.../python3.9/site-packages/dask/dataframe/groupby.py in <dictcomp>(.0)
   1232             **{
   1233                 i: self.obj[i]
-> 1234                 if np.isscalar(i) and i in self.obj.columns
   1235                 else self.obj.index
   1236                 for i in by

AttributeError: 'Series' object has no attribute 'columns'

```

The above computation works fine when grouping the full dataframe, for eg `ddf.groupby("A").cumsum().compute()`
**Environment**:

- Dask version: '2022.01.0'
- Python version: 3.9
- Operating System: linux
- Install method (conda, pip, source): pip




Discussion:
Thanks for taking the time to write this up! Here's another workaround for dask:

```python
print(ddf.groupby("A")["B"].cumsum().compute())
```

I think I'll be able to make a quick fix for this. 
Ok it is more involved than I had hoped. But I just wanted to report back that the failing logic is specifically in the `_cum_agg` method so only cumsum, cumprod and the like should be having this issue. 

Resolving patch:
diff --git a/dask/dataframe/groupby.py b/dask/dataframe/groupby.py
--- a/dask/dataframe/groupby.py
+++ b/dask/dataframe/groupby.py
@@ -1231,7 +1231,7 @@ def _cum_agg(self, token, chunk, aggregate, initial):
         cumpart_ext = cumpart_raw_frame.assign(
             **{
                 i: self.obj[i]
-                if np.isscalar(i) and i in self.obj.columns
+                if np.isscalar(i) and i in getattr(self.obj, "columns", [])
                 else self.obj.index
                 for i in by
             }
@@ -1282,9 +1282,12 @@ def _cum_agg(self, token, chunk, aggregate, initial):
                 aggregate,
                 initial,
             )
-        graph = HighLevelGraph.from_collections(
-            name, dask, dependencies=[cumpart_raw, cumpart_ext, cumlast]
-        )
+
+        dependencies = [cumpart_raw]
+        if self.obj.npartitions > 1:
+            dependencies += [cumpart_ext, cumlast]
+
+        graph = HighLevelGraph.from_collections(name, dask, dependencies=dependencies)
         return new_dd_object(graph, name, chunk(self._meta), self.obj.divisions)
 
     def _shuffle(self, meta):


Test patch:
diff --git a/dask/dataframe/tests/test_groupby.py b/dask/dataframe/tests/test_groupby.py
--- a/dask/dataframe/tests/test_groupby.py
+++ b/dask/dataframe/tests/test_groupby.py
@@ -430,6 +430,19 @@ def test_series_groupby_propagates_names():
     assert_eq(result, expected)
 
 
+@pytest.mark.parametrize("npartitions", (1, 2))
+@pytest.mark.parametrize("func", ("cumsum", "cumprod", "cumcount"))
+def test_series_groupby_cumfunc_with_named_index(npartitions, func):
+    df = pd.DataFrame(
+        {"x": [1, 2, 3, 4, 5, 6, 7], "y": [8, 9, 6, 2, 3, 5, 6]}
+    ).set_index("x")
+    ddf = dd.from_pandas(df, npartitions)
+    assert ddf.npartitions == npartitions
+    expected = getattr(df["y"].groupby("x"), func)()
+    result = getattr(ddf["y"].groupby("x"), func)()
+    assert_eq(result, expected)
+
+
 def test_series_groupby():
     s = pd.Series([1, 2, 2, 1, 1])
     pd_group = s.groupby(s)