Repository: geopandas/geopandas

Issue:
BUG: dissolve with multiple aggregations produces FutureWarning
- [x] I have checked that this issue has not already been reported.

- [x] I have confirmed this bug exists on the latest version of geopandas.

- [x] (optional) I have confirmed this bug exists on the main branch of geopandas.

---

#### Summary

When a list (or dict of lists) is passed into the `aggfunc` argument of `GeoDataFrame.dissolve`, it produces a `FutureWarning`.

#### Code Sample, a copy-pastable example

```python
import warnings
warnings.simplefilter("always")
import geopandas
world = geopandas.read_file(geopandas.datasets.get_path('naturalearth_lowres'))
continents = world.dissolve(by='continent', aggfunc=
{
    'pop_est': ['sum', 'min', 'max'],
    'name': 'count',
    'gdp_md_est': ['sum', 'min', 'max'],
})
```

#### Problem description

The code above produces a `FutureWarning`:
```
/Users/martina/Library/Caches/pypoetry/virtualenvs/geopandas-J5P32w_s-py3.9/lib/python3.9/site-packages/pandas/core/frame.py:9130: FutureWarning: merging between different levels is deprecated and will be removed in a future version. (1 levels on the left,2 on the right)
  return merge(
```

#### Expected Output

This should not produce a warning. This code will break in a future version of Pandas.

While the warning is suppressed by default, it appears when enabled, e.g. in unit tests, documentation builds (PR #2303 adds such code as an example in the documentation.)

#### Output of ``geopandas.show_versions()``

<details>


SYSTEM INFO
-----------
python     : 3.9.9 (main, Nov 21 2021, 03:23:44)  [Clang 13.0.0 (clang-1300.0.29.3)]
executable : /Users/martina/Library/Caches/pypoetry/virtualenvs/geopandas-J5P32w_s-py3.9/bin/python
machine    : macOS-12.1-x86_64-i386-64bit

GEOS, GDAL, PROJ INFO
---------------------
GEOS       : 3.10.1
GEOS lib   : /usr/local/Cellar/geos/3.10.1_1/lib/libgeos_c.dylib
GDAL       : 3.3.0
GDAL data dir: /Users/martina/Library/Caches/pypoetry/virtualenvs/geopandas-J5P32w_s-py3.9/lib/python3.9/site-packages/fiona/gdal_data
PROJ       : 8.2.0
PROJ data dir: /Users/martina/Library/Caches/pypoetry/virtualenvs/geopandas-J5P32w_s-py3.9/lib/python3.9/site-packages/pyproj/proj_dir/share/proj

PYTHON DEPENDENCIES
-------------------
geopandas  : 0.10.2+29.g4bd0eb9
pandas     : 1.3.5
fiona      : 1.8.20
numpy      : 1.22.1
shapely    : 1.8.0
rtree      : 0.9.7
pyproj     : 3.3.0
matplotlib : 3.5.1
mapclassify: 2.4.3
geopy      : 2.2.0
psycopg2   : None
geoalchemy2: None
pyarrow    : None
pygeos     : None

</details>



Discussion:

Resolving patch:
diff --git a/geopandas/geodataframe.py b/geopandas/geodataframe.py
--- a/geopandas/geodataframe.py
+++ b/geopandas/geodataframe.py
@@ -1552,6 +1552,7 @@ def dissolve(
         # Process non-spatial component
         data = self.drop(labels=self.geometry.name, axis=1)
         aggregated_data = data.groupby(**groupby_kwargs).agg(aggfunc)
+        aggregated_data.columns = aggregated_data.columns.to_flat_index()
 
         # Process spatial component
         def merge_geometries(block):


Test patch:
diff --git a/geopandas/tests/test_dissolve.py b/geopandas/tests/test_dissolve.py
--- a/geopandas/tests/test_dissolve.py
+++ b/geopandas/tests/test_dissolve.py
@@ -8,6 +8,8 @@
 from pandas.testing import assert_frame_equal
 import pytest
 
+from geopandas.testing import assert_geodataframe_equal
+
 
 @pytest.fixture
 def nybb_polydf():
@@ -297,3 +299,21 @@ def test_dissolve_dropna_warn(nybb_polydf):
         UserWarning, match="dropna kwarg is not supported for pandas < 1.1.0"
     ):
         nybb_polydf.dissolve(dropna=False)
+
+
+def test_dissolve_multi_agg(nybb_polydf, merged_shapes):
+
+    merged_shapes[("BoroCode", "min")] = [3, 1]
+    merged_shapes[("BoroCode", "max")] = [5, 2]
+    merged_shapes[("BoroName", "count")] = [3, 2]
+
+    with pytest.warns(None) as record:
+        test = nybb_polydf.dissolve(
+            by="manhattan_bronx",
+            aggfunc={
+                "BoroCode": ["min", "max"],
+                "BoroName": "count",
+            },
+        )
+    assert_geodataframe_equal(test, merged_shapes)
+    assert len(record) == 0