Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/core/window/rolling.py: 21%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

699 statements  

1""" 

2Provide a generic structure to support window functions, 

3similar to how we have a Groupby object. 

4""" 

5 

6from __future__ import annotations 

7 

8import copy 

9from datetime import timedelta 

10from functools import partial 

11import inspect 

12from typing import ( 

13 TYPE_CHECKING, 

14 Any, 

15 Concatenate, 

16 Literal, 

17 Self, 

18 cast, 

19 final, 

20 overload, 

21) 

22 

23import numpy as np 

24 

25from pandas._libs.tslibs import ( 

26 BaseOffset, 

27 Timedelta, 

28 to_offset, 

29) 

30import pandas._libs.window.aggregations as window_aggregations 

31from pandas.compat._optional import import_optional_dependency 

32from pandas.errors import DataError 

33from pandas.util._decorators import set_module 

34 

35from pandas.core.dtypes.common import ( 

36 ensure_float64, 

37 is_arrow_temporal_dtype, 

38 is_bool, 

39 is_integer, 

40 is_numeric_dtype, 

41 needs_i8_conversion, 

42) 

43from pandas.core.dtypes.dtypes import ArrowDtype 

44from pandas.core.dtypes.generic import ( 

45 ABCDataFrame, 

46 ABCSeries, 

47) 

48from pandas.core.dtypes.missing import notna 

49 

50from pandas.core._numba import executor 

51from pandas.core.algorithms import factorize 

52from pandas.core.apply import ( 

53 ResamplerWindowApply, 

54 reconstruct_func, 

55) 

56from pandas.core.arrays import ExtensionArray 

57from pandas.core.base import SelectionMixin 

58import pandas.core.common as com 

59from pandas.core.indexers.objects import ( 

60 BaseIndexer, 

61 FixedWindowIndexer, 

62 GroupByIndexer, 

63 VariableWindowIndexer, 

64) 

65from pandas.core.indexes.api import ( 

66 DatetimeIndex, 

67 Index, 

68 MultiIndex, 

69 PeriodIndex, 

70 TimedeltaIndex, 

71) 

72from pandas.core.reshape.concat import concat 

73from pandas.core.util.numba_ import ( 

74 get_jit_arguments, 

75 maybe_use_numba, 

76 prepare_function_arguments, 

77) 

78from pandas.core.window.common import ( 

79 flex_binary_moment, 

80 zsqrt, 

81) 

82from pandas.core.window.numba_ import ( 

83 generate_manual_numpy_nan_agg_with_axis, 

84 generate_numba_apply_func, 

85 generate_numba_table_func, 

86) 

87 

88if TYPE_CHECKING: 

89 from collections.abc import Callable 

90 from collections.abc import ( 

91 Hashable, 

92 Iterator, 

93 Sized, 

94 ) 

95 

96 from pandas._typing import ( 

97 ArrayLike, 

98 NDFrameT, 

99 QuantileInterpolation, 

100 P, 

101 TimeUnit, 

102 T, 

103 WindowingRankType, 

104 npt, 

105 ) 

106 

107 from pandas import ( 

108 DataFrame, 

109 Series, 

110 ) 

111 from pandas.core.generic import NDFrame 

112 from pandas.core.groupby.ops import BaseGrouper 

113 

114from pandas.core.arrays.datetimelike import dtype_to_unit 

115 

116 

117class BaseWindow(SelectionMixin["NDFrame"]): 

118 """Provides utilities for performing windowing operations.""" 

119 

120 _attributes: list[str] = [] 

121 exclusions: frozenset[Hashable] = frozenset() 

122 _on: Index 

123 

124 def __init__( 

125 self, 

126 obj: NDFrame, 

127 window=None, 

128 min_periods: int | None = None, 

129 center: bool | None = False, 

130 win_type: str | None = None, 

131 on: str | Index | None = None, 

132 closed: str | None = None, 

133 step: int | None = None, 

134 method: str = "single", 

135 *, 

136 selection=None, 

137 ) -> None: 

138 self.obj = obj 

139 self.on = on 

140 self.closed = closed 

141 self.step = step 

142 self.window = window 

143 self.min_periods = min_periods 

144 self.center = center 

145 self.win_type = win_type 

146 self.method = method 

147 self._win_freq_i8: int | None = None 

148 if self.on is None: 

149 self._on = self.obj.index 

150 elif isinstance(self.on, Index): 

151 self._on = self.on 

152 elif isinstance(self.obj, ABCDataFrame) and self.on in self.obj.columns: 

153 self._on = Index(self.obj[self.on]) 

154 else: 

155 raise ValueError( 

156 f"invalid on specified as {self.on}, " 

157 "must be a column (of DataFrame), an Index or None" 

158 ) 

159 

160 self._selection = selection 

161 self._validate() 

162 

163 def _validate(self) -> None: 

164 if self.center is not None and not is_bool(self.center): 

165 raise ValueError("center must be a boolean") 

166 if self.min_periods is not None: 

167 if not is_integer(self.min_periods): 

168 raise ValueError("min_periods must be an integer") 

169 if self.min_periods < 0: 

170 raise ValueError("min_periods must be >= 0") 

171 if is_integer(self.window) and self.min_periods > self.window: 

172 raise ValueError( 

173 f"min_periods {self.min_periods} must be <= window {self.window}" 

174 ) 

175 if self.closed is not None and self.closed not in [ 

176 "right", 

177 "both", 

178 "left", 

179 "neither", 

180 ]: 

181 raise ValueError("closed must be 'right', 'left', 'both' or 'neither'") 

182 if not isinstance(self.obj, (ABCSeries, ABCDataFrame)): 

183 raise TypeError(f"invalid type: {type(self)}") 

184 if isinstance(self.window, BaseIndexer): 

185 # Validate that the passed BaseIndexer subclass has 

186 # a get_window_bounds with the correct signature. 

187 get_window_bounds_signature = inspect.signature( 

188 self.window.get_window_bounds 

189 ).parameters.keys() 

190 expected_signature = inspect.signature( 

191 BaseIndexer().get_window_bounds 

192 ).parameters.keys() 

193 if get_window_bounds_signature != expected_signature: 

194 raise ValueError( 

195 f"{type(self.window).__name__} does not implement " 

196 f"the correct signature for get_window_bounds" 

197 ) 

198 if self.method not in ["table", "single"]: 

199 raise ValueError("method must be 'table' or 'single") 

200 if self.step is not None: 

201 if not is_integer(self.step): 

202 raise ValueError("step must be an integer") 

203 if self.step < 0: 

204 raise ValueError("step must be >= 0") 

205 

206 def _check_window_bounds( 

207 self, start: np.ndarray, end: np.ndarray, num_vals: int 

208 ) -> None: 

209 if len(start) != len(end): 

210 raise ValueError( 

211 f"start ({len(start)}) and end ({len(end)}) bounds must be the " 

212 f"same length" 

213 ) 

214 if len(start) != (num_vals + (self.step or 1) - 1) // (self.step or 1): 

215 raise ValueError( 

216 f"start and end bounds ({len(start)}) must be the same length " 

217 f"as the object ({num_vals}) divided by the step ({self.step}) " 

218 f"if given and rounded up" 

219 ) 

220 

221 def _slice_axis_for_step(self, index: Index, result: Sized | None = None) -> Index: 

222 """ 

223 Slices the index for a given result and the preset step. 

224 """ 

225 return ( 

226 index 

227 if result is None or len(result) == len(index) 

228 else index[:: self.step] 

229 ) 

230 

231 def _validate_numeric_only(self, name: str, numeric_only: bool) -> None: 

232 """ 

233 Validate numeric_only argument, raising if invalid for the input. 

234 

235 Parameters 

236 ---------- 

237 name : str 

238 Name of the operator (kernel). 

239 numeric_only : bool 

240 Value passed by user. 

241 """ 

242 if ( 

243 self._selected_obj.ndim == 1 

244 and numeric_only 

245 and not is_numeric_dtype(self._selected_obj.dtype) 

246 ): 

247 raise NotImplementedError( 

248 f"{type(self).__name__}.{name} does not implement numeric_only" 

249 ) 

250 

251 def _make_numeric_only(self, obj: NDFrameT) -> NDFrameT: 

252 """Subset DataFrame to numeric columns. 

253 

254 Parameters 

255 ---------- 

256 obj : DataFrame 

257 

258 Returns 

259 ------- 

260 obj subset to numeric-only columns. 

261 """ 

262 result = obj.select_dtypes(include=["number"], exclude=["timedelta"]) 

263 return result 

264 

265 def _create_data(self, obj: NDFrameT, numeric_only: bool = False) -> NDFrameT: 

266 """ 

267 Split data into blocks & return conformed data. 

268 """ 

269 # filter out the on from the object 

270 if self.on is not None and not isinstance(self.on, Index) and obj.ndim == 2: 

271 obj = obj.reindex(columns=obj.columns.difference([self.on], sort=False)) 

272 if obj.ndim > 1 and numeric_only: 

273 obj = self._make_numeric_only(obj) 

274 return obj 

275 

276 def _gotitem(self, key, ndim, subset=None): 

277 """ 

278 Sub-classes to define. Return a sliced object. 

279 

280 Parameters 

281 ---------- 

282 key : str / list of selections 

283 ndim : {1, 2} 

284 requested ndim of result 

285 subset : object, default None 

286 subset to act on 

287 """ 

288 # create a new object to prevent aliasing 

289 if subset is None: 

290 subset = self.obj 

291 

292 # we need to make a shallow copy of ourselves 

293 # with the same groupby 

294 kwargs = {attr: getattr(self, attr) for attr in self._attributes} 

295 

296 selection = self._infer_selection(key, subset) 

297 new_win = type(self)(subset, selection=selection, **kwargs) 

298 return new_win 

299 

300 def __getattr__(self, attr: str): 

301 if attr in self._internal_names_set: 

302 return object.__getattribute__(self, attr) 

303 if attr in self.obj: 

304 return self[attr] 

305 

306 raise AttributeError( 

307 f"'{type(self).__name__}' object has no attribute '{attr}'" 

308 ) 

309 

310 def _dir_additions(self): 

311 return self.obj._dir_additions() 

312 

313 def __repr__(self) -> str: 

314 """ 

315 Provide a nice str repr of our rolling object. 

316 """ 

317 attrs_list = ( 

318 f"{attr_name}={getattr(self, attr_name)}" 

319 for attr_name in self._attributes 

320 if getattr(self, attr_name, None) is not None and attr_name[0] != "_" 

321 ) 

322 attrs = ",".join(attrs_list) 

323 return f"{type(self).__name__} [{attrs}]" 

324 

325 def __iter__(self) -> Iterator[Any]: 

326 obj = self._selected_obj.set_axis(self._on) 

327 obj = self._create_data(obj) 

328 indexer = self._get_window_indexer() 

329 

330 start, end = indexer.get_window_bounds( 

331 num_values=len(obj), 

332 min_periods=self.min_periods, 

333 center=self.center, 

334 closed=self.closed, 

335 step=self.step, 

336 ) 

337 self._check_window_bounds(start, end, len(obj)) 

338 

339 for s, e in zip(start, end, strict=True): 

340 result = obj.iloc[slice(s, e)] 

341 yield result 

342 

343 def _prep_values(self, values: ArrayLike) -> np.ndarray: 

344 """Convert input to numpy arrays for Cython routines""" 

345 if needs_i8_conversion(values.dtype) or is_arrow_temporal_dtype(values.dtype): 

346 # GH#66445 ArrowDtype timestamps/durations are not covered by 

347 # needs_i8_conversion, so without the second check they fell through 

348 # to the ExtensionArray branch below and were silently converted to 

349 # float64 counts instead of raising like their NumPy counterparts. 

350 raise NotImplementedError( 

351 f"ops for {type(self).__name__} for this " 

352 f"dtype {values.dtype} is not implemented" 

353 ) 

354 # GH #12373 : rolling functions error on float32 data 

355 # make sure the data is coerced to float64 

356 try: 

357 if isinstance(values, ExtensionArray): 

358 values = values.to_numpy(np.float64, na_value=np.nan) 

359 else: 

360 values = ensure_float64(values) 

361 except (ValueError, TypeError) as err: 

362 raise TypeError(f"cannot handle this type -> {values.dtype}") from err 

363 

364 # Convert inf to nan for C funcs 

365 inf = np.isinf(values) 

366 if inf.any(): 

367 values = np.where(inf, np.nan, values) 

368 

369 return values 

370 

371 def _insert_on_column(self, result: DataFrame, obj: DataFrame) -> None: 

372 # if we have an 'on' column we want to put it back into 

373 # the results in the same location 

374 from pandas import Series 

375 

376 if self.on is not None and not self._on.equals(obj.index): 

377 name = self._on.name 

378 extra_col = Series(self._on, index=self.obj.index, name=name, copy=False) 

379 if name in result.columns: 

380 # TODO: sure we want to overwrite results? 

381 result[name] = extra_col 

382 elif name in result.index.names: 

383 pass 

384 elif name in self._selected_obj.columns: 

385 # insert in the same location as we had in _selected_obj 

386 old_cols = self._selected_obj.columns 

387 new_cols = result.columns 

388 old_loc = old_cols.get_loc(name) 

389 overlap = new_cols.intersection(old_cols[:old_loc]) 

390 new_loc = len(overlap) 

391 result.insert(new_loc, name, extra_col) 

392 else: 

393 # insert at the end 

394 result[name] = extra_col 

395 

396 @property 

397 def _index_array(self) -> npt.NDArray[np.int64] | None: 

398 # TODO: why do we get here with e.g. MultiIndex? 

399 if isinstance(self._on, (PeriodIndex, DatetimeIndex, TimedeltaIndex)): 

400 return self._on.asi8 

401 elif isinstance(self._on.dtype, ArrowDtype) and self._on.dtype.kind in "mM": 

402 return self._on.to_numpy(dtype=np.int64) 

403 return None 

404 

405 def _resolve_output(self, out: DataFrame, obj: DataFrame) -> DataFrame: 

406 """Validate and finalize result.""" 

407 if out.shape[1] == 0 and obj.shape[1] > 0: 

408 raise DataError("No numeric types to aggregate") 

409 if out.shape[1] == 0: 

410 return obj.astype("float64") 

411 

412 self._insert_on_column(out, obj) 

413 return out 

414 

415 def _get_window_indexer(self) -> BaseIndexer: 

416 """ 

417 Return an indexer class that will compute the window start and end bounds 

418 """ 

419 if isinstance(self.window, BaseIndexer): 

420 return self.window 

421 if self._win_freq_i8 is not None: 

422 return VariableWindowIndexer( 

423 index_array=self._index_array, 

424 window_size=self._win_freq_i8, 

425 center=self.center, 

426 ) 

427 return FixedWindowIndexer(window_size=self.window) 

428 

429 def _apply_series( 

430 self, homogeneous_func: Callable[..., ArrayLike], name: str | None = None 

431 ) -> Series: 

432 """ 

433 Series version of _apply_columnwise 

434 """ 

435 obj = self._create_data(self._selected_obj) 

436 

437 if name == "count": 

438 # GH 12541: Special case for count where we support date-like types 

439 obj = notna(obj).astype(int) 

440 try: 

441 values = self._prep_values(obj._values) 

442 except (TypeError, NotImplementedError) as err: 

443 raise DataError("No numeric types to aggregate") from err 

444 

445 result = homogeneous_func(values) 

446 index = self._slice_axis_for_step(obj.index, result) 

447 return obj._constructor(result, index=index, name=obj.name) 

448 

449 def _apply_columnwise( 

450 self, 

451 homogeneous_func: Callable[..., ArrayLike], 

452 name: str, 

453 numeric_only: bool = False, 

454 ) -> DataFrame | Series: 

455 """ 

456 Apply the given function to the DataFrame broken down into homogeneous 

457 sub-frames. 

458 """ 

459 self._validate_numeric_only(name, numeric_only) 

460 if self._selected_obj.ndim == 1: 

