diff --git a/doc/source/whatsnew/v2.1.0.rst b/doc/source/whatsnew/v2.1.0.rst index 12d35288d1ee6..9000b3fc446c5 100644 --- a/doc/source/whatsnew/v2.1.0.rst +++ b/doc/source/whatsnew/v2.1.0.rst @@ -195,7 +195,7 @@ Groupby/resample/rolling Reshaping ^^^^^^^^^ -- +- Bug in :meth:`DataFrame.transpose` inferring dtype for object column (:issue:`51546`) - Sparse diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 8cd0ffadcc17c..de4e7deb8d2a9 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -3575,7 +3575,11 @@ def transpose(self, *args, copy: bool = False) -> DataFrame: new_vals = new_vals.copy() result = self._constructor( - new_vals, index=self.columns, columns=self.index, copy=False + new_vals, + index=self.columns, + columns=self.index, + copy=False, + dtype=new_vals.dtype, ) if using_copy_on_write() and len(self) > 0: result._mgr.add_references(self._mgr) # type: ignore[arg-type] @@ -3597,7 +3601,9 @@ def transpose(self, *args, copy: bool = False) -> DataFrame: new_arr = self.values.T if copy: new_arr = new_arr.copy() - result = self._constructor(new_arr, index=self.columns, columns=self.index) + result = self._constructor( + new_arr, index=self.columns, columns=self.index, dtype=new_arr.dtype + ) return result.__finalize__(self, method="transpose") diff --git a/pandas/tests/frame/methods/test_transpose.py b/pandas/tests/frame/methods/test_transpose.py index 6213a6dbbd0ca..e8710cea95219 100644 --- a/pandas/tests/frame/methods/test_transpose.py +++ b/pandas/tests/frame/methods/test_transpose.py @@ -7,6 +7,8 @@ DataFrame, DatetimeIndex, IntervalIndex, + Series, + Timestamp, date_range, timedelta_range, ) @@ -63,7 +65,7 @@ def test_transpose_tzaware_2col_mixed_tz(self): df4 = DataFrame({"A": dti, "B": dti2}) assert (df4.dtypes == [dti.dtype, dti2.dtype]).all() assert (df4.T.dtypes == object).all() - tm.assert_frame_equal(df4.T.T, df4) + tm.assert_frame_equal(df4.T.T, df4.astype(object)) @pytest.mark.parametrize("tz", [None, "America/New_York"]) def test_transpose_preserves_dtindex_equality_with_dst(self, tz): @@ -83,7 +85,7 @@ def test_transpose_object_to_tzaware_mixed_tz(self): df2 = DataFrame([dti, dti2]) assert (df2.dtypes == object).all() res2 = df2.T - assert (res2.dtypes == [dti.dtype, dti2.dtype]).all() + assert (res2.dtypes == object).all() def test_transpose_uint64(self, uint64_frame): result = uint64_frame.T @@ -128,3 +130,42 @@ def test_transpose_get_view_dt64tzget_view(self): rtrip = result._mgr.blocks[0].values assert np.shares_memory(arr._ndarray, rtrip._ndarray) + + def test_transpose_not_inferring_dt(self): + # GH#51546 + df = DataFrame( + { + "a": [Timestamp("2019-12-31"), Timestamp("2019-12-31")], + }, + dtype=object, + ) + result = df.T + expected = DataFrame( + [[Timestamp("2019-12-31"), Timestamp("2019-12-31")]], + columns=[0, 1], + index=["a"], + dtype=object, + ) + tm.assert_frame_equal(result, expected) + + def test_transpose_not_inferring_dt_mixed_blocks(self): + # GH#51546 + df = DataFrame( + { + "a": Series( + [Timestamp("2019-12-31"), Timestamp("2019-12-31")], dtype=object + ), + "b": [Timestamp("2019-12-31"), Timestamp("2019-12-31")], + } + ) + result = df.T + expected = DataFrame( + [ + [Timestamp("2019-12-31"), Timestamp("2019-12-31")], + [Timestamp("2019-12-31"), Timestamp("2019-12-31")], + ], + columns=[0, 1], + index=["a", "b"], + dtype=object, + ) + tm.assert_frame_equal(result, expected) diff --git a/pandas/tests/groupby/test_quantile.py b/pandas/tests/groupby/test_quantile.py index bc0422d41e74a..5801223c0e718 100644 --- a/pandas/tests/groupby/test_quantile.py +++ b/pandas/tests/groupby/test_quantile.py @@ -467,7 +467,7 @@ def test_groupby_quantile_dt64tz_period(): # Check that we match the group-by-group result exp = {i: df.iloc[i::5].quantile(0.5) for i in range(5)} - expected = DataFrame(exp).T + expected = DataFrame(exp).T.infer_objects() expected.index = expected.index.astype(np.int_) tm.assert_frame_equal(result, expected)