Repository: dask/dask

Issue:
Dask & Pandas giving different results for groupby aggregations 
<!-- 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.
-->

**Describe the issue**:
Performing an aggregation on a groupby gives different results in both pandas and dask. Dask results vary across separate runs, while Pandas results remains constant.

I've done a fresh installation of (only) dask on a separate environment, yet still have the same results. I've installed dask version `'2022.9.2` 

**Minimal Complete Verifiable Example**:

```
import dask
dask.__version__

# Loading Data
df = dask.datasets.timeseries(seed=42)

# Dask Computation
df_zelda = df[df['name']=='Zelda']
dask_f = df_zelda.groupby("name").aggregate({"x": "sum", "y": "max"}).compute()

# Pandas computation
pandas_df = df_zelda.compute()
pandas_f = pandas_df.groupby("name").aggregate({"x": "sum", "y": "max"})

print(dask_f)
print(pandas_f)

```

**Anything else we need to know?**:

Screenshot as shown: 

![alt text](https://i.imgur.com/vGRelRp.png)

**Environment**:

- Dask version: 2022.9.2
- Python version: 3.8.0
- Operating System: Windows
- Install method (conda, pip, source): pip 

Selecting columns from a timeseries DataFrame changes the data
**What happened**:

Selecting columns from a `DataFrame` created by `dask.datasets.timeseries` can sometimes change the data in those columns. It seems likely that the problem has something to do with `optimize_dataframe_getitem`, because using `compute(optimize_graph=False)` avoids the unexpected behavior.

**What you expected to happen**:

Selecting columns should **never** change the values in those columns.

**Minimal Complete Verifiable Example**:

```python
import dask
import dask.dataframe as dd

ddf = dask.datasets.timeseries(
    end='2000-01-02',
    freq='3600s',
    partition_freq='1d',
    seed=1,
)

columns = ["x"]
dd.assert_eq(
    ddf[columns].compute(),
    ddf.compute()[columns],
)
```

This fails! (and moving to an earlier Dask version doesn't seem to resolve the problem)


Discussion:
I tested this on the dask 2022.8.0 version and the code executes correctly (the computed results match), so there is something in the recent upgrades that breaks the calculation.
Examining this further, it seems the issue is related to the name of the column "x". Specifically, renaming column "x" to another name resolves the issue in 2022.9.2. This might be related to https://github.com/dask/dask/issues/9313.
Thanks @etjkai. 

+ @ian-r-rose -- can you take a look?
@etjkai if you `.persist() the original df (like below) does it work for you?

```python
import dask
dask.__version__

# Loading Data
df = dask.datasets.timeseries(seed=42).persist() ## <---- change here

# Dask Computation
df_zelda = df[df['name']=='Zelda']
dask_f = df_zelda.groupby("name").aggregate({"x": "sum", "y": "max"}).compute()

# Pandas computation
pandas_df = df_zelda.compute()
pandas_f = pandas_df.groupby("name").aggregate({"x": "sum", "y": "max"})

print(dask_f)
print(pandas_f)
```
Thanks for the report @etjkai! I can reproduce the issue locally as well.

A quick git bisect points to #9442
I suspect this has the same underlying cause as #9514 
That's not good! Thanks for surfacing @rjzamora. Have you noticed this other places outside of `timeseries`? I'm wondering if this issue applies to all DataFrames, or if it's related to our random seeding in `timeseries`
>I'm wondering if this issue applies to all DataFrames, or if it's related to our random seeding in timeseries

I'm 99.9% sure it's related to random sampling. I believe the random state evolution for a partition depends on the number and order of columns.
> I'm 99.9% sure it's related to random sampling

That's good to hear : ) Definitely still a bug, but glad it's isolated to `timeseries(...)` 

Resolving patch:
diff --git a/dask/dataframe/io/demo.py b/dask/dataframe/io/demo.py
--- a/dask/dataframe/io/demo.py
+++ b/dask/dataframe/io/demo.py
@@ -72,7 +72,7 @@ class MakeTimeseriesPart(DataFrameIOFunction):
 
     def __init__(self, dtypes, freq, kwargs, columns=None):
         self._columns = columns or list(dtypes.keys())
-        self.dtypes = {c: dtypes[c] for c in self.columns}
+        self.dtypes = dtypes
         self.freq = freq
         self.kwargs = kwargs
 
@@ -98,22 +98,34 @@ def __call__(self, part):
         if isinstance(state_data, int):
             state_data = random_state_data(1, state_data)
         return make_timeseries_part(
-            divisions[0], divisions[1], self.dtypes, self.freq, state_data, self.kwargs
+            divisions[0],
+            divisions[1],
+            self.dtypes,
+            self.columns,
+            self.freq,
+            state_data,
+            self.kwargs,
         )
 
 
-def make_timeseries_part(start, end, dtypes, freq, state_data, kwargs):
+def make_timeseries_part(start, end, dtypes, columns, freq, state_data, kwargs):
     index = pd.date_range(start=start, end=end, freq=freq, name="timestamp")
     state = np.random.RandomState(state_data)
-    columns = {}
+    data = {}
     for k, dt in dtypes.items():
         kws = {
             kk.rsplit("_", 1)[1]: v
             for kk, v in kwargs.items()
             if kk.rsplit("_", 1)[0] == k
         }
-        columns[k] = make[dt](len(index), state, **kws)
-    df = pd.DataFrame(columns, index=index, columns=sorted(columns))
+        # Note: we compute data for all dtypes in order, not just those in the output
+        # columns. This ensures the same output given the same state_data, regardless
+        # of whether there is any column projection.
+        # cf. https://github.com/dask/dask/pull/9538#issuecomment-1267461887
+        result = make[dt](len(index), state, **kws)
+        if k in columns:
+            data[k] = result
+    df = pd.DataFrame(data, index=index, columns=columns)
     if df.index[-1] == end:
         df = df.iloc[:-1]
     return df
@@ -184,7 +196,9 @@ def make_timeseries(
     return from_map(
         MakeTimeseriesPart(dtypes, freq, kwargs),
         parts,
-        meta=make_timeseries_part("2000", "2000", dtypes, "1H", state_data[0], kwargs),
+        meta=make_timeseries_part(
+            "2000", "2000", dtypes, list(dtypes.keys()), "1H", state_data[0], kwargs
+        ),
         divisions=divisions,
         label="make-timeseries",
         token=tokenize(start, end, dtypes, freq, partition_freq, state_data),


Test patch:
diff --git a/dask/dataframe/io/tests/test_demo.py b/dask/dataframe/io/tests/test_demo.py
--- a/dask/dataframe/io/tests/test_demo.py
+++ b/dask/dataframe/io/tests/test_demo.py
@@ -5,6 +5,7 @@
 from dask.blockwise import Blockwise, optimize_blockwise
 from dask.dataframe._compat import tm
 from dask.dataframe.optimize import optimize_dataframe_getitem
+from dask.dataframe.utils import assert_eq
 
 
 def test_make_timeseries():
@@ -157,3 +158,15 @@ def test_make_timeseries_getitem_compute():
     df3 = df2.compute()
     assert df3["y"].min() > 0
     assert list(df.columns) == list(df3.columns)
+
+
+def test_make_timeseries_column_projection():
+    ddf = dd.demo.make_timeseries(
+        "2001", "2002", freq="1D", partition_freq="3M", seed=42
+    )
+
+    assert_eq(ddf[["x"]].compute(), ddf.compute()[["x"]])
+    assert_eq(
+        ddf.groupby("name").aggregate({"x": "sum", "y": "max"}).compute(),
+        ddf.compute().groupby("name").aggregate({"x": "sum", "y": "max"}),
+    )