461 return self._apply_series(homogeneous_func, name) 

462 

463 obj = self._create_data(self._selected_obj, numeric_only) 

464 if name == "count": 

465 # GH 12541: Special case for count where we support date-like types 

466 obj = notna(obj).astype(int) 

467 obj._mgr = obj._mgr.consolidate() 

468 

469 taker = [] 

470 res_values = [] 

471 for i, arr in enumerate(obj._iter_column_arrays()): 

472 # GH#42736 operate column-wise instead of block-wise 

473 # As of 2.0, hfunc will raise for nuisance columns 

474 try: 

475 arr = self._prep_values(arr) 

476 except (TypeError, NotImplementedError) as err: 

477 raise DataError( 

478 f"Cannot aggregate non-numeric type: {arr.dtype}" 

479 ) from err 

480 res = homogeneous_func(arr) 

481 res_values.append(res) 

482 taker.append(i) 

483 

484 index = self._slice_axis_for_step( 

485 obj.index, res_values[0] if len(res_values) > 0 else None 

486 ) 

487 df = type(obj)._from_arrays( 

488 res_values, 

489 index=index, 

490 columns=obj.columns.take(taker), 

491 verify_integrity=False, 

492 ) 

493 

494 return self._resolve_output(df, obj) 

495 

496 def _apply_tablewise( 

497 self, 

498 homogeneous_func: Callable[..., ArrayLike], 

499 name: str | None = None, 

500 numeric_only: bool = False, 

501 ) -> DataFrame | Series: 

502 """ 

503 Apply the given function to the DataFrame across the entire object 

504 """ 

505 if self._selected_obj.ndim == 1: 

506 raise ValueError("method='table' not applicable for Series objects.") 

507 obj = self._create_data(self._selected_obj, numeric_only) 

508 values = self._prep_values(obj.to_numpy()) 

509 result = homogeneous_func(values) 

510 index = self._slice_axis_for_step(obj.index, result) 

511 columns = ( 

512 obj.columns 

513 if result.shape[1] == len(obj.columns) 

514 else obj.columns[:: self.step] 

515 ) 

516 out = obj._constructor(result, index=index, columns=columns) 

517 

518 return self._resolve_output(out, obj) 

519 

520 def _apply_pairwise( 

521 self, 

522 target: DataFrame | Series, 

523 other: DataFrame | Series | None, 

524 pairwise: bool | None, 

525 func: Callable[[DataFrame | Series, DataFrame | Series], DataFrame | Series], 

526 numeric_only: bool, 

527 ) -> DataFrame | Series: 

528 """ 

529 Apply the given pairwise function given 2 pandas objects (DataFrame/Series) 

530 """ 

531 target = self._create_data(target, numeric_only) 

532 if other is None: 

533 other = target 

534 # only default unset 

535 pairwise = True if pairwise is None else pairwise 

536 elif not isinstance(other, (ABCDataFrame, ABCSeries)): 

537 raise ValueError("other must be a DataFrame or Series") 

538 elif other.ndim == 2 and numeric_only: 

539 other = self._make_numeric_only(other) 

540 

541 return flex_binary_moment(target, other, func, pairwise=bool(pairwise)) 

542 

543 def _apply( 

544 self, 

545 func: Callable[..., Any], 

546 name: str, 

547 numeric_only: bool = False, 

548 numba_args: tuple[Any, ...] = (), 

549 **kwargs, 

550 ): 

551 """ 

552 Rolling statistical measure using supplied function. 

553 

554 Designed to be used with passed-in Cython array-based functions. 

555 

556 Parameters 

557 ---------- 

558 func : callable function to apply 

559 name : str, 

560 numba_args : tuple 

561 args to be passed when func is a numba func 

562 **kwargs 

563 additional arguments for rolling function and window function 

564 

565 Returns 

566 ------- 

567 y : type of input 

568 """ 

569 window_indexer = self._get_window_indexer() 

570 min_periods = ( 

571 self.min_periods 

572 if self.min_periods is not None 

573 else window_indexer.window_size 

574 ) 

575 

576 def homogeneous_func(values: np.ndarray): 

577 # calculation function 

578 

579 if values.size == 0: 

580 return values.copy() 

581 

582 def calc(x): 

583 start, end = window_indexer.get_window_bounds( 

584 num_values=len(x), 

585 min_periods=min_periods, 

586 center=self.center, 

587 closed=self.closed, 

588 step=self.step, 

589 ) 

590 self._check_window_bounds(start, end, len(x)) 

591 

592 return func(x, start, end, min_periods, *numba_args) 

593 

594 with np.errstate(all="ignore"): 

595 result = calc(values) 

596 

597 return result 

598 

599 if self.method == "single": 

600 return self._apply_columnwise(homogeneous_func, name, numeric_only) 

601 else: 

602 return self._apply_tablewise(homogeneous_func, name, numeric_only) 

603 

604 def _numba_apply( 

605 self, 

606 func: Callable[..., Any], 

607 engine_kwargs: dict[str, bool] | None = None, 

608 **func_kwargs, 

609 ): 

610 window_indexer = self._get_window_indexer() 

611 min_periods = ( 

612 self.min_periods 

613 if self.min_periods is not None 

614 else window_indexer.window_size 

615 ) 

616 obj = self._create_data(self._selected_obj) 

617 values = self._prep_values(obj.to_numpy()) 

618 if values.ndim == 1: 

619 values = values.reshape(-1, 1) 

620 start, end = window_indexer.get_window_bounds( 

621 num_values=len(values), 

622 min_periods=min_periods, 

623 center=self.center, 

624 closed=self.closed, 

625 step=self.step, 

626 ) 

627 self._check_window_bounds(start, end, len(values)) 

628 # For now, map everything to float to match the Cython impl 

629 # even though it is wrong 

630 # TODO: Could preserve correct dtypes in future 

631 # xref #53214 

632 dtype_mapping = executor.float_dtype_mapping 

633 aggregator = executor.generate_shared_aggregator( 

634 func, 

635 dtype_mapping, 

636 is_grouped_kernel=False, 

637 **get_jit_arguments(engine_kwargs), 

638 ) 

639 result = aggregator( 

640 values.T, start=start, end=end, min_periods=min_periods, **func_kwargs 

641 ).T 

642 index = self._slice_axis_for_step(obj.index, result) 

643 if obj.ndim == 1: 

644 result = result.squeeze() 

645 out = obj._constructor(result, index=index, name=obj.name) 

646 return out 

647 else: 

648 columns = self._slice_axis_for_step(obj.columns, result.T) 

649 out = obj._constructor(result, index=index, columns=columns) 

650 return self._resolve_output(out, obj) 

651 

652 def aggregate(self, func=None, *args, **kwargs): 

653 relabeling, func, columns, order = reconstruct_func(func, **kwargs) 

654 result = ResamplerWindowApply(self, func, args=args, kwargs=kwargs).agg() 

655 if isinstance(result, ABCDataFrame) and relabeling: 

656 result = result.iloc[:, order] 

657 result.columns = columns 

658 if result is None: 

659 return self.apply(func, raw=False, args=args, kwargs=kwargs) 

660 return result 

661 

662 agg = aggregate 

663 

664 

665class BaseWindowGroupBy(BaseWindow): 

666 """ 

667 Provide the groupby windowing facilities. 

668 """ 

669 

670 _grouper: BaseGrouper 

671 _as_index: bool 

672 _attributes: list[str] = ["_grouper"] 

673 

674 def __init__( 

675 self, 

676 obj: DataFrame | Series, 

677 *args, 

678 _grouper: BaseGrouper, 

679 _as_index: bool = True, 

680 **kwargs, 

681 ) -> None: 

682 from pandas.core.groupby.ops import BaseGrouper 

683 

684 if not isinstance(_grouper, BaseGrouper): 

685 raise ValueError("Must pass a BaseGrouper object.") 

686 self._grouper = _grouper 

687 self._as_index = _as_index 

688 # GH 32262: It's convention to keep the grouping column in 

689 # groupby.<agg_func>, but unexpected to users in 

690 # groupby.rolling.<agg_func> 

691 obj = obj.drop(columns=self._grouper.names, errors="ignore") 

692 # GH 15354 

693 if kwargs.get("step") is not None: 

694 raise NotImplementedError("step not implemented for groupby") 

695 super().__init__(obj, *args, **kwargs) 

696 

697 def _apply( 

698 self, 

699 func: Callable[..., Any], 

700 name: str, 

701 numeric_only: bool = False, 

702 numba_args: tuple[Any, ...] = (), 

703 **kwargs, 

704 ) -> DataFrame | Series: 

705 result = super()._apply( 

706 func, 

707 name, 

708 numeric_only, 

709 numba_args, 

710 **kwargs, 

711 ) 

712 # Reconstruct the resulting MultiIndex 

713 # 1st set of levels = group by labels 

714 # 2nd set of levels = original DataFrame/Series index 

715 grouped_object_index = self.obj.index 

716 grouped_index_name = [*grouped_object_index.names] 

717 groupby_keys = copy.copy(self._grouper.names) 

718 result_index_names = groupby_keys + grouped_index_name 

719 

720 drop_columns = [ 

721 key 

722 for key in self._grouper.names 

723 if key not in self.obj.index.names or key is None 

724 ] 

725 

726 if len(drop_columns) != len(groupby_keys): 

727 # Our result will have still kept the column in the result 

728 result = result.drop(columns=drop_columns, errors="ignore") 

729 

730 codes = self._grouper.codes 

731 levels = copy.copy(self._grouper.levels) 

732 

733 group_indices = self._grouper.indices.values() 

734 if group_indices: 

735 indexer = np.concatenate(list(group_indices)) 

736 else: 

737 indexer = np.array([], dtype=np.intp) 

738 codes = [c.take(indexer) for c in codes] 

739 

740 # if the index of the original dataframe needs to be preserved, append 

741 # this index (but reordered) to the codes/levels from the groupby 

742 if grouped_object_index is not None: 

743 idx = grouped_object_index.take(indexer) 

744 if not isinstance(idx, MultiIndex): 

745 idx = MultiIndex.from_arrays([idx]) 

746 codes.extend(list(idx.codes)) 

747 levels.extend(list(idx.levels)) 

748 

749 result_index = MultiIndex( 

750 levels, codes, names=result_index_names, verify_integrity=False 

751 ) 

752 

753 result.index = result_index 

754 if not self._as_index: 

755 result = result.reset_index(level=list(range(len(groupby_keys)))) 

756 return result 

757 

758 def _apply_pairwise( 

759 self, 

760 target: DataFrame | Series, 

761 other: DataFrame | Series | None, 

762 pairwise: bool | None, 

763 func: Callable[[DataFrame | Series, DataFrame | Series], DataFrame | Series], 

764 numeric_only: bool, 

765 ) -> DataFrame | Series: 

766 """ 

767 Apply the given pairwise function given 2 pandas objects (DataFrame/Series) 

768 """ 

769 # Manually drop the grouping column first 

770 target = target.drop(columns=self._grouper.names, errors="ignore") 

771 result = super()._apply_pairwise(target, other, pairwise, func, numeric_only) 

772 # 1) Determine the levels + codes of the groupby levels 

773 if other is not None and not all( 

774 len(group) == len(other) for group in self._grouper.indices.values() 

775 ): 

776 # GH 42915 

777 # len(other) != len(any group), so must reindex (expand) the result 

778 # from flex_binary_moment to a "transform"-like result 

779 # per groupby combination 

780 old_result_len = len(result) 

781 result = concat( 

782 [ 

783 result.take(gb_indices).reindex(result.index) 

784 for gb_indices in self._grouper.indices.values() 

785 ] 

786 ) 

787 

788 gb_pairs = ( 

789 com.maybe_make_list(pair) for pair in self._grouper.indices.keys() 

790 ) 

791 groupby_codes = [] 

792 groupby_levels = [] 

793 # e.g. [[1, 2], [4, 5]] as [[1, 4], [2, 5]] 

794 for gb_level_pair in map(list, zip(*gb_pairs, strict=True)): 

795 labels = np.repeat(np.array(gb_level_pair), old_result_len) 

796 codes, levels = factorize(labels) 

797 groupby_codes.append(codes) 

798 groupby_levels.append(levels) 

799 else: 

800 # pairwise=True or len(other) == len(each group), so repeat 

801 # the groupby labels by the number of columns in the original object 

802 groupby_codes = self._grouper.codes 

803 # error: Incompatible types in assignment (expression has type 

804 # "List[Index]", variable has type "List[Union[ndarray, Index]]") 

805 groupby_levels = self._grouper.levels # type: ignore[assignment] 

806 

807 group_indices = self._grouper.indices.values() 

808 if group_indices: 

809 indexer = np.concatenate(list(group_indices)) 

810 else: 

811 indexer = np.array([], dtype=np.intp) 

812 

813 if target.ndim == 1: 

814 repeat_by = 1 

815 else: 

816 repeat_by = len(target.columns) 

817 groupby_codes = [ 

818 np.repeat(c.take(indexer), repeat_by) for c in groupby_codes 

819 ] 

820 # 2) Determine the levels + codes of the result from super()._apply_pairwise 

821 if isinstance(result.index, MultiIndex): 

822 result_codes = list(result.index.codes) 

823 result_levels = list(result.index.levels) 

824 result_names = list(result.index.names) 

825 else: 

826 idx_codes, idx_levels = factorize(result.index) 

827 result_codes = [idx_codes] 

828 result_levels = [idx_levels] 

829 result_names = [result.index.name] 

830 

831 # 3) Create the resulting index by combining 1) + 2) 

832 result_codes = groupby_codes + result_codes 

833 result_levels = groupby_levels + result_levels 

834 result_names = self._grouper.names + result_names 

835 

836 result_index = MultiIndex( 

837 result_levels, result_codes, names=result_names, verify_integrity=False 

838 ) 

839 result.index = result_index 

840 return result 

841 

842 def _create_data(self, obj: NDFrameT, numeric_only: bool = False) -> NDFrameT: 

843 """ 

844 Split data into blocks & return conformed data. 

845 """ 

846 # Ensure the object we're rolling over is monotonically sorted relative 

847 # to the groups 

848 # GH 36197 

849 if not obj.empty: 

850 groupby_order = np.concatenate(list(self._grouper.indices.values())).astype( 

851 np.int64 

852 ) 

853 obj = obj.take(groupby_order) 

854 return super()._create_data(obj, numeric_only) 

855 

856 def _gotitem(self, key, ndim, subset=None): 

857 # we are setting the index on the actual object 

858 # here so our index is carried through to the selected obj 

859 # when we do the splitting for the groupby 

860 if self.on is not None: 

861 # GH 43355 

862 subset = self.obj.set_index(self._on) 

863 return super()._gotitem(key, ndim, subset=subset) 

864 

865 

866@set_module("pandas.api.typing") 

867class Window(BaseWindow): 

