diff --git a/doc/source/whatsnew/v0.25.0.rst b/doc/source/whatsnew/v0.25.0.rst index 18a3785867714..0d6e94cb1e3d0 100644 --- a/doc/source/whatsnew/v0.25.0.rst +++ b/doc/source/whatsnew/v0.25.0.rst @@ -775,6 +775,7 @@ Reshaping - Bug in :func:`DataFrame.sort_index` where an error is thrown when a multi-indexed ``DataFrame`` is sorted on all levels with the initial level sorted last (:issue:`26053`) - Bug in :meth:`Series.nlargest` treats ``True`` as smaller than ``False`` (:issue:`26154`) - Bug in :func:`DataFrame.pivot_table` with a :class:`IntervalIndex` as pivot index would raise ``TypeError`` (:issue:`25814`) +- Bug in :meth:`DataFrame.transpose` where transposing a DataFrame with a timezone-aware datetime column would incorrectly raise ``ValueError`` (:issue:`26825`) Sparse ^^^^^^ @@ -802,6 +803,7 @@ Other - Removed unused C functions from vendored UltraJSON implementation (:issue:`26198`) - Allow :class:`Index` and :class:`RangeIndex` to be passed to numpy ``min`` and ``max`` functions (:issue:`26125`) - Use actual class name in repr of empty objects of a ``Series`` subclass (:issue:`27001`). +- Bug in :class:`DataFrame` where passing an object array of timezone-aware `datetime` objects would incorrectly raise ``ValueError`` (:issue:`13287`) .. _whatsnew_0.250.contributors: diff --git a/pandas/core/groupby/generic.py b/pandas/core/groupby/generic.py index 1b4e001620286..a10920b7a5afb 100644 --- a/pandas/core/groupby/generic.py +++ b/pandas/core/groupby/generic.py @@ -21,10 +21,12 @@ from pandas.errors import AbstractMethodError from pandas.util._decorators import Appender, Substitution -from pandas.core.dtypes.cast import maybe_downcast_to_dtype +from pandas.core.dtypes.cast import ( + maybe_convert_objects, maybe_downcast_to_dtype) from pandas.core.dtypes.common import ( ensure_int64, ensure_platform_int, is_bool, is_datetimelike, - is_integer_dtype, is_interval_dtype, is_numeric_dtype, is_scalar) + is_integer_dtype, is_interval_dtype, is_numeric_dtype, is_object_dtype, + is_scalar) from pandas.core.dtypes.missing import isna, notna from pandas._typing import FrameOrSeries @@ -334,7 +336,6 @@ def _decide_output_index(self, output, labels): def _wrap_applied_output(self, keys, values, not_indexed_same=False): from pandas.core.index import _all_indexes_same - from pandas.core.tools.numeric import to_numeric if len(keys) == 0: return DataFrame(index=keys) @@ -406,7 +407,6 @@ def first_not_none(values): # provide a reduction (Frame -> Series) if groups are # unique if self.squeeze: - # assign the name to this series if singular_series: values[0].name = keys[0] @@ -481,14 +481,7 @@ def first_not_none(values): # as we are stacking can easily have object dtypes here so = self._selected_obj if so.ndim == 2 and so.dtypes.apply(is_datetimelike).any(): - result = result.apply( - lambda x: to_numeric(x, errors='ignore')) - date_cols = self._selected_obj.select_dtypes( - include=['datetime', 'timedelta']).columns - date_cols = date_cols.intersection(result.columns) - result[date_cols] = (result[date_cols] - ._convert(datetime=True, - coerce=True)) + result = _recast_datetimelike_result(result) else: result = result._convert(datetime=True) @@ -1710,3 +1703,35 @@ def _normalize_keyword_aggregation(kwargs): order.append((column, com.get_callable_name(aggfunc) or aggfunc)) return aggspec, columns, order + + +def _recast_datetimelike_result(result: DataFrame) -> DataFrame: + """ + If we have date/time like in the original, then coerce dates + as we are stacking can easily have object dtypes here. + + Parameters + ---------- + result : DataFrame + + Returns + ------- + DataFrame + + Notes + ----- + - Assumes Groupby._selected_obj has ndim==2 and at least one + datetimelike column + """ + result = result.copy() + + obj_cols = [idx for idx in range(len(result.columns)) + if is_object_dtype(result.dtypes[idx])] + + # See GH#26285 + for n in obj_cols: + converted = maybe_convert_objects(result.iloc[:, n].values, + convert_numeric=False) + + result.iloc[:, n] = converted + return result diff --git a/pandas/core/internals/construction.py b/pandas/core/internals/construction.py index d766d7f06d34a..ecdf8a1f77b94 100644 --- a/pandas/core/internals/construction.py +++ b/pandas/core/internals/construction.py @@ -159,9 +159,28 @@ def init_ndarray(values, index, columns, dtype=None, copy=False): # on the entire block; this is to convert if we have datetimelike's # embedded in an object type if dtype is None and is_object_dtype(values): - values = maybe_infer_to_datetimelike(values) - return create_block_manager_from_blocks([values], [columns, index]) + if values.ndim == 2 and values.shape[0] != 1: + # transpose and separate blocks + + dvals_list = [maybe_infer_to_datetimelike(row) for row in values] + for n in range(len(dvals_list)): + if isinstance(dvals_list[n], np.ndarray): + dvals_list[n] = dvals_list[n].reshape(1, -1) + + from pandas.core.internals.blocks import make_block + + # TODO: What about re-joining object columns? + block_values = [make_block(dvals_list[n], placement=[n]) + for n in range(len(dvals_list))] + + else: + datelike_vals = maybe_infer_to_datetimelike(values) + block_values = [datelike_vals] + else: + block_values = [values] + + return create_block_manager_from_blocks(block_values, [columns, index]) def init_dict(data, index, columns, dtype=None): diff --git a/pandas/tests/arithmetic/test_datetime64.py b/pandas/tests/arithmetic/test_datetime64.py index 64b4e162483f1..b1091d38c10d0 100644 --- a/pandas/tests/arithmetic/test_datetime64.py +++ b/pandas/tests/arithmetic/test_datetime64.py @@ -448,8 +448,7 @@ def test_dti_cmp_null_scalar_inequality(self, tz_naive_fixture, other, # GH#19301 tz = tz_naive_fixture dti = pd.date_range('2016-01-01', periods=2, tz=tz) - # FIXME: ValueError with transpose - dtarr = tm.box_expected(dti, box_with_array, transpose=False) + dtarr = tm.box_expected(dti, box_with_array) msg = 'Invalid comparison between' with pytest.raises(TypeError, match=msg): dtarr < other @@ -597,49 +596,63 @@ def test_dti_cmp_nat_behaves_like_float_cmp_nan(self): @pytest.mark.parametrize('op', [operator.eq, operator.ne, operator.gt, operator.ge, operator.lt, operator.le]) - def test_comparison_tzawareness_compat(self, op, box_with_array): + def test_comparison_tzawareness_compat(self, op, box_df_fail): # GH#18162 + box = box_df_fail + dr = pd.date_range('2016-01-01', periods=6) dz = dr.tz_localize('US/Pacific') - # FIXME: ValueError with transpose - dr = tm.box_expected(dr, box_with_array, transpose=False) - dz = tm.box_expected(dz, box_with_array, transpose=False) + dr = tm.box_expected(dr, box) + dz = tm.box_expected(dz, box) msg = 'Cannot compare tz-naive and tz-aware' with pytest.raises(TypeError, match=msg): op(dr, dz) - if box_with_array is not pd.DataFrame: - # DataFrame op is invalid until transpose bug is fixed - with pytest.raises(TypeError, match=msg): - op(dr, list(dz)) - with pytest.raises(TypeError, match=msg): - op(dr, np.array(list(dz), dtype=object)) + # FIXME: DataFrame case fails to raise for == and !=, wrong + # message for inequalities + with pytest.raises(TypeError, match=msg): + op(dr, list(dz)) + with pytest.raises(TypeError, match=msg): + op(dr, np.array(list(dz), dtype=object)) with pytest.raises(TypeError, match=msg): op(dz, dr) - if box_with_array is not pd.DataFrame: - # DataFrame op is invalid until transpose bug is fixed - with pytest.raises(TypeError, match=msg): - op(dz, list(dr)) - with pytest.raises(TypeError, match=msg): - op(dz, np.array(list(dr), dtype=object)) + + # FIXME: DataFrame case fails to raise for == and !=, wrong + # message for inequalities + with pytest.raises(TypeError, match=msg): + op(dz, list(dr)) + with pytest.raises(TypeError, match=msg): + op(dz, np.array(list(dr), dtype=object)) # Check that there isn't a problem aware-aware and naive-naive do not # raise assert_all(dr == dr) assert_all(dz == dz) - if box_with_array is not pd.DataFrame: - # DataFrame doesn't align the lists correctly unless we transpose, - # which we cannot do at the moment - assert (dr == list(dr)).all() - assert (dz == list(dz)).all() + + # FIXME: DataFrame case fails to raise for == and !=, wrong + # message for inequalities + assert (dr == list(dr)).all() + assert (dz == list(dz)).all() + + @pytest.mark.parametrize('op', [operator.eq, operator.ne, + operator.gt, operator.ge, + operator.lt, operator.le]) + def test_comparison_tzawareness_compat_scalars(self, op, box_with_array): + # GH#18162 + dr = pd.date_range('2016-01-01', periods=6) + dz = dr.tz_localize('US/Pacific') + + dr = tm.box_expected(dr, box_with_array) + dz = tm.box_expected(dz, box_with_array) # Check comparisons against scalar Timestamps ts = pd.Timestamp('2000-03-14 01:59') ts_tz = pd.Timestamp('2000-03-14 01:59', tz='Europe/Amsterdam') assert_all(dr > ts) + msg = 'Cannot compare tz-naive and tz-aware' with pytest.raises(TypeError, match=msg): op(dr, ts_tz) @@ -662,8 +675,7 @@ def test_scalar_comparison_tzawareness(self, op, other, tz_aware_fixture, tz = tz_aware_fixture dti = pd.date_range('2016-01-01', periods=2, tz=tz) - # FIXME: ValueError with transpose - dtarr = tm.box_expected(dti, box_with_array, transpose=False) + dtarr = tm.box_expected(dti, box_with_array) msg = 'Cannot compare tz-naive and tz-aware' with pytest.raises(TypeError, match=msg): op(dtarr, other) @@ -725,17 +737,16 @@ def test_dt64arr_cmp_scalar_invalid(self, other, tz_naive_fixture, xbox = box_with_array if box_with_array is not pd.Index else np.ndarray rng = date_range('1/1/2000', periods=10, tz=tz) - # FIXME: ValueError with transpose - rng = tm.box_expected(rng, box_with_array, transpose=False) + rng = tm.box_expected(rng, box_with_array) result = rng == other expected = np.array([False] * 10) - expected = tm.box_expected(expected, xbox, transpose=False) + expected = tm.box_expected(expected, xbox) tm.assert_equal(result, expected) result = rng != other expected = np.array([True] * 10) - expected = tm.box_expected(expected, xbox, transpose=False) + expected = tm.box_expected(expected, xbox) tm.assert_equal(result, expected) msg = 'Invalid comparison between' with pytest.raises(TypeError, match=msg): @@ -826,9 +837,8 @@ def test_dt64arr_add_timedeltalike_scalar(self, tz_naive_fixture, expected = pd.date_range('2000-01-01 02:00', '2000-02-01 02:00', tz=tz) - # FIXME: calling with transpose=True raises ValueError - rng = tm.box_expected(rng, box_with_array, transpose=False) - expected = tm.box_expected(expected, box_with_array, transpose=False) + rng = tm.box_expected(rng, box_with_array) + expected = tm.box_expected(expected, box_with_array) result = rng + two_hours tm.assert_equal(result, expected) @@ -841,9 +851,8 @@ def test_dt64arr_iadd_timedeltalike_scalar(self, tz_naive_fixture, expected = pd.date_range('2000-01-01 02:00', '2000-02-01 02:00', tz=tz) - # FIXME: calling with transpose=True raises ValueError - rng = tm.box_expected(rng, box_with_array, transpose=False) - expected = tm.box_expected(expected, box_with_array, transpose=False) + rng = tm.box_expected(rng, box_with_array) + expected = tm.box_expected(expected, box_with_array) rng += two_hours tm.assert_equal(rng, expected) @@ -856,9 +865,8 @@ def test_dt64arr_sub_timedeltalike_scalar(self, tz_naive_fixture, expected = pd.date_range('1999-12-31 22:00', '2000-01-31 22:00', tz=tz) - # FIXME: calling with transpose=True raises ValueError - rng = tm.box_expected(rng, box_with_array, transpose=False) - expected = tm.box_expected(expected, box_with_array, transpose=False) + rng = tm.box_expected(rng, box_with_array) + expected = tm.box_expected(expected, box_with_array) result = rng - two_hours tm.assert_equal(result, expected) @@ -871,9 +879,8 @@ def test_dt64arr_isub_timedeltalike_scalar(self, tz_naive_fixture, expected = pd.date_range('1999-12-31 22:00', '2000-01-31 22:00', tz=tz) - # FIXME: calling with transpose=True raises ValueError - rng = tm.box_expected(rng, box_with_array, transpose=False) - expected = tm.box_expected(expected, box_with_array, transpose=False) + rng = tm.box_expected(rng, box_with_array) + expected = tm.box_expected(expected, box_with_array) rng -= two_hours tm.assert_equal(rng, expected) @@ -928,9 +935,6 @@ def test_dt64arr_add_sub_td64_nat(self, box_with_array, tz_naive_fixture): def test_dt64arr_add_sub_td64ndarray(self, tz_naive_fixture, box_with_array): - if box_with_array is pd.DataFrame: - pytest.xfail("FIXME: ValueError with transpose; " - "alignment error without") tz = tz_naive_fixture dti = pd.date_range('2016-01-01', periods=3, tz=tz) @@ -952,7 +956,7 @@ def test_dt64arr_add_sub_td64ndarray(self, tz_naive_fixture, result = dtarr - tdarr tm.assert_equal(result, expected) - msg = 'cannot subtract' + msg = 'cannot subtract|bad operand type for unary -' with pytest.raises(TypeError, match=msg): tdarr - dtarr @@ -997,13 +1001,11 @@ def test_dt64arr_sub_timestamp(self, box_with_array): tz='US/Eastern') ts = ser[0] - # FIXME: transpose raises ValueError - ser = tm.box_expected(ser, box_with_array, transpose=False) + ser = tm.box_expected(ser, box_with_array) delta_series = pd.Series([np.timedelta64(0, 'D'), np.timedelta64(1, 'D')]) - expected = tm.box_expected(delta_series, box_with_array, - transpose=False) + expected = tm.box_expected(delta_series, box_with_array) tm.assert_equal(ser - ts, expected) tm.assert_equal(ts - ser, -expected) @@ -1011,20 +1013,19 @@ def test_dt64arr_sub_timestamp(self, box_with_array): def test_dt64arr_sub_NaT(self, box_with_array): # GH#18808 dti = pd.DatetimeIndex([pd.NaT, pd.Timestamp('19900315')]) - ser = tm.box_expected(dti, box_with_array, transpose=False) + ser = tm.box_expected(dti, box_with_array) result = ser - pd.NaT expected = pd.Series([pd.NaT, pd.NaT], dtype='timedelta64[ns]') - # FIXME: raises ValueError with transpose - expected = tm.box_expected(expected, box_with_array, transpose=False) + expected = tm.box_expected(expected, box_with_array) tm.assert_equal(result, expected) dti_tz = dti.tz_localize('Asia/Tokyo') - ser_tz = tm.box_expected(dti_tz, box_with_array, transpose=False) + ser_tz = tm.box_expected(dti_tz, box_with_array) result = ser_tz - pd.NaT expected = pd.Series([pd.NaT, pd.NaT], dtype='timedelta64[ns]') - expected = tm.box_expected(expected, box_with_array, transpose=False) + expected = tm.box_expected(expected, box_with_array) tm.assert_equal(result, expected) # ------------------------------------------------------------- @@ -1044,16 +1045,13 @@ def test_dt64arr_naive_sub_dt64ndarray(self, box_with_array): def test_dt64arr_aware_sub_dt64ndarray_raises(self, tz_aware_fixture, box_with_array): - if box_with_array is pd.DataFrame: - pytest.xfail("FIXME: ValueError with transpose; " - "alignment error without") tz = tz_aware_fixture dti = pd.date_range('2016-01-01', periods=3, tz=tz) dt64vals = dti.values dtarr = tm.box_expected(dti, box_with_array) - msg = 'DatetimeArray subtraction must have the same timezones or' + msg = 'subtraction must have the same timezones or' with pytest.raises(TypeError, match=msg): dtarr - dt64vals with pytest.raises(TypeError, match=msg): @@ -1064,9 +1062,6 @@ def test_dt64arr_aware_sub_dt64ndarray_raises(self, tz_aware_fixture, def test_dt64arr_add_dt64ndarray_raises(self, tz_naive_fixture, box_with_array): - if box_with_array is pd.DataFrame: - pytest.xfail("FIXME: ValueError with transpose; " - "alignment error without") tz = tz_naive_fixture dti = pd.date_range('2016-01-01', periods=3, tz=tz) @@ -1214,9 +1209,8 @@ def test_dti_add_tick_tzaware(self, tz_aware_fixture, box_with_array): expected = DatetimeIndex(['2010-11-01 05:00', '2010-11-01 06:00', '2010-11-01 07:00'], freq='H', tz=tz) - # FIXME: these raise ValueError with transpose=True - dates = tm.box_expected(dates, box_with_array, transpose=False) - expected = tm.box_expected(expected, box_with_array, transpose=False) + dates = tm.box_expected(dates, box_with_array) + expected = tm.box_expected(expected, box_with_array) # TODO: parametrize over the scalar being added? radd? sub? offset = dates + pd.offsets.Hour(5) @@ -1369,26 +1363,25 @@ def test_dt64arr_add_sub_DateOffset(self, box_with_array): s = DatetimeIndex([Timestamp('2000-01-15 00:15:00', tz='US/Central'), Timestamp('2000-02-15', tz='US/Central')], name='a') - # FIXME: ValueError with tzaware DataFrame transpose - s = tm.box_expected(s, box_with_array, transpose=False) + s = tm.box_expected(s, box_with_array) result = s + pd.offsets.Day() result2 = pd.offsets.Day() + s exp = DatetimeIndex([Timestamp('2000-01-16 00:15:00', tz='US/Central'), Timestamp('2000-02-16', tz='US/Central')], name='a') - exp = tm.box_expected(exp, box_with_array, transpose=False) + exp = tm.box_expected(exp, box_with_array) tm.assert_equal(result, exp) tm.assert_equal(result2, exp) s = DatetimeIndex([Timestamp('2000-01-15 00:15:00', tz='US/Central'), Timestamp('2000-02-15', tz='US/Central')], name='a') - s = tm.box_expected(s, box_with_array, transpose=False) + s = tm.box_expected(s, box_with_array) result = s + pd.offsets.MonthEnd() result2 = pd.offsets.MonthEnd() + s exp = DatetimeIndex([Timestamp('2000-01-31 00:15:00', tz='US/Central'), Timestamp('2000-02-29', tz='US/Central')], name='a') - exp = tm.box_expected(exp, box_with_array, transpose=False) + exp = tm.box_expected(exp, box_with_array) tm.assert_equal(result, exp) tm.assert_equal(result2, exp) @@ -1425,9 +1418,6 @@ def test_dt64arr_add_mixed_offset_array(self, box_with_array): def test_dt64arr_add_sub_offset_ndarray(self, tz_naive_fixture, box_with_array): # GH#18849 - if box_with_array is pd.DataFrame: - pytest.xfail("FIXME: ValueError with transpose; " - "alignment error without") tz = tz_naive_fixture dti = pd.date_range('2017-01-01', periods=2, tz=tz) diff --git a/pandas/tests/arithmetic/test_timedelta64.py b/pandas/tests/arithmetic/test_timedelta64.py index 22b5fd452d661..0ae325cfce787 100644 --- a/pandas/tests/arithmetic/test_timedelta64.py +++ b/pandas/tests/arithmetic/test_timedelta64.py @@ -869,10 +869,8 @@ def test_td64arr_add_timestamp(self, box_with_array, tz_naive_fixture): idx = TimedeltaIndex(['1 day', '2 day']) expected = DatetimeIndex(['2011-01-02', '2011-01-03'], tz=tz) - # FIXME: fails with transpose=True because of tz-aware DataFrame - # transpose bug - idx = tm.box_expected(idx, box_with_array, transpose=False) - expected = tm.box_expected(expected, box_with_array, transpose=False) + idx = tm.box_expected(idx, box_with_array) + expected = tm.box_expected(expected, box_with_array) result = idx + other tm.assert_equal(result, expected) diff --git a/pandas/tests/frame/test_constructors.py b/pandas/tests/frame/test_constructors.py index c6508072cb8c7..434ee2f8bf0af 100644 --- a/pandas/tests/frame/test_constructors.py +++ b/pandas/tests/frame/test_constructors.py @@ -2400,3 +2400,32 @@ def test_nested_dict_construction(self): index=pd.Index([2001, 2002, 2003]) ) tm.assert_frame_equal(result, expected) + + def test_from_tzaware_object_array(self): + # GH#26825 2D object array of tzaware timestamps should not raise + dti = pd.date_range('2016-04-05 04:30', periods=3, tz='UTC') + data = dti._data.astype(object).reshape(1, -1) + df = pd.DataFrame(data) + assert df.shape == (1, 3) + assert (df.dtypes == dti.dtype).all() + assert (df == dti).all().all() + + def test_from_tzaware_mixed_object_array(self): + # GH#26825 + arr = np.array([ + [Timestamp('2013-01-01 00:00:00'), + Timestamp('2013-01-02 00:00:00'), + Timestamp('2013-01-03 00:00:00')], + [Timestamp('2013-01-01 00:00:00-0500', tz='US/Eastern'), + pd.NaT, + Timestamp('2013-01-03 00:00:00-0500', tz='US/Eastern')], + [Timestamp('2013-01-01 00:00:00+0100', tz='CET'), + pd.NaT, + Timestamp('2013-01-03 00:00:00+0100', tz='CET')]], + dtype=object).T + res = DataFrame(arr, columns=['A', 'B', 'C']) + + expected_dtypes = ['datetime64[ns]', + 'datetime64[ns, US/Eastern]', + 'datetime64[ns, CET]'] + assert (res.dtypes == expected_dtypes).all() diff --git a/pandas/tests/frame/test_dtypes.py b/pandas/tests/frame/test_dtypes.py index 96cf70483d4e7..7ed601e4f7046 100644 --- a/pandas/tests/frame/test_dtypes.py +++ b/pandas/tests/frame/test_dtypes.py @@ -978,9 +978,11 @@ def test_astype(self): Timestamp('2013-01-03 00:00:00+0100', tz='CET')]], dtype=object).T + expected = DataFrame(expected, + index=self.tzframe.index, + columns=self.tzframe.columns, dtype=object) result = self.tzframe.astype(object) - assert_frame_equal(result, DataFrame( - expected, index=self.tzframe.index, columns=self.tzframe.columns)) + assert_frame_equal(result, expected) result = self.tzframe.astype('datetime64[ns]') expected = DataFrame({'A': date_range('20130101', periods=3), diff --git a/pandas/tests/frame/test_operators.py b/pandas/tests/frame/test_operators.py index f1c8445bf98e0..1e932879e9ad0 100644 --- a/pandas/tests/frame/test_operators.py +++ b/pandas/tests/frame/test_operators.py @@ -793,3 +793,44 @@ def test_no_warning(self, all_arithmetic_operators): b = df['B'] with tm.assert_produces_warning(None): getattr(df, all_arithmetic_operators)(b, 0) + + +class TestTranspose: + def test_transpose_tzaware_1col_single_tz(self): + # GH#26825 + dti = pd.date_range('2016-04-05 04:30', periods=3, tz='UTC') + + df = pd.DataFrame(dti) + assert (df.dtypes == dti.dtype).all() + res = df.T + assert (res.dtypes == dti.dtype).all() + + def test_transpose_tzaware_2col_single_tz(self): + # GH#26825 + dti = pd.date_range('2016-04-05 04:30', periods=3, tz='UTC') + + df3 = pd.DataFrame({'A': dti, 'B': dti}) + assert (df3.dtypes == dti.dtype).all() + res3 = df3.T + assert (res3.dtypes == dti.dtype).all() + + def test_transpose_tzaware_2col_mixed_tz(self): + # GH#26825 + dti = pd.date_range('2016-04-05 04:30', periods=3, tz='UTC') + dti2 = dti.tz_convert('US/Pacific') + + df4 = pd.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) + + def test_transpose_object_to_tzaware_mixed_tz(self): + # GH#26825 + dti = pd.date_range('2016-04-05 04:30', periods=3, tz='UTC') + dti2 = dti.tz_convert('US/Pacific') + + # mixed all-tzaware dtypes + df2 = pd.DataFrame([dti, dti2]) + assert (df2.dtypes == object).all() + res2 = df2.T + assert (res2.dtypes == [dti.dtype, dti2.dtype]).all() diff --git a/pandas/tests/groupby/test_function.py b/pandas/tests/groupby/test_function.py index 3d9bfcd126377..14f27f0c4c7d8 100644 --- a/pandas/tests/groupby/test_function.py +++ b/pandas/tests/groupby/test_function.py @@ -963,12 +963,14 @@ def test_count(): df['9th'] = df['9th'].astype('category') - for key in '1st', '2nd', ['1st', '2nd']: + for key in ['1st', '2nd', ['1st', '2nd']]: left = df.groupby(key).count() right = df.groupby(key).apply(DataFrame.count).drop(key, axis=1) tm.assert_frame_equal(left, right) - # GH5610 + +def test_count_non_nulls(): + # GH#5610 # count counts non-nulls df = pd.DataFrame([[1, 2, 'foo'], [1, np.nan, 'bar'], diff --git a/pandas/tests/groupby/test_groupby.py b/pandas/tests/groupby/test_groupby.py index 3da3ab22b643b..dcd0d3938c6a5 100644 --- a/pandas/tests/groupby/test_groupby.py +++ b/pandas/tests/groupby/test_groupby.py @@ -129,12 +129,14 @@ def func(dataf): result = df.groupby('X', squeeze=False).count() assert isinstance(result, DataFrame) + +def test_inconsistent_return_type(): # GH5592 # inconsistent return type df = DataFrame(dict(A=['Tiger', 'Tiger', 'Tiger', 'Lamb', 'Lamb', - 'Pony', 'Pony'], B=Series( - np.arange(7), dtype='int64'), C=date_range( - '20130101', periods=7))) + 'Pony', 'Pony'], + B=Series(np.arange(7), dtype='int64'), + C=date_range('20130101', periods=7))) def f(grp): return grp.iloc[0]