|
17 | 17 | Type,
|
18 | 18 | Union,
|
19 | 19 | )
|
| 20 | +import warnings |
20 | 21 |
|
21 | 22 | import numpy as np
|
22 | 23 |
|
@@ -469,31 +470,39 @@ def _get_window_indexer(self, window: int) -> BaseIndexer:
|
469 | 470 | return VariableWindowIndexer(index_array=self._on.asi8, window_size=window)
|
470 | 471 | return FixedWindowIndexer(window_size=window)
|
471 | 472 |
|
472 |
| - def _apply_series(self, homogeneous_func: Callable[..., ArrayLike]) -> "Series": |
| 473 | + def _apply_series( |
| 474 | + self, homogeneous_func: Callable[..., ArrayLike], name: Optional[str] = None |
| 475 | + ) -> "Series": |
473 | 476 | """
|
474 | 477 | Series version of _apply_blockwise
|
475 | 478 | """
|
476 | 479 | obj = self._create_data(self._selected_obj)
|
477 | 480 |
|
478 | 481 | try:
|
479 |
| - values = self._prep_values(obj.values) |
| 482 | + # GH 12541: Special case for count where we support date-like types |
| 483 | + input = obj.values if name != "count" else notna(obj.values).astype(int) |
| 484 | + values = self._prep_values(input) |
480 | 485 | except (TypeError, NotImplementedError) as err:
|
481 | 486 | raise DataError("No numeric types to aggregate") from err
|
482 | 487 |
|
483 | 488 | result = homogeneous_func(values)
|
484 | 489 | return obj._constructor(result, index=obj.index, name=obj.name)
|
485 | 490 |
|
486 | 491 | def _apply_blockwise(
|
487 |
| - self, homogeneous_func: Callable[..., ArrayLike] |
| 492 | + self, homogeneous_func: Callable[..., ArrayLike], name: Optional[str] = None |
488 | 493 | ) -> FrameOrSeriesUnion:
|
489 | 494 | """
|
490 | 495 | Apply the given function to the DataFrame broken down into homogeneous
|
491 | 496 | sub-frames.
|
492 | 497 | """
|
493 | 498 | if self._selected_obj.ndim == 1:
|
494 |
| - return self._apply_series(homogeneous_func) |
| 499 | + return self._apply_series(homogeneous_func, name) |
495 | 500 |
|
496 | 501 | obj = self._create_data(self._selected_obj)
|
| 502 | + if name == "count": |
| 503 | + # GH 12541: Special case for count where we support date-like types |
| 504 | + obj = notna(obj).astype(int) |
| 505 | + obj._mgr = obj._mgr.consolidate() |
497 | 506 | mgr = obj._mgr
|
498 | 507 |
|
499 | 508 | def hfunc(bvalues: ArrayLike) -> ArrayLike:
|
@@ -606,7 +615,7 @@ def calc(x):
|
606 | 615 |
|
607 | 616 | return result
|
608 | 617 |
|
609 |
| - return self._apply_blockwise(homogeneous_func) |
| 618 | + return self._apply_blockwise(homogeneous_func, name) |
610 | 619 |
|
611 | 620 | def aggregate(self, func, *args, **kwargs):
|
612 | 621 | result, how = self._aggregate(func, *args, **kwargs)
|
@@ -1265,33 +1274,8 @@ class RollingAndExpandingMixin(BaseWindow):
|
1265 | 1274 | )
|
1266 | 1275 |
|
1267 | 1276 | def count(self):
|
1268 |
| - # GH 32865. Using count with custom BaseIndexer subclass |
1269 |
| - # implementations shouldn't end up here |
1270 |
| - assert not isinstance(self.window, BaseIndexer) |
1271 |
| - |
1272 |
| - obj = self._create_data(self._selected_obj) |
1273 |
| - |
1274 |
| - def hfunc(values: np.ndarray) -> np.ndarray: |
1275 |
| - result = notna(values) |
1276 |
| - result = result.astype(int) |
1277 |
| - frame = type(obj)(result.T) |
1278 |
| - result = self._constructor( |
1279 |
| - frame, |
1280 |
| - window=self._get_window(), |
1281 |
| - min_periods=self.min_periods or 0, |
1282 |
| - center=self.center, |
1283 |
| - axis=self.axis, |
1284 |
| - closed=self.closed, |
1285 |
| - ).sum() |
1286 |
| - return result.values.T |
1287 |
| - |
1288 |
| - new_mgr = obj._mgr.apply(hfunc) |
1289 |
| - out = obj._constructor(new_mgr) |
1290 |
| - if obj.ndim == 1: |
1291 |
| - out.name = obj.name |
1292 |
| - else: |
1293 |
| - self._insert_on_column(out, obj) |
1294 |
| - return out |
| 1277 | + window_func = self._get_cython_func_type("roll_sum") |
| 1278 | + return self._apply(window_func, center=self.center, name="count") |
1295 | 1279 |
|
1296 | 1280 | _shared_docs["apply"] = dedent(
|
1297 | 1281 | r"""
|
@@ -2050,14 +2034,16 @@ def aggregate(self, func, *args, **kwargs):
|
2050 | 2034 | @Substitution(name="rolling")
|
2051 | 2035 | @Appender(_shared_docs["count"])
|
2052 | 2036 | def count(self):
|
2053 |
| - |
2054 |
| - # different impl for freq counting |
2055 |
| - # GH 32865. Use a custom count function implementation |
2056 |
| - # when using a BaseIndexer subclass as a window |
2057 |
| - if self.is_freq_type or isinstance(self.window, BaseIndexer): |
2058 |
| - window_func = self._get_roll_func("roll_count") |
2059 |
| - return self._apply(window_func, center=self.center, name="count") |
2060 |
| - |
| 2037 | + if self.min_periods is None: |
| 2038 | + warnings.warn( |
| 2039 | + ( |
| 2040 | + "min_periods=None will default to the size of window " |
| 2041 | + "consistent with other methods in a future version. " |
| 2042 | + "Specify min_periods=0 instead." |
| 2043 | + ), |
| 2044 | + FutureWarning, |
| 2045 | + ) |
| 2046 | + self.min_periods = 0 |
2061 | 2047 | return super().count()
|
2062 | 2048 |
|
2063 | 2049 | @Substitution(name="rolling")
|
|
0 commit comments