-
-
Notifications
You must be signed in to change notification settings - Fork 18.5k
DEPR: __array__ for tz-aware Series/Index #24596
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
9aa0413
ea44792
3c1ffd0
66d1843
328338c
349f818
50f4fbd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1227,7 +1227,7 @@ Deprecations | |
.. _whatsnew_0240.deprecations.datetimelike_int_ops: | ||
|
||
Integer Addition/Subtraction with Datetimes and Timedeltas is Deprecated | ||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
In the past, users could—in some cases—add or subtract integers or integer-dtype | ||
arrays from :class:`Timestamp`, :class:`DatetimeIndex` and :class:`TimedeltaIndex`. | ||
|
@@ -1265,6 +1265,74 @@ the object's ``freq`` attribute (:issue:`21939`, :issue:`23878`). | |
dti = pd.date_range('2001-01-01', periods=2, freq='7D') | ||
dti + pd.Index([1 * dti.freq, 2 * dti.freq]) | ||
|
||
|
||
.. _whatsnew_0240.deprecations.tz_aware_array: | ||
|
||
Converting Timezone-Aware Series and Index to NumPy Arrays | ||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | ||
|
||
The conversion from a :class:`Series` or :class:`Index` with timezone-aware | ||
datetime data will change to preserve timezones by default (:issue:`23569`). | ||
|
||
NumPy doesn't have a dedicated dtype for timezone-aware datetimes. | ||
In the past, converting a :class:`Series` or :class:`DatetimeIndex` with | ||
timezone-aware datatimes would convert to a NumPy array by | ||
|
||
1. converting the tz-aware data to UTC | ||
2. dropping the timezone-info | ||
3. returning a :class:`numpy.ndarray` with ``datetime64[ns]`` dtype | ||
|
||
Future versions of pandas will preserve the timezone information by returning an | ||
object-dtype NumPy array where each value is a :class:`Timestamp` with the correct | ||
timezone attached | ||
|
||
.. ipython:: python | ||
|
||
ser = pd.Series(pd.date_range('2000', periods=2, tz="CET")) | ||
ser | ||
|
||
The default behavior remains the same, but issues a warning | ||
|
||
.. code-block:: python | ||
TomAugspurger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
In [8]: np.asarray(ser) | ||
/bin/ipython:1: FutureWarning: Converting timezone-aware DatetimeArray to timezone-naive | ||
ndarray with 'datetime64[ns]' dtype. In the future, this will return an ndarray | ||
with 'object' dtype where each element is a 'pandas.Timestamp' with the correct 'tz'. | ||
|
||
To accept the future behavior, pass 'dtype=object'. | ||
To keep the old behavior, pass 'dtype="datetime64[ns]"'. | ||
#!/bin/python3 | ||
Out[8]: | ||
array(['1999-12-31T23:00:00.000000000', '2000-01-01T23:00:00.000000000'], | ||
dtype='datetime64[ns]') | ||
|
||
The previous or future behavior can be obtained, without any warnings, by specifying | ||
the ``dtype`` | ||
|
||
*Previous Behavior* | ||
|
||
.. ipython:: python | ||
TomAugspurger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
np.asarray(ser, dtype='datetime64[ns]') | ||
|
||
*Future Behavior* | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we usually call this current |
||
|
||
.. ipython:: python | ||
|
||
# New behavior | ||
np.asarray(ser, dtype=object) | ||
|
||
|
||
Or by using :meth:`Series.to_numpy` | ||
|
||
.. ipython:: python | ||
|
||
ser.to_numpy() | ||
jreback marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ser.to_numpy(dtype="datetime64[ns]") | ||
|
||
All the above applies to a :class:`DatetimeIndex` with tz-aware values as well. | ||
|
||
.. _whatsnew_0240.prior_deprecations: | ||
|
||
Removal of prior version deprecations/changes | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1020,7 +1020,7 @@ def maybe_cast_to_datetime(value, dtype, errors='raise'): | |
# datetime64tz is assumed to be naive which should | ||
# be localized to the timezone. | ||
is_dt_string = is_string_dtype(value) | ||
value = to_datetime(value, errors=errors) | ||
value = to_datetime(value, errors=errors).array | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Need to look at this closer. |
||
if is_dt_string: | ||
# Strings here are naive, so directly localize | ||
value = value.tz_localize(dtype.tz) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -403,6 +403,7 @@ def _hash_categories(categories, ordered=True): | |
from pandas.core.util.hashing import ( | ||
hash_array, _combine_hash_arrays, hash_tuples | ||
) | ||
from pandas.core.dtypes.common import is_datetime64tz_dtype, _NS_DTYPE | ||
TomAugspurger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
if len(categories) and isinstance(categories[0], tuple): | ||
# assumes if any individual category is a tuple, then all our. ATM | ||
|
@@ -420,6 +421,11 @@ def _hash_categories(categories, ordered=True): | |
# find a better solution | ||
hashed = hash((tuple(categories), ordered)) | ||
return hashed | ||
|
||
if is_datetime64tz_dtype(categories.dtype): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, possibly. We'll still need the special case for datetime64tz_dtype to pass There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. maybe add a TODO here, this is kind of special casing |
||
# Avoid future warning. | ||
categories = categories.astype(_NS_DTYPE) | ||
|
||
cat_array = hash_array(np.asarray(categories), categorize=False) | ||
if ordered: | ||
cat_array = np.vstack([ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -581,7 +581,12 @@ def can_do_equal_len(): | |
setter(item, v) | ||
|
||
# we have an equal len ndarray/convertible to our labels | ||
elif np.array(value).ndim == 2: | ||
# hasattr first, to avoid coercing to ndarray without reason. | ||
# But we may be relying on the ndarray coercion to check ndim. | ||
# Why not just convert to an ndarray earlier on if needed? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hoping to clean up the type on There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can you add a TODO for any section that we should change later |
||
elif ((hasattr(value, 'ndim') and value.ndim == 2) | ||
or (not hasattr(value, 'ndim') and | ||
np.array(value).ndim) == 2): | ||
|
||
# note that this coerces the dtype if we are mixed | ||
# GH 7551 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1447,8 +1447,20 @@ def quantile(self, qs, interpolation='linear', axis=0): | |
------- | ||
Block | ||
""" | ||
values = self.get_values() | ||
values, _ = self._try_coerce_args(values, values) | ||
if self.is_datetimetz: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this is getting super messy There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed. A proper fix is updating There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. None of the branches I have in progress would help here. Allowing for DatetimeArray to be reshaped to (1, nrows) would. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a TODO here |
||
# TODO: cleanup this special case. | ||
# We need to operate on i8 values for datetimetz | ||
# but `Block.get_values()` returns an ndarray of objects | ||
# right now. We need an API for "values to do numeric-like ops on" | ||
values = self.values.asi8 | ||
|
||
# TODO: NonConsolidatableMixin shape | ||
# Usual shape inconsistencies for ExtensionBlocks | ||
if self.ndim > 1: | ||
values = values[None, :] | ||
else: | ||
values = self.get_values() | ||
values, _ = self._try_coerce_args(values, values) | ||
|
||
is_empty = values.shape[axis] == 0 | ||
orig_scalar = not is_list_like(qs) | ||
|
@@ -2055,10 +2067,6 @@ def _na_value(self): | |
def fill_value(self): | ||
return tslibs.iNaT | ||
|
||
def to_dense(self): | ||
# TODO(DatetimeBlock): remove | ||
return np.asarray(self.values) | ||
|
||
def get_values(self, dtype=None): | ||
""" | ||
return object dtype as boxed values, such as Timestamps/Timedelta | ||
|
@@ -2330,6 +2338,12 @@ def get_values(self, dtype=None): | |
values = values.reshape(1, -1) | ||
return values | ||
|
||
def to_dense(self): | ||
TomAugspurger marked this conversation as resolved.
Show resolved
Hide resolved
|
||
# we request M8[ns] dtype here, even though it discards tzinfo, | ||
# as lots of code (e.g. anything using values_from_object) | ||
# expects that behavior. | ||
return np.asarray(self.values, dtype=_NS_DTYPE) | ||
|
||
def _slice(self, slicer): | ||
""" return a slice of my values """ | ||
if isinstance(slicer, tuple): | ||
|
Uh oh!
There was an error while loading. Please reload this page.