868 """ 

869 Provide rolling window calculations. 

870 

871 Parameters 

872 ---------- 

873 window : int, timedelta, str, offset, or BaseIndexer subclass 

874 Interval of the moving window. 

875 

876 If an integer, the delta between the start and end of each window. 

877 The number of points in the window depends on the ``closed`` argument. 

878 

879 If a timedelta, str, or offset, the time period of each window. Each 

880 window will be a variable sized based on the observations included in 

881 the time-period. This is only valid for datetimelike indexes. 

882 To learn more about the offsets & frequency strings, please see 

883 :ref:`this link<timeseries.offset_aliases>`. 

884 

885 If a BaseIndexer subclass, the window boundaries 

886 based on the defined ``get_window_bounds`` method. Additional rolling 

887 keyword arguments, namely ``min_periods``, ``center``, ``closed`` and 

888 ``step`` will be passed to ``get_window_bounds``. 

889 

890 min_periods : int, default None 

891 Minimum number of observations in window required to have a value; 

892 otherwise, result is ``np.nan``. 

893 

894 For a window that is specified by an offset, ``min_periods`` will default to 1. 

895 

896 For a window that is specified by an integer, ``min_periods`` will default 

897 to the size of the window. 

898 

899 center : bool, default False 

900 If False, set the window labels as the right edge of the window index. 

901 

902 If True, set the window labels as the center of the window index. 

903 

904 win_type : str, default None 

905 If ``None``, all points are evenly weighted. 

906 

907 If a string, it must be a valid `scipy.signal window function 

908 <https://docs.scipy.org/doc/scipy/reference/signal.windows.html#module-scipy.signal.windows>`__. 

909 

910 Certain Scipy window types require additional parameters to be passed 

911 in the aggregation function. The additional parameters must match 

912 the keywords specified in the Scipy window type method signature. 

913 

914 on : str, optional 

915 For a DataFrame, a column label or Index level on which 

916 to calculate the rolling window, rather than the DataFrame's index. 

917 

918 For integer ``window`` values, the window bounds are based on the number 

919 of observations and are not calculated using the values of the 

920 ``on`` column. The ``on`` column is excluded from the aggregation, 

921 but is included in the result when its values differ from the 

922 object's index. 

923 

924 closed : str, default None 

925 Determines the inclusivity of points in the window 

926 

927 If ``'right'``, uses the window (first, last] meaning the last point 

928 is included in the calculations. 

929 

930 If ``'left'``, uses the window [first, last) meaning the first point 

931 is included in the calculations. 

932 

933 If ``'both'``, uses the window [first, last] meaning all points in 

934 the window are included in the calculations. 

935 

936 If ``'neither'``, uses the window (first, last) meaning the first 

937 and last points in the window are excluded from calculations. 

938 

939 () and [] are referencing open and closed set 

940 notation respetively. 

941 

942 Default ``None`` (``'right'``). 

943 

944 step : int, default None 

945 Evaluate the window at every ``step`` result, equivalent to slicing as 

946 ``[::step]``. ``window`` must be an integer. Using a step argument other 

947 than None or 1 will produce a result with a different shape than the input. 

948 

949 method : str {'single', 'table'}, default 'single' 

950 

951 Execute the rolling operation per single column or row (``'single'``) 

952 or over the entire object (``'table'``). 

953 

954 This argument is only implemented when specifying ``engine='numba'`` 

955 in the method call. 

956 

957 Returns 

958 ------- 

959 pandas.api.typing.Window or pandas.api.typing.Rolling 

960 An instance of Window is returned if ``win_type`` is passed. Otherwise, 

961 an instance of Rolling is returned. 

962 

963 See Also 

964 -------- 

965 expanding : Provides expanding transformations. 

966 ewm : Provides exponential weighted functions. 

967 

968 Notes 

969 ----- 

970 See :ref:`Windowing Operations <window.generic>` for further usage details 

971 and examples. 

972 

973 Examples 

974 -------- 

975 >>> df = pd.DataFrame({"B": [0, 1, 2, np.nan, 4]}) 

976 >>> df 

977 B 

978 0 0.0 

979 1 1.0 

980 2 2.0 

981 3 NaN 

982 4 4.0 

983 

984 **window** 

985 

986 Rolling sum with a window length of 2 observations. 

987 

988 >>> df.rolling(2).sum() 

989 B 

990 0 NaN 

991 1 1.0 

992 2 3.0 

993 3 NaN 

994 4 NaN 

995 

996 Rolling sum with a window span of 2 seconds. 

997 

998 >>> df_time = pd.DataFrame( 

999 ... {"B": [0, 1, 2, np.nan, 4]}, 

1000 ... index=[ 

1001 ... pd.Timestamp("20130101 09:00:00"), 

1002 ... pd.Timestamp("20130101 09:00:02"), 

1003 ... pd.Timestamp("20130101 09:00:03"), 

1004 ... pd.Timestamp("20130101 09:00:05"), 

1005 ... pd.Timestamp("20130101 09:00:06"), 

1006 ... ], 

1007 ... ) 

1008 

1009 >>> df_time 

1010 B 

1011 2013-01-01 09:00:00 0.0 

1012 2013-01-01 09:00:02 1.0 

1013 2013-01-01 09:00:03 2.0 

1014 2013-01-01 09:00:05 NaN 

1015 2013-01-01 09:00:06 4.0 

1016 

1017 >>> df_time.rolling("2s").sum() 

1018 B 

1019 2013-01-01 09:00:00 0.0 

1020 2013-01-01 09:00:02 1.0 

1021 2013-01-01 09:00:03 3.0 

1022 2013-01-01 09:00:05 NaN 

1023 2013-01-01 09:00:06 4.0 

1024 

1025 Rolling sum with forward looking windows with 2 observations. 

1026 

1027 >>> indexer = pd.api.indexers.FixedForwardWindowIndexer(window_size=2) 

1028 >>> df.rolling(window=indexer, min_periods=1).sum() 

1029 B 

1030 0 1.0 

1031 1 3.0 

1032 2 2.0 

1033 3 4.0 

1034 4 4.0 

1035 

1036 **min_periods** 

1037 

1038 Rolling sum with a window length of 2 observations, but only needs a minimum of 1 

1039 observation to calculate a value. 

1040 

1041 >>> df.rolling(2, min_periods=1).sum() 

1042 B 

1043 0 0.0 

1044 1 1.0 

1045 2 3.0 

1046 3 2.0 

1047 4 4.0 

1048 

1049 **center** 

1050 

1051 Rolling sum with the result assigned to the center of the window index. 

1052 

1053 >>> df.rolling(3, min_periods=1, center=True).sum() 

1054 B 

1055 0 1.0 

1056 1 3.0 

1057 2 3.0 

1058 3 6.0 

1059 4 4.0 

1060 

1061 >>> df.rolling(3, min_periods=1, center=False).sum() 

1062 B 

1063 0 0.0 

1064 1 1.0 

1065 2 3.0 

1066 3 3.0 

1067 4 6.0 

1068 

1069 **step** 

1070 

1071 Rolling sum with a window length of 2 observations, minimum of 1 observation to 

1072 calculate a value, and a step of 2. 

1073 

1074 >>> df.rolling(2, min_periods=1, step=2).sum() 

1075 B 

1076 0 0.0 

1077 2 3.0 

1078 4 4.0 

1079 

1080 **win_type** 

1081 

1082 Rolling sum with a window length of 2, using the Scipy ``'gaussian'`` 

1083 window type. ``std`` is required in the aggregation function. 

1084 

1085 >>> df.rolling(2, win_type="gaussian").sum(std=3) 

1086 B 

1087 0 NaN 

1088 1 0.986207 

1089 2 2.958621 

1090 3 NaN 

1091 4 NaN 

1092 

1093 **on** 

1094 

1095 Rolling sum with a window length of 2 days. 

1096 

1097 >>> df = pd.DataFrame( 

1098 ... { 

1099 ... "A": [ 

1100 ... pd.to_datetime("2020-01-01"), 

1101 ... pd.to_datetime("2020-01-01"), 

1102 ... pd.to_datetime("2020-01-02"), 

1103 ... ], 

1104 ... "B": [1, 2, 3], 

1105 ... }, 

1106 ... index=pd.date_range("2020", periods=3), 

1107 ... ) 

1108 

1109 >>> df 

1110 A B 

1111 2020-01-01 2020-01-01 1 

1112 2020-01-02 2020-01-01 2 

1113 2020-01-03 2020-01-02 3 

1114 

1115 >>> df.rolling("2D", on="A").sum() 

1116 A B 

1117 2020-01-01 2020-01-01 1.0 

1118 2020-01-02 2020-01-01 3.0 

1119 2020-01-03 2020-01-02 6.0 

1120 """ 

1121 

1122 _attributes = [ 

1123 "window", 

1124 "min_periods", 

1125 "center", 

1126 "win_type", 

1127 "on", 

1128 "closed", 

1129 "step", 

1130 "method", 

1131 ] 

1132 

1133 def _validate(self) -> None: 

1134 super()._validate() 

1135 

1136 if not isinstance(self.win_type, str): 

1137 raise ValueError(f"Invalid win_type {self.win_type}") 

1138 signal = import_optional_dependency( 

1139 "scipy.signal.windows", extra="Scipy is required to generate window weight." 

1140 ) 

1141 self._scipy_weight_generator = getattr(signal, self.win_type, None) 

1142 if self._scipy_weight_generator is None: 

1143 raise ValueError(f"Invalid win_type {self.win_type}") 

1144 

1145 if isinstance(self.window, BaseIndexer): 

1146 raise NotImplementedError( 

1147 "BaseIndexer subclasses not implemented with win_types." 

1148 ) 

1149 if not is_integer(self.window) or self.window < 0: 

1150 raise ValueError("window must be an integer 0 or greater") 

1151 

1152 if self.method != "single": 

1153 raise NotImplementedError("'single' is the only supported method type.") 

1154 

1155 def _center_window(self, result: np.ndarray, offset: int) -> np.ndarray: 

1156 """ 

1157 Center the result in the window for weighted rolling aggregations. 

1158 """ 

1159 if offset > 0: 

1160 lead_indexer = [slice(offset, None)] 

1161 result = np.copy(result[tuple(lead_indexer)]) 

1162 return result 

1163 

1164 def _apply( 

1165 self, 

1166 func: Callable[[np.ndarray, int, int], np.ndarray], 

1167 name: str, 

1168 numeric_only: bool = False, 

1169 numba_args: tuple[Any, ...] = (), 

1170 **kwargs, 

1171 ): 

1172 """ 

1173 Rolling with weights statistical measure using supplied function. 

1174 

1175 Designed to be used with passed-in Cython array-based functions. 

1176 

1177 Parameters 

1178 ---------- 

1179 func : callable function to apply 

1180 name : str, 

1181 numeric_only : bool, default False 

1182 Whether to only operate on bool, int, and float columns 

1183 numba_args : tuple 

1184 unused 

1185 **kwargs 

1186 additional arguments for scipy windows if necessary 

1187 

1188 Returns 

1189 ------- 

1190 y : type of input 

1191 """ 

1192 # "None" not callable [misc] 

1193 window = self._scipy_weight_generator( # type: ignore[misc] 

1194 self.window, **kwargs 

1195 ) 

1196 offset = (len(window) - 1) // 2 if self.center else 0 

1197 

1198 def homogeneous_func(values: np.ndarray): 

1199 # calculation function 

1200 

1201 if values.size == 0: 

1202 return values.copy() 

1203 

1204 def calc(x): 

1205 additional_nans = np.full(offset, np.nan) 

1206 x = np.concatenate((x, additional_nans)) 

1207 return func( 

1208 x, 

1209 window, 

1210 self.min_periods if self.min_periods is not None else len(window), 

1211 ) 

1212 

1213 with np.errstate(all="ignore"): 

1214 # Our weighted aggregations return memoryviews 

1215 result = np.asarray(calc(values)) 

1216 

1217 if self.center: 

1218 result = self._center_window(result, offset) 

1219 

1220 return result 

1221 

1222 return self._apply_columnwise(homogeneous_func, name, numeric_only)[ 

1223 :: self.step 

1224 ] 

1225 

1226 def aggregate(self, func=None, *args, **kwargs): 

1227 """ 

1228 Aggregate using one or more operations over the specified axis. 

1229 

1230 Parameters 

1231 ---------- 

1232 func : function, str, list or dict 

1233 Function to use for aggregating the data. If a function, must either 

1234 work when passed a Series/DataFrame or 

1235 when passed to Series/DataFrame.apply. 

1236 

1237 Accepted combinations are: 

1238 

1239 - function 

1240 - string function name 

1241 - list of functions and/or function names, e.g. ``[np.sum, 'mean']`` 

1242 - dict of axis labels -> functions, function names or list of such. 

1243 

1244 *args 

1245 Positional arguments to pass to `func`. 

1246 **kwargs 

1247 Keyword arguments to pass to `func`. 

1248 

1249 Returns 

1250 ------- 

1251 scalar, Series or DataFrame 

1252 

1253 The return can be: 

1254 

1255 * scalar : when Series.agg is called with single function 

1256 * Series : when DataFrame.agg is called with a single function 

1257 * DataFrame : when DataFrame.agg is called with several functions 

1258 

1259 See Also 

1260 -------- 

1261 DataFrame.aggregate : Similar DataFrame method. 

1262 Series.aggregate : Similar Series method. 

1263 

1264 Notes 

1265 ----- 

1266 The aggregation operations are always performed over an axis, either the 

1267 index (default) or the column axis. This behavior is different from 

1268 `numpy` aggregation functions (`mean`, `median`, `prod`, `sum`, `std`, 

1269 `var`), where the default is to compute the aggregation of the flattened 

1270 array, e.g., ``numpy.mean(arr_2d)`` as opposed to 

1271 ``numpy.mean(arr_2d, axis=0)``. 

1272 

1273 `agg` is an alias for `aggregate`. Use the alias. 

1274 

1275 Functions that mutate the passed object can produce unexpected 

1276 behavior or errors and are not supported. See :ref:`gotchas.udf-mutation` 

1277 for more details. 

1278 

1279 A passed user-defined-function will be passed a Series for evaluation. 

1280 

1281 If ``func`` defines an index relabeling, ``axis`` must be ``0`` or ``index``. 

1282 

1283 Examples 

1284 -------- 

1285 >>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]}) 

1286 >>> df 

1287 A B C 

1288 0 1 4 7 

1289 1 2 5 8 

1290 2 3 6 9 

1291 

1292 >>> df.rolling(2, win_type="boxcar").agg("mean") 

1293 A B C 

1294 0 NaN NaN NaN 

1295 1 1.5 4.5 7.5 

1296 2 2.5 5.5 8.5 

1297 """ 

1298 result = ResamplerWindowApply(self, func, args=args, kwargs=kwargs).agg() 

1299 if result is None: 

1300 # these must apply directly 

1301 result = func(self) # pyright: ignore[reportOptionalCall] 

1302 

1303 return result 

1304 

1305 agg = aggregate 

1306 

1307 def sum(self, numeric_only: bool = False, **kwargs): 

1308 """ 

1309 Calculate the rolling weighted window sum. 

1310 

1311 The window type is determined by the ``win_type`` parameter specified 

1312 in :meth:`DataFrame.rolling` or :meth:`Series.rolling`. Additional 

1313 keyword arguments are passed to the SciPy window function. 

1314 

1315 Parameters 

1316 ---------- 

1317 numeric_only : bool, default False 

1318 Include only float, int, boolean columns. 

1319 

1320 **kwargs 

1321 Keyword arguments to configure the ``SciPy`` weighted window type. 

1322 

1323 Returns 

1324 ------- 

1325 Series or DataFrame 

1326 Return type is the same as the original object with ``np.float64`` dtype. 

1327 

1328 See Also 

1329 -------- 

1330 Series.rolling : Calling rolling with Series data. 

1331 DataFrame.rolling : Calling rolling with DataFrames. 

1332 Series.sum : Aggregating sum for Series. 

1333 DataFrame.sum : Aggregating sum for DataFrame. 

1334 

1335 Examples 

1336 -------- 

1337 >>> ser = pd.Series([0, 1, 5, 2, 8]) 

1338 

1339 To get an instance of :class:`~pandas.core.window.rolling.Window` we need 

1340 to pass the parameter `win_type`. 

1341 

1342 >>> type(ser.rolling(2, win_type="gaussian")) 

1343 <class 'pandas.api.typing.Window'> 

1344 

1345 In order to use the `SciPy` Gaussian window we need to provide the parameters 

1346 `M` and `std`. The parameter `M` corresponds to 2 in our example. 

1347 We pass the second parameter `std` as a parameter of the following method 

1348 (`sum` in this case): 

1349 

1350 >>> ser.rolling(2, win_type="gaussian").sum(std=3) 

1351 0 NaN 

1352 1 0.986207 

1353 2 5.917243 

1354 3 6.903450 

1355 4 9.862071 

1356 dtype: float64 

1357 """ 

1358 window_func = window_aggregations.roll_weighted_sum 

