Repository: pandas-dev/pandas
Pull request: Groupby crash on a single level
- [/] closes #30208
- [/] tests added / passed
- [/] passes `black pandas`
- [/] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry


Problem statement:
Groupby crash on a single level 
#### Code Sample, a copy-pastable example if possible

```pytb
test = pd.DataFrame({
    'COL1': [1]
}, index=[0])

test.columns.name = 'COL'
test.columns.names = ['COL']

test.groupby(axis=1, level='COL')

#### Problem description

/opt/research-maintainer/cfm/1901-py3/lib/python3.6/site-packages/pandas/core/groupby.py in _get_grouper(obj, key, axis, level, sort, mutated, validate)
   2828                 if obj.index.name != level:
   2829                     raise ValueError('level name %s is not the name of the '
-> 2830                                      'index' % level)
   2831             elif level > 0 or level < -1:
   2832                 raise ValueError('level > 0 or level < -1 only valid with '

ValueError: level name COL is not the name of the index
```

#### Expected Output

Not crashing I think?

#### Output of ``pd.show_versions()``

<details>

INSTALLED VERSIONS
------------------
commit: None
python: 3.6.8.final.0
python-bits: 64
OS: Linux
OS-release: 2.6.32-642.6.2.el6.x86_64
machine: x86_64
processor: x86_64
byteorder: little
LC_ALL: None
LANG: en_US.UTF-8
LOCALE: en_US.UTF-8

pandas: 0.21.1
pytest: 4.4.1
pip: 9.0.1
setuptools: 28.8.0
Cython: 0.27.3
numpy: 1.13.3
scipy: 0.19.1
pyarrow: 0.13.0
xarray: 0.8.2
IPython: 5.1.0
sphinx: 1.4.4
patsy: 0.4.1
dateutil: 2.6.1
pytz: 2017.2
blosc: None
bottleneck: None
tables: 3.4.4
numexpr: 2.6.5
feather: None
matplotlib: 2.1.2
openpyxl: None
xlrd: None
xlwt: None
xlsxwriter: None
lxml: None
bs4: 4.6.0
html5lib: 0.9999999
sqlalchemy: 1.2.18
pymysql: None
psycopg2: None
jinja2: 2.8
s3fs: None
fastparquet: None
pandas_gbq: None
pandas_datareader: None


</details>

Hints from issue discussion:
In 

```pytb
> /Users/taugspurger/sandbox/pandas/pandas/core/groupby/grouper.py(495)get_grouper()
    493             if isinstance(level, str):
    494                 if obj.index.name != level:
--> 495                     raise ValueError(f"level name {level} is not the name of the index")
```

we should likely be checking the axis requested by the user, not just `obj.index`. It'd be `obj.columns` in this case.

Not sure if that will fix it entirely, but that's a start. @nlepleux are you interested in looking into this?
Sure, I'd be happy to help

Commit message: Fix groupby crash when axis = 1 and columns is not a MultiIndex

Patch to review:
diff --git a/pandas/core/groupby/grouper.py b/pandas/core/groupby/grouper.py
index b0df04f18ff1d..dca3062f67d01 100644
--- a/pandas/core/groupby/grouper.py
+++ b/pandas/core/groupby/grouper.py
@@ -491,8 +491,14 @@ def get_grouper(
                     raise ValueError("multiple levels only valid with MultiIndex")
 
             if isinstance(level, str):
-                if obj.index.name != level:
-                    raise ValueError(f"level name {level} is not the name of the index")
+                if axis == 0:
+                    axis_name = "index"
+                else:
+                    axis_name = "columns"
+                if getattr(obj, axis_name).name != level:
+                    raise ValueError(
+                        f"level name {level} is not the name of the {axis_name}"
+                    )
             elif level > 0 or level < -1:
                 raise ValueError("level > 0 or level < -1 only valid with MultiIndex")
 
diff --git a/pandas/tests/groupby/test_grouping.py b/pandas/tests/groupby/test_grouping.py
index 2c84c2f034fc6..c4096ef76ce9e 100644
--- a/pandas/tests/groupby/test_grouping.py
+++ b/pandas/tests/groupby/test_grouping.py
@@ -511,6 +511,18 @@ def test_groupby_level_index_names(self):
         with pytest.raises(ValueError, match=msg):
             df.groupby(level="foo")
 
+    def test_groupby_level_columns_names(self):
+        # This used to raise with 'level name exp is not the name of the index'
+        df = (
+            DataFrame({"exp": ["A"] * 3 + ["B"] * 3, "var1": range(6)})
+            .set_index("exp")
+            .T
+        )
+        df.groupby(level="exp", axis=1)
+        msg = "level name foo is not the name of the columns"
+        with pytest.raises(ValueError, match=msg):
+            df.groupby(level="foo", axis=1)
+
     @pytest.mark.parametrize("sort", [True, False])
     def test_groupby_level_with_nas(self, sort):
         # GH 17537


Code review comments:
diff_hunk: @@ -491,8 +491,14 @@ def get_grouper(
                     raise ValueError("multiple levels only valid with MultiIndex")
 
             if isinstance(level, str):
-                if obj.index.name != level:
-                    raise ValueError(f"level name {level} is not the name of the index")
+                if axis == 0:
path: pandas/core/groupby/grouper.py
text: @user1:
use ```obj._get_axis_name(axis)`` here instead

@author:
will do, thanks