diff --git a/doc/source/whatsnew/v0.17.0.txt b/doc/source/whatsnew/v0.17.0.txt index cc8f135eb62b0..19fe4e73f1f4d 100644 --- a/doc/source/whatsnew/v0.17.0.txt +++ b/doc/source/whatsnew/v0.17.0.txt @@ -37,6 +37,7 @@ Highlights include: - Support for ``Series.dt.strftime`` to generate formatted strings for datetime-likes, see :ref:`here ` - Development installed versions of pandas will now have ``PEP440`` compliant version strings (:issue:`9518`) - Support for reading SAS xport files, see :ref:`here ` +- Removal of the automatic TimeSeries broadcasting, deprecated since 0.8.0, see :ref:`here ` Check the :ref:`API Changes ` and :ref:`deprecations ` before updating. @@ -663,6 +664,7 @@ Deprecations can easily be replaced by using the ``add`` and ``mul`` methods: ``DataFrame.add(other, fill_value=0)`` and ``DataFrame.mul(other, fill_value=1.)`` (:issue:`10735`). +- ``TimeSeries`` deprecated in favor of ``Series`` (note that this has been alias since 0.13.0), (:issue:`10890`) .. _whatsnew_0170.prior_deprecations: @@ -672,6 +674,36 @@ Removal of prior version deprecations/changes - Remove use of some deprecated numpy comparison operations, mainly in tests. (:issue:`10569`) - Removal of ``na_last`` parameters from ``Series.order()`` and ``Series.sort()``, in favor of ``na_position``, xref (:issue:`5231`) - Remove of ``percentile_width`` from ``.describe()``, in favor of ``percentiles``. (:issue:`7088`) +- Removal of ``colSpace`` parameter from ``DataFrame.to_string()``, in favor of ``col_space``, circa 0.8.0 version. +- Removal of automatic time-series broadcasting (:issue:`2304`) + + .. ipython :: python + + np.random.seed(1234) + df = DataFrame(np.random.randn(5,2),columns=list('AB'),index=date_range('20130101',periods=5)) + df + + Previously + + .. code-block:: python + + In [3]: df + df.A + FutureWarning: TimeSeries broadcasting along DataFrame index by default is deprecated. + Please use DataFrame. to explicitly broadcast arithmetic operations along the index + + Out[3]: + A B + 2013-01-01 0.942870 -0.719541 + 2013-01-02 2.865414 1.120055 + 2013-01-03 -1.441177 0.166574 + 2013-01-04 1.719177 0.223065 + 2013-01-05 0.031393 -2.226989 + + Current + + .. ipython :: python + + df.add(df.A,axis='index') .. _whatsnew_0170.performance: diff --git a/pandas/core/frame.py b/pandas/core/frame.py index 1f222f9f99cbe..a9979b4eb3810 100644 --- a/pandas/core/frame.py +++ b/pandas/core/frame.py @@ -1396,7 +1396,7 @@ def to_stata( writer.write_file() @Appender(fmt.docstring_to_string, indents=1) - def to_string(self, buf=None, columns=None, col_space=None, colSpace=None, + def to_string(self, buf=None, columns=None, col_space=None, header=True, index=True, na_rep='NaN', formatters=None, float_format=None, sparsify=None, index_names=True, justify=None, line_width=None, max_rows=None, max_cols=None, @@ -1405,11 +1405,6 @@ def to_string(self, buf=None, columns=None, col_space=None, colSpace=None, Render a DataFrame to a console-friendly tabular output. """ - if colSpace is not None: # pragma: no cover - warnings.warn("colSpace is deprecated, use col_space", - FutureWarning) - col_space = colSpace - formatter = fmt.DataFrameFormatter(self, buf=buf, columns=columns, col_space=col_space, na_rep=na_rep, formatters=formatters, @@ -3359,16 +3354,7 @@ def _combine_series_infer(self, other, func, level=None, fill_value=None): return self._constructor(data=self._series, index=self.index, columns=self.columns) - # teeny hack because one does DataFrame + TimeSeries all the time - if self.index.is_all_dates and other.index.is_all_dates: - warnings.warn(("TimeSeries broadcasting along DataFrame index " - "by default is deprecated. Please use " - "DataFrame. to explicitly broadcast arithmetic " - "operations along the index"), - FutureWarning) - return self._combine_match_index(other, func, level=level, fill_value=fill_value) - else: - return self._combine_match_columns(other, func, level=level, fill_value=fill_value) + return self._combine_match_columns(other, func, level=level, fill_value=fill_value) def _combine_match_index(self, other, func, level=None, fill_value=None): left, right = self.align(other, join='outer', axis=0, level=level, copy=False) diff --git a/pandas/core/series.py b/pandas/core/series.py index 8768d0e139e7b..0c17104bb701e 100644 --- a/pandas/core/series.py +++ b/pandas/core/series.py @@ -261,6 +261,7 @@ def _set_axis(self, axis, labels, fastpath=False): is_all_dates = labels.is_all_dates if is_all_dates: + if not isinstance(labels, (DatetimeIndex, PeriodIndex, TimedeltaIndex)): labels = DatetimeIndex(labels) @@ -2779,7 +2780,14 @@ def _try_cast(arr, take_fast_path): return subarr # backwards compatiblity -TimeSeries = Series +class TimeSeries(Series): + + def __init__(self, *args, **kwargs): + # deprecation TimeSeries, #10890 + warnings.warn("TimeSeries is deprecated. Please use Series", + FutureWarning, stacklevel=2) + + super(TimeSeries, self).__init__(*args, **kwargs) #---------------------------------------------------------------------- # Add plotting methods to Series diff --git a/pandas/io/pytables.py b/pandas/io/pytables.py index 8ef6363f836ae..b23a183cdc145 100644 --- a/pandas/io/pytables.py +++ b/pandas/io/pytables.py @@ -13,7 +13,8 @@ import os import numpy as np -from pandas import (Series, TimeSeries, DataFrame, Panel, Panel4D, Index, +import pandas as pd +from pandas import (Series, DataFrame, Panel, Panel4D, Index, MultiIndex, Int64Index, Timestamp) from pandas.sparse.api import SparseSeries, SparseDataFrame, SparsePanel from pandas.sparse.array import BlockIndex, IntIndex @@ -164,7 +165,7 @@ class DuplicateWarning(Warning): Series: u('series'), SparseSeries: u('sparse_series'), - TimeSeries: u('series'), + pd.TimeSeries: u('series'), DataFrame: u('frame'), SparseDataFrame: u('sparse_frame'), Panel: u('wide'), diff --git a/pandas/io/tests/generate_legacy_storage_files.py b/pandas/io/tests/generate_legacy_storage_files.py index 86c5a9e0d7f19..0ca5ced1b8d1a 100644 --- a/pandas/io/tests/generate_legacy_storage_files.py +++ b/pandas/io/tests/generate_legacy_storage_files.py @@ -1,8 +1,8 @@ """ self-contained to write legacy storage (pickle/msgpack) files """ from __future__ import print_function from distutils.version import LooseVersion -from pandas import (Series, TimeSeries, DataFrame, Panel, - SparseSeries, SparseTimeSeries, SparseDataFrame, SparsePanel, +from pandas import (Series, DataFrame, Panel, + SparseSeries, SparseDataFrame, SparsePanel, Index, MultiIndex, PeriodIndex, bdate_range, to_msgpack, date_range, period_range, bdate_range, Timestamp, Categorical, Period) @@ -36,7 +36,7 @@ def _create_sp_tsseries(): arr[-1:] = nan date_index = bdate_range('1/1/2011', periods=len(arr)) - bseries = SparseTimeSeries(arr, index=date_index, kind='block') + bseries = SparseSeries(arr, index=date_index, kind='block') bseries.name = 'btsseries' return bseries @@ -78,7 +78,7 @@ def create_data(): series = dict(float=Series(data['A']), int=Series(data['B']), mixed=Series(data['E']), - ts=TimeSeries(np.arange(10).astype(np.int64), index=date_range('20130101',periods=10)), + ts=Series(np.arange(10).astype(np.int64), index=date_range('20130101',periods=10)), mi=Series(np.arange(5).astype(np.float64), index=MultiIndex.from_tuples(tuple(zip(*[[1, 1, 2, 2, 2], [3, 4, 3, 4, 5]])), names=['one', 'two'])), diff --git a/pandas/sparse/series.py b/pandas/sparse/series.py index a8addfab17c26..62d6a34655e1d 100644 --- a/pandas/sparse/series.py +++ b/pandas/sparse/series.py @@ -7,7 +7,7 @@ from numpy import nan, ndarray import numpy as np - +import warnings import operator from pandas.core.common import isnull, _values_from_object, _maybe_match_name @@ -770,4 +770,11 @@ def from_coo(cls, A, dense_index=False): bool_method=None, use_numexpr=False, force=True) # backwards compatiblity -SparseTimeSeries = SparseSeries +class SparseTimeSeries(SparseSeries): + + def __init__(self, *args, **kwargs): + # deprecation TimeSeries, #10890 + warnings.warn("SparseTimeSeries is deprecated. Please use SparseSeries", + FutureWarning, stacklevel=2) + + super(SparseTimeSeries, self).__init__(*args, **kwargs) diff --git a/pandas/sparse/tests/test_sparse.py b/pandas/sparse/tests/test_sparse.py index 103f3992f950a..8d24025f3c3cf 100644 --- a/pandas/sparse/tests/test_sparse.py +++ b/pandas/sparse/tests/test_sparse.py @@ -30,7 +30,7 @@ import pandas.sparse.frame as spf from pandas._sparse import BlockIndex, IntIndex -from pandas.sparse.api import (SparseSeries, SparseTimeSeries, +from pandas.sparse.api import (SparseSeries, SparseDataFrame, SparsePanel, SparseArray) import pandas.tests.test_frame as test_frame @@ -160,6 +160,12 @@ def test_iteration_and_str(self): [x for x in self.bseries] str(self.bseries) + def test_TimeSeries_deprecation(self): + + # deprecation TimeSeries, #10890 + with tm.assert_produces_warning(FutureWarning): + pd.SparseTimeSeries(1,index=pd.date_range('20130101',periods=3)) + def test_construct_DataFrame_with_sp_series(self): # it works! df = DataFrame({'col': self.bseries}) @@ -258,7 +264,7 @@ def _check_const(sparse, name): # Sparse time series works date_index = bdate_range('1/1/2000', periods=len(self.bseries)) s5 = SparseSeries(self.bseries, index=date_index) - tm.assertIsInstance(s5, SparseTimeSeries) + tm.assertIsInstance(s5, SparseSeries) # pass Series bseries2 = SparseSeries(self.bseries.to_dense()) @@ -1189,14 +1195,19 @@ def _compare_to_dense(a, b, da, db, op): frame['A'].reindex(fidx[::2]), SparseSeries([], index=[])] - for op in ops: + for op in opnames: _compare_to_dense(frame, frame[::2], frame.to_dense(), - frame[::2].to_dense(), op) + frame[::2].to_dense(), getattr(operator, op)) + + # 2304, no auto-broadcasting for i, s in enumerate(series): + f = lambda a, b: getattr(a,op)(b,axis='index') _compare_to_dense(frame, s, frame.to_dense(), - s.to_dense(), op) - _compare_to_dense(s, frame, s.to_dense(), - frame.to_dense(), op) + s.to_dense(), f) + + # rops are not implemented + #_compare_to_dense(s, frame, s.to_dense(), + # frame.to_dense(), f) # cross-sectional operations series = [frame.xs(fidx[0]), diff --git a/pandas/tests/test_frame.py b/pandas/tests/test_frame.py index 022594e296c2a..9687d9b742126 100644 --- a/pandas/tests/test_frame.py +++ b/pandas/tests/test_frame.py @@ -6039,46 +6039,47 @@ def test_combineSeries(self): #added = self.mixed_int + (100*series).astype('int32') #_check_mixed_int(added, dtype = dict(A = 'int32', B = 'float64', C = 'int32', D = 'int64')) - # TimeSeries - buf = StringIO() - tmp = sys.stderr - sys.stderr = buf - try: - ts = self.tsframe['A'] - added = self.tsframe + ts - - for key, col in compat.iteritems(self.tsframe): - result = col + ts - assert_series_equal(added[key], result, check_names=False) - self.assertEqual(added[key].name, key) - if col.name == ts.name: - self.assertEqual(result.name, 'A') - else: - self.assertTrue(result.name is None) + # TimeSeries + ts = self.tsframe['A'] + + # 10890 + # we no longer allow auto timeseries broadcasting + # and require explict broadcasting + added = self.tsframe.add(ts, axis='index') + + for key, col in compat.iteritems(self.tsframe): + result = col + ts + assert_series_equal(added[key], result, check_names=False) + self.assertEqual(added[key].name, key) + if col.name == ts.name: + self.assertEqual(result.name, 'A') + else: + self.assertTrue(result.name is None) - smaller_frame = self.tsframe[:-5] - smaller_added = smaller_frame + ts + smaller_frame = self.tsframe[:-5] + smaller_added = smaller_frame.add(ts, axis='index') - self.assertTrue(smaller_added.index.equals(self.tsframe.index)) + self.assertTrue(smaller_added.index.equals(self.tsframe.index)) - smaller_ts = ts[:-5] - smaller_added2 = self.tsframe + smaller_ts - assert_frame_equal(smaller_added, smaller_added2) + smaller_ts = ts[:-5] + smaller_added2 = self.tsframe.add(smaller_ts, axis='index') + assert_frame_equal(smaller_added, smaller_added2) - # length 0 - result = self.tsframe + ts[:0] + # length 0, result is all-nan + result = self.tsframe.add(ts[:0], axis='index') + expected = DataFrame(np.nan,index=self.tsframe.index,columns=self.tsframe.columns) + assert_frame_equal(result, expected) - # Frame is length 0 - result = self.tsframe[:0] + ts - self.assertEqual(len(result), 0) + # Frame is all-nan + result = self.tsframe[:0].add(ts, axis='index') + expected = DataFrame(np.nan,index=self.tsframe.index,columns=self.tsframe.columns) + assert_frame_equal(result, expected) - # empty but with non-empty index - frame = self.tsframe[:1].reindex(columns=[]) - result = frame * ts - self.assertEqual(len(result), len(ts)) - finally: - sys.stderr = tmp + # empty but with non-empty index + frame = self.tsframe[:1].reindex(columns=[]) + result = frame.mul(ts,axis='index') + self.assertEqual(len(result), len(ts)) def test_combineFunc(self): result = self.frame * 2 diff --git a/pandas/tests/test_groupby.py b/pandas/tests/test_groupby.py index fa2e6e911ab5e..d1073b6c4d7ab 100644 --- a/pandas/tests/test_groupby.py +++ b/pandas/tests/test_groupby.py @@ -502,9 +502,8 @@ def test_groupby_bounds_check(self): self.assertRaises(AssertionError, pd.algos.groupby_object,a, b) def test_groupby_grouper_f_sanity_checked(self): - import pandas as pd dates = date_range('01-Jan-2013', periods=12, freq='MS') - ts = pd.TimeSeries(np.random.randn(12), index=dates) + ts = Series(np.random.randn(12), index=dates) # GH3035 # index.map is used to apply grouper to the index diff --git a/pandas/tests/test_series.py b/pandas/tests/test_series.py index 3567c98e71bce..6424a190dba9f 100644 --- a/pandas/tests/test_series.py +++ b/pandas/tests/test_series.py @@ -666,6 +666,12 @@ def test_astype(self): self.assertEqual(astyped.dtype, dtype) self.assertEqual(astyped.name, s.name) + def test_TimeSeries_deprecation(self): + + # deprecation TimeSeries, #10890 + with tm.assert_produces_warning(FutureWarning): + pd.TimeSeries(1,index=date_range('20130101',periods=3)) + def test_constructor(self): # Recognize TimeSeries self.assertTrue(self.ts.is_time_series) @@ -4515,10 +4521,10 @@ def test_operators_frame(self): # rpow does not work with DataFrame df = DataFrame({'A': self.ts}) - tm.assert_almost_equal(self.ts + self.ts, (self.ts + df)['A']) - tm.assert_almost_equal(self.ts ** self.ts, (self.ts ** df)['A']) - tm.assert_almost_equal(self.ts < self.ts, (self.ts < df)['A']) - tm.assert_almost_equal(self.ts / self.ts, (self.ts / df)['A']) + tm.assert_almost_equal(self.ts + self.ts, self.ts + df['A']) + tm.assert_almost_equal(self.ts ** self.ts, self.ts ** df['A']) + tm.assert_almost_equal(self.ts < self.ts, self.ts < df['A']) + tm.assert_almost_equal(self.ts / self.ts, self.ts / df['A']) def test_operators_combine(self): def _check_fill(meth, op, a, b, fill_value=0): diff --git a/pandas/tests/test_strings.py b/pandas/tests/test_strings.py index 6a9ad175f42dd..7886a63c6df46 100644 --- a/pandas/tests/test_strings.py +++ b/pandas/tests/test_strings.py @@ -15,7 +15,7 @@ from pandas.compat import range, lrange, u, unichr import pandas.compat as compat -from pandas import (Index, Series, TimeSeries, DataFrame, isnull, notnull, +from pandas import (Index, Series, DataFrame, isnull, notnull, bdate_range, date_range, MultiIndex) import pandas.core.common as com diff --git a/pandas/tseries/tests/test_period.py b/pandas/tseries/tests/test_period.py index eb5c6759bfa45..e0434bfec3be4 100644 --- a/pandas/tseries/tests/test_period.py +++ b/pandas/tseries/tests/test_period.py @@ -24,7 +24,7 @@ from numpy.random import randn from pandas.compat import range, lrange, lmap, zip -from pandas import Series, TimeSeries, DataFrame, _np_version_under1p9 +from pandas import Series, DataFrame, _np_version_under1p9 from pandas import tslib from pandas.util.testing import(assert_series_equal, assert_almost_equal, assertRaisesRegexp) @@ -1191,7 +1191,7 @@ def test_hash_error(self): def test_make_time_series(self): index = PeriodIndex(freq='A', start='1/1/2001', end='12/1/2009') series = Series(1, index=index) - tm.assertIsInstance(series, TimeSeries) + tm.assertIsInstance(series, Series) def test_astype(self): idx = period_range('1990', '2009', freq='A') diff --git a/pandas/tseries/tests/test_resample.py b/pandas/tseries/tests/test_resample.py index 4b3085dc8259f..7dafc88bf9239 100644 --- a/pandas/tseries/tests/test_resample.py +++ b/pandas/tseries/tests/test_resample.py @@ -980,7 +980,7 @@ def _simple_ts(start, end, freq='D'): def _simple_pts(start, end, freq='D'): rng = period_range(start, end, freq=freq) - return TimeSeries(np.random.randn(len(rng)), index=rng) + return Series(np.random.randn(len(rng)), index=rng) class TestResamplePeriodIndex(tm.TestCase): @@ -1177,7 +1177,7 @@ def test_resample_to_quarterly(self): def test_resample_fill_missing(self): rng = PeriodIndex([2000, 2005, 2007, 2009], freq='A') - s = TimeSeries(np.random.randn(4), index=rng) + s = Series(np.random.randn(4), index=rng) stamps = s.to_timestamp() @@ -1191,12 +1191,12 @@ def test_resample_fill_missing(self): def test_cant_fill_missing_dups(self): rng = PeriodIndex([2000, 2005, 2005, 2007, 2007], freq='A') - s = TimeSeries(np.random.randn(5), index=rng) + s = Series(np.random.randn(5), index=rng) self.assertRaises(Exception, s.resample, 'A') def test_resample_5minute(self): rng = period_range('1/1/2000', '1/5/2000', freq='T') - ts = TimeSeries(np.random.randn(len(rng)), index=rng) + ts = Series(np.random.randn(len(rng)), index=rng) result = ts.resample('5min') expected = ts.to_timestamp().resample('5min') @@ -1402,7 +1402,7 @@ def test_evenly_divisible_with_no_extra_bins(self): 'COOP_DLY_TRN_QT': 30, 'COOP_DLY_SLS_AMT': 20}] * 28 + [{'REST_KEY': 2, 'DLY_TRN_QT': 70, 'DLY_SLS_AMT': 10, 'COOP_DLY_TRN_QT': 50, 'COOP_DLY_SLS_AMT': 20}] * 28, - index=index.append(index)).sort() + index=index.append(index)).sort_index() index = date_range('2001-5-4',periods=4,freq='7D') expected = DataFrame( @@ -1430,7 +1430,7 @@ def test_apply(self): grouped = self.ts.groupby(grouper) - f = lambda x: x.order()[-3:] + f = lambda x: x.sort_values()[-3:] applied = grouped.apply(f) expected = self.ts.groupby(lambda x: x.year).apply(f) diff --git a/pandas/tseries/tests/test_timeseries.py b/pandas/tseries/tests/test_timeseries.py index e02973136863d..f416a8939ac82 100644 --- a/pandas/tseries/tests/test_timeseries.py +++ b/pandas/tseries/tests/test_timeseries.py @@ -9,7 +9,7 @@ import numpy as np randn = np.random.randn -from pandas import (Index, Series, TimeSeries, DataFrame, +from pandas import (Index, Series, DataFrame, isnull, date_range, Timestamp, Period, DatetimeIndex, Int64Index, to_datetime, bdate_range, Float64Index, TimedeltaIndex, NaT) @@ -60,7 +60,7 @@ def setUp(self): self.dups = Series(np.random.randn(len(dates)), index=dates) def test_constructor(self): - tm.assertIsInstance(self.dups, TimeSeries) + tm.assertIsInstance(self.dups, Series) tm.assertIsInstance(self.dups.index, DatetimeIndex) def test_is_unique_monotonic(self): diff --git a/pandas/tseries/tests/test_timeseries_legacy.py b/pandas/tseries/tests/test_timeseries_legacy.py index 6889f8e2afbb2..4cbc171364ee6 100644 --- a/pandas/tseries/tests/test_timeseries_legacy.py +++ b/pandas/tseries/tests/test_timeseries_legacy.py @@ -8,7 +8,7 @@ import numpy as np randn = np.random.randn -from pandas import (Index, Series, TimeSeries, DataFrame, +from pandas import (Index, Series, DataFrame, isnull, date_range, Timestamp, DatetimeIndex, Int64Index, to_datetime, bdate_range) diff --git a/pandas/tseries/util.py b/pandas/tseries/util.py index 6c534de0a7aaa..4f29b2bf31f83 100644 --- a/pandas/tseries/util.py +++ b/pandas/tseries/util.py @@ -28,7 +28,7 @@ def pivot_annual(series, freq=None): Parameters ---------- - series : TimeSeries + series : Series freq : string or None, default None Returns