1359 # error: Argument 1 to "_apply" of "Window" has incompatible type 

1360 # "Callable[[ndarray, ndarray, int], ndarray]"; expected 

1361 # "Callable[[ndarray, int, int], ndarray]" 

1362 return self._apply( 

1363 window_func, # type: ignore[arg-type] 

1364 name="sum", 

1365 numeric_only=numeric_only, 

1366 **kwargs, 

1367 ) 

1368 

1369 def mean(self, numeric_only: bool = False, **kwargs): 

1370 """ 

1371 Calculate the rolling weighted window mean. 

1372 

1373 The window type is determined by the ``win_type`` parameter specified 

1374 in :meth:`DataFrame.rolling` or :meth:`Series.rolling`. Additional 

1375 keyword arguments are passed to the SciPy window function. 

1376 

1377 Parameters 

1378 ---------- 

1379 numeric_only : bool, default False 

1380 Include only float, int, boolean columns. 

1381 

1382 **kwargs 

1383 Keyword arguments to configure the ``SciPy`` weighted window type. 

1384 

1385 Returns 

1386 ------- 

1387 Series or DataFrame 

1388 Return type is the same as the original object with ``np.float64`` dtype. 

1389 

1390 See Also 

1391 -------- 

1392 Series.rolling : Calling rolling with Series data. 

1393 DataFrame.rolling : Calling rolling with DataFrames. 

1394 Series.mean : Aggregating mean for Series. 

1395 DataFrame.mean : Aggregating mean for DataFrame. 

1396 

1397 Examples 

1398 -------- 

1399 >>> ser = pd.Series([0, 1, 5, 2, 8]) 

1400 

1401 To get an instance of :class:`~pandas.core.window.rolling.Window` we need 

1402 to pass the parameter `win_type`. 

1403 

1404 >>> type(ser.rolling(2, win_type="gaussian")) 

1405 <class 'pandas.api.typing.Window'> 

1406 

1407 In order to use the `SciPy` Gaussian window we need to provide the parameters 

1408 `M` and `std`. The parameter `M` corresponds to 2 in our example. 

1409 We pass the second parameter `std` as a parameter of the following method: 

1410 

1411 >>> ser.rolling(2, win_type="gaussian").mean(std=3) 

1412 0 NaN 

1413 1 0.5 

1414 2 3.0 

1415 3 3.5 

1416 4 5.0 

1417 dtype: float64 

1418 """ 

1419 window_func = window_aggregations.roll_weighted_mean 

1420 # error: Argument 1 to "_apply" of "Window" has incompatible type 

1421 # "Callable[[ndarray, ndarray, int], ndarray]"; expected 

1422 # "Callable[[ndarray, int, int], ndarray]" 

1423 return self._apply( 

1424 window_func, # type: ignore[arg-type] 

1425 name="mean", 

1426 numeric_only=numeric_only, 

1427 **kwargs, 

1428 ) 

1429 

1430 def var(self, ddof: int = 1, numeric_only: bool = False, **kwargs): 

1431 """ 

1432 Calculate the rolling weighted window variance. 

1433 

1434 The window type is determined by the ``win_type`` parameter specified 

1435 in :meth:`DataFrame.rolling` or :meth:`Series.rolling`. Additional 

1436 keyword arguments are passed to the SciPy window function. 

1437 

1438 Parameters 

1439 ---------- 

1440 ddof : int, default 1 

1441 Delta Degrees of Freedom. The divisor used in calculations 

1442 is ``N - ddof``, where ``N`` represents the number of elements. 

1443 numeric_only : bool, default False 

1444 Include only float, int, boolean columns. 

1445 

1446 **kwargs 

1447 Keyword arguments to configure the ``SciPy`` weighted window type. 

1448 

1449 Returns 

1450 ------- 

1451 Series or DataFrame 

1452 Return type is the same as the original object with ``np.float64`` dtype. 

1453 

1454 See Also 

1455 -------- 

1456 Series.rolling : Calling rolling with Series data. 

1457 DataFrame.rolling : Calling rolling with DataFrames. 

1458 Series.var : Aggregating var for Series. 

1459 DataFrame.var : Aggregating var for DataFrame. 

1460 

1461 Examples 

1462 -------- 

1463 >>> ser = pd.Series([0, 1, 5, 2, 8]) 

1464 

1465 To get an instance of :class:`~pandas.core.window.rolling.Window` we need 

1466 to pass the parameter `win_type`. 

1467 

1468 >>> type(ser.rolling(2, win_type="gaussian")) 

1469 <class 'pandas.api.typing.Window'> 

1470 

1471 In order to use the `SciPy` Gaussian window we need to provide the parameters 

1472 `M` and `std`. The parameter `M` corresponds to 2 in our example. 

1473 We pass the second parameter `std` as a parameter of the following method: 

1474 

1475 >>> ser.rolling(2, win_type="gaussian").var(std=3) 

1476 0 NaN 

1477 1 0.5 

1478 2 8.0 

1479 3 4.5 

1480 4 18.0 

1481 dtype: float64 

1482 """ 

1483 window_func = partial(window_aggregations.roll_weighted_var, ddof=ddof) 

1484 kwargs.pop("name", None) 

1485 return self._apply(window_func, name="var", numeric_only=numeric_only, **kwargs) 

1486 

1487 def std(self, ddof: int = 1, numeric_only: bool = False, **kwargs): 

1488 """ 

1489 Calculate the rolling weighted window standard deviation. 

1490 

1491 The window type is determined by the ``win_type`` parameter specified 

1492 in :meth:`DataFrame.rolling` or :meth:`Series.rolling`. Additional 

1493 keyword arguments are passed to the SciPy window function. 

1494 

1495 Parameters 

1496 ---------- 

1497 ddof : int, default 1 

1498 Delta Degrees of Freedom. The divisor used in calculations 

1499 is ``N - ddof``, where ``N`` represents the number of elements. 

1500 numeric_only : bool, default False 

1501 Include only float, int, boolean columns. 

1502 

1503 **kwargs 

1504 Keyword arguments to configure the ``SciPy`` weighted window type. 

1505 

1506 Returns 

1507 ------- 

1508 Series or DataFrame 

1509 Return type is the same as the original object with ``np.float64`` dtype. 

1510 

1511 See Also 

1512 -------- 

1513 Series.rolling : Calling rolling with Series data. 

1514 DataFrame.rolling : Calling rolling with DataFrames. 

1515 Series.std : Aggregating std for Series. 

1516 DataFrame.std : Aggregating std for DataFrame. 

1517 

1518 Examples 

1519 -------- 

1520 >>> ser = pd.Series([0, 1, 5, 2, 8]) 

1521 

1522 To get an instance of :class:`~pandas.core.window.rolling.Window` we need 

1523 to pass the parameter `win_type`. 

1524 

1525 >>> type(ser.rolling(2, win_type="gaussian")) 

1526 <class 'pandas.api.typing.Window'> 

1527 

1528 In order to use the `SciPy` Gaussian window we need to provide the parameters 

1529 `M` and `std`. The parameter `M` corresponds to 2 in our example. 

1530 We pass the second parameter `std` as a parameter of the following method: 

1531 

1532 >>> ser.rolling(2, win_type="gaussian").std(std=3) 

1533 0 NaN 

1534 1 0.707107 

1535 2 2.828427 

1536 3 2.121320 

1537 4 4.242641 

1538 dtype: float64 

1539 """ 

1540 return zsqrt( 

1541 self.var(ddof=ddof, name="std", numeric_only=numeric_only, **kwargs) 

1542 ) 

1543 

1544 

1545class RollingAndExpandingMixin(BaseWindow): 

1546 def count(self, numeric_only: bool = False): 

1547 window_func = window_aggregations.roll_sum 

1548 return self._apply(window_func, name="count", numeric_only=numeric_only) 

1549 

1550 def apply( 

1551 self, 

1552 func: Callable[..., Any], 

1553 raw: bool = False, 

1554 engine: Literal["cython", "numba"] | None = None, 

1555 engine_kwargs: dict[str, bool] | None = None, 

1556 args: tuple[Any, ...] | None = None, 

1557 kwargs: dict[str, Any] | None = None, 

1558 ): 

1559 if args is None: 

1560 args = () 

1561 if kwargs is None: 

1562 kwargs = {} 

1563 

1564 if not is_bool(raw): 

1565 raise ValueError("raw parameter must be `True` or `False`") 

1566 

1567 numba_args: tuple[Any, ...] = () 

1568 if maybe_use_numba(engine): 

1569 if raw is False: 

1570 raise ValueError("raw must be `True` when using the numba engine") 

1571 numba_args, kwargs = prepare_function_arguments( 

1572 func, args, kwargs, num_required_args=1 

1573 ) 

1574 if self.method == "single": 

1575 apply_func = generate_numba_apply_func( 

1576 func, **get_jit_arguments(engine_kwargs) 

1577 ) 

1578 else: 

1579 apply_func = generate_numba_table_func( 

1580 func, **get_jit_arguments(engine_kwargs) 

1581 ) 

1582 elif engine in ("cython", None): 

1583 if engine_kwargs is not None: 

1584 raise ValueError("cython engine does not accept engine_kwargs") 

1585 apply_func = self._generate_cython_apply_func(args, kwargs, raw, func) 

1586 else: 

1587 raise ValueError("engine must be either 'numba' or 'cython'") 

1588 

1589 return self._apply( 

1590 apply_func, 

1591 name="apply", 

1592 numba_args=numba_args, 

1593 ) 

1594 

1595 def _generate_cython_apply_func( 

1596 self, 

1597 args: tuple[Any, ...], 

1598 kwargs: dict[str, Any], 

1599 raw: bool | np.bool_, 

1600 function: Callable[..., Any], 

1601 ) -> Callable[[np.ndarray, np.ndarray, np.ndarray, int], np.ndarray]: 

1602 from pandas import Series 

1603 

1604 window_func = partial( 

1605 window_aggregations.roll_apply, 

1606 args=args, 

1607 kwargs=kwargs, 

1608 raw=bool(raw), 

1609 function=function, 

1610 ) 

1611 

1612 def apply_func(values, begin, end, min_periods, raw=raw): 

1613 if not raw: 

1614 # GH 45912 

1615 values = Series(values, index=self._on, copy=False) 

1616 return window_func(values, begin, end, min_periods) 

1617 

1618 return apply_func 

1619 

1620 @overload 

1621 def pipe( 

1622 self, 

1623 func: Callable[Concatenate[Self, P], T], 

1624 *args: P.args, 

1625 **kwargs: P.kwargs, 

1626 ) -> T: ... 

1627 

1628 @overload 

1629 def pipe( 

1630 self, 

1631 func: tuple[Callable[..., T], str], 

1632 *args: Any, 

1633 **kwargs: Any, 

1634 ) -> T: ... 

1635 

1636 def pipe( 

1637 self, 

1638 func: Callable[Concatenate[Self, P], T] | tuple[Callable[..., T], str], 

1639 *args: Any, 

1640 **kwargs: Any, 

1641 ) -> T: 

1642 return com.pipe(self, func, *args, **kwargs) 

1643 

1644 def sum( 

1645 self, 

1646 numeric_only: bool = False, 

1647 engine: Literal["cython", "numba"] | None = None, 

1648 engine_kwargs: dict[str, bool] | None = None, 

1649 ): 

1650 if maybe_use_numba(engine): 

1651 if self.method == "table": 

1652 func = generate_manual_numpy_nan_agg_with_axis(np.nansum) 

1653 return self.apply( 

1654 func, 

1655 raw=True, 

1656 engine=engine, 

1657 engine_kwargs=engine_kwargs, 

1658 ) 

1659 else: 

1660 from pandas.core._numba.kernels import sliding_sum 

1661 

1662 return self._numba_apply(sliding_sum, engine_kwargs) 

1663 window_func = window_aggregations.roll_sum 

1664 return self._apply(window_func, name="sum", numeric_only=numeric_only) 

1665 

1666 def max( 

1667 self, 

1668 numeric_only: bool = False, 

1669 engine: Literal["cython", "numba"] | None = None, 

1670 engine_kwargs: dict[str, bool] | None = None, 

1671 ): 

1672 if maybe_use_numba(engine): 

1673 if self.method == "table": 

1674 func = generate_manual_numpy_nan_agg_with_axis(np.nanmax) 

1675 return self.apply( 

1676 func, 

1677 raw=True, 

1678 engine=engine, 

1679 engine_kwargs=engine_kwargs, 

1680 ) 

1681 else: 

1682 from pandas.core._numba.kernels import sliding_min_max 

1683 

1684 return self._numba_apply(sliding_min_max, engine_kwargs, is_max=True) 

1685 window_func = window_aggregations.roll_max 

1686 return self._apply(window_func, name="max", numeric_only=numeric_only) 

1687 

1688 def min( 

1689 self, 

1690 numeric_only: bool = False, 

1691 engine: Literal["cython", "numba"] | None = None, 

1692 engine_kwargs: dict[str, bool] | None = None, 

1693 ): 

1694 if maybe_use_numba(engine): 

1695 if self.method == "table": 

1696 func = generate_manual_numpy_nan_agg_with_axis(np.nanmin) 

1697 return self.apply( 

1698 func, 

1699 raw=True, 

1700 engine=engine, 

1701 engine_kwargs=engine_kwargs, 

1702 ) 

1703 else: 

1704 from pandas.core._numba.kernels import sliding_min_max 

1705 

1706 return self._numba_apply(sliding_min_max, engine_kwargs, is_max=False) 

1707 window_func = window_aggregations.roll_min 

1708 return self._apply(window_func, name="min", numeric_only=numeric_only) 

1709 

1710 def mean( 

1711 self, 

1712 numeric_only: bool = False, 

1713 engine: Literal["cython", "numba"] | None = None, 

1714 engine_kwargs: dict[str, bool] | None = None, 

1715 ): 

1716 if maybe_use_numba(engine): 

1717 if self.method == "table": 

1718 func = generate_manual_numpy_nan_agg_with_axis(np.nanmean) 

1719 return self.apply( 

1720 func, 

1721 raw=True, 

1722 engine=engine, 

1723 engine_kwargs=engine_kwargs, 

1724 ) 

1725 else: 

1726 from pandas.core._numba.kernels import sliding_mean 

1727 

1728 return self._numba_apply(sliding_mean, engine_kwargs) 

1729 window_func = window_aggregations.roll_mean 

1730 return self._apply(window_func, name="mean", numeric_only=numeric_only) 

1731 

1732 def median( 

1733 self, 

1734 numeric_only: bool = False, 

1735 engine: Literal["cython", "numba"] | None = None, 

1736 engine_kwargs: dict[str, bool] | None = None, 

1737 ): 

1738 if maybe_use_numba(engine): 

1739 if self.method == "table": 

1740 func = generate_manual_numpy_nan_agg_with_axis(np.nanmedian) 

1741 else: 

1742 func = np.nanmedian 

1743 

1744 return self.apply( 

1745 func, 

1746 raw=True, 

1747 engine=engine, 

1748 engine_kwargs=engine_kwargs, 

1749 ) 

1750 window_func = window_aggregations.roll_median_c 

1751 return self._apply(window_func, name="median", numeric_only=numeric_only) 

1752 

1753 def std( 

1754 self, 

1755 ddof: int = 1, 

1756 numeric_only: bool = False, 

1757 engine: Literal["cython", "numba"] | None = None, 

1758 engine_kwargs: dict[str, bool] | None = None, 

1759 ): 

1760 if maybe_use_numba(engine): 

1761 if self.method == "table": 

1762 raise NotImplementedError("std not supported with method='table'") 

1763 from pandas.core._numba.kernels import sliding_var 

1764 

1765 return zsqrt(self._numba_apply(sliding_var, engine_kwargs, ddof=ddof)) 

1766 window_func = window_aggregations.roll_var 

1767 

1768 def zsqrt_func(values, begin, end, min_periods): 

1769 return zsqrt(window_func(values, begin, end, min_periods, ddof=ddof)) 

