Repository: pandas-dev/pandas
Pull request: BUG: Fix DateFrameGroupBy.mean error for Int64 dtype
- [x] closes #32219
- [x] tests added / passed
- [x] passes `black pandas`
- [x] passes `git diff upstream/master -u -- "*.py" | flake8 --diff`
- [x] whatsnew entry

It looks like this was due to the `TypeError` not being caught

Problem statement:
calling `mean` on a `DataFrameGroupBy` with `Int64` dtype results in `TypeError` 
```python
import pandas as pd

df = pd.DataFrame({
    'a' : [0,0,1,1,2,2,3,3],
    'b' : [1,2,3,4,5,6,7,8]
},
dtype='Int64')

df.groupby('a').mean()

```
#### Problem description

Using the new nullable integer data type, calling `mean` after grouping results in a `TypeError`. Using `int64` dtype it works:

```python
import pandas as pd

df = pd.DataFrame({
    'a' : [0,0,1,1,2,2,3,3],
    'b' : [1,2,3,4,5,6,7,8]
},
dtype='int64')

print(df.groupby('a').mean())
```

as does keeping `Int64` dtype but taking a single column to give a `SeriesGroupBy`:

```python
import pandas as pd

df = pd.DataFrame({
    'a' : [0,0,1,1,2,2,3,3],
    'b' : [1,2,3,4,5,6,7,8]
},
dtype='Int64')

print(df.groupby('a')['b'].mean())
```

The error does not occur when calling `min`, `max` or `first`, but does also occur with `median` and `std`.

#### Expected Output

```
     b
a     
0  1.5
1  3.5
2  5.5
3  7.5
```


#### Output of ``pd.show_versions()``

<details>

[paste the output of ``pd.show_versions()`` here below this line]
INSTALLED VERSIONS
------------------
commit           : None
python           : 3.7.3.final.0
python-bits      : 64
OS               : Linux
OS-release       : 4.15.0-74-generic
machine          : x86_64
processor        : x86_64
byteorder        : little
LC_ALL           : None
LANG             : en_GB.UTF-8
LOCALE           : en_GB.UTF-8

pandas           : 1.0.1
numpy            : 1.18.1
pytz             : 2019.1
dateutil         : 2.8.0
pip              : 19.1.1
setuptools       : 41.0.1
Cython           : None
pytest           : 5.3.4
hypothesis       : None
sphinx           : None
blosc            : None
feather          : None
xlsxwriter       : None
lxml.etree       : 4.3.3
html5lib         : None
pymysql          : None
psycopg2         : None
jinja2           : 2.10.1
IPython          : 7.5.0
pandas_datareader: None
bs4              : 4.8.1
bottleneck       : None
fastparquet      : None
gcsfs            : None
lxml.etree       : 4.3.3
matplotlib       : 3.1.2
numexpr          : None
odfpy            : None
openpyxl         : None
pandas_gbq       : None
pyarrow          : None
pytables         : None
pytest           : 5.3.4
pyxlsb           : None
s3fs             : None
scipy            : 1.3.0
sqlalchemy       : None
tables           : None
tabulate         : None
xarray           : None
xlrd             : 1.2.0
xlwt             : None
xlsxwriter       : None
numba            : None
</details>

Hints from issue discussion:
Update: using `agg` and passing a list consisting just of `'mean'` works:

```python
import pandas as pd
import numpy as np

df = pd.DataFrame({
    'a' : [0,0,1,1,2,2,3,3],
    'b' : [1,2,3,4,5,6,7,8]
},
dtype='Int64')

df.groupby('a').agg(['mean'])
```

but passing `'mean'` on its own doesn't:

```python
df = pd.DataFrame({
    'a' : [0,0,1,1,2,2,3,3],
    'b' : [1,2,3,4,5,6,7,8]
},
dtype='Int64')

df.groupby('a').agg('mean')
```

Commit message: Nit

Patch to review:
diff --git a/doc/source/whatsnew/v1.0.2.rst b/doc/source/whatsnew/v1.0.2.rst
index f491774991090..91752ef157a49 100644
--- a/doc/source/whatsnew/v1.0.2.rst
+++ b/doc/source/whatsnew/v1.0.2.rst
@@ -80,6 +80,7 @@ Bug fixes
 - Fixed bug in setting values using a slice indexer with string dtype (:issue:`31772`)
 - Fixed bug where :meth:`GroupBy.first` and :meth:`GroupBy.last` would raise a ``TypeError`` when groups contained ``pd.NA`` in a column of object dtype (:issue:`32123`)
 - Fix bug in :meth:`Series.convert_dtypes` for series with mix of integers and strings (:issue:`32117`)
+- Fixed bug where :meth:`DataFrameGroupBy.mean` would raise a ``TypeError`` on ``Int64`` dtype columns (:issue:`32219`)
 
 .. ---------------------------------------------------------------------------
 
diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py
index 1bb512aee39e2..555e496080cdd 100644
--- a/pandas/core/groupby/generic.py
+++ b/pandas/core/groupby/generic.py
@@ -1083,7 +1083,7 @@ def _cython_agg_blocks(
                         result = type(block.values)._from_sequence(
                             result.ravel(), dtype=block.values.dtype
                         )
-                    except ValueError:
+                    except (ValueError, TypeError):
                         # reshape to be valid for non-Extension Block
                         result = result.reshape(1, -1)
 
diff --git a/pandas/tests/groupby/test_apply.py b/pandas/tests/groupby/test_apply.py
index 18ad5d90b3f60..3e2f2d318fc43 100644
--- a/pandas/tests/groupby/test_apply.py
+++ b/pandas/tests/groupby/test_apply.py
@@ -866,3 +866,24 @@ def fct(group):
         [[1.0, 2.0], [3.0], [np.nan]], index=pd.Index(["a", "b", "none"], name="A")
     )
     tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize("contains_na", [True, False])
+def test_apply_mean_with_nullable_integer(contains_na):
+    # https://github.com/pandas-dev/pandas/issues/32219
+    if contains_na:
+        values = {
+            "a": [1, 1, 1, 2, 2, 2, 3, 3, 3],
+            "b": [1, pd.NA, 2, 1, pd.NA, 2, 1, pd.NA, 2],
+        }
+    else:
+        values = {"a": [1, 1, 2, 2, 3, 3], "b": [1, 2, 1, 2, 1, 2]}
+
+    groups = pd.DataFrame(values, dtype="Int64").groupby("a")
+    result = groups.mean()
+
+    idx = pd.Index([1, 2, 3], dtype=object, name="a")
+    arr = np.array([1.5] * 3, dtype=float)
+    expected = pd.DataFrame({"b": arr}, index=idx)
+
+    tm.assert_frame_equal(result, expected)


Code review comments:
diff_hunk: @@ -866,3 +866,24 @@ def fct(group):
         [[1.0, 2.0], [3.0], [np.nan]], index=pd.Index(["a", "b", "none"], name="A")
     )
     tm.assert_series_equal(result, expected)
+
+
+@pytest.mark.parametrize("contains_na", [True, False])
+def test_apply_mean_with_nullable_integer(contains_na):
+    # https://github.com/pandas-dev/pandas/issues/32219
+    if contains_na:
path: pandas/tests/groupby/test_apply.py
text: @user1:
IMO you can put "values" as the values of the parameteration, with a comment explaining that one of the arrays is with nullable integers, and one is not.
then you can remove the ```if/else``` clause completely.

@author:
Good idea