Repository: pandas-dev/pandas

Issue:
ENH: dataframe.astype() exception message to include column name
#### Is your feature request related to a problem?

When using dataframe.astype() and there is a column missing or there are some values that cannot be correctly converted, there is an exception raised. But there is no way to know which column is missing or which column has the wrong value.

#### Describe the solution you'd like

The exception message of the dataframe.astype() should contain the column name responsible for the exception (missing column(s) or column with wrong values).

#### API breaking implications

This does not introduce any breaking changes

#### Additional context

Some examples of the current exceptions raised by astype():

```
KeyError: 'Only a column name can be used for the key in a dtype mappings argument.'

TypeError: object cannot be converted to an IntegerDtype

ValueError: invalid literal for int() with base 10: 'test'
```



Discussion:

Patch:
diff --git a/doc/source/whatsnew/v2.0.0.rst b/doc/source/whatsnew/v2.0.0.rst
index 508d5d8bc4cc1..70e9895504eb9 100644
--- a/doc/source/whatsnew/v2.0.0.rst
+++ b/doc/source/whatsnew/v2.0.0.rst
@@ -36,7 +36,7 @@ Other enhancements
 - Added ``index`` parameter to :meth:`DataFrame.to_dict` (:issue:`46398`)
 - Added metadata propagation for binary operators on :class:`DataFrame` (:issue:`28283`)
 - :class:`.CategoricalConversionWarning`, :class:`.InvalidComparison`, :class:`.InvalidVersion`, :class:`.LossySetitemError`, and :class:`.NoBufferPresent` are now exposed in ``pandas.errors`` (:issue:`27656`)
--
+- :func:`DataFrame.astype` exception message thrown improved to include column name when type conversion is not possible. (:issue:`47571`)
 
 .. ---------------------------------------------------------------------------
 .. _whatsnew_200.notable_bug_fixes:
diff --git a/pandas/core/generic.py b/pandas/core/generic.py
index e052c77471c8d..23ada120505d5 100644
--- a/pandas/core/generic.py
+++ b/pandas/core/generic.py
@@ -6264,7 +6264,13 @@ def astype(
                 if isna(cdt):
                     res_col = col.copy() if copy else col
                 else:
-                    res_col = col.astype(dtype=cdt, copy=copy, errors=errors)
+                    try:
+                        res_col = col.astype(dtype=cdt, copy=copy, errors=errors)
+                    except ValueError as ex:
+                        ex.args = (
+                            f"{ex}: Error while type casting for column '{col_name}'",
+                        )
+                        raise
                 results.append(res_col)
 
         elif is_extension_array_dtype(dtype) and self.ndim > 1:


Test patch:
diff --git a/pandas/tests/frame/methods/test_astype.py b/pandas/tests/frame/methods/test_astype.py
index 28c264d5c7335..a4ab39c76cfbf 100644
--- a/pandas/tests/frame/methods/test_astype.py
+++ b/pandas/tests/frame/methods/test_astype.py
@@ -543,6 +543,18 @@ def test_astype_arg_for_errors(self):
 
         df.astype(np.int8, errors="ignore")
 
+    def test_astype_invalid_conversion(self):
+        # GH#47571
+        df = DataFrame({"a": [1, 2, "text"], "b": [1, 2, 3]})
+
+        msg = (
+            "invalid literal for int() with base 10: 'text': "
+            "Error while type casting for column 'a'"
+        )
+
+        with pytest.raises(ValueError, match=re.escape(msg)):
+            df.astype({"a": int})
+
     def test_astype_arg_for_errors_dictlist(self):
         # GH#25905
         df = DataFrame(