1770 

1771 return self._apply( 

1772 zsqrt_func, 

1773 name="std", 

1774 numeric_only=numeric_only, 

1775 ) 

1776 

1777 def var( 

1778 self, 

1779 ddof: int = 1, 

1780 numeric_only: bool = False, 

1781 engine: Literal["cython", "numba"] | None = None, 

1782 engine_kwargs: dict[str, bool] | None = None, 

1783 ): 

1784 if maybe_use_numba(engine): 

1785 if self.method == "table": 

1786 raise NotImplementedError("var not supported with method='table'") 

1787 from pandas.core._numba.kernels import sliding_var 

1788 

1789 return self._numba_apply(sliding_var, engine_kwargs, ddof=ddof) 

1790 window_func = partial(window_aggregations.roll_var, ddof=ddof) 

1791 return self._apply( 

1792 window_func, 

1793 name="var", 

1794 numeric_only=numeric_only, 

1795 ) 

1796 

1797 def skew(self, numeric_only: bool = False): 

1798 window_func = window_aggregations.roll_skew 

1799 return self._apply( 

1800 window_func, 

1801 name="skew", 

1802 numeric_only=numeric_only, 

1803 ) 

1804 

1805 def sem(self, ddof: int = 1, numeric_only: bool = False): 

1806 # Raise here so error message says sem instead of std 

1807 self._validate_numeric_only("sem", numeric_only) 

1808 return self.std(numeric_only=numeric_only, ddof=ddof) / ( 

1809 self.count(numeric_only=numeric_only) 

1810 ).pow(0.5) 

1811 

1812 def kurt(self, numeric_only: bool = False): 

1813 window_func = window_aggregations.roll_kurt 

1814 return self._apply( 

1815 window_func, 

1816 name="kurt", 

1817 numeric_only=numeric_only, 

1818 ) 

1819 

1820 def first(self, numeric_only: bool = False): 

1821 window_func = window_aggregations.roll_first 

1822 return self._apply( 

1823 window_func, 

1824 name="first", 

1825 numeric_only=numeric_only, 

1826 ) 

1827 

1828 def last(self, numeric_only: bool = False): 

1829 window_func = window_aggregations.roll_last 

1830 return self._apply( 

1831 window_func, 

1832 name="last", 

1833 numeric_only=numeric_only, 

1834 ) 

1835 

1836 def quantile( 

1837 self, 

1838 q: float, 

1839 interpolation: QuantileInterpolation = "linear", 

1840 numeric_only: bool = False, 

1841 ): 

1842 if q == 1.0: 

1843 window_func = window_aggregations.roll_max 

1844 elif q == 0.0: 

1845 window_func = window_aggregations.roll_min 

1846 else: 

1847 window_func = partial( 

1848 window_aggregations.roll_quantile, 

1849 quantile=q, 

1850 interpolation=interpolation, 

1851 ) 

1852 

1853 return self._apply(window_func, name="quantile", numeric_only=numeric_only) 

1854 

1855 def rank( 

1856 self, 

1857 method: WindowingRankType = "average", 

1858 ascending: bool = True, 

1859 pct: bool = False, 

1860 numeric_only: bool = False, 

1861 ): 

1862 window_func = partial( 

1863 window_aggregations.roll_rank, 

1864 method=method, 

1865 ascending=ascending, 

1866 percentile=pct, 

1867 ) 

1868 

1869 return self._apply(window_func, name="rank", numeric_only=numeric_only) 

1870 

1871 def nunique( 

1872 self, 

1873 numeric_only: bool = False, 

1874 ): 

1875 window_func = partial( 

1876 window_aggregations.roll_nunique, 

1877 ) 

1878 

1879 return self._apply(window_func, name="nunique", numeric_only=numeric_only) 

1880 

1881 def cov( 

1882 self, 

1883 other: DataFrame | Series | None = None, 

1884 pairwise: bool | None = None, 

1885 ddof: int = 1, 

1886 numeric_only: bool = False, 

1887 ): 

1888 if self.step is not None: 

1889 raise NotImplementedError("step not implemented for cov") 

1890 self._validate_numeric_only("cov", numeric_only) 

1891 

1892 from pandas import Series 

1893 

1894 def cov_func(x, y): 

1895 x_array = self._prep_values(x) 

1896 y_array = self._prep_values(y) 

1897 window_indexer = self._get_window_indexer() 

1898 min_periods = ( 

1899 self.min_periods 

1900 if self.min_periods is not None 

1901 else window_indexer.window_size 

1902 ) 

1903 start, end = window_indexer.get_window_bounds( 

1904 num_values=len(x_array), 

1905 min_periods=min_periods, 

1906 center=self.center, 

1907 closed=self.closed, 

1908 step=self.step, 

1909 ) 

1910 self._check_window_bounds(start, end, len(x_array)) 

1911 

1912 result = window_aggregations.roll_cov( 

1913 x_array, y_array, start, end, min_periods, ddof 

1914 ) 

1915 return Series(result, index=x.index, name=x.name, copy=False) 

1916 

1917 return self._apply_pairwise( 

1918 self._selected_obj, other, pairwise, cov_func, numeric_only 

1919 ) 

1920 

1921 def corr( 

1922 self, 

1923 other: DataFrame | Series | None = None, 

1924 pairwise: bool | None = None, 

1925 ddof: int = 1, 

1926 numeric_only: bool = False, 

1927 ): 

1928 if self.step is not None: 

1929 raise NotImplementedError("step not implemented for corr") 

1930 self._validate_numeric_only("corr", numeric_only) 

1931 

1932 from pandas import Series 

1933 

1934 def corr_func(x, y): 

1935 x_array = self._prep_values(x) 

1936 y_array = self._prep_values(y) 

1937 window_indexer = self._get_window_indexer() 

1938 min_periods = ( 

1939 self.min_periods 

1940 if self.min_periods is not None 

1941 else window_indexer.window_size 

1942 ) 

1943 start, end = window_indexer.get_window_bounds( 

1944 num_values=len(x_array), 

1945 min_periods=min_periods, 

1946 center=self.center, 

1947 closed=self.closed, 

1948 step=self.step, 

1949 ) 

1950 self._check_window_bounds(start, end, len(x_array)) 

1951 

1952 result = window_aggregations.roll_corr( 

1953 x_array, y_array, start, end, min_periods 

1954 ) 

1955 return Series(result, index=x.index, name=x.name, copy=False) 

1956 

1957 return self._apply_pairwise( 

1958 self._selected_obj, other, pairwise, corr_func, numeric_only 

1959 ) 

1960 

1961 

1962@set_module("pandas.api.typing") 

1963class Rolling(RollingAndExpandingMixin): 

1964 _attributes: list[str] = [ 

1965 "window", 

1966 "min_periods", 

1967 "center", 

1968 "win_type", 

1969 "on", 

1970 "closed", 

1971 "step", 

1972 "method", 

1973 ] 

1974 

1975 def _validate(self) -> None: 

1976 super()._validate() 

1977 

1978 # we allow rolling on a datetimelike index 

1979 if ( 

1980 self.obj.empty 

1981 or isinstance(self._on, (DatetimeIndex, TimedeltaIndex, PeriodIndex)) 

1982 or (isinstance(self._on.dtype, ArrowDtype) and self._on.dtype.kind in "mM") 

1983 ) and isinstance(self.window, (str, BaseOffset, timedelta)): 

1984 self._validate_datetimelike_monotonic() 

1985 

1986 # this will raise ValueError on non-fixed freqs 

1987 try: 

1988 freq = to_offset(self.window) 

1989 except (TypeError, ValueError) as err: 

1990 raise ValueError( 

1991 f"passed window {self.window} is not " 

1992 "compatible with a datetimelike index" 

1993 ) from err 

1994 if isinstance(self._on, PeriodIndex): 

1995 # error: Incompatible types in assignment (expression has type 

1996 # "float", variable has type "Optional[int]") 

1997 self._win_freq_i8 = freq.nanos / ( # type: ignore[assignment] 

1998 self._on.freq.nanos / self._on.freq.n 

1999 ) 

2000 else: 

2001 try: 

2002 unit = dtype_to_unit(self._on.dtype) # type: ignore[arg-type] 

2003 except TypeError: 

2004 # if not a datetime dtype, eg for empty dataframes 

2005 unit = "ns" 

2006 unit = cast("TimeUnit", unit) 

2007 self._win_freq_i8 = Timedelta(freq.nanos).as_unit(unit)._value 

2008 

2009 # min_periods must be an integer 

2010 if self.min_periods is None: 

2011 self.min_periods = 1 

2012 

2013 if self.step is not None: 

2014 raise NotImplementedError( 

2015 "step is not supported with frequency windows" 

2016 ) 

2017 

2018 elif isinstance(self.window, BaseIndexer): 

2019 # Passed BaseIndexer subclass should handle all other rolling kwargs 

2020 pass 

2021 elif not is_integer(self.window) or self.window < 0: 

2022 raise ValueError("window must be an integer 0 or greater") 

2023 

2024 def _validate_datetimelike_monotonic(self) -> None: 

2025 """ 

2026 Validate self._on is monotonic (increasing or decreasing) and has 

2027 no NaT values for frequency windows. 

2028 """ 

2029 if self._on.hasnans: 

2030 self._raise_monotonic_error("values must not have NaT") 

2031 if not (self._on.is_monotonic_increasing or self._on.is_monotonic_decreasing): 

2032 self._raise_monotonic_error("values must be monotonic") 

2033 

2034 def _raise_monotonic_error(self, msg: str): 

2035 on = self.on 

2036 if on is None: 

2037 on = "index" 

2038 raise ValueError(f"{on} {msg}") 

2039 

2040 def aggregate(self, func=None, *args, **kwargs): 

2041 """ 

2042 Aggregate using one or more operations over the specified axis. 

2043 

2044 This method allows combining multiple aggregation functions (e.g. 

2045 ``'sum'``, ``'mean'``) in a single call, returning a result for each 

2046 function applied to each rolling window. 

2047 

2048 Parameters 

2049 ---------- 

2050 func : function, str, list or dict 

2051 Function to use for aggregating the data. If a function, must either 

2052 work when passed a Series/Dataframe or 

2053 when passed to Series/Dataframe.apply. 

2054 

2055 Accepted combinations are: 

2056 

2057 - function 

2058 - string function name 

2059 - list of functions and/or function names, e.g. ``[np.sum, 'mean']`` 

2060 - dict of axis labels -> functions, function names or list of such. 

2061 

2062 *args 

2063 Positional arguments to pass to `func`. 

2064 **kwargs 

2065 Keyword arguments to pass to `func`. 

2066 

2067 Returns 

2068 ------- 

2069 scalar, Series or DataFrame 

2070 

2071 The return can be: 

2072 

2073 * scalar : when Series.agg is called with single function 

2074 * Series : when DataFrame.agg is called with a single function 

2075 * DataFrame : when DataFrame.agg is called with several functions 

2076 

2077 See Also 

2078 -------- 

2079 Series.rolling : Calling object with Series data. 

2080 DataFrame.rolling : Calling object with DataFrame data. 

2081 

2082 Notes 

2083 ----- 

2084 The aggregation operations are always performed over an axis, either the 

2085 index (default) or the column axis. This behavior is different from 

2086 `numpy` aggregation functions (`mean`, `median`, `prod`, `sum`, `std`, 

2087 `var`), where the default is to compute the aggregation of the flattened 

2088 array, e.g., ``numpy.mean(arr_2d)`` as opposed to 

2089 ``numpy.mean(arr_2d, axis=0)``. 

2090 

2091 `agg` is an alias for `aggregate`. Use the alias. 

2092 

2093 Functions that mutate the passed object can produce unexpected 

2094 behavior or errors and are not supported. See :ref:`gotchas.udf-mutation` 

2095 for more details. 

2096 

2097 A passed user-defined-function will be passed a Series for evaluation. 

2098 

2099 If ``func`` defines an index relabeling, ``axis`` must be ``0`` or ``index``. 

2100 

2101 Examples 

2102 -------- 

2103 >>> df = pd.DataFrame({"A": [1, 2, 3], "B": [4, 5, 6], "C": [7, 8, 9]}) 

2104 >>> df 

2105 A B C 

2106 0 1 4 7 

2107 1 2 5 8 

2108 2 3 6 9 

2109 

2110 >>> df.rolling(2).sum() 

2111 A B C 

2112 0 NaN NaN NaN 

2113 1 3.0 9.0 15.0 

2114 2 5.0 11.0 17.0 

2115 

2116 >>> df.rolling(2).agg({"A": "sum", "B": "min"}) 

2117 A B 

2118 0 NaN NaN 

2119 1 3.0 4.0 

2120 2 5.0 5.0 

2121 """ 

2122 return super().aggregate(func, *args, **kwargs) 

2123 

2124 agg = aggregate 

2125 

2126 def count(self, numeric_only: bool = False): 

2127 """ 

2128 Calculate the rolling count of non NaN observations. 

2129 

2130 This is useful for identifying windows with missing data, as it counts 

2131 only non-NaN entries within each window. 

2132 

2133 Parameters 

2134 ---------- 

2135 numeric_only : bool, default False 

2136 Include only float, int, boolean columns. 

2137 

2138 Returns 

2139 ------- 

2140 Series or DataFrame 

2141 Return type is the same as the original object with ``np.float64`` dtype. 

2142 

2143 See Also 

2144 -------- 

2145 Series.rolling : Calling rolling with Series data. 

2146 DataFrame.rolling : Calling rolling with DataFrames. 

2147 Series.count : Aggregating count for Series. 

2148 DataFrame.count : Aggregating count for DataFrame. 

2149 

2150 Examples 

2151 -------- 

2152 >>> s = pd.Series([2, 3, np.nan, 10]) 

2153 >>> s.rolling(2).count() 

2154 0 NaN 

2155 1 2.0 

2156 2 1.0 

2157 3 1.0 

2158 dtype: float64 

2159 >>> s.rolling(3).count() 

2160 0 NaN 

2161 1 NaN 

2162 2 2.0 

2163 3 2.0 

2164 dtype: float64 

2165 >>> s.rolling(4).count() 

2166 0 NaN 

2167 1 NaN 

2168 2 NaN 

2169 3 3.0 

2170 dtype: float64 

2171 """ 

2172 return super().count(numeric_only) 

2173 

2174 def apply( 

2175 self, 

2176 func: Callable[..., Any], 

2177 raw: bool = False, 

2178 engine: Literal["cython", "numba"] | None = None, 

2179 engine_kwargs: dict[str, bool] | None = None, 

2180 args: tuple[Any, ...] | None = None, 

2181 kwargs: dict[str, Any] | None = None, 

2182 ): 

