diff --git a/doc/source/whatsnew/v1.4.0.rst b/doc/source/whatsnew/v1.4.0.rst index 7270227e113da..55c149d757811 100644 --- a/doc/source/whatsnew/v1.4.0.rst +++ b/doc/source/whatsnew/v1.4.0.rst @@ -703,6 +703,7 @@ Reshaping - Bug in :meth:`DataFrame.append` failing to retain ``index.name`` when appending a list of :class:`Series` objects (:issue:`44109`) - Fixed metadata propagation in :meth:`Dataframe.apply` method, consequently fixing the same issue for :meth:`Dataframe.transform`, :meth:`Dataframe.nunique` and :meth:`Dataframe.mode` (:issue:`28283`) - Bug in :meth:`DataFrame.stack` with ``ExtensionDtype`` columns incorrectly raising (:issue:`43561`) +- Bug in :meth:`Series.unstack` with object doing unwanted type inference on resulting columns (:issue:`44595`) - Sparse diff --git a/pandas/core/reshape/reshape.py b/pandas/core/reshape/reshape.py index 6c6b14653df75..a4f2c5c87ff49 100644 --- a/pandas/core/reshape/reshape.py +++ b/pandas/core/reshape/reshape.py @@ -213,7 +213,9 @@ def get_result(self, values, value_columns, fill_value): columns = self.get_new_columns(value_columns) index = self.new_index - return self.constructor(values, index=index, columns=columns) + return self.constructor( + values, index=index, columns=columns, dtype=values.dtype + ) def get_new_values(self, values, fill_value=None): diff --git a/pandas/tests/extension/base/reshaping.py b/pandas/tests/extension/base/reshaping.py index 8f241679d5108..b7bb4c95372cc 100644 --- a/pandas/tests/extension/base/reshaping.py +++ b/pandas/tests/extension/base/reshaping.py @@ -3,12 +3,6 @@ import numpy as np import pytest -from pandas.core.dtypes.common import ( - is_datetime64tz_dtype, - is_interval_dtype, - is_period_dtype, -) - import pandas as pd from pandas.api.extensions import ExtensionArray from pandas.core.internals import ExtensionBlock @@ -327,17 +321,11 @@ def test_unstack(self, data, index, obj): expected = ser.astype(object).unstack( level=level, fill_value=data.dtype.na_value ) - if obj == "series": - # TODO: special cases belong in dtype-specific tests - if is_datetime64tz_dtype(data.dtype): - assert expected.dtypes.apply(is_datetime64tz_dtype).all() - expected = expected.astype(object) - if is_period_dtype(data.dtype): - assert expected.dtypes.apply(is_period_dtype).all() - expected = expected.astype(object) - if is_interval_dtype(data.dtype): - assert expected.dtypes.apply(is_interval_dtype).all() - expected = expected.astype(object) + if obj == "series" and not isinstance(ser.dtype, pd.SparseDtype): + # GH#34457 SparseArray.astype(object) gives Sparse[object] + # instead of np.dtype(object) + assert (expected.dtypes == object).all() + result = result.astype(object) self.assert_frame_equal(result, expected) diff --git a/pandas/tests/series/methods/test_unstack.py b/pandas/tests/series/methods/test_unstack.py index 6f8f6d638dd56..23b068214dd91 100644 --- a/pandas/tests/series/methods/test_unstack.py +++ b/pandas/tests/series/methods/test_unstack.py @@ -10,6 +10,18 @@ import pandas._testing as tm +def test_unstack_preserves_object(): + mi = MultiIndex.from_product([["bar", "foo"], ["one", "two"]]) + + ser = Series(np.arange(4.0), index=mi, dtype=object) + + res1 = ser.unstack() + assert (res1.dtypes == object).all() + + res2 = ser.unstack(level=0) + assert (res2.dtypes == object).all() + + def test_unstack(): index = MultiIndex( levels=[["bar", "foo"], ["one", "three", "two"]],