-
-
Notifications
You must be signed in to change notification settings - Fork 18.6k
REF: back DatetimeBlock, TimedeltaBlock by DTA/TDA #40456
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
fae2a97
c5e3dd9
7a4d545
c776390
62b5806
c3ce503
3b0e819
868f436
14b4087
f076370
d7f2718
626c2a9
3fbc3a5
f148306
4b820d2
6f4e5e6
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 |
---|---|---|
|
@@ -9544,6 +9544,9 @@ def func(values: np.ndarray): | |
|
||
def blk_func(values, axis=1): | ||
if isinstance(values, ExtensionArray): | ||
if values.ndim == 2: | ||
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. isn't this just 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. sure. next pass |
||
# i.e. DatetimeArray, TimedeltaArray | ||
return values._reduce(name, axis=1, skipna=skipna, **kwds) | ||
return values._reduce(name, skipna=skipna, **kwds) | ||
else: | ||
return op(values, axis=axis, skipna=skipna, **kwds) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,6 @@ | |
writers, | ||
) | ||
from pandas._libs.internals import BlockPlacement | ||
from pandas._libs.tslibs import conversion | ||
from pandas._typing import ( | ||
ArrayLike, | ||
Dtype, | ||
|
@@ -47,7 +46,6 @@ | |
maybe_downcast_numeric, | ||
maybe_downcast_to_dtype, | ||
maybe_upcast, | ||
sanitize_to_nanoseconds, | ||
soft_convert_objects, | ||
) | ||
from pandas.core.dtypes.common import ( | ||
|
@@ -938,7 +936,11 @@ def setitem(self, indexer, value): | |
return self.coerce_to_target_dtype(value).setitem(indexer, value) | ||
|
||
if self.dtype.kind in ["m", "M"]: | ||
arr = self.array_values.T | ||
arr = self.values | ||
if self.ndim > 1: | ||
# Dont transpose with ndim=1 bc we would fail to invalidate | ||
# arr.freq | ||
arr = arr.T | ||
arr[indexer] = value | ||
return self | ||
|
||
|
@@ -1172,6 +1174,7 @@ def _interpolate_with_fill( | |
limit_area=limit_area, | ||
) | ||
|
||
values = maybe_coerce_values(values) | ||
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. prob can have maybe_coerce_values do downcasting (maybe) |
||
blocks = [self.make_block_same_class(values)] | ||
return self._maybe_downcast(blocks, downcast) | ||
|
||
|
@@ -1227,6 +1230,7 @@ def func(yvalues: np.ndarray) -> np.ndarray: | |
|
||
# interp each column independently | ||
interp_values = np.apply_along_axis(func, axis, data) | ||
interp_values = maybe_coerce_values(interp_values) | ||
|
||
blocks = [self.make_block_same_class(interp_values)] | ||
return self._maybe_downcast(blocks, downcast) | ||
|
@@ -1788,27 +1792,32 @@ class NDArrayBackedExtensionBlock(HybridMixin, Block): | |
Block backed by an NDArrayBackedExtensionArray | ||
""" | ||
|
||
values: NDArrayBackedExtensionArray | ||
|
||
@property | ||
def is_view(self) -> bool: | ||
""" return a boolean if I am possibly a view """ | ||
# check the ndarray values of the DatetimeIndex values | ||
return self.values._ndarray.base is not None | ||
|
||
def internal_values(self): | ||
# Override to return DatetimeArray and TimedeltaArray | ||
return self.array_values | ||
return self.values | ||
|
||
def get_values(self, dtype: Optional[DtypeObj] = None) -> np.ndarray: | ||
""" | ||
return object dtype as boxed values, such as Timestamps/Timedelta | ||
""" | ||
values = self.array_values | ||
values = self.values | ||
if is_object_dtype(dtype): | ||
# DTA/TDA constructor and astype can handle 2D | ||
# error: "Callable[..., Any]" has no attribute "astype" | ||
values = values.astype(object) # type: ignore[attr-defined] | ||
values = values.astype(object) | ||
# TODO(EA2D): reshape not needed with 2D EAs | ||
return np.asarray(values).reshape(self.shape) | ||
|
||
def iget(self, key): | ||
# GH#31649 we need to wrap scalars in Timestamp/Timedelta | ||
# TODO(EA2D): this can be removed if we ever have 2D EA | ||
# error: "Callable[..., Any]" has no attribute "reshape" | ||
return self.array_values.reshape(self.shape)[key] # type: ignore[attr-defined] | ||
return self.values.reshape(self.shape)[key] | ||
|
||
def putmask(self, mask, new) -> List[Block]: | ||
mask = extract_bool_array(mask) | ||
|
@@ -1817,16 +1826,13 @@ def putmask(self, mask, new) -> List[Block]: | |
return self.astype(object).putmask(mask, new) | ||
|
||
# TODO(EA2D): reshape unnecessary with 2D EAs | ||
# error: "Callable[..., Any]" has no attribute "reshape" | ||
arr = self.array_values.reshape(self.shape) # type: ignore[attr-defined] | ||
arr = cast("NDArrayBackedExtensionArray", arr) | ||
arr = self.values.reshape(self.shape) | ||
arr.T.putmask(mask, new) | ||
return [self] | ||
|
||
def where(self, other, cond, errors="raise") -> List[Block]: | ||
# TODO(EA2D): reshape unnecessary with 2D EAs | ||
# error: "Callable[..., Any]" has no attribute "reshape" | ||
arr = self.array_values.reshape(self.shape) # type: ignore[attr-defined] | ||
arr = self.values.reshape(self.shape) | ||
|
||
cond = extract_bool_array(cond) | ||
|
||
|
@@ -1837,7 +1843,6 @@ def where(self, other, cond, errors="raise") -> List[Block]: | |
|
||
# TODO(EA2D): reshape not needed with 2D EAs | ||
res_values = res_values.reshape(self.values.shape) | ||
res_values = maybe_coerce_values(res_values) | ||
nb = self.make_block_same_class(res_values) | ||
return [nb] | ||
|
||
|
@@ -1862,19 +1867,15 @@ def diff(self, n: int, axis: int = 0) -> List[Block]: | |
by apply. | ||
""" | ||
# TODO(EA2D): reshape not necessary with 2D EAs | ||
# error: "Callable[..., Any]" has no attribute "reshape" | ||
values = self.array_values.reshape(self.shape) # type: ignore[attr-defined] | ||
values = self.values.reshape(self.shape) | ||
|
||
new_values = values - values.shift(n, axis=axis) | ||
new_values = maybe_coerce_values(new_values) | ||
return [self.make_block(new_values)] | ||
|
||
def shift(self, periods: int, axis: int = 0, fill_value: Any = None) -> List[Block]: | ||
# TODO(EA2D) this is unnecessary if these blocks are backed by 2D EA | ||
# error: "Callable[..., Any]" has no attribute "reshape" | ||
values = self.array_values.reshape(self.shape) # type: ignore[attr-defined] | ||
# TODO(EA2D) this is unnecessary if these blocks are backed by 2D EAs | ||
values = self.values.reshape(self.shape) | ||
new_values = values.shift(periods, fill_value=fill_value, axis=axis) | ||
new_values = maybe_coerce_values(new_values) | ||
return [self.make_block_same_class(new_values)] | ||
|
||
def fillna( | ||
|
@@ -1887,38 +1888,27 @@ def fillna( | |
# TODO: don't special-case td64 | ||
return self.astype(object).fillna(value, limit, inplace, downcast) | ||
|
||
values = self.array_values | ||
# error: "Callable[..., Any]" has no attribute "copy" | ||
values = values if inplace else values.copy() # type: ignore[attr-defined] | ||
# error: "Callable[..., Any]" has no attribute "fillna" | ||
new_values = values.fillna( # type: ignore[attr-defined] | ||
value=value, limit=limit | ||
) | ||
new_values = maybe_coerce_values(new_values) | ||
values = self.values | ||
values = values if inplace else values.copy() | ||
new_values = values.fillna(value=value, limit=limit) | ||
return [self.make_block_same_class(values=new_values)] | ||
|
||
|
||
class DatetimeLikeBlockMixin(NDArrayBackedExtensionBlock): | ||
"""Mixin class for DatetimeBlock, DatetimeTZBlock, and TimedeltaBlock.""" | ||
|
||
values: Union[DatetimeArray, TimedeltaArray] | ||
|
||
is_numeric = False | ||
|
||
@cache_readonly | ||
def array_values(self): | ||
return ensure_wrapped_if_datetimelike(self.values) | ||
return self.values | ||
|
||
|
||
class DatetimeBlock(DatetimeLikeBlockMixin): | ||
__slots__ = () | ||
|
||
def set_inplace(self, locs, values): | ||
""" | ||
See Block.set.__doc__ | ||
""" | ||
values = conversion.ensure_datetime64ns(values, copy=False) | ||
|
||
self.values[locs] = values | ||
|
||
|
||
class DatetimeTZBlock(ExtensionBlock, DatetimeLikeBlockMixin): | ||
""" implement a datetime64 block with a tz attribute """ | ||
|
@@ -1936,13 +1926,10 @@ class DatetimeTZBlock(ExtensionBlock, DatetimeLikeBlockMixin): | |
putmask = DatetimeLikeBlockMixin.putmask | ||
fillna = DatetimeLikeBlockMixin.fillna | ||
|
||
array_values = ExtensionBlock.array_values | ||
|
||
@property | ||
def is_view(self) -> bool: | ||
""" return a boolean if I am possibly a view """ | ||
# check the ndarray values of the DatetimeIndex values | ||
return self.values._data.base is not None | ||
# error: Incompatible types in assignment (expression has type | ||
# "Callable[[NDArrayBackedExtensionBlock], bool]", base class "ExtensionBlock" | ||
# defined the type as "bool") [assignment] | ||
is_view = NDArrayBackedExtensionBlock.is_view # type: ignore[assignment] | ||
|
||
|
||
class TimeDeltaBlock(DatetimeLikeBlockMixin): | ||
|
@@ -2029,15 +2016,11 @@ def maybe_coerce_values(values) -> ArrayLike: | |
values = extract_array(values, extract_numpy=True) | ||
|
||
if isinstance(values, np.ndarray): | ||
values = sanitize_to_nanoseconds(values) | ||
values = ensure_wrapped_if_datetimelike(values) | ||
|
||
if issubclass(values.dtype.type, str): | ||
values = np.array(values, dtype=object) | ||
|
||
elif isinstance(values.dtype, np.dtype): | ||
# i.e. not datetime64tz, extract DTA/TDA -> ndarray | ||
values = values._data | ||
|
||
return values | ||
|
||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.