2183 """ 

2184 Calculate the rolling custom aggregation function. 

2185 

2186 Applies an arbitrary function to each rolling window. This is useful 

2187 when the built-in rolling methods do not cover the desired computation. 

2188 

2189 Parameters 

2190 ---------- 

2191 func : function 

2192 Must produce a single value from an ndarray input if ``raw=True`` 

2193 or a single value from a Series if ``raw=False``. Can also accept a 

2194 Numba JIT function with ``engine='numba'`` specified. 

2195 

2196 raw : bool, default False 

2197 * ``False`` : passes each row or column as a Series to the 

2198 function. 

2199 * ``True`` : the passed function will receive ndarray 

2200 objects instead. Pandas-only attributes such as ``.iloc`` 

2201 or ``.index`` are not available on ndarrays and will raise 

2202 ``AttributeError`` if used inside ``func``. 

2203 

2204 If you are just applying a NumPy reduction function this will 

2205 achieve much better performance. 

2206 

2207 engine : str, default None 

2208 * ``'cython'`` : Runs rolling apply through C-extensions from cython. 

2209 * ``'numba'`` : Runs rolling apply through JIT compiled code from numba. 

2210 Only available when ``raw`` is set to ``True``. 

2211 * ``None`` : Defaults to ``'cython'`` or 

2212 globally setting ``compute.use_numba``. 

2213 

2214 engine_kwargs : dict, default None 

2215 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2216 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2217 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2218 ``False``. 

2219 

2220 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2221 ``{'nogil': False, 'parallel': False}`` and will be 

2222 applied to both the ``func`` and the ``apply`` rolling aggregation. 

2223 

2224 args : tuple, default None 

2225 Positional arguments to be passed into func. 

2226 

2227 kwargs : dict, default None 

2228 Keyword arguments to be passed into func. 

2229 

2230 Returns 

2231 ------- 

2232 Series or DataFrame 

2233 Return type is the same as the original object with ``np.float64`` dtype. 

2234 

2235 See Also 

2236 -------- 

2237 Series.rolling : Calling rolling with Series data. 

2238 DataFrame.rolling : Calling rolling with DataFrames. 

2239 Series.apply : Aggregating apply for Series. 

2240 DataFrame.apply : Aggregating apply for DataFrame. 

2241 

2242 Notes 

2243 ----- 

2244 When ``raw=False``, the :class:`Series` passed to ``func`` is indexed by the 

2245 column or :class:`Index` used to compute the rolling window. If 

2246 :meth:`DataFrame.rolling` was called with ``on=col``, the index of the 

2247 passed :class:`Series` will be the values of ``col`` rather than the 

2248 original :class:`DataFrame` index. When ``on`` is not specified, the 

2249 index of the passed :class:`Series` is the original index of the input. 

2250 

2251 Examples 

2252 -------- 

2253 >>> ser = pd.Series([1, 6, 5, 4]) 

2254 >>> ser.rolling(2).apply(lambda s: s.sum() - s.min()) 

2255 0 NaN 

2256 1 6.0 

2257 2 6.0 

2258 3 5.0 

2259 dtype: float64 

2260 

2261 By default ``func`` is applied to each column independently. Use 

2262 ``method="table"`` (which requires ``engine="numba"`` and ``raw=True``) to 

2263 instead pass the whole :class:`DataFrame` window to ``func`` as a single 2D 

2264 ndarray, so the function can combine multiple columns. Here a rolling dot 

2265 product of columns ``A`` and ``B`` is computed; the scalar result is 

2266 broadcast across the columns. 

2267 

2268 >>> df = pd.DataFrame({"A": [1, 2, 3, 4, 5], "B": [5, 4, 3, 2, 1]}) 

2269 >>> def dot(window): 

2270 ... return (window[:, 0] * window[:, 1]).sum() 

2271 >>> df.rolling(3, method="table").apply( 

2272 ... dot, engine="numba", raw=True 

2273 ... ) # doctest: +SKIP 

2274 A B 

2275 0 NaN NaN 

2276 1 NaN NaN 

2277 2 22.0 22.0 

2278 3 25.0 25.0 

2279 4 22.0 22.0 

2280 """ 

2281 return super().apply( 

2282 func, 

2283 raw=raw, 

2284 engine=engine, 

2285 engine_kwargs=engine_kwargs, 

2286 args=args, 

2287 kwargs=kwargs, 

2288 ) 

2289 

2290 @overload 

2291 def pipe( 

2292 self, 

2293 func: Callable[Concatenate[Self, P], T], 

2294 *args: P.args, 

2295 **kwargs: P.kwargs, 

2296 ) -> T: ... 

2297 

2298 @overload 

2299 def pipe( 

2300 self, 

2301 func: tuple[Callable[..., T], str], 

2302 *args: Any, 

2303 **kwargs: Any, 

2304 ) -> T: ... 

2305 

2306 @final 

2307 def pipe( 

2308 self, 

2309 func: Callable[Concatenate[Self, P], T] | tuple[Callable[..., T], str], 

2310 *args: Any, 

2311 **kwargs: Any, 

2312 ) -> T: 

2313 """ 

2314 Apply a ``func`` with arguments to this Rolling object and return its result. 

2315 

2316 Use `.pipe` when you want to improve readability by chaining together 

2317 functions that expect 

2318 Series, DataFrames, GroupBy, Rolling, Expanding or Resampler 

2319 objects. 

2320 Instead of writing 

2321 

2322 >>> h = lambda x, arg2, arg3: x + 1 - arg2 * arg3 

2323 >>> g = lambda x, arg1: x * 5 / arg1 

2324 >>> f = lambda x: x**4 

2325 >>> df = pd.DataFrame( 

2326 ... {"A": [1, 2, 3, 4]}, index=pd.date_range("2012-08-02", periods=4) 

2327 ... ) 

2328 >>> h(g(f(df.rolling("2D")), arg1=1), arg2=2, arg3=3) # doctest: +SKIP 

2329 

2330 You can write 

2331 

2332 >>> ( 

2333 ... df.rolling("2D").pipe(f).pipe(g, arg1=1).pipe(h, arg2=2, arg3=3) 

2334 ... ) # doctest: +SKIP 

2335 

2336 which is much more readable. 

2337 

2338 Parameters 

2339 ---------- 

2340 func : callable or tuple of (callable, str) 

2341 Function to apply to this Rolling object or, alternatively, 

2342 a `(callable, data_keyword)` tuple where `data_keyword` is a 

2343 string indicating the keyword of `callable` that expects the 

2344 Rolling object. 

2345 *args : iterable, optional 

2346 Positional arguments passed into `func`. 

2347 **kwargs : dict, optional 

2348 A dictionary of keyword arguments passed into `func`. 

2349 

2350 Returns 

2351 ------- 

2352 Rolling 

2353 The original object with the function `func` applied. 

2354 

2355 See Also 

2356 -------- 

2357 Series.pipe : Apply a function with arguments to a series. 

2358 DataFrame.pipe: Apply a function with arguments to a dataframe. 

2359 apply : Apply function to each group instead of to the 

2360 full Rolling object. 

2361 

2362 Notes 

2363 ----- 

2364 See more `here 

2365 <https://pandas.pydata.org/pandas-docs/stable/user_guide/groupby.html#piping-function-calls>`__. 

2366 

2367 Examples 

2368 -------- 

2369 

2370 >>> df = pd.DataFrame( 

2371 ... {"A": [1, 2, 3, 4]}, index=pd.date_range("2012-08-02", periods=4) 

2372 ... ) 

2373 >>> df 

2374 A 

2375 2012-08-02 1 

2376 2012-08-03 2 

2377 2012-08-04 3 

2378 2012-08-05 4 

2379 

2380 To get the difference between each rolling 

2381 2-day window's maximum and minimum 

2382 value in one pass, you can do 

2383 

2384 >>> df.rolling("2D").pipe(lambda x: x.max() - x.min()) 

2385 A 

2386 2012-08-02 0.0 

2387 2012-08-03 1.0 

2388 2012-08-04 1.0 

2389 2012-08-05 1.0 

2390 """ 

2391 return super().pipe(func, *args, **kwargs) 

2392 

2393 def sum( 

2394 self, 

2395 numeric_only: bool = False, 

2396 engine: Literal["cython", "numba"] | None = None, 

2397 engine_kwargs: dict[str, bool] | None = None, 

2398 ): 

2399 """ 

2400 Calculate the rolling sum. 

2401 

2402 This is equivalent to applying ``numpy.sum`` over each rolling window. 

2403 Missing values (NaN) are excluded from the calculation. 

2404 

2405 Parameters 

2406 ---------- 

2407 numeric_only : bool, default False 

2408 Include only float, int, boolean columns. 

2409 

2410 engine : str, default None 

2411 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2412 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2413 * ``None`` : Defaults to ``'cython'`` or 

2414 globally setting ``compute.use_numba`` 

2415 

2416 engine_kwargs : dict, default None 

2417 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2418 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2419 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2420 ``False``. The default ``engine_kwargs`` for the ``'numba'`` engine is 

2421 ``{'nogil': False, 'parallel': False}``. 

2422 

2423 Returns 

2424 ------- 

2425 Series or DataFrame 

2426 Return type is the same as the original object with ``np.float64`` dtype. 

2427 

2428 See Also 

2429 -------- 

2430 Series.rolling : Calling rolling with Series data. 

2431 DataFrame.rolling : Calling rolling with DataFrames. 

2432 Series.sum : Aggregating sum for Series. 

2433 DataFrame.sum : Aggregating sum for DataFrame. 

2434 

2435 Notes 

2436 ----- 

2437 See :ref:`window.numba_engine` and :ref:`enhancingperf.numba` 

2438 for extended documentation and performance considerations 

2439 for the Numba engine. 

2440 

2441 Examples 

2442 -------- 

2443 >>> s = pd.Series([1, 2, 3, 4, 5]) 

2444 >>> s 

2445 0 1 

2446 1 2 

2447 2 3 

2448 3 4 

2449 4 5 

2450 dtype: int64 

2451 

2452 >>> s.rolling(3).sum() 

2453 0 NaN 

2454 1 NaN 

2455 2 6.0 

2456 3 9.0 

2457 4 12.0 

2458 dtype: float64 

2459 

2460 >>> s.rolling(3, center=True).sum() 

2461 0 NaN 

2462 1 6.0 

2463 2 9.0 

2464 3 12.0 

2465 4 NaN 

2466 dtype: float64 

2467 

2468 For DataFrame, each sum is computed column-wise. 

2469 

2470 >>> df = pd.DataFrame({"A": s, "B": s**2}) 

2471 >>> df 

2472 A B 

2473 0 1 1 

2474 1 2 4 

2475 2 3 9 

2476 3 4 16 

2477 4 5 25 

2478 

2479 >>> df.rolling(3).sum() 

2480 A B 

2481 0 NaN NaN 

2482 1 NaN NaN 

2483 2 6.0 14.0 

2484 3 9.0 29.0 

2485 4 12.0 50.0 

2486 """ 

2487 return super().sum( 

2488 numeric_only=numeric_only, 

2489 engine=engine, 

2490 engine_kwargs=engine_kwargs, 

2491 ) 

2492 

2493 def max( 

2494 self, 

2495 numeric_only: bool = False, 

2496 *args, 

2497 engine: Literal["cython", "numba"] | None = None, 

2498 engine_kwargs: dict[str, bool] | None = None, 

2499 **kwargs, 

2500 ): 

2501 """ 

2502 Calculate the rolling maximum. 

2503 

2504 This is equivalent to applying ``numpy.max`` over each rolling window. 

2505 

2506 Parameters 

2507 ---------- 

2508 numeric_only : bool, default False 

2509 Include only float, int, boolean columns. 

2510 

2511 *args : iterable, optional 

2512 Positional arguments passed into ``func``. 

2513 

2514 engine : str, default None 

2515 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2516 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2517 * ``None`` : Defaults to ``'cython'`` or 

2518 globally setting ``compute.use_numba`` 

2519 

2520 engine_kwargs : dict, default None 

2521 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2522 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2523 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2524 ``False``. 

2525 

2526 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2527 ``{'nogil': False, 'parallel': False}``. 

2528 

2529 **kwargs : mapping, optional 

2530 A dictionary of keyword arguments passed into ``func``. 

2531 

2532 Returns 

2533 ------- 

2534 Series or DataFrame 

2535 Return type is the same as the original object with ``np.float64`` dtype. 

2536 

2537 See Also 

2538 -------- 

2539 Series.rolling : Calling rolling with Series data. 

2540 DataFrame.rolling : Calling rolling with DataFrames. 

2541 Series.max : Aggregating max for Series. 

2542 DataFrame.max : Aggregating max for DataFrame. 

2543 

2544 Notes 

2545 ----- 

2546 See :ref:`window.numba_engine` and :ref:`enhancingperf.numba` 

2547 for extended documentation and performance considerations 

2548 for the Numba engine. 

2549 

2550 Examples 

2551 -------- 

2552 >>> ser = pd.Series([1, 2, 3, 4]) 

2553 >>> ser.rolling(2).max() 

2554 0 NaN 

2555 1 2.0 

2556 2 3.0 

2557 3 4.0 

2558 dtype: float64 

2559 """ 

2560 return super().max( 

2561 numeric_only=numeric_only, 

2562 engine=engine, 

2563 engine_kwargs=engine_kwargs, 

2564 ) 

2565 

2566 def min( 

2567 self, 

2568 numeric_only: bool = False, 

2569 engine: Literal["cython", "numba"] | None = None, 

2570 engine_kwargs: dict[str, bool] | None = None, 

2571 ): 

2572 """ 

2573 Calculate the rolling minimum. 

2574 

2575 This is equivalent to applying ``numpy.min`` over each rolling window. 

2576 

2577 Parameters 

2578 ---------- 

2579 numeric_only : bool, default False 

2580 Include only float, int, boolean columns. 

2581 

2582 engine : str, default None 

2583 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2584 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2585 * ``None`` : Defaults to ``'cython'`` or 

2586 globally setting ``compute.use_numba`` 

2587 

2588 engine_kwargs : dict, default None 

2589 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2590 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2591 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2592 ``False``. 

2593 

2594 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2595 ``{'nogil': False, 'parallel': False}``. 

2596 

2597 Returns 

2598 ------- 

2599 Series or DataFrame 

2600 Return type is the same as the original object with ``np.float64`` dtype. 

2601 

2602 See Also 

2603 -------- 

2604 Series.rolling : Calling rolling with Series data. 

2605 DataFrame.rolling : Calling rolling with DataFrames. 

2606 Series.min : Aggregating min for Series. 

2607 DataFrame.min : Aggregating min for DataFrame. 

2608 

2609 Notes 

2610 ----- 

2611 See :ref:`window.numba_engine` and :ref:`enhancingperf.numba` 

2612 for extended documentation and performance considerations 

2613 for the Numba engine. 

2614 

2615 Examples 

2616 -------- 

2617 Performing a rolling minimum with a window size of 3. 

2618 

2619 >>> s = pd.Series([4, 3, 5, 2, 6]) 

2620 >>> s.rolling(3).min() 

2621 0 NaN 

2622 1 NaN 

2623 2 3.0 

2624 3 2.0 

2625 4 2.0 

2626 dtype: float64 

2627 """ 

2628 return super().min( 

2629 numeric_only=numeric_only, 

2630 engine=engine, 

2631 engine_kwargs=engine_kwargs, 

2632 ) 

2633 

2634 def mean( 

2635 self, 

2636 numeric_only: bool = False, 

2637 engine: Literal["cython", "numba"] | None = None, 

2638 engine_kwargs: dict[str, bool] | None = None, 

2639 ): 

2640 """ 

2641 Calculate the rolling mean. 

2642 

2643 This is equivalent to applying ``numpy.mean`` over each rolling window. 

2644 

2645 Parameters 

2646 ---------- 

2647 numeric_only : bool, default False 

2648 Include only float, int, boolean columns. 

2649 

2650 engine : str, default None 

2651 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2652 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2653 * ``None`` : Defaults to ``'cython'`` or 

2654 globally setting ``compute.use_numba`` 

2655 

2656 engine_kwargs : dict, default None 

2657 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2658 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2659 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2660 ``False``. 

2661 

2662 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2663 ``{'nogil': False, 'parallel': False}``. 

2664 

2665 Returns 

2666 ------- 

2667 Series or DataFrame 

2668 Return type is the same as the original object with ``np.float64`` dtype. 

2669 

2670 See Also 

2671 -------- 

2672 Series.rolling : Calling rolling with Series data. 

2673 DataFrame.rolling : Calling rolling with DataFrames. 

2674 Series.mean : Aggregating mean for Series. 

2675 DataFrame.mean : Aggregating mean for DataFrame. 

2676 

2677 Notes 

2678 ----- 

2679 See :ref:`window.numba_engine` and :ref:`enhancingperf.numba` 

2680 for extended documentation and performance considerations 

2681 for the Numba engine. 

2682 

2683 Examples 

2684 -------- 

2685 The below examples will show rolling mean calculations with window sizes of 

2686 two and three, respectively. 

2687 

2688 >>> s = pd.Series([1, 2, 3, 4]) 

2689 >>> s.rolling(2).mean() 

2690 0 NaN 

2691 1 1.5 

2692 2 2.5 

2693 3 3.5 

2694 dtype: float64 

2695 

2696 >>> s.rolling(3).mean() 

2697 0 NaN 

2698 1 NaN 

2699 2 2.0 

2700 3 3.0 

2701 dtype: float64 

2702 """ 

2703 return super().mean( 

2704 numeric_only=numeric_only, 

2705 engine=engine, 

2706 engine_kwargs=engine_kwargs, 

2707 ) 

2708 

2709 def median( 

2710 self, 

2711 numeric_only: bool = False, 

2712 engine: Literal["cython", "numba"] | None = None, 

2713 engine_kwargs: dict[str, bool] | None = None, 

2714 ): 

2715 """ 

2716 Calculate the rolling median. 

2717 

2718 This is equivalent to applying ``numpy.median`` over each rolling 

2719 window. 

2720 

2721 Parameters 

2722 ---------- 

2723 numeric_only : bool, default False 

2724 Include only float, int, boolean columns. 

2725 

2726 engine : str, default None 

2727 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2728 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2729 * ``None`` : Defaults to ``'cython'`` or 

2730 globally setting ``compute.use_numba`` 

2731 

2732 engine_kwargs : dict, default None 

2733 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2734 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2735 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2736 ``False``. 

2737 

2738 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2739 ``{'nogil': False, 'parallel': False}``. 

2740 

2741 Returns 

2742 ------- 

2743 Series or DataFrame 

2744 Return type is the same as the original object with ``np.float64`` dtype. 

2745 

2746 See Also 

2747 -------- 

2748 Series.rolling : Calling rolling with Series data. 

2749 DataFrame.rolling : Calling rolling with DataFrames. 

2750 Series.median : Aggregating median for Series. 

2751 DataFrame.median : Aggregating median for DataFrame. 

2752 

2753 Notes 

2754 ----- 

2755 See :ref:`window.numba_engine` and :ref:`enhancingperf.numba` 

2756 for extended documentation and performance considerations 

2757 for the Numba engine. 

2758 

2759 Examples 

2760 -------- 

2761 Compute the rolling median of a series with a window size of 3. 

2762 

2763 >>> s = pd.Series([0, 1, 2, 3, 4]) 

2764 >>> s.rolling(3).median() 

2765 0 NaN 

2766 1 NaN 

2767 2 1.0 

2768 3 2.0 

2769 4 3.0 

2770 dtype: float64 

2771 """ 

2772 return super().median( 

2773 numeric_only=numeric_only, 

2774 engine=engine, 

2775 engine_kwargs=engine_kwargs, 

2776 ) 

2777 

2778 def std( 

2779 self, 

2780 ddof: int = 1, 

2781 numeric_only: bool = False, 

2782 engine: Literal["cython", "numba"] | None = None, 

2783 engine_kwargs: dict[str, bool] | None = None, 

2784 ): 

2785 """ 

2786 Calculate the rolling standard deviation. 

2787 

2788 This is equivalent to applying ``numpy.std`` (with the specified 

2789 ``ddof``) over each rolling window. 

2790 

2791 Parameters 

2792 ---------- 

2793 ddof : int, default 1 

2794 Delta Degrees of Freedom. The divisor used in calculations 

2795 is ``N - ddof``, where ``N`` represents the number of elements. 

2796 

2797 numeric_only : bool, default False 

2798 Include only float, int, boolean columns. 

2799 

2800 engine : str, default None 

2801 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2802 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2803 * ``None`` : Defaults to ``'cython'`` or 

2804 globally setting ``compute.use_numba`` 

2805 

2806 engine_kwargs : dict, default None 

2807 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2808 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2809 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2810 ``False``. 

2811 

2812 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2813 ``{'nogil': False, 'parallel': False}``. 

2814 

2815 Returns 

2816 ------- 

2817 Series or DataFrame 

2818 Return type is the same as the original object with ``np.float64`` dtype. 

2819 

2820 See Also 

2821 -------- 

2822 numpy.std : Equivalent method for NumPy array. 

2823 Series.rolling : Calling rolling with Series data. 

2824 DataFrame.rolling : Calling rolling with DataFrames. 

2825 Series.std : Aggregating std for Series. 

2826 DataFrame.std : Aggregating std for DataFrame. 

2827 

2828 Notes 

2829 ----- 

2830 The default ``ddof`` of 1 used in :meth:`Series.std` is different 

2831 than the default ``ddof`` of 0 in :func:`numpy.std`. 

2832 

2833 A minimum of one period is required for the rolling calculation. 

2834 

2835 Examples 

2836 -------- 

2837 >>> s = pd.Series([5, 5, 6, 7, 5, 5, 5]) 

2838 >>> s.rolling(3).std() 

2839 0 NaN 

2840 1 NaN 

2841 2 0.577350 

2842 3 1.000000 

2843 4 1.000000 

2844 5 1.154701 

2845 6 0.000000 

2846 dtype: float64 

2847 """ 

2848 return super().std( 

2849 ddof=ddof, 

2850 numeric_only=numeric_only, 

2851 engine=engine, 

2852 engine_kwargs=engine_kwargs, 

2853 ) 

2854 

2855 def var( 

2856 self, 

2857 ddof: int = 1, 

2858 numeric_only: bool = False, 

2859 engine: Literal["cython", "numba"] | None = None, 

2860 engine_kwargs: dict[str, bool] | None = None, 

2861 ): 

2862 """ 

2863 Calculate the rolling variance. 

2864 

2865 This is equivalent to applying ``numpy.var`` (with the specified 

2866 ``ddof``) over each rolling window. 

2867 

2868 Parameters 

2869 ---------- 

2870 ddof : int, default 1 

2871 Delta Degrees of Freedom. The divisor used in calculations 

2872 is ``N - ddof``, where ``N`` represents the number of elements. 

2873 

2874 numeric_only : bool, default False 

2875 Include only float, int, boolean columns. 

2876 

2877 engine : str, default None 

2878 * ``'cython'`` : Runs the operation through C-extensions from cython. 

2879 * ``'numba'`` : Runs the operation through JIT compiled code from numba. 

2880 * ``None`` : Defaults to ``'cython'`` or 

2881 globally setting ``compute.use_numba`` 

2882 

2883 engine_kwargs : dict, default None 

2884 * For ``'cython'`` engine, there are no accepted ``engine_kwargs`` 

2885 * For ``'numba'`` engine, the engine can accept ``nogil`` 

2886 and ``parallel`` dictionary keys. The values must either be ``True`` or 

2887 ``False``. 

2888 

2889 The default ``engine_kwargs`` for the ``'numba'`` engine is 

2890 ``{'nogil': False, 'parallel': False}``. 

2891 

2892 Returns 

2893 ------- 

2894 Series or DataFrame 

2895 Return type is the same as the original object with ``np.float64`` dtype. 

2896 

2897 See Also 

2898 -------- 

2899 numpy.var : Equivalent method for NumPy array. 

2900 Series.rolling : Calling rolling with Series data. 

2901 DataFrame.rolling : Calling rolling with DataFrames. 

2902 Series.var : Aggregating var for Series. 

2903 DataFrame.var : Aggregating var for DataFrame. 

2904 

2905 Notes 

2906 ----- 

2907 The default ``ddof`` of 1 used in :meth:`Series.var` is different 

2908 than the default ``ddof`` of 0 in :func:`numpy.var`. 

2909 

2910 A minimum of one period is required for the rolling calculation. 

2911 

2912 Examples 

2913 -------- 

2914 >>> s = pd.Series([5, 5, 6, 7, 5, 5, 5]) 

2915 >>> s.rolling(3).var() 

2916 0 NaN 

2917 1 NaN 

2918 2 0.333333 

2919 3 1.000000 

2920 4 1.000000 

2921 5 1.333333 

2922 6 0.000000 

2923 dtype: float64 

2924 """ 

2925 return super().var( 

2926 ddof=ddof, 

2927 numeric_only=numeric_only, 

2928 engine=engine, 

2929 engine_kwargs=engine_kwargs, 

2930 ) 

2931 

2932 def skew(self, numeric_only: bool = False): 

2933 """ 

2934 Calculate the rolling unbiased skewness. 

2935 

2936 This is equivalent to applying ``scipy.stats.skew`` over each rolling 

2937 window. A minimum of three periods is required. 

2938 

2939 Parameters 

2940 ---------- 

2941 numeric_only : bool, default False 

2942 Include only float, int, boolean columns. 

2943 

2944 Returns 

2945 ------- 

2946 Series or DataFrame 

2947 Return type is the same as the original object with ``np.float64`` dtype. 

2948 

2949 See Also 

2950 -------- 

2951 scipy.stats.skew : Third moment of a probability density. 

2952 Series.rolling : Calling rolling with Series data. 

2953 DataFrame.rolling : Calling rolling with DataFrames. 

2954 Series.skew : Aggregating skew for Series. 

2955 DataFrame.skew : Aggregating skew for DataFrame. 

2956 

2957 Notes 

2958 ----- 

2959 

2960 A minimum of three periods is required for the rolling calculation. 

2961 

2962 Examples 

2963 -------- 

2964 >>> ser = pd.Series([1, 5, 2, 7, 15, 6]) 

2965 >>> ser.rolling(3).skew().round(6) 

2966 0 NaN 

2967 1 NaN 

2968 2 1.293343 

2969 3 -0.585583 

2970 4 0.670284 

2971 5 1.652317 

2972 dtype: float64 

2973 """ 

2974 return super().skew(numeric_only=numeric_only) 

2975 

2976 def sem(self, ddof: int = 1, numeric_only: bool = False): 

2977 """ 

2978 Calculate the rolling standard error of mean. 

2979 

2980 This is computed as the rolling standard deviation divided by the 

2981 square root of the rolling count. A minimum of one period is required. 

2982 

2983 Parameters 

2984 ---------- 

2985 ddof : int, default 1 

2986 Delta Degrees of Freedom. The divisor used in calculations 

2987 is ``N - ddof``, where ``N`` represents the number of elements. 

2988 

2989 numeric_only : bool, default False 

2990 Include only float, int, boolean columns. 

2991 

2992 Returns 

2993 ------- 

2994 Series or DataFrame 

2995 Return type is the same as the original object with ``np.float64`` dtype. 

2996 

2997 See Also 

2998 -------- 

2999 Series.rolling : Calling rolling with Series data. 

3000 DataFrame.rolling : Calling rolling with DataFrames. 

3001 Series.sem : Aggregating sem for Series. 

3002 DataFrame.sem : Aggregating sem for DataFrame. 

3003 

3004 Notes 

3005 ----- 

3006 A minimum of one period is required for the calculation. 

3007 

3008 Examples 

3009 -------- 

3010 >>> s = pd.Series([0, 1, 2, 3]) 

3011 >>> s.rolling(2, min_periods=1).sem() 

3012 0 NaN 

3013 1 0.5 

3014 2 0.5 

3015 3 0.5 

3016 dtype: float64 

3017 """ 

3018 # Raise here so error message says sem instead of std 

3019 self._validate_numeric_only("sem", numeric_only) 

3020 return self.std(numeric_only=numeric_only, ddof=ddof) / ( 

3021 self.count(numeric_only) 

3022 ).pow(0.5) 

3023 

3024 def kurt(self, numeric_only: bool = False): 

3025 """ 

3026 Calculate the rolling Fisher's definition of kurtosis without bias. 

3027 

3028 This is equivalent to applying ``scipy.stats.kurtosis`` (with 

3029 ``bias=False``) over each rolling window. A minimum of four periods 

3030 is required. 

3031 

3032 Parameters 

3033 ---------- 

3034 numeric_only : bool, default False 

3035 Include only float, int, boolean columns. 

3036 

3037 Returns 

3038 ------- 

3039 Series or DataFrame 

3040 Return type is the same as the original object with ``np.float64`` dtype. 

3041 

3042 See Also 

3043 -------- 

3044 scipy.stats.kurtosis : Reference SciPy method. 

3045 Series.rolling : Calling rolling with Series data. 

3046 DataFrame.rolling : Calling rolling with DataFrames. 

3047 Series.kurt : Aggregating kurt for Series. 

3048 DataFrame.kurt : Aggregating kurt for DataFrame. 

3049 

3050 Notes 

3051 ----- 

3052 A minimum of four periods is required for the calculation. 

3053 

3054 Examples 

3055 -------- 

3056 The example below will show a rolling calculation with a window size of 

3057 four matching the equivalent function call using `scipy.stats`. 

3058 

3059 >>> arr = [1, 2, 3, 4, 999] 

3060 >>> import scipy.stats 

3061 >>> print(f"{scipy.stats.kurtosis(arr[:-1], bias=False):.6f}") 

3062 -1.200000 

3063 >>> print(f"{scipy.stats.kurtosis(arr[1:], bias=False):.6f}") 

3064 3.999946 

3065 >>> s = pd.Series(arr) 

3066 >>> s.rolling(4).kurt() 

3067 0 NaN 

3068 1 NaN 

3069 2 NaN 

3070 3 -1.200000 

3071 4 3.999946 

3072 dtype: float64 

3073 """ 

3074 return super().kurt(numeric_only=numeric_only) 

3075 

3076 def first(self, numeric_only: bool = False): 

3077 """ 

3078 Calculate the rolling First (left-most) element of the window. 

3079 

3080 Return the first observed value in each rolling window. This is useful 

3081 for tracking the starting value of a window as it slides forward. 

3082 

3083 Parameters 

3084 ---------- 

3085 numeric_only : bool, default False 

3086 Include only float, int, boolean columns. 

3087 

3088 Returns 

3089 ------- 

3090 Series or DataFrame 

3091 Return type is the same as the original object with ``np.float64`` dtype. 

3092 

3093 See Also 

3094 -------- 

3095 GroupBy.first : Similar method for GroupBy objects. 

3096 Rolling.last : Method to get the last element in each window. 

3097 

3098 Examples 

3099 -------- 

3100 The example below will show a rolling calculation with a window size of 

3101 three. 

3102 

3103 >>> s = pd.Series(range(5)) 

3104 >>> s.rolling(3).first() 

3105 0 NaN 

3106 1 NaN 

3107 2 0.0 

3108 3 1.0 

3109 4 2.0 

3110 dtype: float64 

3111 """ 

3112 return super().first(numeric_only=numeric_only) 

3113 

3114 def last(self, numeric_only: bool = False): 

3115 """ 

3116 Calculate the rolling Last (right-most) element of the window. 

3117 

3118 Return the last observed value in each rolling window. This is useful 

3119 for tracking the most recent value of a window as it slides forward. 

3120 

3121 Parameters 

3122 ---------- 

3123 numeric_only : bool, default False 

3124 Include only float, int, boolean columns. 

3125 

3126 Returns 

3127 ------- 

3128 Series or DataFrame 

3129 Return type is the same as the original object with ``np.float64`` dtype. 

3130 

3131 See Also 

3132 -------- 

3133 GroupBy.last : Similar method for GroupBy objects. 

3134 Rolling.first : Method to get the first element in each window. 

3135 

3136 Examples 

3137 -------- 

3138 The example below will show a rolling calculation with a window size of 

3139 three. 

3140 

3141 >>> s = pd.Series(range(5)) 

3142 >>> s.rolling(3).last() 

3143 0 NaN 

3144 1 NaN 

3145 2 2.0 

3146 3 3.0 

3147 4 4.0 

3148 dtype: float64 

3149 """ 

3150 return super().last(numeric_only=numeric_only) 

3151 

3152 def quantile( 

3153 self, 

3154 q: float, 

3155 interpolation: QuantileInterpolation = "linear", 

3156 numeric_only: bool = False, 

3157 ): 

3158 """ 

3159 Calculate the rolling quantile. 

3160 

3161 Return the ``q``-th quantile of the values in each rolling window. The 

3162 ``interpolation`` parameter controls how quantiles falling between two 

3163 data points are handled. 

3164 

3165 Parameters 

3166 ---------- 

3167 q : float 

3168 Quantile to compute. 0 <= quantile <= 1. 

3169 

3170 interpolation : {'linear', 'lower', 'higher', 'midpoint', 'nearest'} 

3171 This optional parameter specifies the interpolation method to use, 

3172 when the desired quantile lies between two data points `i` and `j`: 

3173 

3174 * linear: `i + (j - i) * fraction`, where `fraction` is the 

3175 fractional part of the index surrounded by `i` and `j`. 

3176 * lower: `i`. 

3177 * higher: `j`. 

3178 * nearest: `i` or `j` whichever is nearest. 

3179 * midpoint: (`i` + `j`) / 2. 

3180 

3181 numeric_only : bool, default False 

3182 Include only float, int, boolean columns. 

3183 

3184 Returns 

3185 ------- 

3186 Series or DataFrame 

3187 Return type is the same as the original object with ``np.float64`` dtype. 

3188 

3189 See Also 

3190 -------- 

3191 Series.rolling : Calling rolling with Series data. 

3192 DataFrame.rolling : Calling rolling with DataFrames. 

3193 Series.quantile : Aggregating quantile for Series. 

3194 DataFrame.quantile : Aggregating quantile for DataFrame. 

3195 

3196 Examples 

3197 -------- 

3198 >>> s = pd.Series([1, 2, 3, 4]) 

3199 >>> s.rolling(2).quantile(0.4, interpolation="lower") 

3200 0 NaN 

3201 1 1.0 

3202 2 2.0 

3203 3 3.0 

3204 dtype: float64 

3205 

3206 >>> s.rolling(2).quantile(0.4, interpolation="midpoint") 

3207 0 NaN 

3208 1 1.5 

3209 2 2.5 

3210 3 3.5 

3211 dtype: float64 

3212 """ 

3213 return super().quantile( 

3214 q=q, 

3215 interpolation=interpolation, 

3216 numeric_only=numeric_only, 

3217 ) 

3218 

3219 def rank( 

3220 self, 

3221 method: WindowingRankType = "average", 

3222 ascending: bool = True, 

3223 pct: bool = False, 

3224 numeric_only: bool = False, 

3225 ): 

3226 """ 

3227 Calculate the rolling rank. 

3228 

3229 Compute the rank of each value within each rolling window. Ties are 

3230 resolved using the ``method`` parameter. 

3231 

3232 Parameters 

3233 ---------- 

3234 method : {'average', 'min', 'max'}, default 'average' 

3235 How to rank the group of records that have the same value (i.e. ties): 

3236 

3237 * average: average rank of the group 

3238 * min: lowest rank in the group 

3239 * max: highest rank in the group 

3240 

3241 ascending : bool, default True 

3242 Whether or not the elements should be ranked in ascending order. 

3243 

3244 pct : bool, default False 

3245 Whether or not to display the returned rankings in percentile 

3246 form. 

3247 

3248 numeric_only : bool, default False 

3249 Include only float, int, boolean columns. 

3250 

3251 Returns 

3252 ------- 

3253 Series or DataFrame 

3254 Return type is the same as the original object with ``np.float64`` dtype. 

3255 

3256 See Also 

3257 -------- 

3258 Series.rolling : Calling rolling with Series data. 

3259 DataFrame.rolling : Calling rolling with DataFrames. 

3260 Series.rank : Aggregating rank for Series. 

3261 DataFrame.rank : Aggregating rank for DataFrame. 

3262 

3263 Examples 

3264 -------- 

3265 >>> s = pd.Series([1, 4, 2, 3, 5, 3]) 

3266 >>> s.rolling(3).rank() 

3267 0 NaN 

3268 1 NaN 

3269 2 2.0 

3270 3 2.0 

3271 4 3.0 

3272 5 1.5 

3273 dtype: float64 

3274 

3275 >>> s.rolling(3).rank(method="max") 

3276 0 NaN 

3277 1 NaN 

3278 2 2.0 

3279 3 2.0 

3280 4 3.0 

3281 5 2.0 

3282 dtype: float64 

3283 

3284 >>> s.rolling(3).rank(method="min") 

3285 0 NaN 

3286 1 NaN 

3287 2 2.0 

3288 3 2.0 

3289 4 3.0 

3290 5 1.0 

3291 dtype: float64 

3292 """ 

3293 return super().rank( 

3294 method=method, 

3295 ascending=ascending, 

3296 pct=pct, 

3297 numeric_only=numeric_only, 

3298 ) 

3299 

3300 def nunique( 

3301 self, 

3302 numeric_only: bool = False, 

3303 ): 

3304 """ 

3305 Calculate the rolling nunique. 

3306 

3307 .. versionadded:: 3.0.0 

3308 

3309 Parameters 

3310 ---------- 

3311 numeric_only : bool, default False 

3312 Include only float, int, boolean columns. 

3313 

3314 Returns 

3315 ------- 

3316 Series or DataFrame 

3317 Return type is the same as the original object with ``np.float64`` dtype. 

3318 

3319 See Also 

3320 -------- 

3321 Series.rolling : Calling rolling with Series data. 

3322 DataFrame.rolling : Calling rolling with DataFrames. 

3323 Series.nunique : Aggregating nunique for Series. 

3324 DataFrame.nunique : Aggregating nunique for DataFrame. 

3325 

3326 Examples 

3327 -------- 

3328 >>> s = pd.Series([1, 4, 2, np.nan, 3, 3, 4, 5]) 

3329 >>> s.rolling(3).nunique() 

3330 0 NaN 

3331 1 NaN 

3332 2 3.0 

3333 3 NaN 

3334 4 NaN 

3335 5 NaN 

3336 6 2.0 

3337 7 3.0 

3338 dtype: float64 

3339 """ 

3340 return super().nunique( 

3341 numeric_only=numeric_only, 

3342 ) 

3343 

3344 def cov( 

3345 self, 

3346 other: DataFrame | Series | None = None, 

3347 pairwise: bool | None = None, 

3348 ddof: int = 1, 

3349 numeric_only: bool = False, 

3350 ): 

3351 """ 

3352 Calculate the rolling sample covariance. 

3353 

3354 Compute the sample covariance between the calling object and ``other`` 

3355 over each rolling window. If ``other`` is not supplied, pairwise 

3356 covariances of the columns are computed. 

3357 

3358 Parameters 

3359 ---------- 

3360 other : Series or DataFrame, optional 

3361 If not supplied then will default to self and produce pairwise 

3362 output. 

3363 

3364 pairwise : bool, default None 

3365 If False then only matching columns between self and other will be 

3366 used and the output will be a DataFrame. 

3367 If True then all pairwise combinations will be calculated and the 

3368 output will be a MultiIndexed DataFrame in the case of DataFrame 

3369 inputs. In the case of missing elements, only complete pairwise 

3370 observations will be used. 

3371 

3372 ddof : int, default 1 

3373 Delta Degrees of Freedom. The divisor used in calculations 

3374 is ``N - ddof``, where ``N`` represents the number of elements. 

3375 

3376 numeric_only : bool, default False 

3377 Include only float, int, boolean columns. 

3378 

3379 Returns 

3380 ------- 

3381 Series or DataFrame 

3382 Return type is the same as the original object with ``np.float64`` dtype. 

3383 

3384 See Also 

3385 -------- 

3386 Series.rolling : Calling rolling with Series data. 

3387 DataFrame.rolling : Calling rolling with DataFrames. 

3388 Series.cov : Aggregating cov for Series. 

3389 DataFrame.cov : Aggregating cov for DataFrame. 

3390 

3391 Examples 

3392 -------- 

3393 >>> ser1 = pd.Series([1, 2, 3, 4]) 

3394 >>> ser2 = pd.Series([1, 4, 5, 8]) 

3395 >>> ser1.rolling(2).cov(ser2) 

3396 0 NaN 

3397 1 1.5 

3398 2 0.5 

3399 3 1.5 

3400 dtype: float64 

3401 """ 

3402 return super().cov( 

3403 other=other, 

3404 pairwise=pairwise, 

3405 ddof=ddof, 

3406 numeric_only=numeric_only, 

3407 ) 

3408 

3409 def corr( 

3410 self, 

3411 other: DataFrame | Series | None = None, 

3412 pairwise: bool | None = None, 

3413 ddof: int = 1, 

3414 numeric_only: bool = False, 

3415 ): 

3416 """ 

3417 Calculate the rolling correlation. 

3418 

3419 Compute the Pearson correlation coefficient between the calling object 

3420 and ``other`` over each rolling window. If ``other`` is not supplied, 

3421 pairwise correlations of the columns are computed. 

3422 

3423 Parameters 

3424 ---------- 

3425 other : Series or DataFrame, optional 

3426 If not supplied then will default to self and produce pairwise 

3427 output. 

3428 

3429 pairwise : bool, default None 

3430 If False then only matching columns between self and other will be 

3431 used and the output will be a DataFrame. 

3432 If True then all pairwise combinations will be calculated and the 

3433 output will be a MultiIndexed DataFrame in the case of DataFrame 

3434 inputs. In the case of missing elements, only complete pairwise 

3435 observations will be used. 

3436 

3437 ddof : int, default 1 

3438 Delta Degrees of Freedom. The divisor used in calculations 

3439 is ``N - ddof``, where ``N`` represents the number of elements. 

3440 

3441 numeric_only : bool, default False 

3442 Include only float, int, boolean columns. 

3443 

3444 Returns 

3445 ------- 

3446 Series or DataFrame 

3447 Return type is the same as the original object with ``np.float64`` dtype. 

3448 

3449 See Also 

3450 -------- 

3451 cov : Similar method to calculate covariance. 

3452 numpy.corrcoef : NumPy Pearson's correlation calculation. 

3453 Series.rolling : Calling rolling with Series data. 

3454 DataFrame.rolling : Calling rolling with DataFrames. 

3455 Series.corr : Aggregating corr for Series. 

3456 DataFrame.corr : Aggregating corr for DataFrame. 

3457 

3458 Notes 

3459 ----- 

3460 This function uses Pearson's definition of correlation 

3461 (https://en.wikipedia.org/wiki/Pearson_correlation_coefficient). 

3462 

3463 When `other` is not specified, the output will be self correlation (e.g. 

3464 all 1's), except for :class:`~pandas.DataFrame` inputs with `pairwise` 

3465 set to `True`. 

3466 

3467 Function will return ``NaN`` for correlations of equal valued sequences; 

3468 this is the result of a 0/0 division error. 

3469 

3470 When `pairwise` is set to `False`, only matching columns between `self` and 

3471 `other` will be used. 

3472 

3473 When `pairwise` is set to `True`, the output will be a MultiIndex DataFrame 

3474 with the original index on the first level, and the `other` DataFrame 

3475 columns on the second level. 

3476 

3477 In the case of missing elements, only complete pairwise observations 

3478 will be used. 

3479 

3480 Examples 

3481 -------- 

3482 The below example shows a rolling calculation with a window size of 

3483 four matching the equivalent function call using :meth:`numpy.corrcoef`. 

3484 

3485 >>> v1 = [3, 3, 3, 5, 8] 

3486 >>> v2 = [3, 4, 4, 4, 8] 

3487 >>> np.corrcoef(v1[:-1], v2[:-1]) 

3488 array([[1. , 0.33333333], 

3489 [0.33333333, 1. ]]) 

3490 >>> np.corrcoef(v1[1:], v2[1:]) 

3491 array([[1. , 0.9169493], 

3492 [0.9169493, 1. ]]) 

3493 >>> s1 = pd.Series(v1) 

3494 >>> s2 = pd.Series(v2) 

3495 >>> s1.rolling(4).corr(s2) 

3496 0 NaN 

3497 1 NaN 

3498 2 NaN 

3499 3 0.333333 

3500 4 0.916949 

3501 dtype: float64 

3502 

3503 The below example shows a similar rolling calculation on a 

3504 DataFrame using the pairwise option. 

3505 

3506 >>> matrix = np.array( 

3507 ... [[51.0, 35.0], [49.0, 30.0], [47.0, 32.0], [46.0, 31.0], [50.0, 36.0]] 

3508 ... ) 

3509 >>> np.corrcoef(matrix[:-1, 0], matrix[:-1, 1]) 

3510 array([[1. , 0.6263001], 

3511 [0.6263001, 1. ]]) 

3512 >>> np.corrcoef(matrix[1:, 0], matrix[1:, 1]) 

3513 array([[1. , 0.55536811], 

3514 [0.55536811, 1. ]]) 

3515 >>> df = pd.DataFrame(matrix, columns=["X", "Y"]) 

3516 >>> df 

3517 X Y 

3518 0 51.0 35.0 

3519 1 49.0 30.0 

3520 2 47.0 32.0 

3521 3 46.0 31.0 

3522 4 50.0 36.0 

3523 >>> df.rolling(4).corr(pairwise=True) 

3524 X Y 

3525 0 X NaN NaN 

3526 Y NaN NaN 

3527 1 X NaN NaN 

3528 Y NaN NaN 

3529 2 X NaN NaN 

3530 Y NaN NaN 

3531 3 X 1.000000 0.626300 

3532 Y 0.626300 1.000000 

3533 4 X 1.000000 0.555368 

3534 Y 0.555368 1.000000 

3535 """ 

3536 return super().corr( 

3537 other=other, 

3538 pairwise=pairwise, 

3539 ddof=ddof, 

3540 numeric_only=numeric_only, 

3541 ) 

3542 

3543 

3544Rolling.__doc__ = Window.__doc__ 

3545 

3546 

3547@set_module("pandas.api.typing") 

3548class RollingGroupBy(BaseWindowGroupBy, Rolling): 

3549 """ 

3550 Provide a rolling groupby implementation. 

3551 """ 

3552 

3553 _attributes = Rolling._attributes + BaseWindowGroupBy._attributes 

3554 

3555 def _get_window_indexer(self) -> GroupByIndexer: 

3556 """ 

3557 Return an indexer class that will compute the window start and end bounds 

3558 

3559 Returns 

3560 ------- 

3561 GroupByIndexer 

3562 """ 

3563 rolling_indexer: type[BaseIndexer] 

3564 indexer_kwargs: dict[str, Any] | None = None 

3565 index_array = self._index_array 

3566 if isinstance(self.window, BaseIndexer): 

3567 rolling_indexer = type(self.window) 

3568 indexer_kwargs = self.window.__dict__.copy() 

3569 assert isinstance(indexer_kwargs, dict) # for mypy 

3570 # We'll be using the index of each group later 

3571 indexer_kwargs.pop("index_array", None) 

3572 window = self.window 

3573 elif self._win_freq_i8 is not None: 

3574 rolling_indexer = VariableWindowIndexer 

3575 # error: Incompatible types in assignment (expression has type 

3576 # "int", variable has type "BaseIndexer") 

3577 window = self._win_freq_i8 # type: ignore[assignment] 

3578 else: 

3579 rolling_indexer = FixedWindowIndexer 

3580 window = self.window 

3581 window_indexer = GroupByIndexer( 

3582 index_array=index_array, 

3583 window_size=window, 

3584 groupby_indices=self._grouper.indices, 

3585 window_indexer=rolling_indexer, 

3586 indexer_kwargs=indexer_kwargs, 

3587 ) 

3588 return window_indexer 

3589 

3590 def _validate_datetimelike_monotonic(self) -> None: 

3591 """ 

3592 Validate that each group in self._on is monotonic 

3593 """ 

3594 # GH 46061 

3595 if self._on.hasnans: 

3596 self._raise_monotonic_error("values must not have NaT") 

3597 for group_indices in self._grouper.indices.values(): 

3598 group_on = self._on.take(group_indices) 

3599 if not ( 

3600 group_on.is_monotonic_increasing or group_on.is_monotonic_decreasing 

3601 ): 

3602 on = "index" if self.on is None else self.on 

3603 raise ValueError( 

3604 f"Each group within {on} must be monotonic. " 

3605 f"Sort the values in {on} first." 

3606 )