Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pandas/core/generic.py: 23%

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

2166 statements  

1# pyright: reportPropertyTypeMismatch=false 

2from __future__ import annotations 

3 

4import collections 

5from copy import deepcopy 

6import datetime as dt 

7from functools import partial 

8from json import loads 

9import operator 

10import pickle 

11import re 

12import sys 

13from typing import ( 

14 TYPE_CHECKING, 

15 Any, 

16 ClassVar, 

17 Concatenate, 

18 Literal, 

19 NoReturn, 

20 Self, 

21 cast, 

22 final, 

23 overload, 

24) 

25import warnings 

26 

27import numpy as np 

28 

29from pandas._config import config 

30 

31from pandas._libs import lib 

32from pandas._libs.lib import is_range_indexer 

33from pandas._libs.tslibs import ( 

34 Period, 

35 Timestamp, 

36 to_offset, 

37) 

38from pandas._typing import ( 

39 AlignJoin, 

40 AnyArrayLike, 

41 ArrayLike, 

42 Axes, 

43 Axis, 

44 AxisInt, 

45 CompressionOptions, 

46 DtypeArg, 

47 DtypeBackend, 

48 DtypeObj, 

49 FilePath, 

50 FillnaOptions, 

51 FloatFormatType, 

52 FormattersType, 

53 Frequency, 

54 IgnoreRaise, 

55 IndexKeyFunc, 

56 IndexLabel, 

57 InterpolateOptions, 

58 IntervalClosedType, 

59 JSONSerializable, 

60 Level, 

61 ListLike, 

62 Manager, 

63 NaPosition, 

64 NDFrameT, 

65 OpenFileErrors, 

66 RandomState, 

67 ReindexMethod, 

68 Renamer, 

69 Scalar, 

70 SequenceNotStr, 

71 SortKind, 

72 StorageOptions, 

73 Suffixes, 

74 T, 

75 TimeAmbiguous, 

76 TimedeltaConvertibleTypes, 

77 TimeNonexistent, 

78 TimestampConvertibleTypes, 

79 TimeUnit, 

80 ValueKeyFunc, 

81 WriteBuffer, 

82 WriteExcelBuffer, 

83 npt, 

84) 

85from pandas.compat import CHAINED_WARNING_DISABLED 

86from pandas.compat._constants import ( 

87 REF_COUNT_METHOD, 

88) 

89from pandas.compat._optional import import_optional_dependency 

90from pandas.compat.numpy import function as nv 

91from pandas.errors import ( 

92 AbstractMethodError, 

93 ChainedAssignmentError, 

94 InvalidIndexError, 

95 Pandas4Warning, 

96) 

97from pandas.errors.cow import _chained_assignment_method_msg 

98from pandas.util._decorators import ( 

99 deprecate_kwarg, 

100 doc, 

101) 

102from pandas.util._exceptions import find_stack_level 

103from pandas.util._validators import ( 

104 check_dtype_backend, 

105 validate_ascending, 

106 validate_bool_kwarg, 

107 validate_inclusive, 

108) 

109 

110from pandas.core.dtypes.astype import astype_is_view 

111from pandas.core.dtypes.cast import can_hold_element 

112from pandas.core.dtypes.common import ( 

113 ensure_object, 

114 ensure_platform_int, 

115 ensure_str, 

116 is_bool, 

117 is_bool_dtype, 

118 is_dict_like, 

119 is_extension_array_dtype, 

120 is_list_like, 

121 is_number, 

122 is_numeric_dtype, 

123 is_re_compilable, 

124 is_scalar, 

125 pandas_dtype, 

126) 

127from pandas.core.dtypes.dtypes import ( 

128 DatetimeTZDtype, 

129 ExtensionDtype, 

130 PeriodDtype, 

131) 

132from pandas.core.dtypes.generic import ( 

133 ABCDataFrame, 

134 ABCSeries, 

135) 

136from pandas.core.dtypes.inference import ( 

137 is_hashable, 

138 is_nested_list_like, 

139) 

140from pandas.core.dtypes.missing import ( 

141 isna, 

142 notna, 

143) 

144 

145from pandas.core import ( 

146 algorithms as algos, 

147 arraylike, 

148 common, 

149 indexing, 

150 missing, 

151 nanops, 

152 sample, 

153) 

154from pandas.core.array_algos.replace import should_use_regex 

155from pandas.core.arrays import ExtensionArray 

156from pandas.core.base import PandasObject 

157from pandas.core.construction import extract_array 

158from pandas.core.flags import Flags 

159from pandas.core.indexes.api import ( 

160 DatetimeIndex, 

161 Index, 

162 MultiIndex, 

163 PeriodIndex, 

164 default_index, 

165 ensure_index, 

166) 

167from pandas.core.internals import BlockManager 

168from pandas.core.methods.describe import describe_ndframe 

169from pandas.core.missing import ( 

170 clean_fill_method, 

171 clean_reindex_fill_method, 

172 find_valid_index, 

173) 

174from pandas.core.reshape.concat import concat 

175from pandas.core.shared_docs import _shared_docs 

176from pandas.core.sorting import get_indexer_indexer 

177from pandas.core.window import ( 

178 Expanding, 

179 ExponentialMovingWindow, 

180 Rolling, 

181 Window, 

182) 

183 

184from pandas.io.formats.format import ( 

185 DataFrameFormatter, 

186 DataFrameRenderer, 

187) 

188from pandas.io.formats.printing import pprint_thing 

189 

190if TYPE_CHECKING: 

191 from collections.abc import ( 

192 Callable, 

193 Hashable, 

194 Iterator, 

195 Mapping, 

196 Sequence, 

197 ) 

198 

199 from pandas._libs.tslibs import BaseOffset 

200 from pandas._typing import P 

201 

202 from pandas import ( 

203 DataFrame, 

204 ExcelWriter, 

205 HDFStore, 

206 Series, 

207 ) 

208 from pandas.core.indexers.objects import BaseIndexer 

209 from pandas.core.resample import Resampler 

210 

211 

212# goal is to be able to define the docs close to function, while still being 

213# able to share 

214_shared_docs = {**_shared_docs} 

215_shared_doc_kwargs = { 

216 "axes": "keywords for axes", 

217 "klass": "Series/DataFrame", 

218 "axes_single_arg": "{0 or 'index'} for Series, {0 or 'index', 1 or 'columns'} for DataFrame", # noqa: E501 

219 "inplace": """ 

220 inplace : bool, default False 

221 If True, performs operation inplace.""", 

222 "optional_by": """ 

223 by : str or list of str 

224 Name or list of names to sort by""", 

225} 

226 

227 

228class NDFrame(PandasObject, indexing.IndexingMixin): 

229 """ 

230 N-dimensional analogue of DataFrame. Store multi-dimensional in a 

231 size-mutable, labeled data structure 

232 

233 Parameters 

234 ---------- 

235 data : BlockManager 

236 axes : list 

237 copy : bool, default False 

238 """ 

239 

240 _internal_names: list[str] = [ 

241 "_mgr", 

242 "_cache", 

243 "_name", 

244 "_metadata", 

245 "_flags", 

246 ] 

247 _internal_names_set: set[str] = set(_internal_names) 

248 _accessors: set[str] = set() 

249 _hidden_attrs: frozenset[str] = frozenset([]) 

250 _metadata: list[str] = [] 

251 _mgr: Manager 

252 _attrs: dict[Hashable, Any] 

253 _typ: str 

254 

255 # ---------------------------------------------------------------------- 

256 # Constructors 

257 

258 def __init__(self, data: Manager) -> None: 

259 object.__setattr__(self, "_mgr", data) 

260 object.__setattr__(self, "_attrs", {}) 

261 object.__setattr__(self, "_flags", Flags(self, allows_duplicate_labels=True)) 

262 

263 @final 

264 @classmethod 

265 def _init_mgr( 

266 cls, 

267 mgr: Manager, 

268 axes: dict[Literal["index", "columns"], Axes | None], 

269 dtype: DtypeObj | None = None, 

270 copy: bool = False, 

271 ) -> Manager: 

272 """passed a manager and a axes dict""" 

273 for a, axe in axes.items(): 

274 if axe is not None: 

275 axe = ensure_index(axe) 

276 bm_axis = cls._get_block_manager_axis(a) 

277 mgr = mgr.reindex_axis(axe, axis=bm_axis) 

278 

279 # make a copy if explicitly requested 

280 if copy: 

281 mgr = mgr.copy(deep=True) 

282 if dtype is not None: 

283 # avoid further copies if we can 

284 if ( 

285 isinstance(mgr, BlockManager) 

286 and len(mgr.blocks) == 1 

287 and mgr.blocks[0].values.dtype == dtype 

288 ): 

289 pass 

290 else: 

291 mgr = mgr.astype(dtype=dtype) 

292 return mgr 

293 

294 @final 

295 @classmethod 

296 def _from_mgr(cls, mgr: Manager, axes: list[Index]) -> Self: 

297 """ 

298 Construct a new object of this type from a Manager object and axes. 

299 

300 Parameters 

301 ---------- 

302 mgr : Manager 

303 Must have the same ndim as cls. 

304 axes : list[Index] 

305 

306 Notes 

307 ----- 

308 The axes must match mgr.axes, but are required for future-proofing 

309 in the event that axes are refactored out of the Manager objects. 

310 """ 

311 obj = cls.__new__(cls) 

312 NDFrame.__init__(obj, mgr) 

313 return obj 

314 

315 # ---------------------------------------------------------------------- 

316 # attrs and flags 

317 

318 @property 

319 def attrs(self) -> dict[Hashable, Any]: 

320 """ 

321 Dictionary of global attributes of this dataset. 

322 

323 .. warning:: 

324 

325 attrs is experimental and may change without warning. 

326 

327 See Also 

328 -------- 

329 DataFrame.flags : Global flags applying to this object. 

330 

331 Notes 

332 ----- 

333 Many operations that create new datasets will copy ``attrs``. Copies 

334 are always deep so that changing ``attrs`` will only affect the 

335 present dataset. :func:`pandas.concat` and :func:`pandas.merge` will 

336 only copy ``attrs`` if all input datasets have the same ``attrs``. 

337 

338 Examples 

339 -------- 

340 For Series: 

341 

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

343 >>> ser.attrs = {"A": [10, 20, 30]} 

344 >>> ser.attrs 

345 {'A': [10, 20, 30]} 

346 

347 For DataFrame: 

348 

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

350 >>> df.attrs = {"A": [10, 20, 30]} 

351 >>> df.attrs 

352 {'A': [10, 20, 30]} 

353 """ 

354 return self._attrs 

355 

356 @attrs.setter 

357 def attrs(self, value: Mapping[Hashable, Any]) -> None: 

358 self._attrs = dict(value) 

359 

360 @final 

361 @property 

362 def flags(self) -> Flags: 

363 """ 

364 Get the properties associated with this pandas object. 

365 

366 The available flags are 

367 

368 * :attr:`Flags.allows_duplicate_labels` 

369 

370 See Also 

371 -------- 

372 Flags : Flags that apply to pandas objects. 

373 DataFrame.attrs : Global metadata applying to this dataset. 

374 

375 Notes 

376 ----- 

377 "Flags" differ from "metadata". Flags reflect properties of the 

378 pandas object (the Series or DataFrame). Metadata refer to properties 

379 of the dataset, and should be stored in :attr:`DataFrame.attrs`. 

380 

381 Examples 

382 -------- 

383 >>> df = pd.DataFrame({"A": [1, 2]}) 

384 >>> df.flags 

385 <Flags(allows_duplicate_labels=True)> 

386 

387 Flags can be get or set using ``.`` 

388 

389 >>> df.flags.allows_duplicate_labels 

390 True 

391 >>> df.flags.allows_duplicate_labels = False 

392 

393 Or by slicing with a key 

394 

395 >>> df.flags["allows_duplicate_labels"] 

396 False 

397 >>> df.flags["allows_duplicate_labels"] = True 

398 """ 

399 return self._flags 

400 

401 @final 

402 def set_flags( 

403 self, 

404 *, 

405 copy: bool | lib.NoDefault = lib.no_default, 

406 allows_duplicate_labels: bool | None = None, 

407 ) -> Self: 

408 """ 

409 Return a new object with updated flags. 

410 

411 This method creates a shallow copy of the original object, preserving its 

412 underlying data while modifying its global flags. In particular, it allows 

413 you to update properties such as whether duplicate labels are permitted. This 

414 behavior is especially useful in method chains, where one wishes to 

415 adjust DataFrame or Series characteristics without altering the original object. 

416 

417 Parameters 

418 ---------- 

419 copy : bool, default False 

420 This keyword is now ignored; changing its value will have no 

421 impact on the method. 

422 

423 .. deprecated:: 3.0.0 

424 

425 This keyword is ignored and will be removed in pandas 4.0. Since 

426 pandas 3.0, this method always returns a new object using a lazy 

427 copy mechanism that defers copies until necessary 

428 (Copy-on-Write). See the `user guide on Copy-on-Write 

429 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

430 for more details. 

431 

432 allows_duplicate_labels : bool, optional 

433 Whether the returned object allows duplicate labels. 

434 

435 Returns 

436 ------- 

437 Series or DataFrame 

438 The same type as the caller. 

439 

440 See Also 

441 -------- 

442 DataFrame.attrs : Global metadata applying to this dataset. 

443 DataFrame.flags : Global flags applying to this object. 

444 

445 Notes 

446 ----- 

447 This method returns a new object that's a view on the same data 

448 as the input. Mutating the input or the output values will be reflected 

449 in the other. 

450 

451 This method is intended to be used in method chains. 

452 

453 "Flags" differ from "metadata". Flags reflect properties of the 

454 pandas object (the Series or DataFrame). Metadata refer to properties 

455 of the dataset, and should be stored in :attr:`DataFrame.attrs`. 

456 

457 Examples 

458 -------- 

459 >>> df = pd.DataFrame({"A": [1, 2]}) 

460 >>> df.flags.allows_duplicate_labels 

461 True 

462 >>> df2 = df.set_flags(allows_duplicate_labels=False) 

463 >>> df2.flags.allows_duplicate_labels 

464 False 

465 """ 

466 self._check_copy_deprecation(copy) 

467 df = self.copy(deep=False) 

468 if allows_duplicate_labels is not None: 

469 df.flags["allows_duplicate_labels"] = allows_duplicate_labels 

470 return df 

471 

472 @final 

473 @classmethod 

474 def _validate_dtype(cls, dtype) -> DtypeObj | None: 

475 """validate the passed dtype""" 

476 if dtype is not None: 

477 dtype = pandas_dtype(dtype) 

478 

479 # a compound dtype 

480 if dtype.kind == "V" and not isinstance(dtype, ExtensionDtype): 

481 raise NotImplementedError( 

482 "compound dtypes are not implemented " 

483 f"in the {cls.__name__} constructor" 

484 ) 

485 

486 return dtype 

487 

488 # ---------------------------------------------------------------------- 

489 # Construction 

490 

491 # error: Signature of "_constructor" incompatible with supertype "PandasObject" 

492 @property 

493 def _constructor(self) -> Callable[..., Self]: # type: ignore[override] 

494 """ 

495 Used when a manipulation result has the same dimensions as the 

496 original. 

497 """ 

498 raise AbstractMethodError(self) 

499 

500 # ---------------------------------------------------------------------- 

501 # Axis 

502 _AXIS_ORDERS: list[Literal["index", "columns"]] 

503 _AXIS_TO_AXIS_NUMBER: dict[Axis, AxisInt] = {0: 0, "index": 0, "rows": 0} 

504 _info_axis_number: int 

505 _info_axis_name: Literal["index", "columns"] 

506 _AXIS_LEN: int 

507 

508 @final 

509 def _construct_axes_dict( 

510 self, axes: Sequence[Axis] | None = None, **kwargs: AxisInt 

511 ) -> dict: 

512 """Return an axes dictionary for myself.""" 

513 d = {a: self._get_axis(a) for a in (axes or self._AXIS_ORDERS)} 

514 # error: Argument 1 to "update" of "MutableMapping" has incompatible type 

515 # "Dict[str, Any]"; expected "SupportsKeysAndGetItem[Union[int, str], Any]" 

516 d.update(kwargs) # type: ignore[arg-type] 

517 return d 

518 

519 @final 

520 @classmethod 

521 def _get_axis_number(cls, axis: Axis) -> AxisInt: 

522 try: 

523 return cls._AXIS_TO_AXIS_NUMBER[axis] 

524 except KeyError as err: 

525 raise ValueError( 

526 f"No axis named {axis} for object type {cls.__name__}" 

527 ) from err 

528 

529 @final 

530 @classmethod 

531 def _get_axis_name(cls, axis: Axis) -> Literal["index", "columns"]: 

532 axis_number = cls._get_axis_number(axis) 

533 return cls._AXIS_ORDERS[axis_number] 

534 

535 @final 

536 def _get_axis(self, axis: Axis) -> Index: 

537 axis_number = self._get_axis_number(axis) 

538 assert axis_number in {0, 1} 

539 return self.index if axis_number == 0 else self.columns 

540 

541 @final 

542 @classmethod 

543 def _get_block_manager_axis(cls, axis: Axis) -> AxisInt: 

544 """Map the axis to the block_manager axis.""" 

545 axis = cls._get_axis_number(axis) 

546 ndim = cls._AXIS_LEN 

547 if ndim == 2: 

548 # i.e. DataFrame 

549 return 1 - axis 

550 return axis 

551 

552 @final 

553 def _get_axis_resolvers(self, axis: str) -> dict[str, Series | MultiIndex]: 

554 # index or columns 

555 axis_index = getattr(self, axis) 

556 d = {} 

557 prefix = axis[0] 

558 

559 for i, name in enumerate(axis_index.names): 

560 if name is not None: 

561 key = level = name 

562 else: 

563 # prefix with 'i' or 'c' depending on the input axis 

564 # e.g., you must do ilevel_0 for the 0th level of an unnamed 

565 # multiiindex 

566 key = f"{prefix}level_{i}" 

567 level = i 

568 

569 level_values = axis_index.get_level_values(level) 

570 s = level_values.to_series() 

571 s.index = axis_index 

572 d[key] = s 

573 

574 # put the index/columns itself in the dict 

575 if isinstance(axis_index, MultiIndex): 

576 dindex = axis_index 

577 else: 

578 dindex = axis_index.to_series() 

579 

580 d[axis] = dindex 

581 return d 

582 

583 @final 

584 def _get_index_resolvers(self) -> dict[Hashable, Series | MultiIndex]: 

585 from pandas.core.computation.parsing import clean_column_name 

586 

587 d: dict[str, Series | MultiIndex] = {} 

588 for axis_name in self._AXIS_ORDERS: 

589 d.update(self._get_axis_resolvers(axis_name)) 

590 

591 return {clean_column_name(k): v for k, v in d.items() if not isinstance(k, int)} 

592 

593 @final 

594 def _get_cleaned_column_resolvers(self) -> dict[Hashable, Series]: 

595 """ 

596 Return the special character free column resolvers of a DataFrame. 

597 

598 Column names with special characters are 'cleaned up' so that they can 

599 be referred to by backtick quoting. 

600 Used in :meth:`DataFrame.eval`. 

601 """ 

602 from pandas.core.computation.parsing import clean_column_name 

603 

604 if isinstance(self, ABCSeries): 

605 return {clean_column_name(self.name): self} 

606 

607 return {clean_column_name(k): v for k, v in self.items()} 

608 

609 @final 

610 @property 

611 def _info_axis(self) -> Index: 

612 return getattr(self, self._info_axis_name) 

613 

614 @property 

615 def shape(self) -> tuple[int, ...]: 

616 """ 

617 Return a tuple of axis dimensions 

618 """ 

619 return tuple(len(self._get_axis(a)) for a in self._AXIS_ORDERS) 

620 

621 @property 

622 def axes(self) -> list[Index]: 

623 """ 

624 Return index label(s) of the internal NDFrame 

625 """ 

626 # we do it this way because if we have reversed axes, then 

627 # the block manager shows then reversed 

628 return [self._get_axis(a) for a in self._AXIS_ORDERS] 

629 

630 @final 

631 @property 

632 def ndim(self) -> int: 

633 """ 

634 Return an int representing the number of axes / array dimensions. 

635 

636 Return 1 if Series. Otherwise return 2 if DataFrame. 

637 

638 See Also 

639 -------- 

640 numpy.ndarray.ndim : Number of array dimensions. 

641 

642 Examples 

643 -------- 

644 >>> s = pd.Series({"a": 1, "b": 2, "c": 3}) 

645 >>> s.ndim 

646 1 

647 

648 >>> df = pd.DataFrame({"col1": [1, 2], "col2": [3, 4]}) 

649 >>> df.ndim 

650 2 

651 """ 

652 return self._mgr.ndim 

653 

654 @final 

655 @property 

656 def size(self) -> int: 

657 """ 

658 Return an int representing the number of elements in this object. 

659 

660 Return the number of rows if Series. Otherwise return the number of 

661 rows times number of columns if DataFrame. 

662 

663 See Also 

664 -------- 

665 numpy.ndarray.size : Number of elements in the array. 

666 

667 Examples 

668 -------- 

669 >>> s = pd.Series({"a": 1, "b": 2, "c": 3}) 

670 >>> s.size 

671 3 

672 

673 >>> df = pd.DataFrame({"col1": [1, 2], "col2": [3, 4]}) 

674 >>> df.size 

675 4 

676 """ 

677 

678 return int(np.prod(self.shape)) 

679 

680 def set_axis( 

681 self, 

682 labels, 

683 *, 

684 axis: Axis = 0, 

685 copy: bool | lib.NoDefault = lib.no_default, 

686 ) -> Self: 

687 """ 

688 Assign desired index to given axis. 

689 

690 Indexes for%(extended_summary_sub)s row labels can be changed by assigning 

691 a list-like or Index. 

692 

693 Parameters 

694 ---------- 

695 labels : list-like, Index 

696 The values for the new index. 

697 

698 axis : %(axes_single_arg)s, default 0 

699 The axis to update. The value 0 identifies the rows. For `Series` 

700 this parameter is unused and defaults to 0. 

701 

702 copy : bool, default False 

703 This keyword is now ignored; changing its value will have no 

704 impact on the method. 

705 

706 .. deprecated:: 3.0.0 

707 

708 This keyword is ignored and will be removed in pandas 4.0. Since 

709 pandas 3.0, this method always returns a new object using a lazy 

710 copy mechanism that defers copies until necessary 

711 (Copy-on-Write). See the `user guide on Copy-on-Write 

712 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

713 for more details. 

714 

715 Returns 

716 ------- 

717 %(klass)s 

718 An object of type %(klass)s. 

719 

720 See Also 

721 -------- 

722 %(klass)s.rename_axis : Alter the name of the index%(see_also_sub)s. 

723 """ 

724 self._check_copy_deprecation(copy) 

725 return self._set_axis_nocheck(labels, axis, inplace=False) 

726 

727 @overload 

728 def _set_axis_nocheck( 

729 self, labels, axis: Axis, inplace: Literal[False] 

730 ) -> Self: ... 

731 

732 @overload 

733 def _set_axis_nocheck(self, labels, axis: Axis, inplace: Literal[True]) -> None: ... 

734 

735 @overload 

736 def _set_axis_nocheck(self, labels, axis: Axis, inplace: bool) -> Self | None: ... 

737 

738 @final 

739 def _set_axis_nocheck(self, labels, axis: Axis, inplace: bool) -> Self | None: 

740 if inplace: 

741 setattr(self, self._get_axis_name(axis), labels) 

742 return None 

743 obj = self.copy(deep=False) 

744 setattr(obj, obj._get_axis_name(axis), labels) 

745 return obj 

746 

747 @final 

748 def _set_axis(self, axis: AxisInt, labels: AnyArrayLike | list) -> None: 

749 """ 

750 This is called from the cython code when we set the `index` attribute 

751 directly, e.g. `series.index = [1, 2, 3]`. 

752 """ 

753 labels = ensure_index(labels) 

754 self._mgr.set_axis(axis, labels) 

755 

756 @final 

757 def droplevel(self, level: IndexLabel, axis: Axis = 0) -> Self: 

758 """ 

759 Return Series/DataFrame with requested index / column level(s) removed. 

760 

761 Parameters 

762 ---------- 

763 level : int, str, or list-like 

764 If a string is given, must be the name of a level 

765 If list-like, elements must be names or positional indexes 

766 of levels. 

767 

768 axis : {0 or 'index', 1 or 'columns'}, default 0 

769 Axis along which the level(s) is removed: 

770 

771 * 0 or 'index': remove level(s) in column. 

772 * 1 or 'columns': remove level(s) in row. 

773 

774 For `Series` this parameter is unused and defaults to 0. 

775 

776 Returns 

777 ------- 

778 Series/DataFrame 

779 Series/DataFrame with requested index / column level(s) removed. 

780 

781 See Also 

782 -------- 

783 DataFrame.replace : Replace values given in `to_replace` with `value`. 

784 DataFrame.pivot : Return reshaped DataFrame organized by given 

785 index / column values. 

786 

787 Examples 

788 -------- 

789 >>> df = ( 

790 ... pd.DataFrame([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]) 

791 ... .set_index([0, 1]) 

792 ... .rename_axis(["a", "b"]) 

793 ... ) 

794 

795 >>> df.columns = pd.MultiIndex.from_tuples( 

796 ... [("c", "e"), ("d", "f")], names=["level_1", "level_2"] 

797 ... ) 

798 

799 >>> df 

800 level_1 c d 

801 level_2 e f 

802 a b 

803 1 2 3 4 

804 5 6 7 8 

805 9 10 11 12 

806 

807 >>> df.droplevel("a") 

808 level_1 c d 

809 level_2 e f 

810 b 

811 2 3 4 

812 6 7 8 

813 10 11 12 

814 

815 >>> df.droplevel("level_2", axis=1) 

816 level_1 c d 

817 a b 

818 1 2 3 4 

819 5 6 7 8 

820 9 10 11 12 

821 """ 

822 labels = self._get_axis(axis) 

823 new_labels = labels.droplevel(level) 

824 return self.set_axis(new_labels, axis=axis) 

825 

826 def pop(self, item: Hashable) -> Series | Any: 

827 result = self[item] 

828 del self[item] 

829 

830 return result 

831 

832 @final 

833 def squeeze(self, axis: Axis | None = None) -> Scalar | Series | DataFrame: 

834 """ 

835 Squeeze 1 dimensional axis objects into scalars. 

836 

837 Series or DataFrames with a single element are squeezed to a scalar. 

838 DataFrames with a single column or a single row are squeezed to a 

839 Series. Otherwise the object is unchanged. 

840 

841 This method is most useful when you don't know if your 

842 object is a Series or DataFrame, but you do know it has just a single 

843 column. In that case you can safely call `squeeze` to ensure you have a 

844 Series. 

845 

846 Parameters 

847 ---------- 

848 axis : {0 or 'index', 1 or 'columns', None}, default None 

849 A specific axis to squeeze. By default, all length-1 axes are 

850 squeezed. For `Series` this parameter is unused and defaults to `None`. 

851 

852 Returns 

853 ------- 

854 DataFrame, Series, or scalar 

855 The projection after squeezing `axis` or all the axes. 

856 

857 See Also 

858 -------- 

859 Series.iloc : Integer-location based indexing for selecting scalars. 

860 DataFrame.iloc : Integer-location based indexing for selecting Series. 

861 Series.to_frame : Inverse of DataFrame.squeeze for a 

862 single-column DataFrame. 

863 

864 Examples 

865 -------- 

866 >>> primes = pd.Series([2, 3, 5, 7]) 

867 

868 Slicing might produce a Series with a single value: 

869 

870 >>> even_primes = primes[primes % 2 == 0] 

871 >>> even_primes 

872 0 2 

873 dtype: int64 

874 

875 >>> even_primes.squeeze() 

876 np.int64(2) 

877 

878 Squeezing objects with more than one value in every axis does nothing: 

879 

880 >>> odd_primes = primes[primes % 2 == 1] 

881 >>> odd_primes 

882 1 3 

883 2 5 

884 3 7 

885 dtype: int64 

886 

887 >>> odd_primes.squeeze() 

888 1 3 

889 2 5 

890 3 7 

891 dtype: int64 

892 

893 Squeezing is even more effective when used with DataFrames. 

894 

895 >>> df = pd.DataFrame([[1, 2], [3, 4]], columns=["a", "b"]) 

896 >>> df 

897 a b 

898 0 1 2 

899 1 3 4 

900 

901 Slicing a single column will produce a DataFrame with the columns 

902 having only one value: 

903 

904 >>> df_a = df[["a"]] 

905 >>> df_a 

906 a 

907 0 1 

908 1 3 

909 

910 So the columns can be squeezed down, resulting in a Series: 

911 

912 >>> df_a.squeeze("columns") 

913 0 1 

914 1 3 

915 Name: a, dtype: int64 

916 

917 Slicing a single row from a single column will produce a single 

918 scalar DataFrame: 

919 

920 >>> df_0a = df.loc[df.index < 1, ["a"]] 

921 >>> df_0a 

922 a 

923 0 1 

924 

925 Squeezing the rows produces a single scalar Series: 

926 

927 >>> df_0a.squeeze("rows") 

928 a 1 

929 Name: 0, dtype: int64 

930 

931 Squeezing all axes will project directly into a scalar: 

932 

933 >>> df_0a.squeeze() 

934 np.int64(1) 

935 """ 

936 axes = range(self._AXIS_LEN) if axis is None else (self._get_axis_number(axis),) 

937 result = self.iloc[ 

938 tuple( 

939 0 if i in axes and len(a) == 1 else slice(None) 

940 for i, a in enumerate(self.axes) 

941 ) 

942 ] 

943 if isinstance(result, NDFrame): 

944 result = result.__finalize__(self, method="squeeze") 

945 return result 

946 

947 # ---------------------------------------------------------------------- 

948 # Rename 

949 

950 @overload 

951 def _rename( 

952 self, 

953 mapper: Renamer | None = ..., 

954 *, 

955 index: Renamer | None = ..., 

956 columns: Renamer | None = ..., 

957 axis: Axis | None = ..., 

958 inplace: Literal[False] = ..., 

959 level: Level | None = ..., 

960 errors: str = ..., 

961 ) -> Self: ... 

962 

963 @overload 

964 def _rename( 

965 self, 

966 mapper: Renamer | None = ..., 

967 *, 

968 index: Renamer | None = ..., 

969 columns: Renamer | None = ..., 

970 axis: Axis | None = ..., 

971 inplace: Literal[True], 

972 level: Level | None = ..., 

973 errors: str = ..., 

974 ) -> None: ... 

975 

976 @overload 

977 def _rename( 

978 self, 

979 mapper: Renamer | None = ..., 

980 *, 

981 index: Renamer | None = ..., 

982 columns: Renamer | None = ..., 

983 axis: Axis | None = ..., 

984 inplace: bool, 

985 level: Level | None = ..., 

986 errors: str = ..., 

987 ) -> Self | None: ... 

988 

989 @final 

990 def _rename( 

991 self, 

992 mapper: Renamer | None = None, 

993 *, 

994 index: Renamer | None = None, 

995 columns: Renamer | None = None, 

996 axis: Axis | None = None, 

997 inplace: bool = False, 

998 level: Level | None = None, 

999 errors: str = "ignore", 

1000 ) -> Self | None: 

1001 # called by Series.rename and DataFrame.rename 

1002 

1003 if mapper is None and index is None and columns is None: 

1004 raise TypeError("must pass an index to rename") 

1005 

1006 if index is not None or columns is not None: 

1007 if axis is not None: 

1008 raise TypeError( 

1009 "Cannot specify both 'axis' and any of 'index' or 'columns'" 

1010 ) 

1011 if mapper is not None: 

1012 raise TypeError( 

1013 "Cannot specify both 'mapper' and any of 'index' or 'columns'" 

1014 ) 

1015 # use the mapper argument 

1016 elif axis and self._get_axis_number(axis) == 1: 

1017 columns = mapper 

1018 else: 

1019 index = mapper 

1020 

1021 self._check_inplace_and_allows_duplicate_labels(inplace) 

1022 result = self if inplace else self.copy(deep=False) 

1023 

1024 for axis_no, replacements in enumerate((index, columns)): 

1025 if replacements is None: 

1026 continue 

1027 

1028 ax = self._get_axis(axis_no) 

1029 f = common.get_rename_function(replacements) 

1030 

1031 if level is not None: 

1032 level = ax._get_level_number(level) 

1033 

1034 if isinstance(replacements, ABCSeries) and not replacements.index.is_unique: 

1035 # GH#58621 

1036 raise ValueError("Cannot rename with a Series with non-unique index.") 

1037 

1038 # GH 13473 

1039 if not callable(replacements): 

1040 if ax._is_multi and level is not None: 

1041 indexer = ax.get_level_values(level).get_indexer_for(replacements) 

1042 else: 

1043 indexer = ax.get_indexer_for(replacements) 

1044 

1045 if errors == "raise" and len(indexer[indexer == -1]): 

1046 missing_labels = [ 

1047 label 

1048 for index, label in enumerate(replacements) 

1049 if indexer[index] == -1 

1050 ] 

1051 raise KeyError(f"{missing_labels} not found in axis") 

1052 

1053 new_index = ax._transform_index(f, level=level) 

1054 result._set_axis_nocheck(new_index, axis=axis_no, inplace=True) 

1055 

1056 if inplace: 

1057 self._update_inplace(result) 

1058 return None 

1059 else: 

1060 return result.__finalize__(self, method="rename") 

1061 

1062 @overload 

1063 def rename_axis( 

1064 self, 

1065 mapper: IndexLabel | lib.NoDefault = ..., 

1066 *, 

1067 index=..., 

1068 columns=..., 

1069 axis: Axis = ..., 

1070 copy: bool | lib.NoDefault = lib.no_default, 

1071 inplace: Literal[False] = ..., 

1072 ) -> Self: ... 

1073 

1074 @overload 

1075 def rename_axis( 

1076 self, 

1077 mapper: IndexLabel | lib.NoDefault = ..., 

1078 *, 

1079 index=..., 

1080 columns=..., 

1081 axis: Axis = ..., 

1082 copy: bool | lib.NoDefault = lib.no_default, 

1083 inplace: Literal[True], 

1084 ) -> None: ... 

1085 

1086 @overload 

1087 def rename_axis( 

1088 self, 

1089 mapper: IndexLabel | lib.NoDefault = ..., 

1090 *, 

1091 index=..., 

1092 columns=..., 

1093 axis: Axis = ..., 

1094 copy: bool | lib.NoDefault = lib.no_default, 

1095 inplace: bool = ..., 

1096 ) -> Self | None: ... 

1097 

1098 def rename_axis( 

1099 self, 

1100 mapper: IndexLabel | lib.NoDefault = lib.no_default, 

1101 *, 

1102 index=lib.no_default, 

1103 columns=lib.no_default, 

1104 axis: Axis = 0, 

1105 copy: bool | lib.NoDefault = lib.no_default, 

1106 inplace: bool = False, 

1107 ) -> Self | None: 

1108 """ 

1109 Set the name of the axis for the index or columns. 

1110 

1111 Parameters 

1112 ---------- 

1113 mapper : scalar, list-like, optional 

1114 Value to set the axis name attribute. 

1115 

1116 Use either ``mapper`` and ``axis`` to 

1117 specify the axis to target with ``mapper``, or ``index`` 

1118 and/or ``columns``. 

1119 index : scalar, list-like, dict-like or function, optional 

1120 A scalar, list-like, dict-like or functions transformations to 

1121 apply to that axis' values. 

1122 columns : scalar, list-like, dict-like or function, optional 

1123 A scalar, list-like, dict-like or functions transformations to 

1124 apply to that axis' values. 

1125 axis : {0 or 'index', 1 or 'columns'}, default 0 

1126 The axis to rename. 

1127 copy : bool, default False 

1128 This keyword is now ignored; changing its value will have no 

1129 impact on the method. 

1130 

1131 .. deprecated:: 3.0.0 

1132 

1133 This keyword is ignored and will be removed in pandas 4.0. Since 

1134 pandas 3.0, this method always returns a new object using a lazy 

1135 copy mechanism that defers copies until necessary 

1136 (Copy-on-Write). See the `user guide on Copy-on-Write 

1137 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

1138 for more details. 

1139 

1140 inplace : bool, default False 

1141 Modifies the object directly, instead of creating a new Series 

1142 or DataFrame. 

1143 

1144 Returns 

1145 ------- 

1146 DataFrame, or None 

1147 The same type as the caller or None if ``inplace=True``. 

1148 

1149 See Also 

1150 -------- 

1151 Series.rename : Alter Series index labels or name. 

1152 DataFrame.rename : Alter DataFrame index labels or name. 

1153 Index.rename : Set new names on index. 

1154 

1155 Notes 

1156 ----- 

1157 ``DataFrame.rename_axis`` supports two calling conventions 

1158 

1159 * ``(index=index_mapper, columns=columns_mapper, ...)`` 

1160 * ``(mapper, axis={'index', 'columns'}, ...)`` 

1161 

1162 The first calling convention will only modify the names of 

1163 the index and/or the names of the Index object that is the columns. 

1164 In this case, the parameter ``copy`` is ignored. 

1165 

1166 The second calling convention will modify the names of the 

1167 corresponding index if mapper is a list or a scalar. 

1168 However, if mapper is dict-like or a function, it will use the 

1169 deprecated behavior of modifying the axis *labels*. 

1170 

1171 We *highly* recommend using keyword arguments to clarify your 

1172 intent. 

1173 

1174 Examples 

1175 -------- 

1176 **DataFrame** 

1177 

1178 >>> df = pd.DataFrame( 

1179 ... {"num_legs": [4, 4, 2], "num_arms": [0, 0, 2]}, ["dog", "cat", "monkey"] 

1180 ... ) 

1181 >>> df 

1182 num_legs num_arms 

1183 dog 4 0 

1184 cat 4 0 

1185 monkey 2 2 

1186 >>> df = df.rename_axis("animal") 

1187 >>> df 

1188 num_legs num_arms 

1189 animal 

1190 dog 4 0 

1191 cat 4 0 

1192 monkey 2 2 

1193 >>> df = df.rename_axis("limbs", axis="columns") 

1194 >>> df 

1195 limbs num_legs num_arms 

1196 animal 

1197 dog 4 0 

1198 cat 4 0 

1199 monkey 2 2 

1200 

1201 **MultiIndex** 

1202 

1203 >>> df.index = pd.MultiIndex.from_product( 

1204 ... [["mammal"], ["dog", "cat", "monkey"]], names=["type", "name"] 

1205 ... ) 

1206 >>> df 

1207 limbs num_legs num_arms 

1208 type name 

1209 mammal dog 4 0 

1210 cat 4 0 

1211 monkey 2 2 

1212 

1213 >>> df.rename_axis(index={"type": "class"}) 

1214 limbs num_legs num_arms 

1215 class name 

1216 mammal dog 4 0 

1217 cat 4 0 

1218 monkey 2 2 

1219 

1220 >>> df.rename_axis(columns=str.upper) 

1221 LIMBS num_legs num_arms 

1222 type name 

1223 mammal dog 4 0 

1224 cat 4 0 

1225 monkey 2 2 

1226 """ 

1227 self._check_copy_deprecation(copy) 

1228 axes = {"index": index, "columns": columns} 

1229 

1230 if axis is not None: 

1231 axis = self._get_axis_number(axis) 

1232 

1233 inplace = validate_bool_kwarg(inplace, "inplace") 

1234 

1235 if mapper is not lib.no_default: 

1236 # Use v0.23 behavior if a scalar or list 

1237 non_mapper = is_scalar(mapper) or ( 

1238 is_list_like(mapper) and not is_dict_like(mapper) 

1239 ) 

1240 if non_mapper: 

1241 return self._set_axis_name(mapper, axis=axis, inplace=inplace) 

1242 else: 

1243 raise ValueError("Use `.rename` to alter labels with a mapper.") 

1244 else: 

1245 # Use new behavior. Means that index and/or columns 

1246 # is specified 

1247 result = self if inplace else self.copy(deep=False) 

1248 

1249 for axis in range(self._AXIS_LEN): 

1250 v = axes.get(self._get_axis_name(axis)) 

1251 if v is lib.no_default: 

1252 continue 

1253 non_mapper = is_scalar(v) or (is_list_like(v) and not is_dict_like(v)) 

1254 if non_mapper: 

1255 newnames = v 

1256 else: 

1257 f = common.get_rename_function(v) 

1258 curnames = self._get_axis(axis).names 

1259 newnames = [f(name) for name in curnames] 

1260 result._set_axis_name(newnames, axis=axis, inplace=True) 

1261 if not inplace: 

1262 return result 

1263 return None 

1264 

1265 @overload 

1266 def _set_axis_name( 

1267 self, name, axis: Axis = ..., *, inplace: Literal[False] = ... 

1268 ) -> Self: ... 

1269 

1270 @overload 

1271 def _set_axis_name( 

1272 self, name, axis: Axis = ..., *, inplace: Literal[True] 

1273 ) -> None: ... 

1274 

1275 @overload 

1276 def _set_axis_name( 

1277 self, name, axis: Axis = ..., *, inplace: bool 

1278 ) -> Self | None: ... 

1279 

1280 @final 

1281 def _set_axis_name( 

1282 self, name, axis: Axis = 0, *, inplace: bool = False 

1283 ) -> Self | None: 

1284 """ 

1285 Set the name(s) of the axis. 

1286 

1287 Parameters 

1288 ---------- 

1289 name : str or list of str 

1290 Name(s) to set. 

1291 axis : {0 or 'index', 1 or 'columns'}, default 0 

1292 The axis to set the label. The value 0 or 'index' specifies index, 

1293 and the value 1 or 'columns' specifies columns. 

1294 inplace : bool, default False 

1295 If `True`, do operation inplace and return None. 

1296 

1297 Returns 

1298 ------- 

1299 Series, DataFrame, or None 

1300 The same type as the caller or `None` if `inplace` is `True`. 

1301 

1302 See Also 

1303 -------- 

1304 DataFrame.rename : Alter the axis labels of :class:`DataFrame`. 

1305 Series.rename : Alter the index labels or set the index name 

1306 of :class:`Series`. 

1307 Index.rename : Set the name of :class:`Index` or :class:`MultiIndex`. 

1308 

1309 Examples 

1310 -------- 

1311 >>> df = pd.DataFrame({"num_legs": [4, 4, 2]}, ["dog", "cat", "monkey"]) 

1312 >>> df 

1313 num_legs 

1314 dog 4 

1315 cat 4 

1316 monkey 2 

1317 >>> df._set_axis_name("animal") 

1318 num_legs 

1319 animal 

1320 dog 4 

1321 cat 4 

1322 monkey 2 

1323 >>> df.index = pd.MultiIndex.from_product( 

1324 ... [["mammal"], ["dog", "cat", "monkey"]] 

1325 ... ) 

1326 >>> df._set_axis_name(["type", "name"]) 

1327 num_legs 

1328 type name 

1329 mammal dog 4 

1330 cat 4 

1331 monkey 2 

1332 """ 

1333 axis = self._get_axis_number(axis) 

1334 idx = self._get_axis(axis).set_names(name) 

1335 

1336 inplace = validate_bool_kwarg(inplace, "inplace") 

1337 renamed = self if inplace else self.copy(deep=False) 

1338 if axis == 0: 

1339 renamed.index = idx 

1340 else: 

1341 renamed.columns = idx 

1342 

1343 if not inplace: 

1344 return renamed 

1345 return None 

1346 

1347 # ---------------------------------------------------------------------- 

1348 # Comparison Methods 

1349 

1350 @final 

1351 def _indexed_same(self, other) -> bool: 

1352 return all( 

1353 self._get_axis(a).equals(other._get_axis(a)) for a in self._AXIS_ORDERS 

1354 ) 

1355 

1356 @final 

1357 def equals(self, other: object) -> bool: 

1358 """ 

1359 Test whether two objects contain the same elements. 

1360 

1361 This function allows two Series or DataFrames to be compared against 

1362 each other to see if they have the same shape and elements. NaNs in 

1363 the same location are considered equal. 

1364 

1365 The row/column index do not need to have the same type, as long 

1366 as the values are considered equal. Corresponding columns and 

1367 index must be of the same dtype. 

1368 

1369 Parameters 

1370 ---------- 

1371 other : Series or DataFrame 

1372 The other Series or DataFrame to be compared with the first. 

1373 

1374 Returns 

1375 ------- 

1376 bool 

1377 True if all elements are the same in both objects, False 

1378 otherwise. 

1379 

1380 See Also 

1381 -------- 

1382 Series.eq : Compare two Series objects of the same length 

1383 and return a Series where each element is True if the element 

1384 in each Series is equal, False otherwise. 

1385 DataFrame.eq : Compare two DataFrame objects of the same shape and 

1386 return a DataFrame where each element is True if the respective 

1387 element in each DataFrame is equal, False otherwise. 

1388 testing.assert_series_equal : Raises an AssertionError if left and 

1389 right are not equal. Provides an easy interface to ignore 

1390 inequality in dtypes, indexes and precision among others. 

1391 testing.assert_frame_equal : Like assert_series_equal, but targets 

1392 DataFrames. 

1393 numpy.array_equal : Return True if two arrays have the same shape 

1394 and elements, False otherwise. 

1395 

1396 Examples 

1397 -------- 

1398 >>> df = pd.DataFrame({1: [10], 2: [20]}) 

1399 >>> df 

1400 1 2 

1401 0 10 20 

1402 

1403 DataFrames df and exactly_equal have the same types and values for 

1404 their elements and column labels, which will return True. 

1405 

1406 >>> exactly_equal = pd.DataFrame({1: [10], 2: [20]}) 

1407 >>> exactly_equal 

1408 1 2 

1409 0 10 20 

1410 >>> df.equals(exactly_equal) 

1411 True 

1412 

1413 DataFrames df and different_column_type have the same element 

1414 types and values, but have different types for the column labels, 

1415 which will still return True. 

1416 

1417 >>> different_column_type = pd.DataFrame({1.0: [10], 2.0: [20]}) 

1418 >>> different_column_type 

1419 1.0 2.0 

1420 0 10 20 

1421 >>> df.equals(different_column_type) 

1422 True 

1423 

1424 DataFrames df and different_data_type have different types for the 

1425 same values for their elements, and will return False even though 

1426 their column labels are the same values and types. 

1427 

1428 >>> different_data_type = pd.DataFrame({1: [10.0], 2: [20.0]}) 

1429 >>> different_data_type 

1430 1 2 

1431 0 10.0 20.0 

1432 >>> df.equals(different_data_type) 

1433 False 

1434 

1435 DataFrames with NaN in the same locations compare equal. 

1436 

1437 >>> df_nan1 = pd.DataFrame({"a": [1, np.nan], "b": [3, np.nan]}) 

1438 >>> df_nan2 = pd.DataFrame({"a": [1, np.nan], "b": [3, np.nan]}) 

1439 >>> df_nan1.equals(df_nan2) 

1440 True 

1441 

1442 If the NaN values are not in the same locations, they compare unequal. 

1443 

1444 >>> df_nan3 = pd.DataFrame({"a": [1, np.nan], "b": [3, 4]}) 

1445 >>> df_nan1.equals(df_nan3) 

1446 False 

1447 """ 

1448 if not (isinstance(other, type(self)) or isinstance(self, type(other))): 

1449 return False 

1450 other = cast(NDFrame, other) 

1451 return self._mgr.equals(other._mgr) 

1452 

1453 # ------------------------------------------------------------------------- 

1454 # Unary Methods 

1455 

1456 @final 

1457 def __neg__(self) -> Self: 

1458 def blk_func(values: ArrayLike): 

1459 if is_bool_dtype(values.dtype): 

1460 # error: Argument 1 to "inv" has incompatible type "Union 

1461 # [ExtensionArray, ndarray[Any, Any]]"; expected 

1462 # "_SupportsInversion[ndarray[Any, dtype[bool_]]]" 

1463 return operator.inv(values) # type: ignore[arg-type] 

1464 else: 

1465 # error: Argument 1 to "neg" has incompatible type "Union 

1466 # [ExtensionArray, ndarray[Any, Any]]"; expected 

1467 # "_SupportsNeg[ndarray[Any, dtype[Any]]]" 

1468 return operator.neg(values) # type: ignore[arg-type] 

1469 

1470 new_data = self._mgr.apply(blk_func) 

1471 res = self._constructor_from_mgr(new_data, axes=new_data.axes) 

1472 return res.__finalize__(self, method="__neg__") 

1473 

1474 @final 

1475 def __pos__(self) -> Self: 

1476 def blk_func(values: ArrayLike): 

1477 if is_bool_dtype(values.dtype): 

1478 return values.copy() 

1479 else: 

1480 # error: Argument 1 to "pos" has incompatible type "Union 

1481 # [ExtensionArray, ndarray[Any, Any]]"; expected 

1482 # "_SupportsPos[ndarray[Any, dtype[Any]]]" 

1483 return operator.pos(values) # type: ignore[arg-type] 

1484 

1485 new_data = self._mgr.apply(blk_func) 

1486 res = self._constructor_from_mgr(new_data, axes=new_data.axes) 

1487 return res.__finalize__(self, method="__pos__") 

1488 

1489 @final 

1490 def __invert__(self) -> Self: 

1491 if not self.size: 

1492 # inv fails with 0 len 

1493 return self.copy(deep=False) 

1494 

1495 new_data = self._mgr.apply(operator.invert) 

1496 res = self._constructor_from_mgr(new_data, axes=new_data.axes) 

1497 return res.__finalize__(self, method="__invert__") 

1498 

1499 @final 

1500 def __bool__(self) -> NoReturn: 

1501 raise ValueError( 

1502 f"The truth value of a {type(self).__name__} is ambiguous. " 

1503 "Use a.empty, a.bool(), a.item(), a.any() or a.all()." 

1504 ) 

1505 

1506 @final 

1507 def abs(self) -> Self: 

1508 """ 

1509 Return a Series/DataFrame with absolute numeric value of each element. 

1510 

1511 This function only applies to elements that are all numeric. 

1512 

1513 Returns 

1514 ------- 

1515 abs 

1516 Series/DataFrame containing the absolute value of each element. 

1517 

1518 See Also 

1519 -------- 

1520 numpy.absolute : Calculate the absolute value element-wise. 

1521 

1522 Notes 

1523 ----- 

1524 For ``complex`` inputs, ``1.2 + 1j``, the absolute value is 

1525 :math:`\\sqrt{ a^2 + b^2 }`. 

1526 

1527 Examples 

1528 -------- 

1529 Absolute numeric values in a Series. 

1530 

1531 >>> s = pd.Series([-1.10, 2, -3.33, 4]) 

1532 >>> s.abs() 

1533 0 1.10 

1534 1 2.00 

1535 2 3.33 

1536 3 4.00 

1537 dtype: float64 

1538 

1539 Absolute numeric values in a Series with complex numbers. 

1540 

1541 >>> s = pd.Series([1.2 + 1j]) 

1542 >>> s.abs() 

1543 0 1.56205 

1544 dtype: float64 

1545 

1546 Absolute numeric values in a Series with a Timedelta element. 

1547 

1548 >>> s = pd.Series([pd.Timedelta("1 days")]) 

1549 >>> s.abs() 

1550 0 1 days 

1551 dtype: timedelta64[us] 

1552 

1553 Select rows with data closest to certain value using argsort (from 

1554 `StackOverflow <https://stackoverflow.com/a/17758115>`__). 

1555 

1556 >>> df = pd.DataFrame( 

1557 ... {"a": [4, 5, 6, 7], "b": [10, 20, 30, 40], "c": [100, 50, -30, -50]} 

1558 ... ) 

1559 >>> df 

1560 a b c 

1561 0 4 10 100 

1562 1 5 20 50 

1563 2 6 30 -30 

1564 3 7 40 -50 

1565 >>> df.loc[(df.c - 43).abs().argsort()] 

1566 a b c 

1567 1 5 20 50 

1568 0 4 10 100 

1569 2 6 30 -30 

1570 3 7 40 -50 

1571 """ 

1572 res_mgr = self._mgr.apply(np.abs) 

1573 return self._constructor_from_mgr(res_mgr, axes=res_mgr.axes).__finalize__( 

1574 self, name="abs" 

1575 ) 

1576 

1577 @final 

1578 def __abs__(self) -> Self: 

1579 return self.abs() 

1580 

1581 @final 

1582 def __round__(self, decimals: int = 0) -> Self: 

1583 return self.round(decimals).__finalize__(self, method="__round__") 

1584 

1585 # ------------------------------------------------------------------------- 

1586 # Label or Level Combination Helpers 

1587 # 

1588 # A collection of helper methods for DataFrame/Series operations that 

1589 # accept a combination of column/index labels and levels. All such 

1590 # operations should utilize/extend these methods when possible so that we 

1591 # have consistent precedence and validation logic throughout the library. 

1592 

1593 @final 

1594 def _is_level_reference(self, key: Level, axis: Axis = 0) -> bool: 

1595 """ 

1596 Test whether a key is a level reference for a given axis. 

1597 

1598 To be considered a level reference, `key` must be a string that: 

1599 - (axis=0): Matches the name of an index level and does NOT match 

1600 a column label. 

1601 - (axis=1): Matches the name of a column level and does NOT match 

1602 an index label. 

1603 

1604 Parameters 

1605 ---------- 

1606 key : Hashable 

1607 Potential level name for the given axis 

1608 axis : int, default 0 

1609 Axis that levels are associated with (0 for index, 1 for columns) 

1610 

1611 Returns 

1612 ------- 

1613 is_level : bool 

1614 """ 

1615 axis_int = self._get_axis_number(axis) 

1616 

1617 return ( 

1618 key is not None 

1619 and is_hashable(key) 

1620 and key in self.axes[axis_int].names 

1621 and not self._is_label_reference(key, axis=axis_int) 

1622 ) 

1623 

1624 @final 

1625 def _is_label_reference(self, key: Level, axis: Axis = 0) -> bool: 

1626 """ 

1627 Test whether a key is a label reference for a given axis. 

1628 

1629 To be considered a label reference, `key` must be a string that: 

1630 - (axis=0): Matches a column label 

1631 - (axis=1): Matches an index label 

1632 

1633 Parameters 

1634 ---------- 

1635 key : Hashable 

1636 Potential label name, i.e. Index entry. 

1637 axis : int, default 0 

1638 Axis perpendicular to the axis that labels are associated with 

1639 (0 means search for column labels, 1 means search for index labels) 

1640 

1641 Returns 

1642 ------- 

1643 is_label: bool 

1644 """ 

1645 axis_int = self._get_axis_number(axis) 

1646 other_axes = (ax for ax in range(self._AXIS_LEN) if ax != axis_int) 

1647 

1648 return is_hashable(key) and any(key in self.axes[ax] for ax in other_axes) 

1649 

1650 @final 

1651 def _is_label_or_level_reference(self, key: Level, axis: AxisInt = 0) -> bool: 

1652 """ 

1653 Test whether a key is a label or level reference for a given axis. 

1654 

1655 To be considered either a label or a level reference, `key` must be a 

1656 string that: 

1657 - (axis=0): Matches a column label or an index level 

1658 - (axis=1): Matches an index label or a column level 

1659 

1660 Parameters 

1661 ---------- 

1662 key : Hashable 

1663 Potential label or level name 

1664 axis : int, default 0 

1665 Axis that levels are associated with (0 for index, 1 for columns) 

1666 

1667 Returns 

1668 ------- 

1669 bool 

1670 """ 

1671 return self._is_level_reference(key, axis=axis) or self._is_label_reference( 

1672 key, axis=axis 

1673 ) 

1674 

1675 @final 

1676 def _check_label_or_level_ambiguity(self, key: Level, axis: Axis = 0) -> None: 

1677 """ 

1678 Check whether `key` is ambiguous. 

1679 

1680 By ambiguous, we mean that it matches both a level of the input 

1681 `axis` and a label of the other axis. 

1682 

1683 Parameters 

1684 ---------- 

1685 key : Hashable 

1686 Label or level name. 

1687 axis : int, default 0 

1688 Axis that levels are associated with (0 for index, 1 for columns). 

1689 

1690 Raises 

1691 ------ 

1692 ValueError: `key` is ambiguous 

1693 """ 

1694 

1695 axis_int = self._get_axis_number(axis) 

1696 other_axes = (ax for ax in range(self._AXIS_LEN) if ax != axis_int) 

1697 

1698 if ( 

1699 key is not None 

1700 and is_hashable(key) 

1701 and key in self.axes[axis_int].names 

1702 and any(key in self.axes[ax] for ax in other_axes) 

1703 ): 

1704 # Build an informative and grammatical warning 

1705 level_article, level_type = ( 

1706 ("an", "index") if axis_int == 0 else ("a", "column") 

1707 ) 

1708 

1709 label_article, label_type = ( 

1710 ("a", "column") if axis_int == 0 else ("an", "index") 

1711 ) 

1712 

1713 msg = ( 

1714 f"'{key}' is both {level_article} {level_type} level and " 

1715 f"{label_article} {label_type} label, which is ambiguous." 

1716 ) 

1717 raise ValueError(msg) 

1718 

1719 @final 

1720 def _get_label_or_level_values(self, key: Level, axis: AxisInt = 0) -> ArrayLike: 

1721 """ 

1722 Return a 1-D array of values associated with `key`, a label or level 

1723 from the given `axis`. 

1724 

1725 Retrieval logic: 

1726 - (axis=0): Return column values if `key` matches a column label. 

1727 Otherwise return index level values if `key` matches an index 

1728 level. 

1729 - (axis=1): Return row values if `key` matches an index label. 

1730 Otherwise return column level values if 'key' matches a column 

1731 level 

1732 

1733 Parameters 

1734 ---------- 

1735 key : Hashable 

1736 Label or level name. 

1737 axis : int, default 0 

1738 Axis that levels are associated with (0 for index, 1 for columns) 

1739 

1740 Returns 

1741 ------- 

1742 np.ndarray or ExtensionArray 

1743 

1744 Raises 

1745 ------ 

1746 KeyError 

1747 if `key` matches neither a label nor a level 

1748 ValueError 

1749 if `key` matches multiple labels 

1750 """ 

1751 axis = self._get_axis_number(axis) 

1752 first_other_axes = next( 

1753 (ax for ax in range(self._AXIS_LEN) if ax != axis), None 

1754 ) 

1755 

1756 if self._is_label_reference(key, axis=axis): 

1757 self._check_label_or_level_ambiguity(key, axis=axis) 

1758 if first_other_axes is None: 

1759 raise ValueError("axis matched all axes") 

1760 values = self.xs(key, axis=first_other_axes)._values 

1761 elif self._is_level_reference(key, axis=axis): 

1762 values = self.axes[axis].get_level_values(key)._values 

1763 else: 

1764 raise KeyError(key) 

1765 

1766 # Check for duplicates 

1767 if values.ndim > 1: 

1768 if first_other_axes is not None and isinstance( 

1769 self._get_axis(first_other_axes), MultiIndex 

1770 ): 

1771 multi_message = ( 

1772 "\n" 

1773 "For a multi-index, the label must be a " 

1774 "tuple with elements corresponding to each level." 

1775 ) 

1776 else: 

1777 multi_message = "" 

1778 

1779 label_axis_name = "column" if axis == 0 else "index" 

1780 raise ValueError( 

1781 f"The {label_axis_name} label '{key}' is not unique.{multi_message}" 

1782 ) 

1783 

1784 return values 

1785 

1786 @final 

1787 def _drop_labels_or_levels(self, keys, axis: AxisInt = 0): 

1788 """ 

1789 Drop labels and/or levels for the given `axis`. 

1790 

1791 For each key in `keys`: 

1792 - (axis=0): If key matches a column label then drop the column. 

1793 Otherwise if key matches an index level then drop the level. 

1794 - (axis=1): If key matches an index label then drop the row. 

1795 Otherwise if key matches a column level then drop the level. 

1796 

1797 Parameters 

1798 ---------- 

1799 keys : str or list of str 

1800 labels or levels to drop 

1801 axis : int, default 0 

1802 Axis that levels are associated with (0 for index, 1 for columns) 

1803 

1804 Returns 

1805 ------- 

1806 dropped: DataFrame 

1807 

1808 Raises 

1809 ------ 

1810 ValueError 

1811 if any `keys` match neither a label nor a level 

1812 """ 

1813 axis = self._get_axis_number(axis) 

1814 

1815 # Validate keys 

1816 keys = common.maybe_make_list(keys) 

1817 invalid_keys = [ 

1818 k for k in keys if not self._is_label_or_level_reference(k, axis=axis) 

1819 ] 

1820 

1821 if invalid_keys: 

1822 raise ValueError( 

1823 "The following keys are not valid labels or " 

1824 f"levels for axis {axis}: {invalid_keys}" 

1825 ) 

1826 

1827 # Compute levels and labels to drop 

1828 levels_to_drop = [k for k in keys if self._is_level_reference(k, axis=axis)] 

1829 

1830 labels_to_drop = [k for k in keys if not self._is_level_reference(k, axis=axis)] 

1831 

1832 # Perform copy upfront and then use inplace operations below. 

1833 # This ensures that we always perform exactly one copy. 

1834 # ``copy`` and/or ``inplace`` options could be added in the future. 

1835 dropped = self.copy(deep=False) 

1836 

1837 if axis == 0: 

1838 # Handle dropping index levels 

1839 if levels_to_drop: 

1840 dropped.reset_index(levels_to_drop, drop=True, inplace=True) 

1841 

1842 # Handle dropping columns labels 

1843 if labels_to_drop: 

1844 dropped.drop(labels_to_drop, axis=1, inplace=True) 

1845 else: 

1846 # Handle dropping column levels 

1847 if levels_to_drop: 

1848 if isinstance(dropped.columns, MultiIndex): 

1849 # Drop the specified levels from the MultiIndex 

1850 dropped.columns = dropped.columns.droplevel(levels_to_drop) 

1851 else: 

1852 # Drop the last level of Index by replacing with 

1853 # a RangeIndex 

1854 dropped.columns = default_index(dropped.columns.size) 

1855 

1856 # Handle dropping index labels 

1857 if labels_to_drop: 

1858 dropped.drop(labels_to_drop, axis=0, inplace=True) 

1859 

1860 return dropped 

1861 

1862 # ---------------------------------------------------------------------- 

1863 # Iteration 

1864 

1865 # https://github.com/python/typeshed/issues/2148#issuecomment-520783318 

1866 # Incompatible types in assignment (expression has type "None", base class 

1867 # "object" defined the type as "Callable[[object], int]") 

1868 __hash__: ClassVar[None] # type: ignore[assignment] 

1869 

1870 def __iter__(self) -> Iterator: 

1871 """ 

1872 Iterate over info axis. 

1873 

1874 Returns 

1875 ------- 

1876 iterator 

1877 Info axis as iterator. 

1878 

1879 See Also 

1880 -------- 

1881 DataFrame.items : Iterate over (column name, Series) pairs. 

1882 DataFrame.itertuples : Iterate over DataFrame rows as namedtuples. 

1883 

1884 Examples 

1885 -------- 

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

1887 >>> for x in df: 

1888 ... print(x) 

1889 A 

1890 B 

1891 """ 

1892 return iter(self._info_axis) 

1893 

1894 # can we get a better explanation of this? 

1895 def keys(self) -> Index: 

1896 """ 

1897 Get the 'info axis' (see Indexing for more). 

1898 

1899 This is index for Series, columns for DataFrame. 

1900 

1901 Returns 

1902 ------- 

1903 Index 

1904 Info axis. 

1905 

1906 See Also 

1907 -------- 

1908 DataFrame.index : The index (row labels) of the DataFrame. 

1909 DataFrame.columns: The column labels of the DataFrame. 

1910 

1911 Examples 

1912 -------- 

1913 >>> d = pd.DataFrame( 

1914 ... data={"A": [1, 2, 3], "B": [0, 4, 8]}, index=["a", "b", "c"] 

1915 ... ) 

1916 >>> d 

1917 A B 

1918 a 1 0 

1919 b 2 4 

1920 c 3 8 

1921 >>> d.keys() 

1922 Index(['A', 'B'], dtype='str') 

1923 """ 

1924 return self._info_axis 

1925 

1926 def items(self): 

1927 """ 

1928 Iterate over (label, values) on info axis 

1929 

1930 This is index for Series and columns for DataFrame. 

1931 

1932 Returns 

1933 ------- 

1934 Generator 

1935 """ 

1936 for h in self._info_axis: 

1937 yield h, self[h] 

1938 

1939 def __len__(self) -> int: 

1940 """Returns length of info axis""" 

1941 return len(self._info_axis) 

1942 

1943 @final 

1944 def __contains__(self, key) -> bool: 

1945 """True if the key is in the info axis""" 

1946 return key in self._info_axis 

1947 

1948 @property 

1949 def empty(self) -> bool: 

1950 """ 

1951 Indicator whether Series/DataFrame is empty. 

1952 

1953 True if Series/DataFrame is entirely empty (no items), meaning any of the 

1954 axes are of length 0. 

1955 

1956 Returns 

1957 ------- 

1958 bool 

1959 If Series/DataFrame is empty, return True, if not return False. 

1960 

1961 See Also 

1962 -------- 

1963 Series.dropna : Return series without null values. 

1964 DataFrame.dropna : Return DataFrame with labels on given axis omitted 

1965 where (all or any) data are missing. 

1966 

1967 Notes 

1968 ----- 

1969 If Series/DataFrame contains only NaNs, it is still not considered empty. See 

1970 the example below. 

1971 

1972 Examples 

1973 -------- 

1974 An example of an actual empty DataFrame. Notice the index is empty: 

1975 

1976 >>> df_empty = pd.DataFrame({"A": []}) 

1977 >>> df_empty 

1978 Empty DataFrame 

1979 Columns: [A] 

1980 Index: [] 

1981 >>> df_empty.empty 

1982 True 

1983 

1984 If we only have NaNs in our DataFrame, it is not considered empty! We 

1985 will need to drop the NaNs to make the DataFrame empty: 

1986 

1987 >>> df = pd.DataFrame({"A": [np.nan]}) 

1988 >>> df 

1989 A 

1990 0 NaN 

1991 >>> df.empty 

1992 False 

1993 >>> df.dropna().empty 

1994 True 

1995 

1996 >>> ser_empty = pd.Series({"A": []}) 

1997 >>> ser_empty 

1998 A [] 

1999 dtype: object 

2000 >>> ser_empty.empty 

2001 False 

2002 >>> ser_empty = pd.Series() 

2003 >>> ser_empty.empty 

2004 True 

2005 """ 

2006 return any(len(self._get_axis(a)) == 0 for a in self._AXIS_ORDERS) 

2007 

2008 # ---------------------------------------------------------------------- 

2009 # Array Interface 

2010 

2011 # This is also set in IndexOpsMixin 

2012 # GH#23114 Ensure ndarray.__op__(DataFrame) returns NotImplemented 

2013 __array_priority__: int = 1000 

2014 

2015 def __array__( 

2016 self, dtype: npt.DTypeLike | None = None, copy: bool | None = None 

2017 ) -> np.ndarray: 

2018 if copy is False and not self._mgr.is_single_block and not self.empty: 

2019 # check this manually, otherwise ._values will already return a copy 

2020 # and np.array(values, copy=False) will not raise an error 

2021 raise ValueError( 

2022 "Unable to avoid copy while creating an array as requested." 

2023 ) 

2024 values = self._values 

2025 if copy is None: 

2026 # Note: branch avoids `copy=None` for NumPy 1.x support 

2027 arr = np.asarray(values, dtype=dtype) 

2028 else: 

2029 arr = np.array(values, dtype=dtype, copy=copy) 

2030 

2031 if ( 

2032 copy is not True 

2033 and astype_is_view(values.dtype, arr.dtype) 

2034 and self._mgr.is_single_block 

2035 ): 

2036 # Check if both conversions can be done without a copy 

2037 if astype_is_view(self.dtypes.iloc[0], values.dtype) and astype_is_view( 

2038 values.dtype, arr.dtype 

2039 ): 

2040 arr = arr.view() 

2041 arr.flags.writeable = False 

2042 return arr 

2043 

2044 @final 

2045 def __array_ufunc__( 

2046 self, ufunc: np.ufunc, method: str, *inputs: Any, **kwargs: Any 

2047 ): 

2048 return arraylike.array_ufunc(self, ufunc, method, *inputs, **kwargs) 

2049 

2050 # ---------------------------------------------------------------------- 

2051 # Picklability 

2052 

2053 @final 

2054 def __getstate__(self) -> dict[str, Any]: 

2055 meta = {k: getattr(self, k, None) for k in self._metadata} 

2056 return { 

2057 "_mgr": self._mgr, 

2058 "_typ": self._typ, 

2059 "_metadata": self._metadata, 

2060 "attrs": self.attrs, 

2061 "_flags": {k: self.flags[k] for k in self.flags._keys}, 

2062 **meta, 

2063 } 

2064 

2065 @final 

2066 def __setstate__(self, state) -> None: 

2067 if isinstance(state, BlockManager): 

2068 self._mgr = state 

2069 elif isinstance(state, dict): 

2070 if "_data" in state and "_mgr" not in state: 

2071 # compat for older pickles 

2072 state["_mgr"] = state.pop("_data") 

2073 typ = state.get("_typ") 

2074 if typ is not None: 

2075 attrs = state.get("_attrs", {}) 

2076 if attrs is None: # should not happen, but better be on the safe side 

2077 attrs = {} 

2078 object.__setattr__(self, "_attrs", attrs) 

2079 flags = state.get("_flags", {"allows_duplicate_labels": True}) 

2080 object.__setattr__(self, "_flags", Flags(self, **flags)) 

2081 

2082 # set in the order of internal names 

2083 # to avoid definitional recursion 

2084 # e.g. say fill_value needing _mgr to be 

2085 # defined 

2086 meta = set(self._internal_names + self._metadata) 

2087 for k in meta: 

2088 if k in state and k != "_flags": 

2089 v = state[k] 

2090 object.__setattr__(self, k, v) 

2091 

2092 for k, v in state.items(): 

2093 if k not in meta: 

2094 object.__setattr__(self, k, v) 

2095 

2096 else: 

2097 raise NotImplementedError("Pre-0.12 pickles are no longer supported") 

2098 elif len(state) == 2: 

2099 raise NotImplementedError("Pre-0.12 pickles are no longer supported") 

2100 

2101 # ---------------------------------------------------------------------- 

2102 # Rendering Methods 

2103 

2104 def __repr__(self) -> str: 

2105 # string representation based upon iterating over self 

2106 # (since, by definition, `PandasContainers` are iterable) 

2107 prepr = f"[{','.join(map(pprint_thing, self))}]" 

2108 return f"{type(self).__name__}({prepr})" 

2109 

2110 @final 

2111 def _repr_latex_(self): 

2112 """ 

2113 Returns a LaTeX representation for a particular object. 

2114 Mainly for use with nbconvert (jupyter notebook conversion to pdf). 

2115 """ 

2116 if config.get_option("styler.render.repr") == "latex": 

2117 return self.to_latex() 

2118 else: 

2119 return None 

2120 

2121 @final 

2122 def _repr_data_resource_(self): 

2123 """ 

2124 Not a real Jupyter special repr method, but we use the same 

2125 naming convention. 

2126 """ 

2127 if config.get_option("display.html.table_schema"): 

2128 data = self.head(config.get_option("display.max_rows")) 

2129 

2130 as_json = data.to_json(orient="table") 

2131 as_json = cast(str, as_json) 

2132 return loads(as_json, object_pairs_hook=collections.OrderedDict) 

2133 

2134 # ---------------------------------------------------------------------- 

2135 # I/O Methods 

2136 

2137 @final 

2138 def to_excel( 

2139 self, 

2140 excel_writer: FilePath | WriteExcelBuffer | ExcelWriter, 

2141 *, 

2142 sheet_name: str = "Sheet1", 

2143 na_rep: str = "", 

2144 float_format: str | None = None, 

2145 columns: Sequence[Hashable] | None = None, 

2146 header: Sequence[Hashable] | bool = True, 

2147 index: bool = True, 

2148 index_label: IndexLabel | None = None, 

2149 startrow: int = 0, 

2150 startcol: int = 0, 

2151 engine: Literal["openpyxl", "xlsxwriter"] | None = None, 

2152 merge_cells: bool = True, 

2153 inf_rep: str = "inf", 

2154 freeze_panes: tuple[int, int] | None = None, 

2155 storage_options: StorageOptions | None = None, 

2156 engine_kwargs: dict[str, Any] | None = None, 

2157 autofilter: bool = False, 

2158 ) -> None: 

2159 """ 

2160 Write object to an Excel sheet. 

2161 

2162 To write a single object to an Excel .xlsx file it is only necessary to 

2163 specify a target file name. To write to multiple sheets it is necessary to 

2164 create an `ExcelWriter` object with a target file name, and specify a sheet 

2165 in the file to write to. 

2166 

2167 Multiple sheets may be written to by specifying unique `sheet_name`. 

2168 With all data written to the file it is necessary to save the changes. 

2169 Note that creating an `ExcelWriter` object with a file name that already exists 

2170 will overwrite the existing file because the default mode is write. 

2171 

2172 Parameters 

2173 ---------- 

2174 excel_writer : path-like, file-like, or ExcelWriter object 

2175 File path or existing ExcelWriter. 

2176 sheet_name : str, default 'Sheet1' 

2177 Name of sheet which will contain DataFrame. 

2178 na_rep : str, default '' 

2179 Missing data representation. 

2180 float_format : str, optional 

2181 Format string for floating point numbers. For example 

2182 ``float_format="%.2f"`` will format 0.1234 to 0.12. 

2183 columns : sequence or list of str, optional 

2184 Columns to write. 

2185 header : bool or list of str, default True 

2186 Write out the column names. If a list of string is given it is 

2187 assumed to be aliases for the column names. 

2188 index : bool, default True 

2189 Write row names (index). 

2190 index_label : str or sequence, optional 

2191 Column label for index column(s) if desired. If not specified, and 

2192 `header` and `index` are True, then the index names are used. A 

2193 sequence should be given if the DataFrame uses MultiIndex. 

2194 startrow : int, default 0 

2195 Upper left cell row to dump data frame. 

2196 startcol : int, default 0 

2197 Upper left cell column to dump data frame. 

2198 engine : str, optional 

2199 Write engine to use, 'openpyxl' or 'xlsxwriter'. You can also set this 

2200 via the options ``io.excel.xlsx.writer`` or 

2201 ``io.excel.xlsm.writer``. 

2202 merge_cells : bool or 'columns', default False 

2203 If True, write MultiIndex index and columns as merged cells. 

2204 If 'columns', merge MultiIndex column cells only. 

2205 inf_rep : str, default 'inf' 

2206 Representation for infinity (there is no native representation for 

2207 infinity in Excel). 

2208 freeze_panes : tuple of int (length 2), optional 

2209 Specifies the one-based bottommost row and rightmost column that 

2210 is to be frozen. 

2211 storage_options : dict, optional 

2212 Extra options that make sense for a particular storage connection, e.g. 

2213 host, port, username, password, etc. For HTTP(S) URLs the key-value pairs 

2214 are forwarded to ``urllib.request.Request`` as header options. For other 

2215 URLs (e.g. starting with "s3://", and "gcs://") the key-value pairs are 

2216 forwarded to ``fsspec.open``. Please see ``fsspec`` and ``urllib`` for more 

2217 details, and for more examples on storage options refer `here 

2218 <https://pandas.pydata.org/docs/user_guide/io.html? 

2219 highlight=storage_options#reading-writing-remote-files>`_. 

2220 

2221 engine_kwargs : dict, optional 

2222 Arbitrary keyword arguments passed to excel engine. 

2223 autofilter : bool, default False 

2224 If True, add automatic filters to all columns. 

2225 

2226 See Also 

2227 -------- 

2228 to_csv : Write DataFrame to a comma-separated values (csv) file. 

2229 ExcelWriter : Class for writing DataFrame objects into excel sheets. 

2230 read_excel : Read an Excel file into a pandas DataFrame. 

2231 read_csv : Read a comma-separated values (csv) file into DataFrame. 

2232 io.formats.style.Styler.to_excel : Add styles to Excel sheet. 

2233 

2234 Notes 

2235 ----- 

2236 For compatibility with :meth:`~DataFrame.to_csv`, 

2237 to_excel serializes lists and dicts to strings before writing. 

2238 

2239 Once a workbook has been saved it is not possible to write further 

2240 data without rewriting the whole workbook. 

2241 

2242 pandas will check the number of rows, columns, 

2243 and cell character count does not exceed Excel's limitations. 

2244 All other limitations must be checked by the user. 

2245 

2246 Examples 

2247 -------- 

2248 

2249 Create, write to and save a workbook: 

2250 

2251 >>> df1 = pd.DataFrame( 

2252 ... [["a", "b"], ["c", "d"]], 

2253 ... index=["row 1", "row 2"], 

2254 ... columns=["col 1", "col 2"], 

2255 ... ) 

2256 >>> df1.to_excel("output.xlsx") # doctest: +SKIP 

2257 

2258 To specify the sheet name: 

2259 

2260 >>> df1.to_excel("output.xlsx", sheet_name="Sheet_name_1") # doctest: +SKIP 

2261 

2262 If you wish to write to more than one sheet in the workbook, it is 

2263 necessary to specify an ExcelWriter object: 

2264 

2265 >>> df2 = df1.copy() 

2266 >>> with pd.ExcelWriter("output.xlsx") as writer: # doctest: +SKIP 

2267 ... df1.to_excel(writer, sheet_name="Sheet_name_1") 

2268 ... df2.to_excel(writer, sheet_name="Sheet_name_2") 

2269 

2270 ExcelWriter can also be used to append to an existing Excel file: 

2271 

2272 >>> with pd.ExcelWriter("output.xlsx", mode="a") as writer: # doctest: +SKIP 

2273 ... df1.to_excel(writer, sheet_name="Sheet_name_3") 

2274 

2275 To set the library that is used to write the Excel file, 

2276 you can pass the `engine` keyword (the default engine is 

2277 automatically chosen depending on the file extension): 

2278 

2279 >>> df1.to_excel("output1.xlsx", engine="xlsxwriter") # doctest: +SKIP 

2280 """ 

2281 if engine_kwargs is None: 

2282 engine_kwargs = {} 

2283 

2284 df = self if isinstance(self, ABCDataFrame) else self.to_frame() 

2285 

2286 from pandas.io.formats.excel import ExcelFormatter 

2287 

2288 formatter = ExcelFormatter( 

2289 df, 

2290 na_rep=na_rep, 

2291 cols=columns, 

2292 header=header, 

2293 float_format=float_format, 

2294 index=index, 

2295 index_label=index_label, 

2296 merge_cells=merge_cells, 

2297 inf_rep=inf_rep, 

2298 autofilter=autofilter, 

2299 ) 

2300 formatter.write( 

2301 excel_writer, 

2302 sheet_name=sheet_name, 

2303 startrow=startrow, 

2304 startcol=startcol, 

2305 freeze_panes=freeze_panes, 

2306 engine=engine, 

2307 storage_options=storage_options, 

2308 engine_kwargs=engine_kwargs, 

2309 ) 

2310 

2311 @final 

2312 def to_json( 

2313 self, 

2314 path_or_buf: FilePath | WriteBuffer[bytes] | WriteBuffer[str] | None = None, 

2315 *, 

2316 orient: Literal["split", "records", "index", "table", "columns", "values"] 

2317 | None = None, 

2318 date_format: str | None = None, 

2319 double_precision: int = 10, 

2320 force_ascii: bool = True, 

2321 date_unit: TimeUnit = "ms", 

2322 default_handler: Callable[[Any], JSONSerializable] | None = None, 

2323 lines: bool = False, 

2324 compression: CompressionOptions = "infer", 

2325 index: bool | None = None, 

2326 indent: int | None = None, 

2327 storage_options: StorageOptions | None = None, 

2328 mode: Literal["a", "w"] = "w", 

2329 ) -> str | None: 

2330 """ 

2331 Convert the object to a JSON string. 

2332 

2333 Note NaN's and None will be converted to null and datetime objects 

2334 will be converted to UNIX timestamps. 

2335 

2336 Parameters 

2337 ---------- 

2338 path_or_buf : str, path object, file-like object, or None, default None 

2339 String, path object (implementing os.PathLike[str]), or file-like 

2340 object implementing a write() function. If None, the result is 

2341 returned as a string. 

2342 orient : str 

2343 Indication of expected JSON string format. 

2344 

2345 * Series: 

2346 

2347 - default is 'index' 

2348 - allowed values are: {'split', 'records', 'index', 'table'}. 

2349 

2350 * DataFrame: 

2351 

2352 - default is 'columns' 

2353 - allowed values are: {'split', 'records', 'index', 'columns', 

2354 'values', 'table'}. 

2355 

2356 * The format of the JSON string: 

2357 

2358 - 'split' : dict like {'index' -> [index], 'columns' -> [columns], 

2359 'data' -> [values]} 

2360 - 'records' : list like [{column -> value}, ... , {column -> value}] 

2361 - 'index' : dict like {index -> {column -> value}} 

2362 - 'columns' : dict like {column -> {index -> value}} 

2363 - 'values' : just the values array 

2364 - 'table' : dict like {'schema': {schema}, 'data': {data}} 

2365 

2366 Describing the data, where data component is like ``orient='records'``. 

2367 

2368 date_format : {None, 'epoch', 'iso'} 

2369 Type of date conversion. 'epoch' = epoch milliseconds, 

2370 'iso' = ISO8601. The default depends on the `orient`. For 

2371 ``orient='table'``, the default is 'iso'. For all other orients, 

2372 the default is 'epoch'. 

2373 

2374 .. deprecated:: 3.0.0 

2375 'epoch' date format is deprecated and will be removed in a future 

2376 version, please use 'iso' instead. 

2377 

2378 double_precision : int, default 10 

2379 The number of decimal places to use when encoding 

2380 floating point values. The possible maximal value is 15. 

2381 Passing double_precision greater than 15 will raise a ValueError. 

2382 force_ascii : bool, default True 

2383 Force encoded string to be ASCII. 

2384 date_unit : str, default 'ms' (milliseconds) 

2385 The time unit to encode to, governs timestamp and ISO8601 

2386 precision. One of 's', 'ms', 'us', 'ns' for second, millisecond, 

2387 microsecond, and nanosecond respectively. 

2388 default_handler : callable, default None 

2389 Handler to call if object cannot otherwise be converted to a 

2390 suitable format for JSON. Should receive a single argument which is 

2391 the object to convert and return a serialisable object. 

2392 lines : bool, default False 

2393 If 'orient' is 'records' write out line-delimited json format. Will 

2394 throw ValueError if incorrect 'orient' since others are not 

2395 list-like. 

2396 

2397 compression : str or dict, default 'infer' 

2398 For on-the-fly compression of the output data. If 'infer' and 

2399 'path_or_buf' is path-like, then detect compression from the following 

2400 extensions: '.gz', 

2401 '.bz2', '.zip', '.xz', '.zst', '.tar', '.tar.gz', '.tar.xz' or '.tar.bz2' 

2402 (otherwise no compression). 

2403 Set to ``None`` for no compression. 

2404 Can also be a dict with key ``'method'`` set to one of 

2405 {``'zip'``, ``'gzip'``, ``'bz2'``, ``'zstd'``, ``'xz'``, ``'tar'``} and 

2406 other key-value pairs are forwarded to 

2407 ``zipfile.ZipFile``, ``gzip.GzipFile``, 

2408 ``bz2.BZ2File``, ``zstandard.ZstdCompressor``, ``lzma.LZMAFile`` or 

2409 ``tarfile.TarFile``, respectively. 

2410 As an example, the following could be passed for faster compression and 

2411 to create a reproducible gzip archive: 

2412 ``compression={'method': 'gzip', 'compresslevel': 1, 'mtime': 1}``. 

2413 

2414 index : bool or None, default None 

2415 The index is only used when 'orient' is 'split', 'index', 'column', 

2416 or 'table'. Of these, 'index' and 'column' do not support 

2417 `index=False`. The string 'index' as a column name with empty :class:`Index` 

2418 or if it is 'index' will raise a ``ValueError``. 

2419 

2420 indent : int, optional 

2421 Length of whitespace used to indent each record. 

2422 

2423 storage_options : dict, optional 

2424 Extra options that make sense for a particular storage connection, e.g. 

2425 host, port, username, password, etc. For HTTP(S) URLs the key-value pairs 

2426 are forwarded to ``urllib.request.Request`` as header options. For other 

2427 URLs (e.g. starting with "s3://", and "gcs://") the key-value pairs are 

2428 forwarded to ``fsspec.open``. Please see ``fsspec`` and ``urllib`` for more 

2429 details, and for more examples on storage options refer `here 

2430 <https://pandas.pydata.org/docs/user_guide/io.html? 

2431 highlight=storage_options#reading-writing-remote-files>`_. 

2432 

2433 mode : str, default 'w' (writing) 

2434 Specify the IO mode for output when supplying a path_or_buf. 

2435 Accepted args are 'w' (writing) and 'a' (append) only. 

2436 mode='a' is only supported when lines is True and orient is 'records'. 

2437 

2438 Returns 

2439 ------- 

2440 None or str 

2441 If path_or_buf is None, returns the resulting json format as a 

2442 string. Otherwise returns None. 

2443 

2444 See Also 

2445 -------- 

2446 read_json : Convert a JSON string to pandas object. 

2447 

2448 Notes 

2449 ----- 

2450 The behavior of ``indent=0`` varies from the stdlib, which does not 

2451 indent the output but does insert newlines. Currently, ``indent=0`` 

2452 and the default ``indent=None`` are equivalent in pandas, though this 

2453 may change in a future release. 

2454 

2455 ``orient='table'`` contains a 'pandas_version' field under 'schema'. 

2456 This stores the version of `pandas` used in the latest revision of the 

2457 schema. 

2458 

2459 Examples 

2460 -------- 

2461 >>> from json import loads, dumps 

2462 >>> df = pd.DataFrame( 

2463 ... [["a", "b"], ["c", "d"]], 

2464 ... index=["row 1", "row 2"], 

2465 ... columns=["col 1", "col 2"], 

2466 ... ) 

2467 

2468 >>> result = df.to_json(orient="split") 

2469 >>> parsed = loads(result) 

2470 >>> dumps(parsed, indent=4) # doctest: +SKIP 

2471 { 

2472 "columns": [ 

2473 "col 1", 

2474 "col 2" 

2475 ], 

2476 "index": [ 

2477 "row 1", 

2478 "row 2" 

2479 ], 

2480 "data": [ 

2481 [ 

2482 "a", 

2483 "b" 

2484 ], 

2485 [ 

2486 "c", 

2487 "d" 

2488 ] 

2489 ] 

2490 } 

2491 

2492 Encoding/decoding a Dataframe using ``'records'`` formatted JSON. 

2493 Note that index labels are not preserved with this encoding. 

2494 

2495 >>> result = df.to_json(orient="records") 

2496 >>> parsed = loads(result) 

2497 >>> dumps(parsed, indent=4) # doctest: +SKIP 

2498 [ 

2499 { 

2500 "col 1": "a", 

2501 "col 2": "b" 

2502 }, 

2503 { 

2504 "col 1": "c", 

2505 "col 2": "d" 

2506 } 

2507 ] 

2508 

2509 Encoding/decoding a Dataframe using ``'index'`` formatted JSON: 

2510 

2511 >>> result = df.to_json(orient="index") 

2512 >>> parsed = loads(result) 

2513 >>> dumps(parsed, indent=4) # doctest: +SKIP 

2514 { 

2515 "row 1": { 

2516 "col 1": "a", 

2517 "col 2": "b" 

2518 }, 

2519 "row 2": { 

2520 "col 1": "c", 

2521 "col 2": "d" 

2522 } 

2523 } 

2524 

2525 Encoding/decoding a Dataframe using ``'columns'`` formatted JSON: 

2526 

2527 >>> result = df.to_json(orient="columns") 

2528 >>> parsed = loads(result) 

2529 >>> dumps(parsed, indent=4) # doctest: +SKIP 

2530 { 

2531 "col 1": { 

2532 "row 1": "a", 

2533 "row 2": "c" 

2534 }, 

2535 "col 2": { 

2536 "row 1": "b", 

2537 "row 2": "d" 

2538 } 

2539 } 

2540 

2541 Encoding/decoding a Dataframe using ``'values'`` formatted JSON: 

2542 

2543 >>> result = df.to_json(orient="values") 

2544 >>> parsed = loads(result) 

2545 >>> dumps(parsed, indent=4) # doctest: +SKIP 

2546 [ 

2547 [ 

2548 "a", 

2549 "b" 

2550 ], 

2551 [ 

2552 "c", 

2553 "d" 

2554 ] 

2555 ] 

2556 

2557 Encoding with Table Schema: 

2558 

2559 >>> result = df.to_json(orient="table") 

2560 >>> parsed = loads(result) 

2561 >>> dumps(parsed, indent=4) # doctest: +SKIP 

2562 { 

2563 "schema": { 

2564 "fields": [ 

2565 { 

2566 "name": "index", 

2567 "type": "string" 

2568 }, 

2569 { 

2570 "name": "col 1", 

2571 "type": "string" 

2572 }, 

2573 { 

2574 "name": "col 2", 

2575 "type": "string" 

2576 } 

2577 ], 

2578 "primaryKey": [ 

2579 "index" 

2580 ], 

2581 "pandas_version": "1.4.0" 

2582 }, 

2583 "data": [ 

2584 { 

2585 "index": "row 1", 

2586 "col 1": "a", 

2587 "col 2": "b" 

2588 }, 

2589 { 

2590 "index": "row 2", 

2591 "col 1": "c", 

2592 "col 2": "d" 

2593 } 

2594 ] 

2595 } 

2596 """ 

2597 from pandas.io import json 

2598 

2599 if date_format is None and orient == "table": 

2600 date_format = "iso" 

2601 elif date_format is None: 

2602 date_format = "epoch" 

2603 dtypes = self.dtypes if self.ndim == 2 else [self.dtype] 

2604 if any(dtype.kind in "mM" for dtype in dtypes): 

2605 warnings.warn( 

2606 "The default 'epoch' date format is deprecated and will be removed " 

2607 "in a future version, please use 'iso' date format instead.", 

2608 Pandas4Warning, 

2609 stacklevel=find_stack_level(), 

2610 ) 

2611 elif date_format == "epoch": 

2612 # GH#57063 

2613 warnings.warn( 

2614 "'epoch' date format is deprecated and will be removed in a future " 

2615 "version, please use 'iso' date format instead.", 

2616 Pandas4Warning, 

2617 stacklevel=find_stack_level(), 

2618 ) 

2619 

2620 config.is_nonnegative_int(indent) 

2621 indent = indent or 0 

2622 

2623 return json.to_json( 

2624 path_or_buf=path_or_buf, 

2625 obj=self, 

2626 orient=orient, 

2627 date_format=date_format, 

2628 double_precision=double_precision, 

2629 force_ascii=force_ascii, 

2630 date_unit=date_unit, 

2631 default_handler=default_handler, 

2632 lines=lines, 

2633 compression=compression, 

2634 index=index, 

2635 indent=indent, 

2636 storage_options=storage_options, 

2637 mode=mode, 

2638 ) 

2639 

2640 @final 

2641 def to_hdf( 

2642 self, 

2643 path_or_buf: FilePath | HDFStore, 

2644 *, 

2645 key: str, 

2646 mode: Literal["a", "w", "r+"] = "a", 

2647 complevel: int | None = None, 

2648 complib: Literal["zlib", "lzo", "bzip2", "blosc"] | None = None, 

2649 append: bool = False, 

2650 format: Literal["fixed", "table"] | None = None, 

2651 index: bool = True, 

2652 min_itemsize: int | dict[str, int] | None = None, 

2653 nan_rep=None, 

2654 dropna: bool | None = None, 

2655 data_columns: Literal[True] | list[str] | None = None, 

2656 errors: OpenFileErrors = "strict", 

2657 encoding: str = "UTF-8", 

2658 ) -> None: 

2659 """ 

2660 Write the contained data to an HDF5 file using HDFStore. 

2661 

2662 Hierarchical Data Format (HDF) is self-describing, allowing an 

2663 application to interpret the structure and contents of a file with 

2664 no outside information. One HDF file can hold a mix of related objects 

2665 which can be accessed as a group or as individual objects. 

2666 

2667 In order to add another DataFrame or Series to an existing HDF file 

2668 please use append mode and a different a key. 

2669 

2670 .. warning:: 

2671 

2672 One can store a subclass of ``DataFrame`` or ``Series`` to HDF5, 

2673 but the type of the subclass is lost upon storing. 

2674 

2675 For more information see the :ref:`user guide <io.hdf5>`. 

2676 

2677 Parameters 

2678 ---------- 

2679 path_or_buf : str or pandas.HDFStore 

2680 File path or HDFStore object. 

2681 key : str 

2682 Identifier for the group in the store. 

2683 mode : {'a', 'w', 'r+'}, default 'a' 

2684 Mode to open file: 

2685 

2686 - 'w': write, a new file is created (an existing file with 

2687 the same name would be deleted). 

2688 - 'a': append, an existing file is opened for reading and 

2689 writing, and if the file does not exist it is created. 

2690 - 'r+': similar to 'a', but the file must already exist. 

2691 complevel : {0-9}, default None 

2692 Specifies a compression level for data. 

2693 A value of 0 or None disables compression. 

2694 complib : {'zlib', 'lzo', 'bzip2', 'blosc'}, default 'zlib' 

2695 Specifies the compression library to be used. 

2696 These additional compressors for Blosc are supported 

2697 (default if no compressor specified: 'blosc:blosclz'): 

2698 {'blosc:blosclz', 'blosc:lz4', 'blosc:lz4hc', 'blosc:snappy', 

2699 'blosc:zlib', 'blosc:zstd'}. 

2700 Specifying a compression library which is not available issues 

2701 a ValueError. 

2702 append : bool, default False 

2703 For Table formats, append the input data to the existing. 

2704 format : {'fixed', 'table', None}, default 'fixed' 

2705 Possible values: 

2706 

2707 - 'fixed': Fixed format. Fast writing/reading. Not-appendable, 

2708 nor searchable. 

2709 - 'table': Table format. Write as a PyTables Table structure 

2710 which may perform worse but allow more flexible operations 

2711 like searching / selecting subsets of the data. 

2712 - If None, pd.get_option('io.hdf.default_format') is checked, 

2713 followed by fallback to "fixed". 

2714 index : bool, default True 

2715 Write DataFrame index as a column. 

2716 min_itemsize : dict or int, optional 

2717 Map column names to minimum string sizes for columns. 

2718 nan_rep : Any, optional 

2719 How to represent null values as str. 

2720 Not allowed with append=True. 

2721 dropna : bool, default False, optional 

2722 Remove missing values. 

2723 data_columns : list of columns or True, optional 

2724 List of columns to create as indexed data columns for on-disk 

2725 queries, or True to use all columns. By default only the axes 

2726 of the object are indexed. See 

2727 :ref:`Query via data columns<io.hdf5-query-data-columns>`. for 

2728 more information. 

2729 Applicable only to format='table'. 

2730 errors : str, default 'strict' 

2731 Specifies how encoding and decoding errors are to be handled. 

2732 See the errors argument for :func:`open` for a full list 

2733 of options. 

2734 encoding : str, default "UTF-8" 

2735 Set character encoding. 

2736 

2737 See Also 

2738 -------- 

2739 read_hdf : Read from HDF file. 

2740 DataFrame.to_orc : Write a DataFrame to the binary orc format. 

2741 DataFrame.to_parquet : Write a DataFrame to the binary parquet format. 

2742 DataFrame.to_sql : Write to a SQL table. 

2743 DataFrame.to_feather : Write out feather-format for DataFrames. 

2744 DataFrame.to_csv : Write out to a csv file. 

2745 

2746 Examples 

2747 -------- 

2748 >>> df = pd.DataFrame( 

2749 ... {"A": [1, 2, 3], "B": [4, 5, 6]}, index=["a", "b", "c"] 

2750 ... ) # doctest: +SKIP 

2751 >>> df.to_hdf("data.h5", key="df", mode="w") # doctest: +SKIP 

2752 

2753 We can add another object to the same file: 

2754 

2755 >>> s = pd.Series([1, 2, 3, 4]) # doctest: +SKIP 

2756 >>> s.to_hdf("data.h5", key="s") # doctest: +SKIP 

2757 

2758 Reading from HDF file: 

2759 

2760 >>> pd.read_hdf("data.h5", "df") # doctest: +SKIP 

2761 A B 

2762 a 1 4 

2763 b 2 5 

2764 c 3 6 

2765 >>> pd.read_hdf("data.h5", "s") # doctest: +SKIP 

2766 0 1 

2767 1 2 

2768 2 3 

2769 3 4 

2770 dtype: int64 

2771 """ 

2772 from pandas.io import pytables 

2773 

2774 # Argument 3 to "to_hdf" has incompatible type "NDFrame"; expected 

2775 # "Union[DataFrame, Series]" [arg-type] 

2776 pytables.to_hdf( 

2777 path_or_buf, 

2778 key, 

2779 self, # type: ignore[arg-type] 

2780 mode=mode, 

2781 complevel=complevel, 

2782 complib=complib, 

2783 append=append, 

2784 format=format, 

2785 index=index, 

2786 min_itemsize=min_itemsize, 

2787 nan_rep=nan_rep, 

2788 dropna=dropna, 

2789 data_columns=data_columns, 

2790 errors=errors, 

2791 encoding=encoding, 

2792 ) 

2793 

2794 @final 

2795 def to_sql( 

2796 self, 

2797 name: str, 

2798 con, 

2799 *, 

2800 schema: str | None = None, 

2801 if_exists: Literal["fail", "replace", "append", "delete_rows"] = "fail", 

2802 index: bool = True, 

2803 index_label: IndexLabel | None = None, 

2804 chunksize: int | None = None, 

2805 dtype: DtypeArg | None = None, 

2806 method: Literal["multi"] | Callable | None = None, 

2807 ) -> int | None: 

2808 """ 

2809 Write records stored in a DataFrame to a SQL database. 

2810 

2811 Databases supported by SQLAlchemy [1]_ are supported. Tables can be 

2812 newly created, appended to, or overwritten. 

2813 

2814 .. warning:: 

2815 The pandas library does not attempt to sanitize inputs provided via a to_sql call. 

2816 Please refer to the documentation for the underlying database driver to see if it 

2817 will properly prevent injection, or alternatively be advised of a security risk when 

2818 executing arbitrary commands in a to_sql call. 

2819 

2820 Parameters 

2821 ---------- 

2822 name : str 

2823 Name of SQL table. 

2824 con : ADBC connection, sqlalchemy.engine.(Engine or Connection) or sqlite3.Connection 

2825 ADBC provides high performance I/O with native type support, where available. 

2826 Using SQLAlchemy makes it possible to use any DB supported by that 

2827 library. Legacy support is provided for sqlite3.Connection objects. The user 

2828 is responsible for engine disposal and connection closure for the SQLAlchemy 

2829 connectable. See `here \ 

2830 <https://docs.sqlalchemy.org/en/20/core/connections.html>`_. 

2831 If passing a sqlalchemy.engine.Connection which is already in a transaction, 

2832 the transaction will not be committed. If passing a sqlite3.Connection, 

2833 it will not be possible to roll back the record insertion. 

2834 

2835 schema : str, optional 

2836 Specify the schema (if database flavor supports this). If None, use 

2837 default schema. 

2838 if_exists : {'fail', 'replace', 'append', 'delete_rows'}, default 'fail' 

2839 How to behave if the table already exists. 

2840 

2841 * fail: Raise a ValueError. 

2842 * replace: Drop the table before inserting new values. 

2843 * append: Insert new values to the existing table. 

2844 * delete_rows: If a table exists, delete all records and insert data. 

2845 

2846 index : bool, default True 

2847 Write DataFrame index as a column. Uses `index_label` as the column 

2848 name in the table. Creates a table index for this column. 

2849 index_label : str or sequence, default None 

2850 Column label for index column(s). If None is given (default) and 

2851 `index` is True, then the index names are used. 

2852 A sequence should be given if the DataFrame uses MultiIndex. 

2853 chunksize : int, optional 

2854 Specify the number of rows in each batch to be written to the database connection at a time. 

2855 By default, all rows will be written at once. Also see the method keyword. 

2856 dtype : dict or scalar, optional 

2857 Specifying the datatype for columns. If a dictionary is used, the 

2858 keys should be the column names and the values should be the 

2859 SQLAlchemy types or strings for the sqlite3 legacy mode. If a 

2860 scalar is provided, it will be applied to all columns. 

2861 method : {None, 'multi', callable}, optional 

2862 Controls the SQL insertion clause used: 

2863 

2864 * None : Uses standard SQL ``INSERT`` clause (one per row). 

2865 * 'multi': Pass multiple values in a single ``INSERT`` clause. 

2866 * callable with signature ``(pd_table, conn, keys, data_iter)``. 

2867 

2868 Details and a sample callable implementation can be found in the 

2869 section :ref:`insert method <io.sql.method>`. 

2870 

2871 Returns 

2872 ------- 

2873 None or int 

2874 Number of rows affected by to_sql. None is returned if the callable 

2875 passed into ``method`` does not return an integer number of rows. 

2876 

2877 The number of returned rows affected is the sum of the ``rowcount`` 

2878 attribute of ``sqlite3.Cursor`` or SQLAlchemy connectable which may not 

2879 reflect the exact number of written rows as stipulated in the 

2880 `sqlite3 <https://docs.python.org/3/library/sqlite3.html#sqlite3.Cursor.rowcount>`__ or 

2881 `SQLAlchemy <https://docs.sqlalchemy.org/en/20/core/connections.html#sqlalchemy.engine.CursorResult.rowcount>`__. 

2882 

2883 Raises 

2884 ------ 

2885 ValueError 

2886 When the table already exists and `if_exists` is 'fail' (the 

2887 default). 

2888 

2889 See Also 

2890 -------- 

2891 read_sql : Read a DataFrame from a table. 

2892 

2893 Notes 

2894 ----- 

2895 Timezone aware datetime columns will be written as 

2896 ``Timestamp with timezone`` type with SQLAlchemy if supported by the 

2897 database. Otherwise, the datetimes will be stored as timezone unaware 

2898 timestamps local to the original timezone. 

2899 

2900 Not all datastores support ``method="multi"``. Oracle, for example, 

2901 does not support multi-value insert. 

2902 

2903 References 

2904 ---------- 

2905 .. [1] https://docs.sqlalchemy.org 

2906 .. [2] https://www.python.org/dev/peps/pep-0249/ 

2907 

2908 Examples 

2909 -------- 

2910 Create an in-memory SQLite database. 

2911 

2912 >>> from sqlalchemy import create_engine 

2913 >>> engine = create_engine('sqlite://', echo=False) 

2914 

2915 Create a table from scratch with 3 rows. 

2916 

2917 >>> df = pd.DataFrame({'name' : ['User 1', 'User 2', 'User 3']}) 

2918 >>> df 

2919 name 

2920 0 User 1 

2921 1 User 2 

2922 2 User 3 

2923 

2924 >>> df.to_sql(name='users', con=engine) 

2925 3 

2926 >>> from sqlalchemy import text 

2927 >>> with engine.connect() as conn: 

2928 ... conn.execute(text("SELECT * FROM users")).fetchall() 

2929 [(0, 'User 1'), (1, 'User 2'), (2, 'User 3')] 

2930 

2931 An `sqlalchemy.engine.Connection` can also be passed to `con`: 

2932 

2933 >>> with engine.begin() as connection: 

2934 ... df1 = pd.DataFrame({'name' : ['User 4', 'User 5']}) 

2935 ... df1.to_sql(name='users', con=connection, if_exists='append') 

2936 2 

2937 

2938 This is allowed to support operations that require that the same 

2939 DBAPI connection is used for the entire operation. 

2940 

2941 >>> df2 = pd.DataFrame({'name' : ['User 6', 'User 7']}) 

2942 >>> df2.to_sql(name='users', con=engine, if_exists='append') 

2943 2 

2944 >>> with engine.connect() as conn: 

2945 ... conn.execute(text("SELECT * FROM users")).fetchall() 

2946 [(0, 'User 1'), (1, 'User 2'), (2, 'User 3'), 

2947 (0, 'User 4'), (1, 'User 5'), (0, 'User 6'), 

2948 (1, 'User 7')] 

2949 

2950 Overwrite the table with just ``df2``. 

2951 

2952 >>> df2.to_sql(name='users', con=engine, if_exists='replace', 

2953 ... index_label='id') 

2954 2 

2955 >>> with engine.connect() as conn: 

2956 ... conn.execute(text("SELECT * FROM users")).fetchall() 

2957 [(0, 'User 6'), (1, 'User 7')] 

2958 

2959 Delete all rows before inserting new records with ``df3`` 

2960 

2961 >>> df3 = pd.DataFrame({"name": ['User 8', 'User 9']}) 

2962 >>> df3.to_sql(name='users', con=engine, if_exists='delete_rows', 

2963 ... index_label='id') 

2964 2 

2965 >>> with engine.connect() as conn: 

2966 ... conn.execute(text("SELECT * FROM users")).fetchall() 

2967 [(0, 'User 8'), (1, 'User 9')] 

2968 

2969 Use ``method`` to define a callable insertion method to do nothing 

2970 if there's a primary key conflict on a table in a PostgreSQL database. 

2971 

2972 >>> from sqlalchemy.dialects.postgresql import insert 

2973 >>> def insert_on_conflict_nothing(table, conn, keys, data_iter): 

2974 ... # "a" is the primary key in "conflict_table" 

2975 ... data = [dict(zip(keys, row)) for row in data_iter] 

2976 ... stmt = insert(table.table).values(data).on_conflict_do_nothing(index_elements=["a"]) 

2977 ... result = conn.execute(stmt) 

2978 ... return result.rowcount 

2979 >>> df_conflict.to_sql(name="conflict_table", con=conn, if_exists="append", # noqa: F821 

2980 ... method=insert_on_conflict_nothing) # doctest: +SKIP 

2981 0 

2982 

2983 For MySQL, a callable to update columns ``b`` and ``c`` if there's a conflict 

2984 on a primary key. 

2985 

2986 >>> from sqlalchemy.dialects.mysql import insert # noqa: F811 

2987 >>> def insert_on_conflict_update(table, conn, keys, data_iter): 

2988 ... # update columns "b" and "c" on primary key conflict 

2989 ... data = [dict(zip(keys, row)) for row in data_iter] 

2990 ... stmt = ( 

2991 ... insert(table.table) 

2992 ... .values(data) 

2993 ... ) 

2994 ... stmt = stmt.on_duplicate_key_update(b=stmt.inserted.b, c=stmt.inserted.c) 

2995 ... result = conn.execute(stmt) 

2996 ... return result.rowcount 

2997 >>> df_conflict.to_sql(name="conflict_table", con=conn, if_exists="append", # noqa: F821 

2998 ... method=insert_on_conflict_update) # doctest: +SKIP 

2999 2 

3000 

3001 Specify the dtype (especially useful for integers with missing values). 

3002 Notice that while pandas is forced to store the data as floating point, 

3003 the database supports nullable integers. When fetching the data with 

3004 Python, we get back integer scalars. 

3005 

3006 >>> df = pd.DataFrame({"A": [1, None, 2]}) 

3007 >>> df 

3008 A 

3009 0 1.0 

3010 1 NaN 

3011 2 2.0 

3012 

3013 >>> from sqlalchemy.types import Integer 

3014 >>> df.to_sql(name='integers', con=engine, index=False, 

3015 ... dtype={"A": Integer()}) 

3016 3 

3017 

3018 >>> with engine.connect() as conn: 

3019 ... conn.execute(text("SELECT * FROM integers")).fetchall() 

3020 [(1,), (None,), (2,)] 

3021 

3022 .. versionadded:: 2.2.0 

3023 

3024 pandas now supports writing via ADBC drivers 

3025 

3026 >>> df = pd.DataFrame({'name' : ['User 10', 'User 11', 'User 12']}) 

3027 >>> df 

3028 name 

3029 0 User 10 

3030 1 User 11 

3031 2 User 12 

3032 

3033 >>> from adbc_driver_sqlite import dbapi # doctest:+SKIP 

3034 >>> with dbapi.connect("sqlite://") as conn: # doctest:+SKIP 

3035 ... df.to_sql(name="users", con=conn) 

3036 3 

3037 """ # noqa: E501 

3038 from pandas.io import sql 

3039 

3040 return sql.to_sql( 

3041 self, 

3042 name, 

3043 con, 

3044 schema=schema, 

3045 if_exists=if_exists, 

3046 index=index, 

3047 index_label=index_label, 

3048 chunksize=chunksize, 

3049 dtype=dtype, 

3050 method=method, 

3051 ) 

3052 

3053 @final 

3054 def to_pickle( 

3055 self, 

3056 path: FilePath | WriteBuffer[bytes], 

3057 *, 

3058 compression: CompressionOptions = "infer", 

3059 protocol: int = pickle.HIGHEST_PROTOCOL, 

3060 storage_options: StorageOptions | None = None, 

3061 ) -> None: 

3062 """ 

3063 Pickle (serialize) object to file. 

3064 

3065 Parameters 

3066 ---------- 

3067 path : str, path object, or file-like object 

3068 String, path object (implementing ``os.PathLike[str]``), or file-like 

3069 object implementing a binary ``write()`` function. File path where 

3070 the pickled object will be stored. 

3071 

3072 compression : str or dict, default 'infer' 

3073 For on-the-fly compression of the output data. If 'infer' and 

3074 'path_or_buf' is path-like, then detect compression from the following 

3075 extensions: '.gz', 

3076 '.bz2', '.zip', '.xz', '.zst', '.tar', '.tar.gz', '.tar.xz' or '.tar.bz2' 

3077 (otherwise no compression). 

3078 Set to ``None`` for no compression. 

3079 Can also be a dict with key ``'method'`` set to one of 

3080 {``'zip'``, ``'gzip'``, ``'bz2'``, ``'zstd'``, ``'xz'``, ``'tar'``} and 

3081 other key-value pairs are forwarded to 

3082 ``zipfile.ZipFile``, ``gzip.GzipFile``, 

3083 ``bz2.BZ2File``, ``zstandard.ZstdCompressor``, ``lzma.LZMAFile`` or 

3084 ``tarfile.TarFile``, respectively. 

3085 As an example, the following could be passed for faster compression and 

3086 to create a reproducible gzip archive: 

3087 ``compression={'method': 'gzip', 'compresslevel': 1, 'mtime': 1}``. 

3088 

3089 protocol : int 

3090 Int which indicates which protocol should be used by the pickler, 

3091 default HIGHEST_PROTOCOL (see [1]_ paragraph 12.1.2). The possible 

3092 values are 0, 1, 2, 3, 4, 5. A negative value for the protocol 

3093 parameter is equivalent to setting its value to HIGHEST_PROTOCOL. 

3094 

3095 .. [1] https://docs.python.org/3/library/pickle.html. 

3096 

3097 storage_options : dict, optional 

3098 Extra options that make sense for a particular storage connection, e.g. 

3099 host, port, username, password, etc. For HTTP(S) URLs the key-value pairs 

3100 are forwarded to ``urllib.request.Request`` as header options. For other 

3101 URLs (e.g. starting with "s3://", and "gcs://") the key-value pairs are 

3102 forwarded to ``fsspec.open``. Please see ``fsspec`` and ``urllib`` for more 

3103 details, and for more examples on storage options refer `here 

3104 <https://pandas.pydata.org/docs/user_guide/io.html? 

3105 highlight=storage_options#reading-writing-remote-files>`_. 

3106 

3107 See Also 

3108 -------- 

3109 read_pickle : Load pickled pandas object (or any object) from file. 

3110 DataFrame.to_hdf : Write DataFrame to an HDF5 file. 

3111 DataFrame.to_sql : Write DataFrame to a SQL database. 

3112 DataFrame.to_parquet : Write a DataFrame to the binary parquet format. 

3113 

3114 Examples 

3115 -------- 

3116 >>> original_df = pd.DataFrame( 

3117 ... {"foo": range(5), "bar": range(5, 10)} 

3118 ... ) # doctest: +SKIP 

3119 >>> original_df # doctest: +SKIP 

3120 foo bar 

3121 0 0 5 

3122 1 1 6 

3123 2 2 7 

3124 3 3 8 

3125 4 4 9 

3126 >>> original_df.to_pickle("./dummy.pkl") # doctest: +SKIP 

3127 

3128 >>> unpickled_df = pd.read_pickle("./dummy.pkl") # doctest: +SKIP 

3129 >>> unpickled_df # doctest: +SKIP 

3130 foo bar 

3131 0 0 5 

3132 1 1 6 

3133 2 2 7 

3134 3 3 8 

3135 4 4 9 

3136 """ 

3137 from pandas.io.pickle import to_pickle 

3138 

3139 to_pickle( 

3140 self, 

3141 path, 

3142 compression=compression, 

3143 protocol=protocol, 

3144 storage_options=storage_options, 

3145 ) 

3146 

3147 @final 

3148 def to_clipboard( 

3149 self, *, excel: bool = True, sep: str | None = None, **kwargs 

3150 ) -> None: 

3151 r""" 

3152 Copy object to the system clipboard. 

3153 

3154 Write a text representation of object to the system clipboard. 

3155 This can be pasted into Excel, for example. 

3156 

3157 Parameters 

3158 ---------- 

3159 excel : bool, default True 

3160 Produce output in a csv format for easy pasting into excel. 

3161 

3162 - True, use the provided separator for csv pasting. 

3163 - False, write a string representation of the object to the clipboard. 

3164 

3165 sep : str, default ``'\t'`` 

3166 Field delimiter. 

3167 **kwargs 

3168 These parameters will be passed to DataFrame.to_csv. 

3169 

3170 See Also 

3171 -------- 

3172 DataFrame.to_csv : Write a DataFrame to a comma-separated values 

3173 (csv) file. 

3174 read_clipboard : Read text from clipboard and pass to read_csv. 

3175 

3176 Notes 

3177 ----- 

3178 Requirements for your platform. 

3179 

3180 - Linux : `xclip`, or `xsel` (with `PyQt4` modules) 

3181 - Windows : none 

3182 - macOS : none 

3183 

3184 This method uses the processes developed for the package `pyperclip`. A 

3185 solution to render any output string format is given in the examples. 

3186 

3187 Examples 

3188 -------- 

3189 Copy the contents of a DataFrame to the clipboard. 

3190 

3191 >>> df = pd.DataFrame([[1, 2, 3], [4, 5, 6]], columns=["A", "B", "C"]) 

3192 

3193 >>> df.to_clipboard(sep=",") # doctest: +SKIP 

3194 ... # Wrote the following to the system clipboard: 

3195 ... # ,A,B,C 

3196 ... # 0,1,2,3 

3197 ... # 1,4,5,6 

3198 

3199 We can omit the index by passing the keyword `index` and setting 

3200 it to false. 

3201 

3202 >>> df.to_clipboard(sep=",", index=False) # doctest: +SKIP 

3203 ... # Wrote the following to the system clipboard: 

3204 ... # A,B,C 

3205 ... # 1,2,3 

3206 ... # 4,5,6 

3207 

3208 Using the original `pyperclip` package for any string output format. 

3209 

3210 .. code-block:: python 

3211 

3212 import pyperclip 

3213 

3214 html = df.style.to_html() 

3215 pyperclip.copy(html) 

3216 """ 

3217 from pandas.io import clipboards 

3218 

3219 clipboards.to_clipboard(self, excel=excel, sep=sep, **kwargs) 

3220 

3221 @final 

3222 def to_xarray(self): 

3223 """ 

3224 Return an xarray object from the pandas object. 

3225 

3226 Returns 

3227 ------- 

3228 xarray.DataArray or xarray.Dataset 

3229 Data in the pandas structure converted to Dataset if the object is 

3230 a DataFrame, or a DataArray if the object is a Series. 

3231 

3232 See Also 

3233 -------- 

3234 DataFrame.to_hdf : Write DataFrame to an HDF5 file. 

3235 DataFrame.to_parquet : Write a DataFrame to the binary parquet format. 

3236 

3237 Notes 

3238 ----- 

3239 See the `xarray docs <https://xarray.pydata.org/en/stable/>`__ 

3240 

3241 Examples 

3242 -------- 

3243 >>> df = pd.DataFrame( 

3244 ... [ 

3245 ... ("falcon", "bird", 389.0, 2), 

3246 ... ("parrot", "bird", 24.0, 2), 

3247 ... ("lion", "mammal", 80.5, 4), 

3248 ... ("monkey", "mammal", np.nan, 4), 

3249 ... ], 

3250 ... columns=["name", "class", "max_speed", "num_legs"], 

3251 ... ) 

3252 >>> df 

3253 name class max_speed num_legs 

3254 0 falcon bird 389.0 2 

3255 1 parrot bird 24.0 2 

3256 2 lion mammal 80.5 4 

3257 3 monkey mammal NaN 4 

3258 

3259 >>> df.to_xarray() # doctest: +SKIP 

3260 <xarray.Dataset> 

3261 Dimensions: (index: 4) 

3262 Coordinates: 

3263 * index (index) int64 32B 0 1 2 3 

3264 Data variables: 

3265 name (index) object 32B 'falcon' 'parrot' 'lion' 'monkey' 

3266 class (index) object 32B 'bird' 'bird' 'mammal' 'mammal' 

3267 max_speed (index) float64 32B 389.0 24.0 80.5 nan 

3268 num_legs (index) int64 32B 2 2 4 4 

3269 

3270 >>> df["max_speed"].to_xarray() # doctest: +SKIP 

3271 <xarray.DataArray 'max_speed' (index: 4)> 

3272 array([389. , 24. , 80.5, nan]) 

3273 Coordinates: 

3274 * index (index) int64 0 1 2 3 

3275 

3276 >>> dates = pd.to_datetime( 

3277 ... ["2018-01-01", "2018-01-01", "2018-01-02", "2018-01-02"] 

3278 ... ) 

3279 >>> df_multiindex = pd.DataFrame( 

3280 ... { 

3281 ... "date": dates, 

3282 ... "animal": ["falcon", "parrot", "falcon", "parrot"], 

3283 ... "speed": [350, 18, 361, 15], 

3284 ... } 

3285 ... ) 

3286 >>> df_multiindex = df_multiindex.set_index(["date", "animal"]) 

3287 

3288 >>> df_multiindex 

3289 speed 

3290 date animal 

3291 2018-01-01 falcon 350 

3292 parrot 18 

3293 2018-01-02 falcon 361 

3294 parrot 15 

3295 

3296 >>> df_multiindex.to_xarray() # doctest: +SKIP 

3297 <xarray.Dataset> 

3298 Dimensions: (date: 2, animal: 2) 

3299 Coordinates: 

3300 * date (date) datetime64[s] 2018-01-01 2018-01-02 

3301 * animal (animal) object 'falcon' 'parrot' 

3302 Data variables: 

3303 speed (date, animal) int64 350 18 361 15 

3304 """ 

3305 xarray = import_optional_dependency("xarray") 

3306 

3307 if self.ndim == 1: 

3308 return xarray.DataArray.from_series(self) 

3309 else: 

3310 return xarray.Dataset.from_dataframe(self) 

3311 

3312 @overload 

3313 def to_latex( 

3314 self, 

3315 buf: None = ..., 

3316 *, 

3317 columns: Sequence[Hashable] | None = ..., 

3318 header: bool | SequenceNotStr[str] = ..., 

3319 index: bool = ..., 

3320 na_rep: str = ..., 

3321 formatters: FormattersType | None = ..., 

3322 float_format: FloatFormatType | None = ..., 

3323 sparsify: bool | None = ..., 

3324 index_names: bool = ..., 

3325 bold_rows: bool = ..., 

3326 column_format: str | None = ..., 

3327 longtable: bool | None = ..., 

3328 escape: bool | None = ..., 

3329 encoding: str | None = ..., 

3330 decimal: str = ..., 

3331 multicolumn: bool | None = ..., 

3332 multicolumn_format: str | None = ..., 

3333 multirow: bool | None = ..., 

3334 caption: str | tuple[str, str] | None = ..., 

3335 label: str | None = ..., 

3336 position: str | None = ..., 

3337 ) -> str: ... 

3338 

3339 @overload 

3340 def to_latex( 

3341 self, 

3342 buf: FilePath | WriteBuffer[str], 

3343 *, 

3344 columns: Sequence[Hashable] | None = ..., 

3345 header: bool | SequenceNotStr[str] = ..., 

3346 index: bool = ..., 

3347 na_rep: str = ..., 

3348 formatters: FormattersType | None = ..., 

3349 float_format: FloatFormatType | None = ..., 

3350 sparsify: bool | None = ..., 

3351 index_names: bool = ..., 

3352 bold_rows: bool = ..., 

3353 column_format: str | None = ..., 

3354 longtable: bool | None = ..., 

3355 escape: bool | None = ..., 

3356 encoding: str | None = ..., 

3357 decimal: str = ..., 

3358 multicolumn: bool | None = ..., 

3359 multicolumn_format: str | None = ..., 

3360 multirow: bool | None = ..., 

3361 caption: str | tuple[str, str] | None = ..., 

3362 label: str | None = ..., 

3363 position: str | None = ..., 

3364 ) -> None: ... 

3365 

3366 @final 

3367 def to_latex( 

3368 self, 

3369 buf: FilePath | WriteBuffer[str] | None = None, 

3370 *, 

3371 columns: Sequence[Hashable] | None = None, 

3372 header: bool | SequenceNotStr[str] = True, 

3373 index: bool = True, 

3374 na_rep: str = "NaN", 

3375 formatters: FormattersType | None = None, 

3376 float_format: FloatFormatType | None = None, 

3377 sparsify: bool | None = None, 

3378 index_names: bool = True, 

3379 bold_rows: bool = False, 

3380 column_format: str | None = None, 

3381 longtable: bool | None = None, 

3382 escape: bool | None = None, 

3383 encoding: str | None = None, 

3384 decimal: str = ".", 

3385 multicolumn: bool | None = None, 

3386 multicolumn_format: str | None = None, 

3387 multirow: bool | None = None, 

3388 caption: str | tuple[str, str] | None = None, 

3389 label: str | None = None, 

3390 position: str | None = None, 

3391 ) -> str | None: 

3392 r""" 

3393 Render object to a LaTeX tabular, longtable, or nested table. 

3394 

3395 Requires ``\usepackage{booktabs}``. The output can be copy/pasted 

3396 into a main LaTeX document or read from an external file 

3397 with ``\input{table.tex}``. 

3398 

3399 .. versionchanged:: 2.0.0 

3400 Refactored to use the Styler implementation via jinja2 templating. 

3401 

3402 Parameters 

3403 ---------- 

3404 buf : str, Path or StringIO-like, optional, default None 

3405 Buffer to write to. If None, the output is returned as a string. 

3406 columns : list of label, optional 

3407 The subset of columns to write. Writes all columns by default. 

3408 header : bool or list of str, default True 

3409 Write out the column names. If a list of strings is given, 

3410 it is assumed to be aliases for the column names. Braces must be escaped. 

3411 index : bool, default True 

3412 Write row names (index). 

3413 na_rep : str, default 'NaN' 

3414 Missing data representation. 

3415 formatters : list of functions or dict of {str: function}, optional 

3416 Formatter functions to apply to columns' elements by position or 

3417 name. The result of each function must be a unicode string. 

3418 List must be of length equal to the number of columns. 

3419 float_format : one-parameter function or str, optional, default None 

3420 Formatter for floating point numbers. For example 

3421 ``float_format="%.2f"`` and ``float_format="{:0.2f}".format`` will 

3422 both result in 0.1234 being formatted as 0.12. 

3423 sparsify : bool, optional 

3424 Set to False for a DataFrame with a hierarchical index to print 

3425 every multiindex key at each row. By default, the value will be 

3426 read from the config module. 

3427 index_names : bool, default True 

3428 Prints the names of the indexes. 

3429 bold_rows : bool, default False 

3430 Make the row labels bold in the output. 

3431 column_format : str, optional 

3432 The columns format as specified in `LaTeX table format 

3433 <https://en.wikibooks.org/wiki/LaTeX/Tables>`__ e.g. 'rcl' for 3 

3434 columns. By default, 'l' will be used for all columns except 

3435 columns of numbers, which default to 'r'. 

3436 longtable : bool, optional 

3437 Use a longtable environment instead of tabular. Requires 

3438 adding a \usepackage{longtable} to your LaTeX preamble. 

3439 By default, the value will be read from the pandas config 

3440 module, and set to `True` if the option ``styler.latex.environment`` is 

3441 `"longtable"`. 

3442 

3443 .. versionchanged:: 2.0.0 

3444 The pandas option affecting this argument has changed. 

3445 escape : bool, optional 

3446 By default, the value will be read from the pandas config 

3447 module and set to `True` if the option ``styler.format.escape`` is 

3448 `"latex"`. When set to False prevents from escaping latex special 

3449 characters in column names. 

3450 

3451 .. versionchanged:: 2.0.0 

3452 The pandas option affecting this argument has changed, as has the 

3453 default value to `False`. 

3454 encoding : str, optional 

3455 A string representing the encoding to use in the output file, 

3456 defaults to 'utf-8'. 

3457 decimal : str, default '.' 

3458 Character recognized as decimal separator, e.g. ',' in Europe. 

3459 multicolumn : bool, default True 

3460 Use \multicolumn to enhance MultiIndex columns. 

3461 The default will be read from the config module, and is set 

3462 as the option ``styler.sparse.columns``. 

3463 

3464 .. versionchanged:: 2.0.0 

3465 The pandas option affecting this argument has changed. 

3466 multicolumn_format : str, default 'r' 

3467 The alignment for multicolumns, similar to `column_format` 

3468 The default will be read from the config module, and is set as the option 

3469 ``styler.latex.multicol_align``. 

3470 

3471 .. versionchanged:: 2.0.0 

3472 The pandas option affecting this argument has changed, as has the 

3473 default value to "r". 

3474 multirow : bool, default True 

3475 Use \multirow to enhance MultiIndex rows. Requires adding a 

3476 \usepackage{multirow} to your LaTeX preamble. Will print 

3477 centered labels (instead of top-aligned) across the contained 

3478 rows, separating groups via clines. The default will be read 

3479 from the pandas config module, and is set as the option 

3480 ``styler.sparse.index``. 

3481 

3482 .. versionchanged:: 2.0.0 

3483 The pandas option affecting this argument has changed, as has the 

3484 default value to `True`. 

3485 caption : str or tuple, optional 

3486 Tuple (full_caption, short_caption), 

3487 which results in ``\caption[short_caption]{full_caption}``; 

3488 if a single string is passed, no short caption will be set. 

3489 label : str, optional 

3490 The LaTeX label to be placed inside ``\label{}`` in the output. 

3491 This is used with ``\ref{}`` in the main ``.tex`` file. 

3492 

3493 position : str, optional 

3494 The LaTeX positional argument for tables, to be placed after 

3495 ``\begin{}`` in the output. 

3496 

3497 Returns 

3498 ------- 

3499 str or None 

3500 If buf is None, returns the result as a string. Otherwise returns None. 

3501 

3502 See Also 

3503 -------- 

3504 io.formats.style.Styler.to_latex : Render a DataFrame to LaTeX 

3505 with conditional formatting. 

3506 DataFrame.to_string : Render a DataFrame to a console-friendly 

3507 tabular output. 

3508 DataFrame.to_html : Render a DataFrame as an HTML table. 

3509 

3510 Notes 

3511 ----- 

3512 As of v2.0.0 this method has changed to use the Styler implementation as 

3513 part of :meth:`.Styler.to_latex` via ``jinja2`` templating. This means 

3514 that ``jinja2`` is a requirement, and needs to be installed, for this method 

3515 to function. It is advised that users switch to using Styler, since that 

3516 implementation is more frequently updated and contains much more 

3517 flexibility with the output. 

3518 

3519 Examples 

3520 -------- 

3521 Convert a general DataFrame to LaTeX with formatting: 

3522 

3523 >>> df = pd.DataFrame(dict(name=['Raphael', 'Donatello'], 

3524 ... age=[26, 45], 

3525 ... height=[181.23, 177.65])) 

3526 >>> print(df.to_latex(index=False, 

3527 ... formatters={"name": str.upper}, 

3528 ... float_format="{:.1f}".format, 

3529 ... )) # doctest: +SKIP 

3530 \begin{tabular}{lrr} 

3531 \toprule 

3532 name & age & height \\ 

3533 \midrule 

3534 RAPHAEL & 26 & 181.2 \\ 

3535 DONATELLO & 45 & 177.7 \\ 

3536 \bottomrule 

3537 \end{tabular} 

3538 """ 

3539 # Get defaults from the pandas config 

3540 if self.ndim == 1: 

3541 self = self.to_frame() 

3542 if longtable is None: 

3543 longtable = config.get_option("styler.latex.environment") == "longtable" 

3544 if escape is None: 

3545 escape = config.get_option("styler.format.escape") == "latex" 

3546 if multicolumn is None: 

3547 multicolumn = config.get_option("styler.sparse.columns") 

3548 if multicolumn_format is None: 

3549 multicolumn_format = config.get_option("styler.latex.multicol_align") 

3550 if multirow is None: 

3551 multirow = config.get_option("styler.sparse.index") 

3552 

3553 if column_format is not None and not isinstance(column_format, str): 

3554 raise ValueError("`column_format` must be str or unicode") 

3555 length = len(self.columns) if columns is None else len(columns) 

3556 if isinstance(header, (list, tuple)) and len(header) != length: 

3557 raise ValueError(f"Writing {length} cols but got {len(header)} aliases") 

3558 

3559 # Refactor formatters/float_format/decimal/na_rep/escape to Styler structure 

3560 base_format_ = { 

3561 "na_rep": na_rep, 

3562 "escape": "latex" if escape else None, 

3563 "decimal": decimal, 

3564 } 

3565 index_format_: dict[str, Any] = {"axis": 0, **base_format_} 

3566 column_format_: dict[str, Any] = {"axis": 1, **base_format_} 

3567 

3568 if isinstance(float_format, str): 

3569 float_format_: Callable | None = lambda x: float_format % x 

3570 else: 

3571 float_format_ = float_format 

3572 

3573 def _wrap(x, alt_format_): 

3574 if isinstance(x, (float, complex)) and float_format_ is not None: 

3575 return float_format_(x) 

3576 else: 

3577 return alt_format_(x) 

3578 

3579 formatters_: list | tuple | dict | Callable | None = None 

3580 if isinstance(formatters, list): 

3581 formatters_ = { 

3582 c: partial(_wrap, alt_format_=formatters[i]) 

3583 for i, c in enumerate(self.columns) 

3584 } 

3585 elif isinstance(formatters, dict): 

3586 index_formatter = formatters.pop("__index__", None) 

3587 column_formatter = formatters.pop("__columns__", None) 

3588 if index_formatter is not None: 

3589 index_format_.update({"formatter": index_formatter}) 

3590 if column_formatter is not None: 

3591 column_format_.update({"formatter": column_formatter}) 

3592 

3593 formatters_ = formatters 

3594 float_columns = self.select_dtypes(include="float").columns 

3595 for col in float_columns: 

3596 if col not in formatters.keys(): 

3597 formatters_.update({col: float_format_}) 

3598 elif formatters is None and float_format is not None: 

3599 formatters_ = partial(_wrap, alt_format_=lambda v: v) 

3600 format_index_ = [index_format_, column_format_] 

3601 format_index_names_ = [index_format_, column_format_] 

3602 

3603 # Deal with hiding indexes and relabelling column names 

3604 hide_: list[dict] = [] 

3605 relabel_index_: list[dict] = [] 

3606 if columns: 

3607 hide_.append( 

3608 { 

3609 "subset": [c for c in self.columns if c not in columns], 

3610 "axis": "columns", 

3611 } 

3612 ) 

3613 if header is False: 

3614 hide_.append({"axis": "columns"}) 

3615 elif isinstance(header, (list, tuple)): 

3616 relabel_index_.append({"labels": header, "axis": "columns"}) 

3617 format_index_ = [index_format_] # column_format is overwritten 

3618 

3619 if index is False: 

3620 hide_.append({"axis": "index"}) 

3621 if index_names is False: 

3622 hide_.append({"names": True, "axis": "index"}) 

3623 

3624 render_kwargs_ = { 

3625 "hrules": True, 

3626 "sparse_index": sparsify, 

3627 "sparse_columns": sparsify, 

3628 "environment": "longtable" if longtable else None, 

3629 "multicol_align": multicolumn_format 

3630 if multicolumn 

3631 else f"naive-{multicolumn_format}", 

3632 "multirow_align": "t" if multirow else "naive", 

3633 "encoding": encoding, 

3634 "caption": caption, 

3635 "label": label, 

3636 "position": position, 

3637 "column_format": column_format, 

3638 "clines": "skip-last;data" 

3639 if (multirow and isinstance(self.index, MultiIndex)) 

3640 else None, 

3641 "bold_rows": bold_rows, 

3642 } 

3643 

3644 return self._to_latex_via_styler( 

3645 buf, 

3646 hide=hide_, 

3647 relabel_index=relabel_index_, 

3648 format={"formatter": formatters_, **base_format_}, 

3649 format_index=format_index_, 

3650 format_index_names=format_index_names_, 

3651 render_kwargs=render_kwargs_, 

3652 ) 

3653 

3654 @final 

3655 def _to_latex_via_styler( 

3656 self, 

3657 buf=None, 

3658 *, 

3659 hide: dict | list[dict] | None = None, 

3660 relabel_index: dict | list[dict] | None = None, 

3661 format: dict | list[dict] | None = None, 

3662 format_index: dict | list[dict] | None = None, 

3663 format_index_names: dict | list[dict] | None = None, 

3664 render_kwargs: dict | None = None, 

3665 ): 

3666 """ 

3667 Render object to a LaTeX tabular, longtable, or nested table. 

3668 

3669 Uses the ``Styler`` implementation with the following, ordered, method chaining: 

3670 

3671 .. code-block:: python 

3672 styler = Styler(DataFrame) 

3673 styler.hide(**hide) 

3674 styler.relabel_index(**relabel_index) 

3675 styler.format(**format) 

3676 styler.format_index(**format_index) 

3677 styler.to_latex(buf=buf, **render_kwargs) 

3678 

3679 Parameters 

3680 ---------- 

3681 buf : str, Path or StringIO-like, optional, default None 

3682 Buffer to write to. If None, the output is returned as a string. 

3683 hide : dict, list of dict 

3684 Keyword args to pass to the method call of ``Styler.hide``. If a list will 

3685 call the method numerous times. 

3686 relabel_index : dict, list of dict 

3687 Keyword args to pass to the method of ``Styler.relabel_index``. If a list 

3688 will call the method numerous times. 

3689 format : dict, list of dict 

3690 Keyword args to pass to the method call of ``Styler.format``. If a list will 

3691 call the method numerous times. 

3692 format_index : dict, list of dict 

3693 Keyword args to pass to the method call of ``Styler.format_index``. If a 

3694 list will call the method numerous times. 

3695 render_kwargs : dict 

3696 Keyword args to pass to the method call of ``Styler.to_latex``. 

3697 

3698 Returns 

3699 ------- 

3700 str or None 

3701 If buf is None, returns the result as a string. Otherwise returns None. 

3702 """ 

3703 from pandas.io.formats.style import Styler 

3704 

3705 self = cast("DataFrame", self) 

3706 styler = Styler(self, uuid="") 

3707 

3708 for kw_name in [ 

3709 "hide", 

3710 "relabel_index", 

3711 "format", 

3712 "format_index", 

3713 "format_index_names", 

3714 ]: 

3715 kw = vars()[kw_name] 

3716 if isinstance(kw, dict): 

3717 getattr(styler, kw_name)(**kw) 

3718 elif isinstance(kw, list): 

3719 for sub_kw in kw: 

3720 getattr(styler, kw_name)(**sub_kw) 

3721 

3722 # bold_rows is not a direct kwarg of Styler.to_latex 

3723 render_kwargs = {} if render_kwargs is None else render_kwargs 

3724 if render_kwargs.pop("bold_rows"): 

3725 styler.map_index(lambda v: "textbf:--rwrap;") 

3726 

3727 return styler.to_latex(buf=buf, **render_kwargs) 

3728 

3729 @overload 

3730 def to_csv( 

3731 self, 

3732 path_or_buf: None = ..., 

3733 *, 

3734 sep: str = ..., 

3735 na_rep: str = ..., 

3736 float_format: str | Callable | None = ..., 

3737 columns: Sequence[Hashable] | None = ..., 

3738 header: bool | list[str] = ..., 

3739 index: bool = ..., 

3740 index_label: IndexLabel | None = ..., 

3741 mode: str = ..., 

3742 encoding: str | None = ..., 

3743 compression: CompressionOptions = ..., 

3744 quoting: int | None = ..., 

3745 quotechar: str = ..., 

3746 lineterminator: str | None = ..., 

3747 chunksize: int | None = ..., 

3748 date_format: str | None = ..., 

3749 doublequote: bool = ..., 

3750 escapechar: str | None = ..., 

3751 decimal: str = ..., 

3752 errors: OpenFileErrors = ..., 

3753 storage_options: StorageOptions = ..., 

3754 ) -> str: ... 

3755 

3756 @overload 

3757 def to_csv( 

3758 self, 

3759 path_or_buf: FilePath | WriteBuffer[bytes] | WriteBuffer[str], 

3760 *, 

3761 sep: str = ..., 

3762 na_rep: str = ..., 

3763 float_format: str | Callable | None = ..., 

3764 columns: Sequence[Hashable] | None = ..., 

3765 header: bool | list[str] = ..., 

3766 index: bool = ..., 

3767 index_label: IndexLabel | None = ..., 

3768 mode: str = ..., 

3769 encoding: str | None = ..., 

3770 compression: CompressionOptions = ..., 

3771 quoting: int | None = ..., 

3772 quotechar: str = ..., 

3773 lineterminator: str | None = ..., 

3774 chunksize: int | None = ..., 

3775 date_format: str | None = ..., 

3776 doublequote: bool = ..., 

3777 escapechar: str | None = ..., 

3778 decimal: str = ..., 

3779 errors: OpenFileErrors = ..., 

3780 storage_options: StorageOptions = ..., 

3781 ) -> None: ... 

3782 

3783 @final 

3784 def to_csv( 

3785 self, 

3786 path_or_buf: FilePath | WriteBuffer[bytes] | WriteBuffer[str] | None = None, 

3787 *, 

3788 sep: str = ",", 

3789 na_rep: str = "", 

3790 float_format: str | Callable | None = None, 

3791 columns: Sequence[Hashable] | None = None, 

3792 header: bool | list[str] = True, 

3793 index: bool = True, 

3794 index_label: IndexLabel | None = None, 

3795 mode: str = "w", 

3796 encoding: str | None = None, 

3797 compression: CompressionOptions = "infer", 

3798 quoting: int | None = None, 

3799 quotechar: str = '"', 

3800 lineterminator: str | None = None, 

3801 chunksize: int | None = None, 

3802 date_format: str | None = None, 

3803 doublequote: bool = True, 

3804 escapechar: str | None = None, 

3805 decimal: str = ".", 

3806 errors: OpenFileErrors = "strict", 

3807 storage_options: StorageOptions | None = None, 

3808 ) -> str | None: 

3809 r""" 

3810 Write object to a comma-separated values (csv) file. 

3811 

3812 Parameters 

3813 ---------- 

3814 path_or_buf : str, path object, file-like object, or None, default None 

3815 String, path object (implementing os.PathLike[str]), or file-like 

3816 object implementing a write() function. If None, the result is 

3817 returned as a string. If a non-binary file object is passed, it should 

3818 be opened with `newline=''`, disabling universal newlines. If a binary 

3819 file object is passed, `mode` might need to contain a `'b'`. 

3820 sep : str, default ',' 

3821 String of length 1. Field delimiter for the output file. 

3822 na_rep : str, default '' 

3823 Missing data representation. 

3824 float_format : str, Callable, default None 

3825 Format string for floating point numbers. If a Callable is given, it takes 

3826 precedence over other numeric formatting parameters, like decimal. 

3827 columns : sequence, optional 

3828 Columns to write. 

3829 header : bool or list of str, default True 

3830 Write out the column names. If a list of strings is given it is 

3831 assumed to be aliases for the column names. 

3832 index : bool, default True 

3833 Write row names (index). 

3834 index_label : str or sequence, or False, default None 

3835 Column label for index column(s) if desired. If None is given, and 

3836 `header` and `index` are True, then the index names are used. A 

3837 sequence should be given if the object uses MultiIndex. If 

3838 False do not print fields for index names. Use index_label=False 

3839 for easier importing in R. 

3840 mode : {'w', 'x', 'a'}, default 'w' 

3841 Forwarded to either `open(mode=)` or `fsspec.open(mode=)` to control 

3842 the file opening. Typical values include: 

3843 

3844 - 'w', truncate the file first. 

3845 - 'x', exclusive creation, failing if the file already exists. 

3846 - 'a', append to the end of file if it exists. 

3847 

3848 encoding : str, optional 

3849 A string representing the encoding to use in the output file, 

3850 defaults to 'utf-8'. `encoding` is not supported if `path_or_buf` 

3851 is a non-binary file object. 

3852 

3853 compression : str or dict, default 'infer' 

3854 For on-the-fly compression of the output data. If 'infer' and 

3855 'path_or_buf' is path-like, then detect compression from the following 

3856 extensions: '.gz', 

3857 '.bz2', '.zip', '.xz', '.zst', '.tar', '.tar.gz', '.tar.xz' or '.tar.bz2' 

3858 (otherwise no compression). 

3859 Set to ``None`` for no compression. 

3860 Can also be a dict with key ``'method'`` set to one of 

3861 {``'zip'``, ``'gzip'``, ``'bz2'``, ``'zstd'``, ``'xz'``, ``'tar'``} and 

3862 other key-value pairs are forwarded to 

3863 ``zipfile.ZipFile``, ``gzip.GzipFile``, 

3864 ``bz2.BZ2File``, ``zstandard.ZstdCompressor``, ``lzma.LZMAFile`` or 

3865 ``tarfile.TarFile``, respectively. 

3866 As an example, the following could be passed for faster compression and 

3867 to create a reproducible gzip archive: 

3868 ``compression={'method': 'gzip', 'compresslevel': 1, 'mtime': 1}``. 

3869 

3870 May be a dict with key 'method' as compression mode 

3871 and other entries as additional compression options if 

3872 compression mode is 'zip'. 

3873 

3874 Passing compression options as keys in dict is 

3875 supported for compression modes 'gzip', 'bz2', 'zstd', and 'zip'. 

3876 quoting : optional constant from csv module 

3877 Defaults to csv.QUOTE_MINIMAL. If you have set a `float_format` 

3878 then floats are converted to strings and thus csv.QUOTE_NONNUMERIC 

3879 will treat them as non-numeric. 

3880 quotechar : str, default '\"' 

3881 String of length 1. Character used to quote fields. 

3882 lineterminator : str, optional 

3883 The newline character or character sequence to use in the output 

3884 file. Defaults to `os.linesep`, which depends on the OS in which 

3885 this method is called ('\\n' for linux, '\\r\\n' for Windows, i.e.). 

3886 chunksize : int or None 

3887 Rows to write at a time. 

3888 date_format : str, default None 

3889 Format string for datetime objects. 

3890 doublequote : bool, default True 

3891 Control quoting of `quotechar` inside a field. 

3892 escapechar : str, default None 

3893 String of length 1. Character used to escape `sep` and `quotechar` 

3894 when appropriate. 

3895 decimal : str, default '.' 

3896 Character recognized as decimal separator. E.g. use ',' for 

3897 European data. 

3898 errors : str, default 'strict' 

3899 Specifies how encoding and decoding errors are to be handled. 

3900 See the errors argument for :func:`open` for a full list 

3901 of options. 

3902 

3903 storage_options : dict, optional 

3904 Extra options that make sense for a particular storage connection, e.g. 

3905 host, port, username, password, etc. For HTTP(S) URLs the key-value pairs 

3906 are forwarded to ``urllib.request.Request`` as header options. For other 

3907 URLs (e.g. starting with "s3://", and "gcs://") the key-value pairs are 

3908 forwarded to ``fsspec.open``. Please see ``fsspec`` and ``urllib`` for more 

3909 details, and for more examples on storage options refer `here 

3910 <https://pandas.pydata.org/docs/user_guide/io.html? 

3911 highlight=storage_options#reading-writing-remote-files>`_. 

3912 

3913 Returns 

3914 ------- 

3915 None or str 

3916 If path_or_buf is None, returns the resulting csv format as a 

3917 string. Otherwise returns None. 

3918 

3919 See Also 

3920 -------- 

3921 read_csv : Load a CSV file into a DataFrame. 

3922 to_excel : Write DataFrame to an Excel file. 

3923 

3924 Examples 

3925 -------- 

3926 Create 'out.csv' containing 'df' without indices 

3927 

3928 >>> df = pd.DataFrame( 

3929 ... [["Raphael", "red", "sai"], ["Donatello", "purple", "bo staff"]], 

3930 ... columns=["name", "mask", "weapon"], 

3931 ... ) 

3932 >>> df.to_csv("out.csv", index=False) # doctest: +SKIP 

3933 

3934 Create 'out.zip' containing 'out.csv' 

3935 

3936 >>> df.to_csv(index=False) 

3937 'name,mask,weapon\nRaphael,red,sai\nDonatello,purple,bo staff\n' 

3938 >>> compression_opts = dict( 

3939 ... method="zip", archive_name="out.csv" 

3940 ... ) # doctest: +SKIP 

3941 >>> df.to_csv( 

3942 ... "out.zip", index=False, compression=compression_opts 

3943 ... ) # doctest: +SKIP 

3944 

3945 To write a csv file to a new folder or nested folder you will first 

3946 need to create it using either Pathlib or os: 

3947 

3948 >>> from pathlib import Path # doctest: +SKIP 

3949 >>> filepath = Path("folder/subfolder/out.csv") # doctest: +SKIP 

3950 >>> filepath.parent.mkdir(parents=True, exist_ok=True) # doctest: +SKIP 

3951 >>> df.to_csv(filepath) # doctest: +SKIP 

3952 

3953 >>> import os # doctest: +SKIP 

3954 >>> os.makedirs("folder/subfolder", exist_ok=True) # doctest: +SKIP 

3955 >>> df.to_csv("folder/subfolder/out.csv") # doctest: +SKIP 

3956 

3957 Format floats to two decimal places: 

3958 

3959 >>> df.to_csv("out1.csv", float_format="%.2f") # doctest: +SKIP 

3960 

3961 Format floats using scientific notation: 

3962 

3963 >>> df.to_csv("out2.csv", float_format="{:.2e}".format) # doctest: +SKIP 

3964 """ 

3965 df = self if isinstance(self, ABCDataFrame) else self.to_frame() 

3966 

3967 formatter = DataFrameFormatter( 

3968 frame=df, 

3969 header=header, 

3970 index=index, 

3971 na_rep=na_rep, 

3972 float_format=float_format, 

3973 decimal=decimal, 

3974 ) 

3975 

3976 return DataFrameRenderer(formatter).to_csv( 

3977 path_or_buf, 

3978 lineterminator=lineterminator, 

3979 sep=sep, 

3980 encoding=encoding, 

3981 errors=errors, 

3982 compression=compression, 

3983 quoting=quoting, 

3984 columns=columns, 

3985 index_label=index_label, 

3986 mode=mode, 

3987 chunksize=chunksize, 

3988 quotechar=quotechar, 

3989 date_format=date_format, 

3990 doublequote=doublequote, 

3991 escapechar=escapechar, 

3992 storage_options=storage_options, 

3993 ) 

3994 

3995 # ---------------------------------------------------------------------- 

3996 # Indexing Methods 

3997 

3998 @final 

3999 def take(self, indices, axis: Axis = 0, **kwargs) -> Self: 

4000 """ 

4001 Return the elements in the given *positional* indices along an axis. 

4002 

4003 This means that we are not indexing according to actual values in 

4004 the index attribute of the object. We are indexing according to the 

4005 actual position of the element in the object. 

4006 

4007 Parameters 

4008 ---------- 

4009 indices : array-like 

4010 An array of ints indicating which positions to take. 

4011 axis : {0 or 'index', 1 or 'columns'}, default 0 

4012 The axis on which to select elements. ``0`` means that we are 

4013 selecting rows, ``1`` means that we are selecting columns. 

4014 For `Series` this parameter is unused and defaults to 0. 

4015 **kwargs 

4016 For compatibility with :meth:`numpy.take`. Has no effect on the 

4017 output. 

4018 

4019 Returns 

4020 ------- 

4021 same type as caller 

4022 An array-like containing the elements taken from the object. 

4023 

4024 See Also 

4025 -------- 

4026 DataFrame.loc : Select a subset of a DataFrame by labels. 

4027 DataFrame.iloc : Select a subset of a DataFrame by positions. 

4028 numpy.take : Take elements from an array along an axis. 

4029 

4030 Examples 

4031 -------- 

4032 >>> df = pd.DataFrame( 

4033 ... [ 

4034 ... ("falcon", "bird", 389.0), 

4035 ... ("parrot", "bird", 24.0), 

4036 ... ("lion", "mammal", 80.5), 

4037 ... ("monkey", "mammal", np.nan), 

4038 ... ], 

4039 ... columns=["name", "class", "max_speed"], 

4040 ... index=[0, 2, 3, 1], 

4041 ... ) 

4042 >>> df 

4043 name class max_speed 

4044 0 falcon bird 389.0 

4045 2 parrot bird 24.0 

4046 3 lion mammal 80.5 

4047 1 monkey mammal NaN 

4048 

4049 Take elements at positions 0 and 3 along the axis 0 (default). 

4050 

4051 Note how the actual indices selected (0 and 1) do not correspond to 

4052 our selected indices 0 and 3. That's because we are selecting the 0th 

4053 and 3rd rows, not rows whose indices equal 0 and 3. 

4054 

4055 >>> df.take([0, 3]) 

4056 name class max_speed 

4057 0 falcon bird 389.0 

4058 1 monkey mammal NaN 

4059 

4060 Take elements at indices 1 and 2 along the axis 1 (column selection). 

4061 

4062 >>> df.take([1, 2], axis=1) 

4063 class max_speed 

4064 0 bird 389.0 

4065 2 bird 24.0 

4066 3 mammal 80.5 

4067 1 mammal NaN 

4068 

4069 We may take elements using negative integers for positive indices, 

4070 starting from the end of the object, just like with Python lists. 

4071 

4072 >>> df.take([-1, -2]) 

4073 name class max_speed 

4074 1 monkey mammal NaN 

4075 3 lion mammal 80.5 

4076 """ 

4077 

4078 nv.validate_take((), kwargs) 

4079 

4080 if isinstance(indices, slice): 

4081 raise TypeError( 

4082 f"{type(self).__name__}.take requires a sequence of integers, " 

4083 "not slice." 

4084 ) 

4085 indices = np.asarray(indices, dtype=np.intp) 

4086 if axis == 0 and indices.ndim == 1 and is_range_indexer(indices, len(self)): 

4087 return self.copy(deep=False) 

4088 

4089 new_data = self._mgr.take( 

4090 indices, 

4091 axis=self._get_block_manager_axis(axis), 

4092 verify=True, 

4093 ) 

4094 return self._constructor_from_mgr(new_data, axes=new_data.axes).__finalize__( 

4095 self, method="take" 

4096 ) 

4097 

4098 @final 

4099 def xs( 

4100 self, 

4101 key: IndexLabel, 

4102 axis: Axis = 0, 

4103 level: IndexLabel | None = None, 

4104 drop_level: bool = True, 

4105 ) -> Self: 

4106 """ 

4107 Return cross-section from the Series/DataFrame. 

4108 

4109 This method takes a `key` argument to select data at a particular 

4110 level of a MultiIndex. 

4111 

4112 Parameters 

4113 ---------- 

4114 key : label or tuple of label 

4115 Label contained in the index, or partially in a MultiIndex. 

4116 axis : {0 or 'index', 1 or 'columns'}, default 0 

4117 Axis to retrieve cross-section on. 

4118 level : object, defaults to first n levels (n=1 or len(key)) 

4119 In case of a key partially contained in a MultiIndex, indicate 

4120 which levels are used. Levels can be referred by label or position. 

4121 drop_level : bool, default True 

4122 If False, returns object with same levels as self. 

4123 

4124 Returns 

4125 ------- 

4126 Series or DataFrame 

4127 Cross-section from the original Series or DataFrame 

4128 corresponding to the selected index levels. 

4129 

4130 See Also 

4131 -------- 

4132 DataFrame.loc : Access a group of rows and columns 

4133 by label(s) or a boolean array. 

4134 DataFrame.iloc : Purely integer-location based indexing 

4135 for selection by position. 

4136 

4137 Notes 

4138 ----- 

4139 `xs` can not be used to set values. 

4140 

4141 MultiIndex Slicers is a generic way to get/set values on 

4142 any level or levels. 

4143 It is a superset of `xs` functionality, see 

4144 :ref:`MultiIndex Slicers <advanced.mi_slicers>`. 

4145 

4146 Examples 

4147 -------- 

4148 >>> d = { 

4149 ... "num_legs": [4, 4, 2, 2], 

4150 ... "num_wings": [0, 0, 2, 2], 

4151 ... "class": ["mammal", "mammal", "mammal", "bird"], 

4152 ... "animal": ["cat", "dog", "bat", "penguin"], 

4153 ... "locomotion": ["walks", "walks", "flies", "walks"], 

4154 ... } 

4155 >>> df = pd.DataFrame(data=d) 

4156 >>> df = df.set_index(["class", "animal", "locomotion"]) 

4157 >>> df 

4158 num_legs num_wings 

4159 class animal locomotion 

4160 mammal cat walks 4 0 

4161 dog walks 4 0 

4162 bat flies 2 2 

4163 bird penguin walks 2 2 

4164 

4165 Get values at specified index 

4166 

4167 >>> df.xs("mammal") 

4168 num_legs num_wings 

4169 animal locomotion 

4170 cat walks 4 0 

4171 dog walks 4 0 

4172 bat flies 2 2 

4173 

4174 Get values at several indexes 

4175 

4176 >>> df.xs(("mammal", "dog", "walks")) 

4177 num_legs 4 

4178 num_wings 0 

4179 Name: (mammal, dog, walks), dtype: int64 

4180 

4181 Get values at specified index and level 

4182 

4183 >>> df.xs("cat", level=1) 

4184 num_legs num_wings 

4185 class locomotion 

4186 mammal walks 4 0 

4187 

4188 Get values at several indexes and levels 

4189 

4190 >>> df.xs(("bird", "walks"), level=[0, "locomotion"]) 

4191 num_legs num_wings 

4192 animal 

4193 penguin 2 2 

4194 

4195 Get values at specified column and axis 

4196 

4197 >>> df.xs("num_wings", axis=1) 

4198 class animal locomotion 

4199 mammal cat walks 0 

4200 dog walks 0 

4201 bat flies 2 

4202 bird penguin walks 2 

4203 Name: num_wings, dtype: int64 

4204 """ 

4205 axis = self._get_axis_number(axis) 

4206 labels = self._get_axis(axis) 

4207 

4208 if isinstance(key, list): 

4209 raise TypeError("list keys are not supported in xs, pass a tuple instead") 

4210 

4211 if level is not None: 

4212 if not isinstance(labels, MultiIndex): 

4213 raise TypeError("Index must be a MultiIndex") 

4214 loc, new_ax = labels.get_loc_level(key, level=level, drop_level=drop_level) 

4215 

4216 # create the tuple of the indexer 

4217 _indexer = [slice(None)] * self.ndim 

4218 _indexer[axis] = loc 

4219 indexer = tuple(_indexer) 

4220 

4221 result = self.iloc[indexer] 

4222 setattr(result, result._get_axis_name(axis), new_ax) 

4223 return result 

4224 

4225 if axis == 1: 

4226 if drop_level: 

4227 return self[key] 

4228 index = self.columns 

4229 else: 

4230 index = self.index 

4231 

4232 if isinstance(index, MultiIndex): 

4233 loc, new_index = index._get_loc_level(key, level=0) 

4234 if not drop_level: 

4235 if lib.is_integer(loc): 

4236 # Slice index must be an integer or None 

4237 new_index = index[loc : loc + 1] 

4238 else: 

4239 new_index = index[loc] 

4240 else: 

4241 loc = index.get_loc(key) 

4242 

4243 if isinstance(loc, np.ndarray): 

4244 if loc.dtype == np.bool_: 

4245 (inds,) = loc.nonzero() 

4246 return self.take(inds, axis=axis) 

4247 else: 

4248 return self.take(loc, axis=axis) 

4249 

4250 if not is_scalar(loc): 

4251 new_index = index[loc] 

4252 

4253 if is_scalar(loc) and axis == 0: 

4254 # In this case loc should be an integer 

4255 if self.ndim == 1: 

4256 # if we encounter an array-like and we only have 1 dim 

4257 # that means that their are list/ndarrays inside the Series! 

4258 # so just return them (GH 6394) 

4259 return self._values[loc] 

4260 

4261 new_mgr = self._mgr.fast_xs(loc) 

4262 

4263 result = self._constructor_sliced_from_mgr(new_mgr, axes=new_mgr.axes) 

4264 result._name = self.index[loc] 

4265 result = result.__finalize__(self) 

4266 elif is_scalar(loc): 

4267 result = self.iloc[:, slice(loc, loc + 1)] 

4268 elif axis == 1: 

4269 result = self.iloc[:, loc] 

4270 else: 

4271 result = self.iloc[loc] 

4272 result.index = new_index 

4273 

4274 return result 

4275 

4276 def __getitem__(self, item): 

4277 raise AbstractMethodError(self) 

4278 

4279 @final 

4280 def _getitem_slice(self, key: slice) -> Self: 

4281 """ 

4282 __getitem__ for the case where the key is a slice object. 

4283 """ 

4284 # _convert_slice_indexer to determine if this slice is positional 

4285 # or label based, and if the latter, convert to positional 

4286 slobj = self.index._convert_slice_indexer(key, kind="getitem") 

4287 if isinstance(slobj, np.ndarray): 

4288 # reachable with DatetimeIndex 

4289 indexer = lib.maybe_indices_to_slice(slobj.astype(np.intp), len(self)) 

4290 if isinstance(indexer, np.ndarray): 

4291 # GH#43223 If we can not convert, use take 

4292 return self.take(indexer, axis=0) 

4293 slobj = indexer 

4294 return self._slice(slobj) 

4295 

4296 def _slice(self, slobj: slice, axis: AxisInt = 0) -> Self: 

4297 """ 

4298 Construct a slice of this container. 

4299 

4300 Slicing with this method is *always* positional. 

4301 """ 

4302 assert isinstance(slobj, slice), type(slobj) 

4303 axis = self._get_block_manager_axis(axis) 

4304 new_mgr = self._mgr.get_slice(slobj, axis=axis) 

4305 result = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) 

4306 result = result.__finalize__(self) 

4307 return result 

4308 

4309 @final 

4310 def __delitem__(self, key) -> None: 

4311 """ 

4312 Delete item 

4313 """ 

4314 deleted = False 

4315 

4316 maybe_shortcut = False 

4317 if self.ndim == 2 and isinstance(self.columns, MultiIndex): 

4318 try: 

4319 # By using engine's __contains__ we effectively 

4320 # restrict to same-length tuples 

4321 maybe_shortcut = key not in self.columns._engine 

4322 except TypeError: 

4323 pass 

4324 

4325 if maybe_shortcut: 

4326 # Allow shorthand to delete all columns whose first len(key) 

4327 # elements match key: 

4328 if not isinstance(key, tuple): 

4329 key = (key,) 

4330 for col in self.columns: 

4331 if isinstance(col, tuple) and col[: len(key)] == key: 

4332 del self[col] 

4333 deleted = True 

4334 if not deleted: 

4335 # If the above loop ran and didn't delete anything because 

4336 # there was no match, this call should raise the appropriate 

4337 # exception: 

4338 loc = self.axes[-1].get_loc(key) 

4339 self._mgr = self._mgr.idelete(loc) 

4340 

4341 # ---------------------------------------------------------------------- 

4342 # Unsorted 

4343 

4344 @final 

4345 def _check_inplace_and_allows_duplicate_labels(self, inplace: bool) -> None: 

4346 if inplace and not self.flags.allows_duplicate_labels: 

4347 raise ValueError( 

4348 "Cannot specify 'inplace=True' when " 

4349 "'self.flags.allows_duplicate_labels' is False." 

4350 ) 

4351 

4352 @final 

4353 def get(self, key, default=None): 

4354 """ 

4355 Get item from object for given key (ex: DataFrame column). 

4356 

4357 Returns ``default`` value if not found. 

4358 

4359 Parameters 

4360 ---------- 

4361 key : object 

4362 Key for which item should be returned. 

4363 default : object, default None 

4364 Default value to return if key is not found. 

4365 

4366 Returns 

4367 ------- 

4368 same type as items contained in object 

4369 Item for given key or ``default`` value, if key is not found. 

4370 

4371 See Also 

4372 -------- 

4373 DataFrame.get : Get item from object for given key (ex: DataFrame column). 

4374 Series.get : Get item from object for given key (ex: DataFrame column). 

4375 

4376 Examples 

4377 -------- 

4378 >>> df = pd.DataFrame( 

4379 ... [ 

4380 ... [24.3, 75.7, "high"], 

4381 ... [31, 87.8, "high"], 

4382 ... [22, 71.6, "medium"], 

4383 ... [35, 95, "medium"], 

4384 ... ], 

4385 ... columns=["temp_celsius", "temp_fahrenheit", "windspeed"], 

4386 ... index=pd.date_range(start="2014-02-12", end="2014-02-15", freq="D"), 

4387 ... ) 

4388 

4389 >>> df 

4390 temp_celsius temp_fahrenheit windspeed 

4391 2014-02-12 24.3 75.7 high 

4392 2014-02-13 31.0 87.8 high 

4393 2014-02-14 22.0 71.6 medium 

4394 2014-02-15 35.0 95.0 medium 

4395 

4396 >>> df.get(["temp_celsius", "windspeed"]) 

4397 temp_celsius windspeed 

4398 2014-02-12 24.3 high 

4399 2014-02-13 31.0 high 

4400 2014-02-14 22.0 medium 

4401 2014-02-15 35.0 medium 

4402 

4403 >>> ser = df["windspeed"] 

4404 >>> ser.get("2014-02-13") 

4405 'high' 

4406 

4407 If the key isn't found, the default value will be used. 

4408 

4409 >>> df.get(["temp_celsius", "temp_kelvin"], default="default_value") 

4410 'default_value' 

4411 

4412 >>> ser.get("2014-02-10", "[unknown]") 

4413 '[unknown]' 

4414 """ 

4415 try: 

4416 return self[key] 

4417 except (KeyError, ValueError, IndexError): 

4418 return default 

4419 

4420 @staticmethod 

4421 def _check_copy_deprecation(copy): 

4422 if copy is not lib.no_default: 

4423 warnings.warn( 

4424 "The copy keyword is deprecated and will be removed in a future " 

4425 "version. Copy-on-Write is active in pandas since 3.0 which utilizes " 

4426 "a lazy copy mechanism that defers copies until necessary. Use " 

4427 ".copy() to make an eager copy if necessary.", 

4428 Pandas4Warning, 

4429 stacklevel=find_stack_level(), 

4430 ) 

4431 

4432 # issue 58667 

4433 @deprecate_kwarg(Pandas4Warning, "method", new_arg_name=None) 

4434 @final 

4435 def reindex_like( 

4436 self, 

4437 other, 

4438 method: Literal["backfill", "bfill", "pad", "ffill", "nearest"] | None = None, 

4439 copy: bool | lib.NoDefault = lib.no_default, 

4440 limit: int | None = None, 

4441 tolerance=None, 

4442 ) -> Self: 

4443 """ 

4444 Return an object with matching indices as other object. 

4445 

4446 Conform the object to the same index on all axes. Optional 

4447 filling logic, placing NaN in locations having no value 

4448 in the previous index. A new object is produced unless the 

4449 new index is equivalent to the current one and copy=False. 

4450 

4451 Parameters 

4452 ---------- 

4453 other : Object of the same data type 

4454 Its row and column indices are used to define the new indices 

4455 of this object. 

4456 method : {None, 'backfill'/'bfill', 'pad'/'ffill', 'nearest'} 

4457 Method to use for filling holes in reindexed DataFrame. 

4458 Please note: this is only applicable to DataFrames/Series with a 

4459 monotonically increasing/decreasing index. 

4460 

4461 .. deprecated:: 3.0.0 

4462 

4463 * None (default): don't fill gaps 

4464 * pad / ffill: propagate last valid observation forward to next 

4465 valid 

4466 * backfill / bfill: use next valid observation to fill gap 

4467 * nearest: use nearest valid observations to fill gap. 

4468 

4469 copy : bool, default False 

4470 This keyword is now ignored; changing its value will have no 

4471 impact on the method. 

4472 

4473 .. deprecated:: 3.0.0 

4474 

4475 This keyword is ignored and will be removed in pandas 4.0. Since 

4476 pandas 3.0, this method always returns a new object using a lazy 

4477 copy mechanism that defers copies until necessary 

4478 (Copy-on-Write). See the `user guide on Copy-on-Write 

4479 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

4480 for more details. 

4481 

4482 limit : int, default None 

4483 Maximum number of consecutive labels to fill for inexact matches. 

4484 tolerance : optional 

4485 Maximum distance between original and new labels for inexact 

4486 matches. The values of the index at the matching locations must 

4487 satisfy the equation ``abs(index[indexer] - target) <= tolerance``. 

4488 

4489 Tolerance may be a scalar value, which applies the same tolerance 

4490 to all values, or list-like, which applies variable tolerance per 

4491 element. List-like includes list, tuple, array, Series, and must be 

4492 the same size as the index and its dtype must exactly match the 

4493 index's type. 

4494 

4495 Returns 

4496 ------- 

4497 Series or DataFrame 

4498 Same type as caller, but with changed indices on each axis. 

4499 

4500 See Also 

4501 -------- 

4502 DataFrame.set_index : Set row labels. 

4503 DataFrame.reset_index : Remove row labels or move them to new columns. 

4504 DataFrame.reindex : Change to new indices or expand indices. 

4505 

4506 Notes 

4507 ----- 

4508 Same as calling 

4509 ``.reindex(index=other.index, columns=other.columns,...)``. 

4510 

4511 Examples 

4512 -------- 

4513 >>> df1 = pd.DataFrame( 

4514 ... [ 

4515 ... [24.3, 75.7, "high"], 

4516 ... [31, 87.8, "high"], 

4517 ... [22, 71.6, "medium"], 

4518 ... [35, 95, "medium"], 

4519 ... ], 

4520 ... columns=["temp_celsius", "temp_fahrenheit", "windspeed"], 

4521 ... index=pd.date_range(start="2014-02-12", end="2014-02-15", freq="D"), 

4522 ... ) 

4523 

4524 >>> df1 

4525 temp_celsius temp_fahrenheit windspeed 

4526 2014-02-12 24.3 75.7 high 

4527 2014-02-13 31.0 87.8 high 

4528 2014-02-14 22.0 71.6 medium 

4529 2014-02-15 35.0 95.0 medium 

4530 

4531 >>> df2 = pd.DataFrame( 

4532 ... [[28, "low"], [30, "low"], [35.1, "medium"]], 

4533 ... columns=["temp_celsius", "windspeed"], 

4534 ... index=pd.DatetimeIndex(["2014-02-12", "2014-02-13", "2014-02-15"]), 

4535 ... ) 

4536 

4537 >>> df2 

4538 temp_celsius windspeed 

4539 2014-02-12 28.0 low 

4540 2014-02-13 30.0 low 

4541 2014-02-15 35.1 medium 

4542 

4543 >>> df2.reindex_like(df1) 

4544 temp_celsius temp_fahrenheit windspeed 

4545 2014-02-12 28.0 NaN low 

4546 2014-02-13 30.0 NaN low 

4547 2014-02-14 NaN NaN NaN 

4548 2014-02-15 35.1 NaN medium 

4549 """ 

4550 self._check_copy_deprecation(copy) 

4551 d = other._construct_axes_dict( 

4552 axes=self._AXIS_ORDERS, 

4553 method=method, 

4554 limit=limit, 

4555 tolerance=tolerance, 

4556 ) 

4557 

4558 return self.reindex(**d) 

4559 

4560 @overload 

4561 def drop( 

4562 self, 

4563 labels: IndexLabel | ListLike = ..., 

4564 *, 

4565 axis: Axis = ..., 

4566 index: IndexLabel | ListLike = ..., 

4567 columns: IndexLabel | ListLike = ..., 

4568 level: Level | None = ..., 

4569 inplace: Literal[True], 

4570 errors: IgnoreRaise = ..., 

4571 ) -> None: ... 

4572 

4573 @overload 

4574 def drop( 

4575 self, 

4576 labels: IndexLabel | ListLike = ..., 

4577 *, 

4578 axis: Axis = ..., 

4579 index: IndexLabel | ListLike = ..., 

4580 columns: IndexLabel | ListLike = ..., 

4581 level: Level | None = ..., 

4582 inplace: Literal[False] = ..., 

4583 errors: IgnoreRaise = ..., 

4584 ) -> Self: ... 

4585 

4586 @overload 

4587 def drop( 

4588 self, 

4589 labels: IndexLabel | ListLike = ..., 

4590 *, 

4591 axis: Axis = ..., 

4592 index: IndexLabel | ListLike = ..., 

4593 columns: IndexLabel | ListLike = ..., 

4594 level: Level | None = ..., 

4595 inplace: bool = ..., 

4596 errors: IgnoreRaise = ..., 

4597 ) -> Self | None: ... 

4598 

4599 def drop( 

4600 self, 

4601 labels: IndexLabel | ListLike = None, 

4602 *, 

4603 axis: Axis = 0, 

4604 index: IndexLabel | ListLike = None, 

4605 columns: IndexLabel | ListLike = None, 

4606 level: Level | None = None, 

4607 inplace: bool = False, 

4608 errors: IgnoreRaise = "raise", 

4609 ) -> Self | None: 

4610 inplace = validate_bool_kwarg(inplace, "inplace") 

4611 

4612 if labels is not None: 

4613 if index is not None or columns is not None: 

4614 raise ValueError("Cannot specify both 'labels' and 'index'/'columns'") 

4615 axis_name = self._get_axis_name(axis) 

4616 axes = {axis_name: labels} 

4617 elif index is not None or columns is not None: 

4618 if axis == 1: 

4619 raise ValueError("Cannot specify both 'axis' and 'index'/'columns'") 

4620 axes = {"index": index} 

4621 if self.ndim == 2: 

4622 axes["columns"] = columns 

4623 else: 

4624 raise ValueError( 

4625 "Need to specify at least one of 'labels', 'index' or 'columns'" 

4626 ) 

4627 

4628 obj = self 

4629 

4630 for axis, labels in axes.items(): 

4631 if labels is not None: 

4632 obj = obj._drop_axis(labels, axis, level=level, errors=errors) 

4633 

4634 if inplace: 

4635 self._update_inplace(obj) 

4636 return None 

4637 else: 

4638 return obj 

4639 

4640 @final 

4641 def _drop_axis( 

4642 self, 

4643 labels, 

4644 axis, 

4645 level=None, 

4646 errors: IgnoreRaise = "raise", 

4647 only_slice: bool = False, 

4648 ) -> Self: 

4649 """ 

4650 Drop labels from specified axis. Used in the ``drop`` method 

4651 internally. 

4652 

4653 Parameters 

4654 ---------- 

4655 labels : single label or list-like 

4656 axis : int or axis name 

4657 level : int or level name, default None 

4658 For MultiIndex 

4659 errors : {'ignore', 'raise'}, default 'raise' 

4660 If 'ignore', suppress error and existing labels are dropped. 

4661 only_slice : bool, default False 

4662 Whether indexing along columns should be view-only. 

4663 

4664 """ 

4665 axis_num = self._get_axis_number(axis) 

4666 axis = self._get_axis(axis) 

4667 

4668 if axis.is_unique: 

4669 if level is not None: 

4670 if not isinstance(axis, MultiIndex): 

4671 raise AssertionError("axis must be a MultiIndex") 

4672 new_axis = axis.drop(labels, level=level, errors=errors) 

4673 else: 

4674 new_axis = axis.drop(labels, errors=errors) 

4675 indexer = axis.get_indexer(new_axis) 

4676 

4677 # Case for non-unique axis 

4678 else: 

4679 is_tuple_labels = is_nested_list_like(labels) or isinstance(labels, tuple) 

4680 labels = ensure_object(common.index_labels_to_array(labels)) 

4681 if level is not None: 

4682 if not isinstance(axis, MultiIndex): 

4683 raise AssertionError("axis must be a MultiIndex") 

4684 mask = ~axis.get_level_values(level).isin(labels) 

4685 

4686 # GH 18561 MultiIndex.drop should raise if label is absent 

4687 if errors == "raise" and mask.all(): 

4688 raise KeyError(f"{labels} not found in axis") 

4689 elif ( 

4690 isinstance(axis, MultiIndex) 

4691 and labels.dtype == "object" 

4692 and not is_tuple_labels 

4693 ): 

4694 # Set level to zero in case of MultiIndex and label is string, 

4695 # because isin can't handle strings for MultiIndexes GH#36293 

4696 # In case of tuples we get dtype object but have to use isin GH#42771 

4697 mask = ~axis.get_level_values(0).isin(labels) 

4698 else: 

4699 mask = ~axis.isin(labels) 

4700 # Check if label doesn't exist along axis 

4701 labels_missing = (axis.get_indexer_for(labels) == -1).any() 

4702 if errors == "raise" and labels_missing: 

4703 raise KeyError(f"{labels} not found in axis") 

4704 

4705 if isinstance(mask.dtype, ExtensionDtype): 

4706 # GH#45860 

4707 mask = mask.to_numpy(dtype=bool) 

4708 

4709 indexer = mask.nonzero()[0] 

4710 new_axis = axis.take(indexer) 

4711 

4712 bm_axis = self.ndim - axis_num - 1 

4713 new_mgr = self._mgr.reindex_indexer( 

4714 new_axis, 

4715 indexer, 

4716 axis=bm_axis, 

4717 allow_dups=True, 

4718 only_slice=only_slice, 

4719 ) 

4720 result = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) 

4721 if self.ndim == 1: 

4722 result._name = self.name 

4723 

4724 return result.__finalize__(self) 

4725 

4726 @final 

4727 def _update_inplace(self, result) -> None: 

4728 """ 

4729 Replace self internals with result. 

4730 

4731 Parameters 

4732 ---------- 

4733 result : same type as self 

4734 """ 

4735 # NOTE: This does *not* call __finalize__ and that's an explicit 

4736 # decision that we may revisit in the future. 

4737 self._mgr = result._mgr 

4738 

4739 @final 

4740 def add_prefix(self, prefix: str, axis: Axis | None = None) -> Self: 

4741 """ 

4742 Prefix labels with string `prefix`. 

4743 

4744 For Series, the row labels are prefixed. 

4745 For DataFrame, the column labels are prefixed. 

4746 

4747 Parameters 

4748 ---------- 

4749 prefix : str 

4750 The string to add before each label. 

4751 axis : {0 or 'index', 1 or 'columns', None}, default None 

4752 Axis to add prefix on 

4753 

4754 .. versionadded:: 2.0.0 

4755 

4756 Returns 

4757 ------- 

4758 Series or DataFrame 

4759 New Series or DataFrame with updated labels. 

4760 

4761 See Also 

4762 -------- 

4763 Series.add_suffix: Suffix row labels with string `suffix`. 

4764 DataFrame.add_suffix: Suffix column labels with string `suffix`. 

4765 

4766 Examples 

4767 -------- 

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

4769 >>> s 

4770 0 1 

4771 1 2 

4772 2 3 

4773 3 4 

4774 dtype: int64 

4775 

4776 >>> s.add_prefix("item_") 

4777 item_0 1 

4778 item_1 2 

4779 item_2 3 

4780 item_3 4 

4781 dtype: int64 

4782 

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

4784 >>> df 

4785 A B 

4786 0 1 3 

4787 1 2 4 

4788 2 3 5 

4789 3 4 6 

4790 

4791 >>> df.add_prefix("col_") 

4792 col_A col_B 

4793 0 1 3 

4794 1 2 4 

4795 2 3 5 

4796 3 4 6 

4797 """ 

4798 f = lambda x: f"{prefix}{x}" 

4799 

4800 axis_name = self._info_axis_name 

4801 if axis is not None: 

4802 axis_name = self._get_axis_name(axis) 

4803 

4804 mapper = {axis_name: f} 

4805 

4806 # error: Keywords must be strings 

4807 # error: No overload variant of "_rename" of "NDFrame" matches 

4808 # argument type "dict[Literal['index', 'columns'], Callable[[Any], str]]" 

4809 return self._rename(**mapper) # type: ignore[call-overload, misc] 

4810 

4811 @final 

4812 def add_suffix(self, suffix: str, axis: Axis | None = None) -> Self: 

4813 """ 

4814 Suffix labels with string `suffix`. 

4815 

4816 For Series, the row labels are suffixed. 

4817 For DataFrame, the column labels are suffixed. 

4818 

4819 Parameters 

4820 ---------- 

4821 suffix : str 

4822 The string to add after each label. 

4823 axis : {0 or 'index', 1 or 'columns', None}, default None 

4824 Axis to add suffix on 

4825 

4826 .. versionadded:: 2.0.0 

4827 

4828 Returns 

4829 ------- 

4830 Series or DataFrame 

4831 New Series or DataFrame with updated labels. 

4832 

4833 See Also 

4834 -------- 

4835 Series.add_prefix: Prefix row labels with string `prefix`. 

4836 DataFrame.add_prefix: Prefix column labels with string `prefix`. 

4837 

4838 Examples 

4839 -------- 

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

4841 >>> s 

4842 0 1 

4843 1 2 

4844 2 3 

4845 3 4 

4846 dtype: int64 

4847 

4848 >>> s.add_suffix("_item") 

4849 0_item 1 

4850 1_item 2 

4851 2_item 3 

4852 3_item 4 

4853 dtype: int64 

4854 

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

4856 >>> df 

4857 A B 

4858 0 1 3 

4859 1 2 4 

4860 2 3 5 

4861 3 4 6 

4862 

4863 >>> df.add_suffix("_col") 

4864 A_col B_col 

4865 0 1 3 

4866 1 2 4 

4867 2 3 5 

4868 3 4 6 

4869 """ 

4870 f = lambda x: f"{x}{suffix}" 

4871 

4872 axis_name = self._info_axis_name 

4873 if axis is not None: 

4874 axis_name = self._get_axis_name(axis) 

4875 

4876 mapper = {axis_name: f} 

4877 # error: Keywords must be strings 

4878 # error: No overload variant of "_rename" of "NDFrame" matches argument 

4879 # type "dict[Literal['index', 'columns'], Callable[[Any], str]]" 

4880 return self._rename(**mapper) # type: ignore[call-overload, misc] 

4881 

4882 @overload 

4883 def sort_values( 

4884 self, 

4885 *, 

4886 axis: Axis = ..., 

4887 ascending: bool | Sequence[bool] = ..., 

4888 inplace: Literal[False] = ..., 

4889 kind: SortKind = ..., 

4890 na_position: NaPosition = ..., 

4891 ignore_index: bool = ..., 

4892 key: ValueKeyFunc = ..., 

4893 ) -> Self: ... 

4894 

4895 @overload 

4896 def sort_values( 

4897 self, 

4898 *, 

4899 axis: Axis = ..., 

4900 ascending: bool | Sequence[bool] = ..., 

4901 inplace: Literal[True], 

4902 kind: SortKind = ..., 

4903 na_position: NaPosition = ..., 

4904 ignore_index: bool = ..., 

4905 key: ValueKeyFunc = ..., 

4906 ) -> None: ... 

4907 

4908 @overload 

4909 def sort_values( 

4910 self, 

4911 *, 

4912 axis: Axis = ..., 

4913 ascending: bool | Sequence[bool] = ..., 

4914 inplace: bool = ..., 

4915 kind: SortKind = ..., 

4916 na_position: NaPosition = ..., 

4917 ignore_index: bool = ..., 

4918 key: ValueKeyFunc = ..., 

4919 ) -> Self | None: ... 

4920 

4921 def sort_values( 

4922 self, 

4923 *, 

4924 axis: Axis = 0, 

4925 ascending: bool | Sequence[bool] = True, 

4926 inplace: bool = False, 

4927 kind: SortKind = "quicksort", 

4928 na_position: NaPosition = "last", 

4929 ignore_index: bool = False, 

4930 key: ValueKeyFunc | None = None, 

4931 ) -> Self | None: 

4932 """ 

4933 Sort by the values along either axis. 

4934 

4935 Parameters 

4936 ----------%(optional_by)s 

4937 axis : %(axes_single_arg)s, default 0 

4938 Axis to be sorted. 

4939 ascending : bool or list of bool, default True 

4940 Sort ascending vs. descending. Specify list for multiple sort 

4941 orders. If this is a list of bools, must match the length of 

4942 the by. 

4943 inplace : bool, default False 

4944 If True, perform operation in-place. 

4945 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, default 'quicksort' 

4946 Choice of sorting algorithm. See also :func:`numpy.sort` for more 

4947 information. `mergesort` and `stable` are the only stable algorithms. For 

4948 DataFrames, this option is only applied when sorting on a single 

4949 column or label. 

4950 na_position : {'first', 'last'}, default 'last' 

4951 Puts NaNs at the beginning if `first`; `last` puts NaNs at the 

4952 end. 

4953 ignore_index : bool, default False 

4954 If True, the resulting axis will be labeled 0, 1, …, n - 1. 

4955 key : callable, optional 

4956 Apply the key function to the values 

4957 before sorting. This is similar to the `key` argument in the 

4958 builtin :meth:`sorted` function, with the notable difference that 

4959 this `key` function should be *vectorized*. It should expect a 

4960 ``Series`` and return a Series with the same shape as the input. 

4961 It will be applied to each column in `by` independently. The values in the 

4962 returned Series will be used as the keys for sorting. 

4963 

4964 Returns 

4965 ------- 

4966 DataFrame or None 

4967 DataFrame with sorted values or None if ``inplace=True``. 

4968 

4969 See Also 

4970 -------- 

4971 DataFrame.sort_index : Sort a DataFrame by the index. 

4972 Series.sort_values : Similar method for a Series. 

4973 

4974 Examples 

4975 -------- 

4976 >>> df = pd.DataFrame( 

4977 ... { 

4978 ... "col1": ["A", "A", "B", np.nan, "D", "C"], 

4979 ... "col2": [2, 1, 9, 8, 7, 4], 

4980 ... "col3": [0, 1, 9, 4, 2, 3], 

4981 ... "col4": ["a", "B", "c", "D", "e", "F"], 

4982 ... } 

4983 ... ) 

4984 >>> df 

4985 col1 col2 col3 col4 

4986 0 A 2 0 a 

4987 1 A 1 1 B 

4988 2 B 9 9 c 

4989 3 NaN 8 4 D 

4990 4 D 7 2 e 

4991 5 C 4 3 F 

4992 

4993 Sort by col1 

4994 

4995 >>> df.sort_values(by=["col1"]) 

4996 col1 col2 col3 col4 

4997 0 A 2 0 a 

4998 1 A 1 1 B 

4999 2 B 9 9 c 

5000 5 C 4 3 F 

5001 4 D 7 2 e 

5002 3 NaN 8 4 D 

5003 

5004 Sort by multiple columns 

5005 

5006 >>> df.sort_values(by=["col1", "col2"]) 

5007 col1 col2 col3 col4 

5008 1 A 1 1 B 

5009 0 A 2 0 a 

5010 2 B 9 9 c 

5011 5 C 4 3 F 

5012 4 D 7 2 e 

5013 3 NaN 8 4 D 

5014 

5015 Sort Descending 

5016 

5017 >>> df.sort_values(by="col1", ascending=False) 

5018 col1 col2 col3 col4 

5019 4 D 7 2 e 

5020 5 C 4 3 F 

5021 2 B 9 9 c 

5022 0 A 2 0 a 

5023 1 A 1 1 B 

5024 3 NaN 8 4 D 

5025 

5026 Putting NAs first 

5027 

5028 >>> df.sort_values(by="col1", ascending=False, na_position="first") 

5029 col1 col2 col3 col4 

5030 3 NaN 8 4 D 

5031 4 D 7 2 e 

5032 5 C 4 3 F 

5033 2 B 9 9 c 

5034 0 A 2 0 a 

5035 1 A 1 1 B 

5036 

5037 Sorting with a key function 

5038 

5039 >>> df.sort_values(by="col4", key=lambda col: col.str.lower()) 

5040 col1 col2 col3 col4 

5041 0 A 2 0 a 

5042 1 A 1 1 B 

5043 2 B 9 9 c 

5044 3 NaN 8 4 D 

5045 4 D 7 2 e 

5046 5 C 4 3 F 

5047 

5048 Natural sort with the key argument, 

5049 using the `natsort <https://github.com/SethMMorton/natsort>` package. 

5050 

5051 >>> df = pd.DataFrame( 

5052 ... { 

5053 ... "hours": ["0hr", "128hr", "0hr", "64hr", "64hr", "128hr"], 

5054 ... "mins": [ 

5055 ... "10mins", 

5056 ... "40mins", 

5057 ... "40mins", 

5058 ... "40mins", 

5059 ... "10mins", 

5060 ... "10mins", 

5061 ... ], 

5062 ... "value": [10, 20, 30, 40, 50, 60], 

5063 ... } 

5064 ... ) 

5065 >>> df 

5066 hours mins value 

5067 0 0hr 10mins 10 

5068 1 128hr 40mins 20 

5069 2 0hr 40mins 30 

5070 3 64hr 40mins 40 

5071 4 64hr 10mins 50 

5072 5 128hr 10mins 60 

5073 >>> from natsort import natsort_keygen 

5074 >>> df.sort_values( 

5075 ... by=["hours", "mins"], 

5076 ... key=natsort_keygen(), 

5077 ... ) 

5078 hours mins value 

5079 0 0hr 10mins 10 

5080 2 0hr 40mins 30 

5081 4 64hr 10mins 50 

5082 3 64hr 40mins 40 

5083 5 128hr 10mins 60 

5084 1 128hr 40mins 20 

5085 """ 

5086 raise AbstractMethodError(self) 

5087 

5088 @overload 

5089 def sort_index( 

5090 self, 

5091 *, 

5092 axis: Axis = ..., 

5093 level: IndexLabel = ..., 

5094 ascending: bool | Sequence[bool] = ..., 

5095 inplace: Literal[True], 

5096 kind: SortKind = ..., 

5097 na_position: NaPosition = ..., 

5098 sort_remaining: bool = ..., 

5099 ignore_index: bool = ..., 

5100 key: IndexKeyFunc = ..., 

5101 ) -> None: ... 

5102 

5103 @overload 

5104 def sort_index( 

5105 self, 

5106 *, 

5107 axis: Axis = ..., 

5108 level: IndexLabel = ..., 

5109 ascending: bool | Sequence[bool] = ..., 

5110 inplace: Literal[False] = ..., 

5111 kind: SortKind = ..., 

5112 na_position: NaPosition = ..., 

5113 sort_remaining: bool = ..., 

5114 ignore_index: bool = ..., 

5115 key: IndexKeyFunc = ..., 

5116 ) -> Self: ... 

5117 

5118 @overload 

5119 def sort_index( 

5120 self, 

5121 *, 

5122 axis: Axis = ..., 

5123 level: IndexLabel = ..., 

5124 ascending: bool | Sequence[bool] = ..., 

5125 inplace: bool = ..., 

5126 kind: SortKind = ..., 

5127 na_position: NaPosition = ..., 

5128 sort_remaining: bool = ..., 

5129 ignore_index: bool = ..., 

5130 key: IndexKeyFunc = ..., 

5131 ) -> Self | None: ... 

5132 

5133 def sort_index( 

5134 self, 

5135 *, 

5136 axis: Axis = 0, 

5137 level: IndexLabel | None = None, 

5138 ascending: bool | Sequence[bool] = True, 

5139 inplace: bool = False, 

5140 kind: SortKind = "quicksort", 

5141 na_position: NaPosition = "last", 

5142 sort_remaining: bool = True, 

5143 ignore_index: bool = False, 

5144 key: IndexKeyFunc | None = None, 

5145 ) -> Self | None: 

5146 inplace = validate_bool_kwarg(inplace, "inplace") 

5147 axis = self._get_axis_number(axis) 

5148 ascending = validate_ascending(ascending) 

5149 

5150 target = self._get_axis(axis) 

5151 

5152 indexer = get_indexer_indexer( 

5153 target, level, ascending, kind, na_position, sort_remaining, key 

5154 ) 

5155 

5156 if indexer is None: 

5157 if inplace: 

5158 result = self 

5159 else: 

5160 result = self.copy(deep=False) 

5161 

5162 if ignore_index: 

5163 if axis == 1: 

5164 result.columns = default_index(len(self.columns)) 

5165 else: 

5166 result.index = default_index(len(self)) 

5167 if inplace: 

5168 return None 

5169 else: 

5170 return result 

5171 

5172 baxis = self._get_block_manager_axis(axis) 

5173 new_data = self._mgr.take(indexer, axis=baxis, verify=False) 

5174 

5175 # reconstruct axis if needed 

5176 if not ignore_index: 

5177 new_axis = new_data.axes[baxis]._sort_levels_monotonic() 

5178 else: 

5179 new_axis = default_index(len(indexer)) 

5180 new_data.set_axis(baxis, new_axis) 

5181 

5182 result = self._constructor_from_mgr(new_data, axes=new_data.axes) 

5183 

5184 if inplace: 

5185 return self._update_inplace(result) 

5186 else: 

5187 return result.__finalize__(self, method="sort_index") 

5188 

5189 def reindex( 

5190 self, 

5191 labels=None, 

5192 *, 

5193 index=None, 

5194 columns=None, 

5195 axis: Axis | None = None, 

5196 method: ReindexMethod | None = None, 

5197 copy: bool | lib.NoDefault = lib.no_default, 

5198 level: Level | None = None, 

5199 fill_value: Scalar | None = np.nan, 

5200 limit: int | None = None, 

5201 tolerance=None, 

5202 ) -> Self: 

5203 """ 

5204 Conform Series/DataFrame to new index with optional filling logic. 

5205 

5206 Places NA/NaN in locations having no value in the previous index. A new object 

5207 is produced unless the new index is equivalent to the current one and 

5208 ``copy=False``. 

5209 

5210 Parameters 

5211 ---------- 

5212 method : {None, 'backfill'/'bfill', 'pad'/'ffill', 'nearest'} 

5213 Method to use for filling holes in reindexed DataFrame. 

5214 Please note: this is only applicable to DataFrames/Series with a 

5215 monotonically increasing/decreasing index. 

5216 

5217 * None (default): don't fill gaps 

5218 * pad / ffill: Propagate last valid observation forward to next 

5219 valid. 

5220 * backfill / bfill: Use next valid observation to fill gap. 

5221 * nearest: Use nearest valid observations to fill gap. 

5222 

5223 copy : bool, default False 

5224 This keyword is now ignored; changing its value will have no 

5225 impact on the method. 

5226 

5227 .. deprecated:: 3.0.0 

5228 

5229 This keyword is ignored and will be removed in pandas 4.0. Since 

5230 pandas 3.0, this method always returns a new object using a lazy 

5231 copy mechanism that defers copies until necessary 

5232 (Copy-on-Write). See the `user guide on Copy-on-Write 

5233 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

5234 for more details. 

5235 

5236 level : int or name 

5237 Broadcast across a level, matching Index values on the 

5238 passed MultiIndex level. 

5239 fill_value : scalar, default np.nan 

5240 Value to use for missing values. Defaults to NaN, but can be any 

5241 "compatible" value. 

5242 limit : int, default None 

5243 Maximum number of consecutive elements to forward or backward fill. 

5244 tolerance : optional 

5245 Maximum distance between original and new labels for inexact 

5246 matches. The values of the index at the matching locations most 

5247 satisfy the equation ``abs(index[indexer] - target) <= tolerance``. 

5248 

5249 Tolerance may be a scalar value, which applies the same tolerance 

5250 to all values, or list-like, which applies variable tolerance per 

5251 element. List-like includes list, tuple, array, Series, and must be 

5252 the same size as the index and its dtype must exactly match the 

5253 index's type. 

5254 

5255 Returns 

5256 ------- 

5257 Series/DataFrame 

5258 Series/DataFrame with changed index. 

5259 

5260 See Also 

5261 -------- 

5262 DataFrame.set_index : Set row labels. 

5263 DataFrame.reset_index : Remove row labels or move them to new columns. 

5264 DataFrame.reindex_like : Change to same indices as other DataFrame. 

5265 

5266 Examples 

5267 -------- 

5268 ``DataFrame.reindex`` supports two calling conventions 

5269 

5270 * ``(index=index_labels, columns=column_labels, ...)`` 

5271 * ``(labels, axis={'index', 'columns'}, ...)`` 

5272 

5273 We *highly* recommend using keyword arguments to clarify your 

5274 intent. 

5275 

5276 Create a DataFrame with some fictional data. 

5277 

5278 >>> index = ["Firefox", "Chrome", "Safari", "IE10", "Konqueror"] 

5279 >>> columns = ["http_status", "response_time"] 

5280 >>> df = pd.DataFrame( 

5281 ... [[200, 0.04], [200, 0.02], [404, 0.07], [404, 0.08], [301, 1.0]], 

5282 ... columns=columns, 

5283 ... index=index, 

5284 ... ) 

5285 >>> df 

5286 http_status response_time 

5287 Firefox 200 0.04 

5288 Chrome 200 0.02 

5289 Safari 404 0.07 

5290 IE10 404 0.08 

5291 Konqueror 301 1.00 

5292 

5293 Create a new index and reindex the DataFrame. By default 

5294 values in the new index that do not have corresponding 

5295 records in the DataFrame are assigned ``NaN``. 

5296 

5297 >>> new_index = ["Safari", "Iceweasel", "Comodo Dragon", "IE10", "Chrome"] 

5298 >>> df.reindex(new_index) 

5299 http_status response_time 

5300 Safari 404.0 0.07 

5301 Iceweasel NaN NaN 

5302 Comodo Dragon NaN NaN 

5303 IE10 404.0 0.08 

5304 Chrome 200.0 0.02 

5305 

5306 We can fill in the missing values by passing a value to 

5307 the keyword ``fill_value``. Because the index is not monotonically 

5308 increasing or decreasing, we cannot use arguments to the keyword 

5309 ``method`` to fill the ``NaN`` values. 

5310 

5311 >>> df.reindex(new_index, fill_value=0) 

5312 http_status response_time 

5313 Safari 404 0.07 

5314 Iceweasel 0 0.00 

5315 Comodo Dragon 0 0.00 

5316 IE10 404 0.08 

5317 Chrome 200 0.02 

5318 

5319 >>> df.reindex(new_index, fill_value="missing") 

5320 http_status response_time 

5321 Safari 404 0.07 

5322 Iceweasel missing missing 

5323 Comodo Dragon missing missing 

5324 IE10 404 0.08 

5325 Chrome 200 0.02 

5326 

5327 We can also reindex the columns. 

5328 

5329 >>> df.reindex(columns=["http_status", "user_agent"]) 

5330 http_status user_agent 

5331 Firefox 200 NaN 

5332 Chrome 200 NaN 

5333 Safari 404 NaN 

5334 IE10 404 NaN 

5335 Konqueror 301 NaN 

5336 

5337 Or we can use "axis-style" keyword arguments 

5338 

5339 >>> df.reindex(["http_status", "user_agent"], axis="columns") 

5340 http_status user_agent 

5341 Firefox 200 NaN 

5342 Chrome 200 NaN 

5343 Safari 404 NaN 

5344 IE10 404 NaN 

5345 Konqueror 301 NaN 

5346 

5347 To further illustrate the filling functionality in 

5348 ``reindex``, we will create a DataFrame with a 

5349 monotonically increasing index (for example, a sequence 

5350 of dates). 

5351 

5352 >>> date_index = pd.date_range("1/1/2010", periods=6, freq="D") 

5353 >>> df2 = pd.DataFrame( 

5354 ... {"prices": [100, 101, np.nan, 100, 89, 88]}, index=date_index 

5355 ... ) 

5356 >>> df2 

5357 prices 

5358 2010-01-01 100.0 

5359 2010-01-02 101.0 

5360 2010-01-03 NaN 

5361 2010-01-04 100.0 

5362 2010-01-05 89.0 

5363 2010-01-06 88.0 

5364 

5365 Suppose we decide to expand the DataFrame to cover a wider 

5366 date range. 

5367 

5368 >>> date_index2 = pd.date_range("12/29/2009", periods=10, freq="D") 

5369 >>> df2.reindex(date_index2) 

5370 prices 

5371 2009-12-29 NaN 

5372 2009-12-30 NaN 

5373 2009-12-31 NaN 

5374 2010-01-01 100.0 

5375 2010-01-02 101.0 

5376 2010-01-03 NaN 

5377 2010-01-04 100.0 

5378 2010-01-05 89.0 

5379 2010-01-06 88.0 

5380 2010-01-07 NaN 

5381 

5382 The index entries that did not have a value in the original data frame 

5383 (for example, '2009-12-29') are by default filled with ``NaN``. 

5384 If desired, we can fill in the missing values using one of several 

5385 options. 

5386 

5387 For example, to back-propagate the last valid value to fill the ``NaN`` 

5388 values, pass ``bfill`` as an argument to the ``method`` keyword. 

5389 

5390 >>> df2.reindex(date_index2, method="bfill") 

5391 prices 

5392 2009-12-29 100.0 

5393 2009-12-30 100.0 

5394 2009-12-31 100.0 

5395 2010-01-01 100.0 

5396 2010-01-02 101.0 

5397 2010-01-03 NaN 

5398 2010-01-04 100.0 

5399 2010-01-05 89.0 

5400 2010-01-06 88.0 

5401 2010-01-07 NaN 

5402 

5403 Please note that the ``NaN`` value present in the original DataFrame 

5404 (at index value 2010-01-03) will not be filled by any of the 

5405 value propagation schemes. This is because filling while reindexing 

5406 does not look at DataFrame values, but only compares the original and 

5407 desired indexes. If you do want to fill in the ``NaN`` values present 

5408 in the original DataFrame, use the ``fillna()`` method. 

5409 

5410 See the :ref:`user guide <basics.reindexing>` for more. 

5411 """ 

5412 # TODO: Decide if we care about having different examples for different 

5413 # kinds 

5414 

5415 # Automatically detect matching level when reindexing from Index to MultiIndex. 

5416 # This prevents values from being incorrectly set to NaN when the source index 

5417 # name matches a index name in the target MultiIndex 

5418 if ( 

5419 level is None 

5420 and index is not None 

5421 and isinstance(index, MultiIndex) 

5422 and not isinstance(self.index, MultiIndex) 

5423 and self.index.name in index.names 

5424 ): 

5425 level = self.index.name 

5426 self._check_copy_deprecation(copy) 

5427 

5428 if index is not None and columns is not None and labels is not None: 

5429 raise TypeError("Cannot specify all of 'labels', 'index', 'columns'.") 

5430 elif index is not None or columns is not None: 

5431 if axis is not None: 

5432 raise TypeError( 

5433 "Cannot specify both 'axis' and any of 'index' or 'columns'" 

5434 ) 

5435 if labels is not None: 

5436 if index is not None: 

5437 columns = labels 

5438 else: 

5439 index = labels 

5440 elif axis and self._get_axis_number(axis) == 1: 

5441 columns = labels 

5442 else: 

5443 index = labels 

5444 axes: dict[Literal["index", "columns"], Any] = { 

5445 "index": index, 

5446 "columns": columns, 

5447 } 

5448 method = clean_reindex_fill_method(method) 

5449 

5450 # if all axes that are requested to reindex are equal, then only copy 

5451 # if indicated must have index names equal here as well as values 

5452 if all( 

5453 self._get_axis(axis_name).identical(ax) 

5454 for axis_name, ax in axes.items() 

5455 if ax is not None 

5456 ): 

5457 return self.copy(deep=False) 

5458 

5459 # check if we are a multi reindex 

5460 if self._needs_reindex_multi(axes, method, level): 

5461 return self._reindex_multi(axes, fill_value) 

5462 

5463 # perform the reindex on the axes 

5464 return self._reindex_axes( 

5465 axes, level, limit, tolerance, method, fill_value 

5466 ).__finalize__(self, method="reindex") 

5467 

5468 @final 

5469 def _reindex_axes( 

5470 self, 

5471 axes, 

5472 level: Level | None, 

5473 limit: int | None, 

5474 tolerance, 

5475 method, 

5476 fill_value: Scalar | None, 

5477 ) -> Self: 

5478 """Perform the reindex for all the axes.""" 

5479 obj = self 

5480 for a in self._AXIS_ORDERS: 

5481 labels = axes[a] 

5482 if labels is None: 

5483 continue 

5484 

5485 ax = self._get_axis(a) 

5486 new_index, indexer = ax.reindex( 

5487 labels, level=level, limit=limit, tolerance=tolerance, method=method 

5488 ) 

5489 

5490 axis = self._get_axis_number(a) 

5491 obj = obj._reindex_with_indexers( 

5492 {axis: [new_index, indexer]}, 

5493 fill_value=fill_value, 

5494 allow_dups=False, 

5495 ) 

5496 

5497 return obj 

5498 

5499 def _needs_reindex_multi(self, axes, method, level: Level | None) -> bool: 

5500 """Check if we do need a multi reindex.""" 

5501 return ( 

5502 (common.count_not_none(*axes.values()) == self._AXIS_LEN) 

5503 and method is None 

5504 and level is None 

5505 # reindex_multi calls self.values, so we only want to go 

5506 # down that path when doing so is cheap. 

5507 and self._can_fast_transpose 

5508 ) 

5509 

5510 def _reindex_multi(self, axes, fill_value): 

5511 raise AbstractMethodError(self) 

5512 

5513 @final 

5514 def _reindex_with_indexers( 

5515 self, 

5516 reindexers, 

5517 fill_value=None, 

5518 allow_dups: bool = False, 

5519 ) -> Self: 

5520 """allow_dups indicates an internal call here""" 

5521 # reindex doing multiple operations on different axes if indicated 

5522 new_data = self._mgr 

5523 for axis in sorted(reindexers.keys()): 

5524 index, indexer = reindexers[axis] 

5525 baxis = self._get_block_manager_axis(axis) 

5526 

5527 if index is None: 

5528 continue 

5529 

5530 index = ensure_index(index) 

5531 if indexer is not None: 

5532 indexer = ensure_platform_int(indexer) 

5533 

5534 # TODO: speed up on homogeneous DataFrame objects (see _reindex_multi) 

5535 new_data = new_data.reindex_indexer( 

5536 index, 

5537 indexer, 

5538 axis=baxis, 

5539 fill_value=fill_value, 

5540 allow_dups=allow_dups, 

5541 ) 

5542 

5543 if new_data is self._mgr: 

5544 new_data = new_data.copy(deep=False) 

5545 

5546 return self._constructor_from_mgr(new_data, axes=new_data.axes).__finalize__( 

5547 self 

5548 ) 

5549 

5550 def filter( 

5551 self, 

5552 items=None, 

5553 like: str | None = None, 

5554 regex: str | None = None, 

5555 axis: Axis | None = None, 

5556 ) -> Self: 

5557 """ 

5558 Subset the DataFrame or Series according to the specified index labels. 

5559 

5560 For DataFrame, filter rows or columns depending on ``axis`` argument. 

5561 Note that this routine does not filter based on content. 

5562 The filter is applied to the labels of the index. 

5563 

5564 Parameters 

5565 ---------- 

5566 items : list-like 

5567 Keep labels from axis which are in items. 

5568 like : str 

5569 Keep labels from axis for which "like in label == True". 

5570 regex : str (regular expression) 

5571 Keep labels from axis for which re.search(regex, label) == True. 

5572 axis : {0 or 'index', 1 or 'columns', None}, default None 

5573 The axis to filter on, expressed either as an index (int) 

5574 or axis name (str). By default this is the info axis, 'columns' for 

5575 ``DataFrame``. For ``Series`` this parameter is unused and defaults to 

5576 ``None``. 

5577 

5578 Returns 

5579 ------- 

5580 Same type as caller 

5581 The filtered subset of the DataFrame or Series. 

5582 

5583 See Also 

5584 -------- 

5585 DataFrame.loc : Access a group of rows and columns 

5586 by label(s) or a boolean array. 

5587 

5588 Notes 

5589 ----- 

5590 The ``items``, ``like``, and ``regex`` parameters are 

5591 enforced to be mutually exclusive. 

5592 

5593 ``axis`` defaults to the info axis that is used when indexing 

5594 with ``[]``. 

5595 

5596 Examples 

5597 -------- 

5598 >>> df = pd.DataFrame( 

5599 ... np.array(([1, 2, 3], [4, 5, 6])), 

5600 ... index=["mouse", "rabbit"], 

5601 ... columns=["one", "two", "three"], 

5602 ... ) 

5603 >>> df 

5604 one two three 

5605 mouse 1 2 3 

5606 rabbit 4 5 6 

5607 

5608 >>> # select columns by name 

5609 >>> df.filter(items=["one", "three"]) 

5610 one three 

5611 mouse 1 3 

5612 rabbit 4 6 

5613 

5614 >>> # select columns by regular expression 

5615 >>> df.filter(regex="e$", axis=1) 

5616 one three 

5617 mouse 1 3 

5618 rabbit 4 6 

5619 

5620 >>> # select rows containing 'bbi' 

5621 >>> df.filter(like="bbi", axis=0) 

5622 one two three 

5623 rabbit 4 5 6 

5624 """ 

5625 nkw = common.count_not_none(items, like, regex) 

5626 if nkw > 1: 

5627 raise TypeError( 

5628 "Keyword arguments `items`, `like`, or `regex` are mutually exclusive" 

5629 ) 

5630 

5631 if axis is None: 

5632 axis = self._info_axis_name 

5633 labels = self._get_axis(axis) 

5634 

5635 if items is not None: 

5636 name = self._get_axis_name(axis) 

5637 items = Index(items).intersection(labels) 

5638 if len(items) == 0: 

5639 # Keep the dtype of labels when we are empty 

5640 items = items.astype(labels.dtype) 

5641 # error: Keywords must be strings 

5642 return self.reindex(**{name: items}) # type: ignore[misc] 

5643 elif like: 

5644 

5645 def f(x) -> bool: 

5646 assert like is not None # needed for mypy 

5647 return like in ensure_str(x) 

5648 

5649 values = labels.map(f) 

5650 return self.loc(axis=axis)[values] 

5651 elif regex: 

5652 

5653 def f(x) -> bool: 

5654 return matcher.search(ensure_str(x)) is not None 

5655 

5656 matcher = re.compile(regex) 

5657 values = labels.map(f) 

5658 return self.loc(axis=axis)[values] 

5659 else: 

5660 raise TypeError("Must pass either `items`, `like`, or `regex`") 

5661 

5662 @final 

5663 def head(self, n: int = 5) -> Self: 

5664 """ 

5665 Return the first `n` rows. 

5666 

5667 This function exhibits the same behavior as ``df[:n]``, returning the 

5668 first ``n`` rows based on position. It is useful for quickly checking 

5669 if your object has the right type of data in it. 

5670 

5671 When ``n`` is positive, it returns the first ``n`` rows. For ``n`` equal to 0, 

5672 it returns an empty object. When ``n`` is negative, it returns 

5673 all rows except the last ``|n|`` rows, mirroring the behavior of ``df[:n]``. 

5674 

5675 If ``n`` is larger than the number of rows, this function returns all rows. 

5676 

5677 Parameters 

5678 ---------- 

5679 n : int, default 5 

5680 Number of rows to select. 

5681 

5682 Returns 

5683 ------- 

5684 same type as caller 

5685 The first `n` rows of the caller object. 

5686 

5687 See Also 

5688 -------- 

5689 DataFrame.tail: Returns the last `n` rows. 

5690 

5691 Examples 

5692 -------- 

5693 >>> df = pd.DataFrame( 

5694 ... { 

5695 ... "animal": [ 

5696 ... "alligator", 

5697 ... "bee", 

5698 ... "falcon", 

5699 ... "lion", 

5700 ... "monkey", 

5701 ... "parrot", 

5702 ... "shark", 

5703 ... "whale", 

5704 ... "zebra", 

5705 ... ] 

5706 ... } 

5707 ... ) 

5708 >>> df 

5709 animal 

5710 0 alligator 

5711 1 bee 

5712 2 falcon 

5713 3 lion 

5714 4 monkey 

5715 5 parrot 

5716 6 shark 

5717 7 whale 

5718 8 zebra 

5719 

5720 Viewing the first 5 lines 

5721 

5722 >>> df.head() 

5723 animal 

5724 0 alligator 

5725 1 bee 

5726 2 falcon 

5727 3 lion 

5728 4 monkey 

5729 

5730 Viewing the first `n` lines (three in this case) 

5731 

5732 >>> df.head(3) 

5733 animal 

5734 0 alligator 

5735 1 bee 

5736 2 falcon 

5737 

5738 For negative values of `n` 

5739 

5740 >>> df.head(-3) 

5741 animal 

5742 0 alligator 

5743 1 bee 

5744 2 falcon 

5745 3 lion 

5746 4 monkey 

5747 5 parrot 

5748 """ 

5749 return self.iloc[:n].copy() 

5750 

5751 @final 

5752 def tail(self, n: int = 5) -> Self: 

5753 """ 

5754 Return the last `n` rows. 

5755 

5756 This function returns last `n` rows from the object based on 

5757 position. It is useful for quickly verifying data, for example, 

5758 after sorting or appending rows. 

5759 

5760 For negative values of `n`, this function returns all rows except 

5761 the first `|n|` rows, equivalent to ``df[|n|:]``. 

5762 

5763 If ``n`` is larger than the number of rows, this function returns all rows. 

5764 

5765 Parameters 

5766 ---------- 

5767 n : int, default 5 

5768 Number of rows to select. 

5769 

5770 Returns 

5771 ------- 

5772 type of caller 

5773 The last `n` rows of the caller object. 

5774 

5775 See Also 

5776 -------- 

5777 DataFrame.head : The first `n` rows of the caller object. 

5778 

5779 Examples 

5780 -------- 

5781 >>> df = pd.DataFrame( 

5782 ... { 

5783 ... "animal": [ 

5784 ... "alligator", 

5785 ... "bee", 

5786 ... "falcon", 

5787 ... "lion", 

5788 ... "monkey", 

5789 ... "parrot", 

5790 ... "shark", 

5791 ... "whale", 

5792 ... "zebra", 

5793 ... ] 

5794 ... } 

5795 ... ) 

5796 >>> df 

5797 animal 

5798 0 alligator 

5799 1 bee 

5800 2 falcon 

5801 3 lion 

5802 4 monkey 

5803 5 parrot 

5804 6 shark 

5805 7 whale 

5806 8 zebra 

5807 

5808 Viewing the last 5 lines 

5809 

5810 >>> df.tail() 

5811 animal 

5812 4 monkey 

5813 5 parrot 

5814 6 shark 

5815 7 whale 

5816 8 zebra 

5817 

5818 Viewing the last `n` lines (three in this case) 

5819 

5820 >>> df.tail(3) 

5821 animal 

5822 6 shark 

5823 7 whale 

5824 8 zebra 

5825 

5826 For negative values of `n` 

5827 

5828 >>> df.tail(-3) 

5829 animal 

5830 3 lion 

5831 4 monkey 

5832 5 parrot 

5833 6 shark 

5834 7 whale 

5835 8 zebra 

5836 """ 

5837 if n == 0: 

5838 return self.iloc[0:0].copy() 

5839 return self.iloc[-n:].copy() 

5840 

5841 @final 

5842 def sample( 

5843 self, 

5844 n: int | None = None, 

5845 frac: float | None = None, 

5846 replace: bool = False, 

5847 weights=None, 

5848 random_state: RandomState | None = None, 

5849 axis: Axis | None = None, 

5850 ignore_index: bool = False, 

5851 ) -> Self: 

5852 """ 

5853 Return a random sample of items from an axis of object. 

5854 

5855 You can use `random_state` for reproducibility. 

5856 

5857 Parameters 

5858 ---------- 

5859 n : int, optional 

5860 Number of items from axis to return. Cannot be used with `frac`. 

5861 Default = 1 if `frac` = None. 

5862 frac : float, optional 

5863 Fraction of axis items to return. Cannot be used with `n`. 

5864 replace : bool, default False 

5865 Allow or disallow sampling of the same row more than once. 

5866 weights : str or ndarray-like, optional 

5867 Default ``None`` results in equal probability weighting. 

5868 If passed a Series, will align with target object on index. Index 

5869 values in weights not found in sampled object will be ignored and 

5870 index values in sampled object not in weights will be assigned 

5871 weights of zero. 

5872 If called on a DataFrame, will accept the name of a column 

5873 when axis = 0. 

5874 Unless weights are a Series, weights must be same length as axis 

5875 being sampled. 

5876 If weights do not sum to 1, they will be normalized to sum to 1. 

5877 Missing values in the weights column will be treated as zero. 

5878 Infinite values not allowed. 

5879 When replace = False will not allow ``(n * max(weights) / sum(weights)) > 1`` 

5880 in order to avoid biased results. See the Notes below for more details. 

5881 random_state : int, array-like, BitGenerator, np.random.RandomState, np.random.Generator, optional 

5882 If int, array-like, or BitGenerator, seed for random number generator. 

5883 If np.random.RandomState or np.random.Generator, use as given. 

5884 Default ``None`` results in sampling with the current state of np.random. 

5885 axis : {0 or 'index', 1 or 'columns', None}, default None 

5886 Axis to sample. Accepts axis number or name. Default is stat axis 

5887 for given data type. For `Series` this parameter is unused and defaults to `None`. 

5888 ignore_index : bool, default False 

5889 If True, the resulting index will be labeled 0, 1, …, n - 1. 

5890 

5891 Returns 

5892 ------- 

5893 Series or DataFrame 

5894 A new object of same type as caller containing `n` items randomly 

5895 sampled from the caller object. 

5896 

5897 See Also 

5898 -------- 

5899 DataFrameGroupBy.sample: Generates random samples from each group of a 

5900 DataFrame object. 

5901 SeriesGroupBy.sample: Generates random samples from each group of a 

5902 Series object. 

5903 numpy.random.choice: Generates a random sample from a given 1-D numpy 

5904 array. 

5905 

5906 Notes 

5907 ----- 

5908 If `frac` > 1, `replacement` should be set to `True`. 

5909 

5910 When replace = False will not allow ``(n * max(weights) / sum(weights)) > 1``, 

5911 since that would cause results to be biased. E.g. sampling 2 items without replacement 

5912 with weights [100, 1, 1] would yield two last items in 1/2 of cases, instead of 1/102. 

5913 This is similar to specifying `n=4` without replacement on a Series with 3 elements. 

5914 

5915 Examples 

5916 -------- 

5917 >>> df = pd.DataFrame( 

5918 ... { 

5919 ... "num_legs": [2, 4, 8, 0], 

5920 ... "num_wings": [2, 0, 0, 0], 

5921 ... "num_specimen_seen": [10, 2, 1, 8], 

5922 ... }, 

5923 ... index=["falcon", "dog", "spider", "fish"], 

5924 ... ) 

5925 >>> df 

5926 num_legs num_wings num_specimen_seen 

5927 falcon 2 2 10 

5928 dog 4 0 2 

5929 spider 8 0 1 

5930 fish 0 0 8 

5931 

5932 Extract 3 random elements from the ``Series`` ``df['num_legs']``: 

5933 Note that we use `random_state` to ensure the reproducibility of 

5934 the examples. 

5935 

5936 >>> df["num_legs"].sample(n=3, random_state=1) 

5937 fish 0 

5938 spider 8 

5939 falcon 2 

5940 Name: num_legs, dtype: int64 

5941 

5942 A random 50% sample of the ``DataFrame`` with replacement: 

5943 

5944 >>> df.sample(frac=0.5, replace=True, random_state=1) 

5945 num_legs num_wings num_specimen_seen 

5946 dog 4 0 2 

5947 fish 0 0 8 

5948 

5949 An upsample sample of the ``DataFrame`` with replacement: 

5950 Note that `replace` parameter has to be `True` for `frac` parameter > 1. 

5951 

5952 >>> df.sample(frac=2, replace=True, random_state=1) 

5953 num_legs num_wings num_specimen_seen 

5954 dog 4 0 2 

5955 fish 0 0 8 

5956 falcon 2 2 10 

5957 falcon 2 2 10 

5958 fish 0 0 8 

5959 dog 4 0 2 

5960 fish 0 0 8 

5961 dog 4 0 2 

5962 

5963 Using a DataFrame column as weights. Rows with larger value in the 

5964 `num_specimen_seen` column are more likely to be sampled. 

5965 

5966 >>> df.sample(n=2, weights="num_specimen_seen", random_state=1) 

5967 num_legs num_wings num_specimen_seen 

5968 falcon 2 2 10 

5969 fish 0 0 8 

5970 """ # noqa: E501 

5971 if axis is None: 

5972 axis = 0 

5973 

5974 axis = self._get_axis_number(axis) 

5975 obj_len = self.shape[axis] 

5976 

5977 # Process random_state argument 

5978 rs = common.random_state(random_state) 

5979 

5980 size = sample.process_sampling_size(n, frac, replace) 

5981 if size is None: 

5982 assert frac is not None 

5983 size = round(frac * obj_len) 

5984 

5985 if weights is not None: 

5986 weights = sample.preprocess_weights(self, weights, axis) 

5987 

5988 sampled_indices = sample.sample(obj_len, size, replace, weights, rs) 

5989 result = self.take(sampled_indices, axis=axis) 

5990 

5991 if ignore_index: 

5992 result.index = default_index(len(result)) 

5993 

5994 return result 

5995 

5996 @overload 

5997 def pipe( 

5998 self, 

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

6000 *args: P.args, 

6001 **kwargs: P.kwargs, 

6002 ) -> T: ... 

6003 

6004 @overload 

6005 def pipe( 

6006 self, 

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

6008 *args: Any, 

6009 **kwargs: Any, 

6010 ) -> T: ... 

6011 

6012 @final 

6013 def pipe( 

6014 self, 

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

6016 *args: Any, 

6017 **kwargs: Any, 

6018 ) -> T: 

6019 r""" 

6020 Apply chainable functions that expect Series or DataFrames. 

6021 

6022 Parameters 

6023 ---------- 

6024 func : function 

6025 Function to apply to the Series/DataFrame. 

6026 ``args``, and ``kwargs`` are passed into ``func``. 

6027 Alternatively a ``(callable, data_keyword)`` tuple where 

6028 ``data_keyword`` is a string indicating the keyword of 

6029 ``callable`` that expects the Series/DataFrame. 

6030 *args : iterable, optional 

6031 Positional arguments passed into ``func``. 

6032 **kwargs : mapping, optional 

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

6034 

6035 Returns 

6036 ------- 

6037 The return type of ``func``. 

6038 The result of applying ``func`` to the Series or DataFrame. 

6039 

6040 See Also 

6041 -------- 

6042 DataFrame.apply : Apply a function along input axis of DataFrame. 

6043 DataFrame.map : Apply a function elementwise on a whole DataFrame. 

6044 Series.map : Apply a mapping correspondence on a 

6045 :class:`~pandas.Series`. 

6046 

6047 Notes 

6048 ----- 

6049 Use ``.pipe`` when chaining together functions that expect 

6050 Series, DataFrames or GroupBy objects. 

6051 

6052 Examples 

6053 -------- 

6054 Constructing an income DataFrame from a dictionary. 

6055 

6056 >>> data = [[8000, 1000], [9500, np.nan], [5000, 2000]] 

6057 >>> df = pd.DataFrame(data, columns=["Salary", "Others"]) 

6058 >>> df 

6059 Salary Others 

6060 0 8000 1000.0 

6061 1 9500 NaN 

6062 2 5000 2000.0 

6063 

6064 Functions that perform tax reductions on an income DataFrame. 

6065 

6066 >>> def subtract_federal_tax(df): 

6067 ... return df * 0.9 

6068 >>> def subtract_state_tax(df, rate): 

6069 ... return df * (1 - rate) 

6070 >>> def subtract_national_insurance(df, rate, rate_increase): 

6071 ... new_rate = rate + rate_increase 

6072 ... return df * (1 - new_rate) 

6073 

6074 Instead of writing 

6075 

6076 >>> subtract_national_insurance( 

6077 ... subtract_state_tax(subtract_federal_tax(df), rate=0.12), 

6078 ... rate=0.05, 

6079 ... rate_increase=0.02, 

6080 ... ) # doctest: +SKIP 

6081 

6082 You can write 

6083 

6084 >>> ( 

6085 ... df.pipe(subtract_federal_tax) 

6086 ... .pipe(subtract_state_tax, rate=0.12) 

6087 ... .pipe(subtract_national_insurance, rate=0.05, rate_increase=0.02) 

6088 ... ) 

6089 Salary Others 

6090 0 5892.48 736.56 

6091 1 6997.32 NaN 

6092 2 3682.80 1473.12 

6093 

6094 If you have a function that takes the data as (say) the second 

6095 argument, pass a tuple indicating which keyword expects the 

6096 data. For example, suppose ``national_insurance`` takes its data as ``df`` 

6097 in the second argument: 

6098 

6099 >>> def subtract_national_insurance(rate, df, rate_increase): 

6100 ... new_rate = rate + rate_increase 

6101 ... return df * (1 - new_rate) 

6102 >>> ( 

6103 ... df.pipe(subtract_federal_tax) 

6104 ... .pipe(subtract_state_tax, rate=0.12) 

6105 ... .pipe( 

6106 ... (subtract_national_insurance, "df"), rate=0.05, rate_increase=0.02 

6107 ... ) 

6108 ... ) 

6109 Salary Others 

6110 0 5892.48 736.56 

6111 1 6997.32 NaN 

6112 2 3682.80 1473.12 

6113 """ 

6114 return common.pipe(self.copy(deep=False), func, *args, **kwargs) 

6115 

6116 # ---------------------------------------------------------------------- 

6117 # Attribute access 

6118 

6119 @final 

6120 def __finalize__(self, other, method: str | None = None, **kwargs) -> Self: 

6121 """ 

6122 Propagate metadata from other to self. 

6123 

6124 This is the default implementation. Subclasses may override this method to 

6125 implement their own metadata handling. 

6126 

6127 Parameters 

6128 ---------- 

6129 other : the object from which to get the attributes that we are going 

6130 to propagate. If ``other`` has an ``input_objs`` attribute, then 

6131 this attribute must contain an iterable of objects, each with an 

6132 ``attrs`` attribute. 

6133 method : str, optional 

6134 A passed method name providing context on where ``__finalize__`` 

6135 was called. 

6136 

6137 .. warning:: 

6138 

6139 The value passed as `method` are not currently considered 

6140 stable across pandas releases. 

6141 

6142 Notes 

6143 ----- 

6144 In case ``other`` has an ``input_objs`` attribute, this method only 

6145 propagates its metadata if each object in ``input_objs`` has the exact 

6146 same metadata as the others. 

6147 """ 

6148 if isinstance(other, NDFrame): 

6149 if other.attrs: 

6150 # We want attrs propagation to have minimal performance 

6151 # impact if attrs are not used; i.e. attrs is an empty dict. 

6152 # One could make the deepcopy unconditionally, but a deepcopy 

6153 # of an empty dict is 50x more expensive than the empty check. 

6154 self.attrs = deepcopy(other.attrs) 

6155 self.flags.allows_duplicate_labels = ( 

6156 self.flags.allows_duplicate_labels 

6157 and other.flags.allows_duplicate_labels 

6158 ) 

6159 # For subclasses using _metadata. 

6160 for name in set(self._metadata) & set(other._metadata): 

6161 assert isinstance(name, str) 

6162 object.__setattr__(self, name, getattr(other, name, None)) 

6163 

6164 elif hasattr(other, "input_objs"): 

6165 objs = other.input_objs 

6166 # propagate attrs only if all inputs have the same attrs 

6167 if all(bool(obj.attrs) for obj in objs): 

6168 # all inputs have non-empty attrs 

6169 attrs = objs[0].attrs 

6170 have_same_attrs = all(obj.attrs == attrs for obj in objs[1:]) 

6171 if have_same_attrs: 

6172 self.attrs = deepcopy(attrs) 

6173 

6174 allows_duplicate_labels = all(x.flags.allows_duplicate_labels for x in objs) 

6175 self.flags.allows_duplicate_labels = allows_duplicate_labels 

6176 

6177 return self 

6178 

6179 @final 

6180 def __getattr__(self, name: str): 

6181 """ 

6182 After regular attribute access, try looking up the name 

6183 This allows simpler access to columns for interactive use. 

6184 """ 

6185 # Note: obj.x will always call obj.__getattribute__('x') prior to 

6186 # calling obj.__getattr__('x'). 

6187 if ( 

6188 name not in self._internal_names_set 

6189 and name not in self._metadata 

6190 and name not in self._accessors 

6191 and self._info_axis._can_hold_identifiers_and_holds_name(name) 

6192 ): 

6193 return self[name] 

6194 return object.__getattribute__(self, name) 

6195 

6196 @final 

6197 def __setattr__(self, name: str, value) -> None: 

6198 """ 

6199 After regular attribute access, try setting the name 

6200 This allows simpler access to columns for interactive use. 

6201 """ 

6202 # first try regular attribute access via __getattribute__, so that 

6203 # e.g. ``obj.x`` and ``obj.x = 4`` will always reference/modify 

6204 # the same attribute. 

6205 

6206 try: 

6207 object.__getattribute__(self, name) 

6208 return object.__setattr__(self, name, value) 

6209 except AttributeError: 

6210 pass 

6211 

6212 # if this fails, go on to more involved attribute setting 

6213 # (note that this matches __getattr__, above). 

6214 if name in self._internal_names_set: 

6215 object.__setattr__(self, name, value) 

6216 elif name in self._metadata: 

6217 object.__setattr__(self, name, value) 

6218 else: 

6219 try: 

6220 existing = getattr(self, name) 

6221 if isinstance(existing, Index): 

6222 object.__setattr__(self, name, value) 

6223 elif name in self._info_axis: 

6224 self[name] = value 

6225 else: 

6226 object.__setattr__(self, name, value) 

6227 except (AttributeError, TypeError): 

6228 if isinstance(self, ABCDataFrame) and (is_list_like(value)): 

6229 warnings.warn( 

6230 "Pandas doesn't allow columns to be " 

6231 "created via a new attribute name - see " 

6232 "https://pandas.pydata.org/pandas-docs/" 

6233 "stable/indexing.html#attribute-access", 

6234 stacklevel=find_stack_level(), 

6235 ) 

6236 object.__setattr__(self, name, value) 

6237 

6238 @final 

6239 def _dir_additions(self) -> set[str]: 

6240 """ 

6241 add the string-like attributes from the info_axis. 

6242 If info_axis is a MultiIndex, its first level values are used. 

6243 """ 

6244 additions = super()._dir_additions() 

6245 if self._info_axis._can_hold_strings: 

6246 additions.update(self._info_axis._dir_additions_for_owner) 

6247 return additions 

6248 

6249 # ---------------------------------------------------------------------- 

6250 # Consolidation of internals 

6251 

6252 @final 

6253 def _consolidate_inplace(self) -> None: 

6254 """Consolidate data in place and return None""" 

6255 

6256 self._mgr = self._mgr.consolidate() 

6257 

6258 @final 

6259 def _consolidate(self): 

6260 """ 

6261 Compute NDFrame with "consolidated" internals (data of each dtype 

6262 grouped together in a single ndarray). 

6263 

6264 Returns 

6265 ------- 

6266 consolidated : same type as caller 

6267 """ 

6268 cons_data = self._mgr.consolidate() 

6269 return self._constructor_from_mgr(cons_data, axes=cons_data.axes).__finalize__( 

6270 self 

6271 ) 

6272 

6273 @final 

6274 @property 

6275 def _is_mixed_type(self) -> bool: 

6276 if self._mgr.is_single_block: 

6277 # Includes all Series cases 

6278 return False 

6279 

6280 if self._mgr.any_extension_types: 

6281 # Even if they have the same dtype, we can't consolidate them, 

6282 # so we pretend this is "mixed'" 

6283 return True 

6284 

6285 return self.dtypes.nunique() > 1 

6286 

6287 @final 

6288 def _get_numeric_data(self) -> Self: 

6289 new_mgr = self._mgr.get_numeric_data() 

6290 return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__(self) 

6291 

6292 @final 

6293 def _get_bool_data(self): 

6294 new_mgr = self._mgr.get_bool_data() 

6295 return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__(self) 

6296 

6297 # ---------------------------------------------------------------------- 

6298 # Internal Interface Methods 

6299 

6300 @property 

6301 def values(self): 

6302 raise AbstractMethodError(self) 

6303 

6304 @property 

6305 def _values(self) -> ArrayLike: 

6306 """internal implementation""" 

6307 raise AbstractMethodError(self) 

6308 

6309 @property 

6310 def dtypes(self): 

6311 """ 

6312 Return the dtypes in the DataFrame. 

6313 

6314 This returns a Series with the data type of each column. 

6315 The result's index is the original DataFrame's columns. Columns 

6316 with mixed types are stored with the ``object`` dtype. See 

6317 :ref:`the User Guide <basics.dtypes>` for more. 

6318 

6319 Returns 

6320 ------- 

6321 pandas.Series 

6322 The data type of each column. 

6323 

6324 See Also 

6325 -------- 

6326 Series.dtypes : Return the dtype object of the underlying data. 

6327 

6328 Examples 

6329 -------- 

6330 >>> df = pd.DataFrame( 

6331 ... { 

6332 ... "float": [1.0], 

6333 ... "int": [1], 

6334 ... "datetime": [pd.Timestamp("20180310")], 

6335 ... "string": ["foo"], 

6336 ... } 

6337 ... ) 

6338 >>> df.dtypes 

6339 float float64 

6340 int int64 

6341 datetime datetime64[us] 

6342 string str 

6343 dtype: object 

6344 """ 

6345 data = self._mgr.get_dtypes() 

6346 return self._constructor_sliced(data, index=self._info_axis, dtype=np.object_) 

6347 

6348 @final 

6349 def astype( 

6350 self, 

6351 dtype, 

6352 copy: bool | lib.NoDefault = lib.no_default, 

6353 errors: IgnoreRaise = "raise", 

6354 ) -> Self: 

6355 """ 

6356 Cast a pandas object to a specified dtype ``dtype``. 

6357 

6358 This method allows the conversion of the data types of pandas objects, 

6359 including DataFrames and Series, to the specified dtype. It supports casting 

6360 entire objects to a single data type or applying different data types to 

6361 individual columns using a mapping. 

6362 

6363 Parameters 

6364 ---------- 

6365 dtype : str, data type, Series or Mapping of column name -> data type 

6366 Use a str, numpy.dtype, pandas.ExtensionDtype or Python type to 

6367 cast entire pandas object to the same type. Alternatively, use a 

6368 mapping, e.g. {col: dtype, ...}, where col is a column label and dtype is 

6369 a numpy.dtype or Python type to cast one or more of the DataFrame's 

6370 columns to column-specific types. 

6371 copy : bool, default False 

6372 This keyword is now ignored; changing its value will have no 

6373 impact on the method. 

6374 

6375 .. deprecated:: 3.0.0 

6376 

6377 This keyword is ignored and will be removed in pandas 4.0. Since 

6378 pandas 3.0, this method always returns a new object using a lazy 

6379 copy mechanism that defers copies until necessary 

6380 (Copy-on-Write). See the `user guide on Copy-on-Write 

6381 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

6382 for more details. 

6383 

6384 errors : {'raise', 'ignore'}, default 'raise' 

6385 Control raising of exceptions on invalid data for provided dtype. 

6386 

6387 - ``raise`` : allow exceptions to be raised 

6388 - ``ignore`` : suppress exceptions. On error return original object. 

6389 

6390 Returns 

6391 ------- 

6392 same type as caller 

6393 The pandas object casted to the specified ``dtype``. 

6394 

6395 See Also 

6396 -------- 

6397 to_datetime : Convert argument to datetime. 

6398 to_timedelta : Convert argument to timedelta. 

6399 to_numeric : Convert argument to a numeric type. 

6400 numpy.ndarray.astype : Cast a numpy array to a specified type. 

6401 

6402 Notes 

6403 ----- 

6404 .. versionchanged:: 2.0.0 

6405 

6406 Using ``astype`` to convert from timezone-naive dtype to 

6407 timezone-aware dtype will raise an exception. 

6408 Use :meth:`Series.dt.tz_localize` instead. 

6409 

6410 Examples 

6411 -------- 

6412 Create a DataFrame: 

6413 

6414 >>> d = {"col1": [1, 2], "col2": [3, 4]} 

6415 >>> df = pd.DataFrame(data=d) 

6416 >>> df.dtypes 

6417 col1 int64 

6418 col2 int64 

6419 dtype: object 

6420 

6421 Cast all columns to int32: 

6422 

6423 >>> df.astype("int32").dtypes 

6424 col1 int32 

6425 col2 int32 

6426 dtype: object 

6427 

6428 Cast col1 to int32 using a dictionary: 

6429 

6430 >>> df.astype({"col1": "int32"}).dtypes 

6431 col1 int32 

6432 col2 int64 

6433 dtype: object 

6434 

6435 Create a series: 

6436 

6437 >>> ser = pd.Series([1, 2], dtype="int32") 

6438 >>> ser 

6439 0 1 

6440 1 2 

6441 dtype: int32 

6442 >>> ser.astype("int64") 

6443 0 1 

6444 1 2 

6445 dtype: int64 

6446 

6447 Convert to categorical type: 

6448 

6449 >>> ser.astype("category") 

6450 0 1 

6451 1 2 

6452 dtype: category 

6453 Categories (2, int32): [1, 2] 

6454 

6455 Convert to ordered categorical type with custom ordering: 

6456 

6457 >>> from pandas.api.types import CategoricalDtype 

6458 >>> cat_dtype = CategoricalDtype(categories=[2, 1], ordered=True) 

6459 >>> ser.astype(cat_dtype) 

6460 0 1 

6461 1 2 

6462 dtype: category 

6463 Categories (2, int64): [2 < 1] 

6464 

6465 Create a series of dates: 

6466 

6467 >>> ser_date = pd.Series(pd.date_range("20200101", periods=3)) 

6468 >>> ser_date 

6469 0 2020-01-01 

6470 1 2020-01-02 

6471 2 2020-01-03 

6472 dtype: datetime64[us] 

6473 """ 

6474 self._check_copy_deprecation(copy) 

6475 if is_dict_like(dtype): 

6476 if self.ndim == 1: # i.e. Series 

6477 if len(dtype) > 1 or self.name not in dtype: 

6478 raise KeyError( 

6479 "Only the Series name can be used for " 

6480 "the key in Series dtype mappings." 

6481 ) 

6482 new_type = dtype[self.name] 

6483 return self.astype(new_type, errors=errors) 

6484 

6485 # GH#44417 cast to Series so we can use .iat below, which will be 

6486 # robust in case we 

6487 from pandas import Series 

6488 

6489 dtype_ser = Series(dtype, dtype=object) 

6490 

6491 for col_name in dtype_ser.index: 

6492 if col_name not in self: 

6493 raise KeyError( 

6494 "Only a column name can be used for the " 

6495 "key in a dtype mappings argument. " 

6496 f"'{col_name}' not found in columns." 

6497 ) 

6498 

6499 dtype_ser = dtype_ser.reindex(self.columns, fill_value=None) 

6500 

6501 results = [] 

6502 for i, (col_name, col) in enumerate(self.items()): 

6503 cdt = dtype_ser.iat[i] 

6504 if isna(cdt): 

6505 res_col = col.copy(deep=False) 

6506 else: 

6507 try: 

6508 res_col = col.astype(dtype=cdt, errors=errors) 

6509 except ValueError as ex: 

6510 ex.args = ( 

6511 f"{ex}: Error while type casting for column '{col_name}'", 

6512 ) 

6513 raise 

6514 results.append(res_col) 

6515 

6516 elif is_extension_array_dtype(dtype) and self.ndim > 1: 

6517 # TODO(EA2D): special case not needed with 2D EAs 

6518 dtype = pandas_dtype(dtype) 

6519 if isinstance(dtype, ExtensionDtype) and all( 

6520 block.values.dtype == dtype for block in self._mgr.blocks 

6521 ): 

6522 return self.copy(deep=False) 

6523 # GH 18099/22869: columnwise conversion to extension dtype 

6524 # GH 24704: self.items handles duplicate column names 

6525 results = [ser.astype(dtype, errors=errors) for _, ser in self.items()] 

6526 

6527 else: 

6528 # else, only a single dtype is given 

6529 new_data = self._mgr.astype(dtype=dtype, errors=errors) 

6530 res = self._constructor_from_mgr(new_data, axes=new_data.axes) 

6531 return res.__finalize__(self, method="astype") 

6532 

6533 # GH 33113: handle empty frame or series 

6534 if not results: 

6535 return self.copy(deep=False) 

6536 

6537 # GH 19920: retain column metadata after concat 

6538 result = concat(results, axis=1) 

6539 # GH#40810 retain subclass 

6540 # error: Incompatible types in assignment 

6541 # (expression has type "Self", variable has type "DataFrame") 

6542 result = self._constructor(result) # type: ignore[assignment] 

6543 result.columns = self.columns 

6544 result = result.__finalize__(self, method="astype") 

6545 # https://github.com/python/mypy/issues/8354 

6546 return cast(Self, result) 

6547 

6548 @final 

6549 def copy(self, deep: bool = True) -> Self: 

6550 """ 

6551 Make a copy of this object's indices and data. 

6552 

6553 When ``deep=True`` (default), a new object will be created with a 

6554 copy of the calling object's data and indices. Modifications to 

6555 the data or indices of the copy will not be reflected in the 

6556 original object (see notes below). 

6557 

6558 When ``deep=False``, a new object will be created without copying 

6559 the calling object's data or index (only references to the data 

6560 and index are copied). With Copy-on-Write, changes to the original 

6561 will *not* be reflected in the shallow copy (and vice versa). The 

6562 shallow copy uses a lazy (deferred) copy mechanism that copies the 

6563 data only when any changes to the original or shallow copy are made, 

6564 ensuring memory efficiency while maintaining data integrity. 

6565 

6566 .. note:: 

6567 In pandas versions prior to 3.0, the default behavior without 

6568 Copy-on-Write was different: changes to the original *were* reflected 

6569 in the shallow copy (and vice versa). See the :ref:`Copy-on-Write 

6570 user guide <copy_on_write>` for more information. 

6571 

6572 Parameters 

6573 ---------- 

6574 deep : bool, default True 

6575 Make a deep copy, including a copy of the data and the indices. 

6576 With ``deep=False`` neither the indices nor the data are copied. 

6577 

6578 Returns 

6579 ------- 

6580 Series or DataFrame 

6581 Object type matches caller. 

6582 

6583 See Also 

6584 -------- 

6585 copy.copy : Return a shallow copy of an object. 

6586 copy.deepcopy : Return a deep copy of an object. 

6587 

6588 Notes 

6589 ----- 

6590 When ``deep=True``, data is copied but actual Python objects 

6591 will not be copied recursively, only the reference to the object. 

6592 This is in contrast to `copy.deepcopy` in the Standard Library, 

6593 which recursively copies object data (see examples below). 

6594 

6595 While ``Index`` objects are copied when ``deep=True``, the underlying 

6596 numpy array is not copied for performance reasons. Since ``Index`` is 

6597 immutable, the underlying data can be safely shared and a copy 

6598 is not needed. 

6599 

6600 Since pandas is not thread safe, see the 

6601 :ref:`gotchas <gotchas.thread-safety>` when copying in a threading 

6602 environment. 

6603 

6604 Copy-on-Write protects shallow copies against accidental modifications. 

6605 This means that any changes to the copied data would make a new copy 

6606 of the data upon write (and vice versa). Changes made to either the 

6607 original or copied variable would not be reflected in the counterpart. 

6608 See :ref:`Copy_on_Write <copy_on_write>` for more information. 

6609 

6610 Examples 

6611 -------- 

6612 >>> s = pd.Series([1, 2], index=["a", "b"]) 

6613 >>> s 

6614 a 1 

6615 b 2 

6616 dtype: int64 

6617 

6618 >>> s_copy = s.copy(deep=True) 

6619 >>> s_copy 

6620 a 1 

6621 b 2 

6622 dtype: int64 

6623 

6624 Due to Copy-on-Write, shallow copies still protect data modifications. 

6625 Note shallow does not get modified below. 

6626 

6627 >>> s = pd.Series([1, 2], index=["a", "b"]) 

6628 >>> shallow = s.copy(deep=False) 

6629 >>> s.iloc[1] = 200 

6630 >>> shallow 

6631 a 1 

6632 b 2 

6633 dtype: int64 

6634 

6635 When the data has object dtype, even a deep copy does not copy the 

6636 underlying Python objects. Updating a nested data object will be 

6637 reflected in the deep copy. 

6638 

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

6640 >>> deep = s.copy() 

6641 >>> s[0][0] = 10 

6642 >>> s 

6643 0 [10, 2] 

6644 1 [3, 4] 

6645 dtype: object 

6646 >>> deep 

6647 0 [10, 2] 

6648 1 [3, 4] 

6649 dtype: object 

6650 """ 

6651 data = self._mgr.copy(deep=deep) 

6652 return self._constructor_from_mgr(data, axes=data.axes).__finalize__( 

6653 self, method="copy" 

6654 ) 

6655 

6656 @final 

6657 def __copy__(self) -> Self: 

6658 return self.copy(deep=False) 

6659 

6660 @final 

6661 def __deepcopy__(self, memo=None) -> Self: 

6662 """ 

6663 Parameters 

6664 ---------- 

6665 memo, default None 

6666 Standard signature. Unused 

6667 """ 

6668 return self.copy(deep=True) 

6669 

6670 @final 

6671 def infer_objects(self, copy: bool | lib.NoDefault = lib.no_default) -> Self: 

6672 """ 

6673 Attempt to infer better dtypes for object columns. 

6674 

6675 Attempts soft conversion of object-dtyped 

6676 columns, leaving non-object and unconvertible 

6677 columns unchanged. The inference rules are the 

6678 same as during normal Series/DataFrame construction. 

6679 

6680 Parameters 

6681 ---------- 

6682 copy : bool, default False 

6683 This keyword is now ignored; changing its value will have no 

6684 impact on the method. 

6685 

6686 .. deprecated:: 3.0.0 

6687 

6688 This keyword is ignored and will be removed in pandas 4.0. Since 

6689 pandas 3.0, this method always returns a new object using a lazy 

6690 copy mechanism that defers copies until necessary 

6691 (Copy-on-Write). See the `user guide on Copy-on-Write 

6692 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

6693 for more details. 

6694 

6695 Returns 

6696 ------- 

6697 same type as input object 

6698 Returns an object of the same type as the input object. 

6699 

6700 See Also 

6701 -------- 

6702 to_datetime : Convert argument to datetime. 

6703 to_timedelta : Convert argument to timedelta. 

6704 to_numeric : Convert argument to numeric type. 

6705 convert_dtypes : Convert argument to best possible dtype. 

6706 

6707 Examples 

6708 -------- 

6709 >>> df = pd.DataFrame({"A": ["a", 1, 2, 3]}) 

6710 >>> df = df.iloc[1:] 

6711 >>> df 

6712 A 

6713 1 1 

6714 2 2 

6715 3 3 

6716 

6717 >>> df.dtypes 

6718 A object 

6719 dtype: object 

6720 

6721 >>> df.infer_objects().dtypes 

6722 A int64 

6723 dtype: object 

6724 """ 

6725 self._check_copy_deprecation(copy) 

6726 new_mgr = self._mgr.convert() 

6727 res = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) 

6728 return res.__finalize__(self, method="infer_objects") 

6729 

6730 @final 

6731 def convert_dtypes( 

6732 self, 

6733 infer_objects: bool = True, 

6734 convert_string: bool = True, 

6735 convert_integer: bool = True, 

6736 convert_boolean: bool = True, 

6737 convert_floating: bool = True, 

6738 dtype_backend: DtypeBackend = "numpy_nullable", 

6739 ) -> Self: 

6740 """ 

6741 Convert columns from numpy dtypes to the best dtypes that support ``pd.NA``. 

6742 

6743 Parameters 

6744 ---------- 

6745 infer_objects : bool, default True 

6746 Whether object dtypes should be converted to the best possible types. 

6747 convert_string : bool, default True 

6748 Whether object dtypes should be converted to ``StringDtype()``. 

6749 convert_integer : bool, default True 

6750 Whether, if possible, conversion can be done to integer extension types. 

6751 convert_boolean : bool, defaults True 

6752 Whether object dtypes should be converted to ``BooleanDtypes()``. 

6753 convert_floating : bool, defaults True 

6754 Whether, if possible, conversion can be done to floating extension types. 

6755 If `convert_integer` is also True, preference will be give to integer 

6756 dtypes if the floats can be faithfully casted to integers. 

6757 dtype_backend : {'numpy_nullable', 'pyarrow'}, default 'numpy_nullable' 

6758 Back-end data type applied to the resultant :class:`DataFrame` or 

6759 :class:`Series` (still experimental). Behaviour is as follows: 

6760 

6761 * ``"numpy_nullable"``: returns nullable-dtype-backed 

6762 :class:`DataFrame` or :class:`Serires`. 

6763 * ``"pyarrow"``: returns pyarrow-backed nullable :class:`ArrowDtype` 

6764 :class:`DataFrame` or :class:`Series`. 

6765 

6766 .. versionadded:: 2.0 

6767 

6768 Returns 

6769 ------- 

6770 Series or DataFrame 

6771 Copy of input object with new dtype. 

6772 

6773 See Also 

6774 -------- 

6775 infer_objects : Infer dtypes of objects. 

6776 to_datetime : Convert argument to datetime. 

6777 to_timedelta : Convert argument to timedelta. 

6778 to_numeric : Convert argument to a numeric type. 

6779 

6780 Notes 

6781 ----- 

6782 By default, ``convert_dtypes`` will attempt to convert a Series (or each 

6783 Series in a DataFrame) to dtypes that support ``pd.NA``. By using the options 

6784 ``convert_string``, ``convert_integer``, ``convert_boolean`` and 

6785 ``convert_floating``, it is possible to turn off individual conversions 

6786 to ``StringDtype``, the integer extension types, ``BooleanDtype`` 

6787 or floating extension types, respectively. 

6788 

6789 For object-dtyped columns, if ``infer_objects`` is ``True``, use the inference 

6790 rules as during normal Series/DataFrame construction. Then, if possible, 

6791 convert to ``StringDtype``, ``BooleanDtype`` or an appropriate integer 

6792 or floating extension type, otherwise leave as ``object``. 

6793 

6794 If the dtype is integer, convert to an appropriate integer extension type. 

6795 

6796 If the dtype is numeric, and consists of all integers, convert to an 

6797 appropriate integer extension type. Otherwise, convert to an 

6798 appropriate floating extension type. 

6799 

6800 In the future, as new dtypes are added that support ``pd.NA``, the results 

6801 of this method will change to support those new dtypes. 

6802 

6803 Examples 

6804 -------- 

6805 >>> df = pd.DataFrame( 

6806 ... { 

6807 ... "a": pd.Series([1, 2, 3], dtype=np.dtype("int32")), 

6808 ... "b": pd.Series(["x", "y", "z"], dtype=np.dtype("O")), 

6809 ... "c": pd.Series([True, False, np.nan], dtype=np.dtype("O")), 

6810 ... "d": pd.Series(["h", "i", np.nan], dtype=np.dtype("O")), 

6811 ... "e": pd.Series([10, np.nan, 20], dtype=np.dtype("float")), 

6812 ... "f": pd.Series([np.nan, 100.5, 200], dtype=np.dtype("float")), 

6813 ... } 

6814 ... ) 

6815 

6816 Start with a DataFrame with default dtypes. 

6817 

6818 >>> df 

6819 a b c d e f 

6820 0 1 x True h 10.0 NaN 

6821 1 2 y False i NaN 100.5 

6822 2 3 z NaN NaN 20.0 200.0 

6823 

6824 >>> df.dtypes 

6825 a int32 

6826 b object 

6827 c object 

6828 d object 

6829 e float64 

6830 f float64 

6831 dtype: object 

6832 

6833 Convert the DataFrame to use best possible dtypes. 

6834 

6835 >>> dfn = df.convert_dtypes() 

6836 >>> dfn 

6837 a b c d e f 

6838 0 1 x True h 10 <NA> 

6839 1 2 y False i <NA> 100.5 

6840 2 3 z <NA> <NA> 20 200.0 

6841 

6842 >>> dfn.dtypes 

6843 a Int32 

6844 b string 

6845 c boolean 

6846 d string 

6847 e Int64 

6848 f Float64 

6849 dtype: object 

6850 

6851 Start with a Series of strings and missing data represented by ``np.nan``. 

6852 

6853 >>> s = pd.Series(["a", "b", np.nan]) 

6854 >>> s 

6855 0 a 

6856 1 b 

6857 2 NaN 

6858 dtype: str 

6859 

6860 Obtain a Series with dtype ``StringDtype``. 

6861 

6862 >>> s.convert_dtypes() 

6863 0 a 

6864 1 b 

6865 2 <NA> 

6866 dtype: string 

6867 """ 

6868 check_dtype_backend(dtype_backend) 

6869 new_mgr = self._mgr.convert_dtypes( 

6870 infer_objects=infer_objects, 

6871 convert_string=convert_string, 

6872 convert_integer=convert_integer, 

6873 convert_boolean=convert_boolean, 

6874 convert_floating=convert_floating, 

6875 dtype_backend=dtype_backend, 

6876 ) 

6877 res = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) 

6878 return res.__finalize__(self, method="convert_dtypes") 

6879 

6880 # ---------------------------------------------------------------------- 

6881 # Filling NA's 

6882 

6883 @final 

6884 def _pad_or_backfill( 

6885 self, 

6886 method: Literal["ffill", "bfill", "pad", "backfill"], 

6887 *, 

6888 axis: None | Axis = None, 

6889 inplace: bool = False, 

6890 limit: None | int = None, 

6891 limit_area: Literal["inside", "outside"] | None = None, 

6892 ): 

6893 if axis is None: 

6894 axis = 0 

6895 axis = self._get_axis_number(axis) 

6896 method = clean_fill_method(method) 

6897 

6898 if axis == 1: 

6899 if not self._mgr.is_single_block and inplace: 

6900 raise NotImplementedError 

6901 # e.g. test_align_fill_method 

6902 result = self.T._pad_or_backfill( 

6903 method=method, limit=limit, limit_area=limit_area 

6904 ).T 

6905 

6906 return result 

6907 

6908 new_mgr = self._mgr.pad_or_backfill( 

6909 method=method, 

6910 limit=limit, 

6911 limit_area=limit_area, 

6912 inplace=inplace, 

6913 ) 

6914 result = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) 

6915 if inplace: 

6916 self._update_inplace(result) 

6917 return self 

6918 else: 

6919 return result.__finalize__(self, method="fillna") 

6920 

6921 @final 

6922 def fillna( 

6923 self, 

6924 value: Hashable | Mapping | Series | DataFrame, 

6925 *, 

6926 axis: Axis | None = None, 

6927 inplace: bool = False, 

6928 limit: int | None = None, 

6929 ) -> Self: 

6930 """ 

6931 Fill NA/NaN values with `value`. 

6932 

6933 Parameters 

6934 ---------- 

6935 value : scalar, dict, Series, or DataFrame 

6936 Value to use to fill holes (e.g. 0), alternately a 

6937 dict/Series/DataFrame of values specifying which value to use for 

6938 each index (for a Series) or column (for a DataFrame). Values not 

6939 in the dict/Series/DataFrame will not be filled. This value cannot 

6940 be a list. 

6941 axis : {0 or 'index'} for Series, {0 or 'index', 1 or 'columns'} for DataFrame 

6942 Axis along which to fill missing values. For `Series` 

6943 this parameter is unused and defaults to 0. 

6944 inplace : bool, default False 

6945 If True, fill in-place. Note: this will modify any 

6946 other views on this object (e.g., a no-copy slice for a column in a 

6947 DataFrame). 

6948 limit : int, default None 

6949 This is the maximum number of entries along the entire axis 

6950 where NaNs will be filled. Must be greater than 0 if not None. 

6951 

6952 Returns 

6953 ------- 

6954 Series/DataFrame 

6955 Object with missing values filled. 

6956 

6957 See Also 

6958 -------- 

6959 ffill : Fill values by propagating the last valid observation to next valid. 

6960 bfill : Fill values by using the next valid observation to fill the gap. 

6961 interpolate : Fill NaN values using interpolation. 

6962 reindex : Conform object to new index. 

6963 asfreq : Convert TimeSeries to specified frequency. 

6964 

6965 Notes 

6966 ----- 

6967 For non-object dtype, ``value=None`` will use the NA value of the dtype. 

6968 See more details in the :ref:`Filling missing data<missing_data.fillna>` 

6969 section. 

6970 

6971 Examples 

6972 -------- 

6973 >>> df = pd.DataFrame( 

6974 ... [ 

6975 ... [np.nan, 2, np.nan, 0], 

6976 ... [3, 4, np.nan, 1], 

6977 ... [np.nan, np.nan, np.nan, np.nan], 

6978 ... [np.nan, 3, np.nan, 4], 

6979 ... ], 

6980 ... columns=list("ABCD"), 

6981 ... ) 

6982 >>> df 

6983 A B C D 

6984 0 NaN 2.0 NaN 0.0 

6985 1 3.0 4.0 NaN 1.0 

6986 2 NaN NaN NaN NaN 

6987 3 NaN 3.0 NaN 4.0 

6988 

6989 Replace all NaN elements with 0s. 

6990 

6991 >>> df.fillna(0) 

6992 A B C D 

6993 0 0.0 2.0 0.0 0.0 

6994 1 3.0 4.0 0.0 1.0 

6995 2 0.0 0.0 0.0 0.0 

6996 3 0.0 3.0 0.0 4.0 

6997 

6998 Replace all NaN elements in column 'A', 'B', 'C', and 'D', with 0, 1, 

6999 2, and 3 respectively. 

7000 

7001 >>> values = {"A": 0, "B": 1, "C": 2, "D": 3} 

7002 >>> df.fillna(value=values) 

7003 A B C D 

7004 0 0.0 2.0 2.0 0.0 

7005 1 3.0 4.0 2.0 1.0 

7006 2 0.0 1.0 2.0 3.0 

7007 3 0.0 3.0 2.0 4.0 

7008 

7009 Only replace the first NaN element. 

7010 

7011 >>> df.fillna(value=values, limit=1) 

7012 A B C D 

7013 0 0.0 2.0 2.0 0.0 

7014 1 3.0 4.0 NaN 1.0 

7015 2 NaN 1.0 NaN 3.0 

7016 3 NaN 3.0 NaN 4.0 

7017 

7018 When filling using a DataFrame, replacement happens along 

7019 the same column names and same indices 

7020 

7021 >>> df2 = pd.DataFrame(np.zeros((4, 4)), columns=list("ABCE")) 

7022 >>> df.fillna(df2) 

7023 A B C D 

7024 0 0.0 2.0 0.0 0.0 

7025 1 3.0 4.0 0.0 1.0 

7026 2 0.0 0.0 0.0 NaN 

7027 3 0.0 3.0 0.0 4.0 

7028 

7029 Note that column D is not affected since it is not present in df2. 

7030 """ 

7031 inplace = validate_bool_kwarg(inplace, "inplace") 

7032 if inplace: 

7033 if not CHAINED_WARNING_DISABLED: 

7034 if sys.getrefcount( 

7035 self 

7036 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

7037 warnings.warn( 

7038 _chained_assignment_method_msg, 

7039 ChainedAssignmentError, 

7040 stacklevel=2, 

7041 ) 

7042 

7043 if isinstance(value, (list, tuple)): 

7044 raise TypeError( 

7045 '"value" parameter must be a scalar or dict, but ' 

7046 f'you passed a "{type(value).__name__}"' 

7047 ) 

7048 

7049 # set the default here, so functions examining the signature 

7050 # can detect if something was set (e.g. in groupby) (GH9221) 

7051 if axis is None: 

7052 axis = 0 

7053 axis = self._get_axis_number(axis) 

7054 

7055 if self.ndim == 1: 

7056 if isinstance(value, (dict, ABCSeries)): 

7057 if not len(value): 

7058 # test_fillna_nonscalar 

7059 return self if inplace else self.copy(deep=False) 

7060 from pandas import Series 

7061 

7062 value = Series(value) 

7063 value = value.reindex(self.index) 

7064 value = value._values 

7065 elif not is_list_like(value): 

7066 pass 

7067 else: 

7068 raise TypeError( 

7069 '"value" parameter must be a scalar, dict ' 

7070 "or Series, but you passed a " 

7071 f'"{type(value).__name__}"' 

7072 ) 

7073 

7074 new_data = self._mgr.fillna(value=value, limit=limit, inplace=inplace) 

7075 

7076 elif isinstance(value, (dict, ABCSeries)): 

7077 result = self if inplace else self.copy(deep=False) 

7078 if axis == 1: 

7079 # Check that all columns in result have the same dtype 

7080 # otherwise don't bother with fillna and losing accurate dtypes 

7081 unique_dtypes = self._mgr.get_unique_dtypes() 

7082 if len(unique_dtypes) > 1: 

7083 raise ValueError( 

7084 "All columns must have the same dtype, but got dtypes: " 

7085 f"{list(unique_dtypes)}" 

7086 ) 

7087 # Use the first column, which we have already validated has the 

7088 # same dtypes as the other columns. 

7089 if not can_hold_element(result.iloc[:, 0], value): 

7090 frame_dtype = unique_dtypes.item() 

7091 raise ValueError( 

7092 f"{value} not a suitable type to fill into {frame_dtype}" 

7093 ) 

7094 result = result.T.fillna(value=value).T 

7095 if inplace: 

7096 self._update_inplace(result) 

7097 result = self 

7098 else: 

7099 for k, v in value.items(): 

7100 if k not in result: 

7101 continue 

7102 

7103 res_k = result[k].fillna(v, limit=limit) 

7104 

7105 if not inplace: 

7106 result[k] = res_k 

7107 # We can write into our existing column(s) iff dtype 

7108 # was preserved. 

7109 elif isinstance(res_k, ABCSeries): 

7110 # i.e. 'k' only shows up once in self.columns 

7111 if res_k.dtype == result[k].dtype: 

7112 result.loc[:, k] = res_k 

7113 else: 

7114 # Different dtype -> no way to do inplace. 

7115 result[k] = res_k 

7116 else: 

7117 # see test_fillna_dict_inplace_nonunique_columns 

7118 locs = result.columns.get_loc(k) 

7119 if isinstance(locs, slice): 

7120 locs = range(self.shape[1])[locs] 

7121 elif isinstance(locs, np.ndarray) and locs.dtype.kind == "b": 

7122 locs = locs.nonzero()[0] 

7123 elif not ( 

7124 isinstance(locs, np.ndarray) and locs.dtype.kind == "i" 

7125 ): 

7126 # Should never be reached, but let's cover our bases 

7127 raise NotImplementedError( 

7128 "Unexpected get_loc result, please report a bug at " 

7129 "https://github.com/pandas-dev/pandas" 

7130 ) 

7131 

7132 for i, loc in enumerate(locs): 

7133 res_loc = res_k.iloc[:, i] 

7134 target = self.iloc[:, loc] 

7135 

7136 if res_loc.dtype == target.dtype: 

7137 result.iloc[:, loc] = res_loc 

7138 else: 

7139 result.isetitem(loc, res_loc) 

7140 return result 

7141 

7142 elif not is_list_like(value): 

7143 if axis == 1: 

7144 result = self.T.fillna(value=value, limit=limit).T 

7145 new_data = result._mgr 

7146 else: 

7147 new_data = self._mgr.fillna(value=value, limit=limit, inplace=inplace) 

7148 elif isinstance(value, ABCDataFrame) and self.ndim == 2: 

7149 new_data = self.where(self.notna(), value)._mgr 

7150 else: 

7151 raise ValueError(f"invalid fill value with a {type(value)}") 

7152 

7153 result = self._constructor_from_mgr(new_data, axes=new_data.axes) 

7154 if inplace: 

7155 self._update_inplace(result) 

7156 return self 

7157 else: 

7158 return result.__finalize__(self, method="fillna") 

7159 

7160 @final 

7161 def ffill( 

7162 self, 

7163 *, 

7164 axis: None | Axis = None, 

7165 inplace: bool = False, 

7166 limit: None | int = None, 

7167 limit_area: Literal["inside", "outside"] | None = None, 

7168 ) -> Self: 

7169 """ 

7170 Fill NA/NaN values by propagating the last valid observation to next valid. 

7171 

7172 Parameters 

7173 ---------- 

7174 axis : {0 or 'index'} for Series, {0 or 'index', 1 or 'columns'} for DataFrame 

7175 Axis along which to fill missing values. For `Series` 

7176 this parameter is unused and defaults to 0. 

7177 inplace : bool, default False 

7178 If True, fill in-place. Note: this will modify any 

7179 other views on this object (e.g., a no-copy slice for a column in a 

7180 DataFrame). 

7181 limit : int, default None 

7182 If method is specified, this is the maximum number of consecutive 

7183 NaN values to forward/backward fill. In other words, if there is 

7184 a gap with more than this number of consecutive NaNs, it will only 

7185 be partially filled. If method is not specified, this is the 

7186 maximum number of entries along the entire axis where NaNs will be 

7187 filled. Must be greater than 0 if not None. 

7188 limit_area : {`None`, 'inside', 'outside'}, default None 

7189 If limit is specified, consecutive NaNs will be filled with this 

7190 restriction. 

7191 

7192 * ``None``: No fill restriction. 

7193 * 'inside': Only fill NaNs surrounded by valid values 

7194 (interpolate). 

7195 * 'outside': Only fill NaNs outside valid values (extrapolate). 

7196 

7197 .. versionadded:: 2.2.0 

7198 

7199 Returns 

7200 ------- 

7201 Series/DataFrame 

7202 Object with missing values filled. 

7203 

7204 See Also 

7205 -------- 

7206 DataFrame.bfill : Fill NA/NaN values by using the next valid observation 

7207 to fill the gap. 

7208 

7209 Examples 

7210 -------- 

7211 >>> df = pd.DataFrame( 

7212 ... [ 

7213 ... [np.nan, 2, np.nan, 0], 

7214 ... [3, 4, np.nan, 1], 

7215 ... [np.nan, np.nan, np.nan, np.nan], 

7216 ... [np.nan, 3, np.nan, 4], 

7217 ... ], 

7218 ... columns=list("ABCD"), 

7219 ... ) 

7220 >>> df 

7221 A B C D 

7222 0 NaN 2.0 NaN 0.0 

7223 1 3.0 4.0 NaN 1.0 

7224 2 NaN NaN NaN NaN 

7225 3 NaN 3.0 NaN 4.0 

7226 

7227 >>> df.ffill() 

7228 A B C D 

7229 0 NaN 2.0 NaN 0.0 

7230 1 3.0 4.0 NaN 1.0 

7231 2 3.0 4.0 NaN 1.0 

7232 3 3.0 3.0 NaN 4.0 

7233 

7234 >>> ser = pd.Series([1, np.nan, 2, 3]) 

7235 >>> ser.ffill() 

7236 0 1.0 

7237 1 1.0 

7238 2 2.0 

7239 3 3.0 

7240 dtype: float64 

7241 """ 

7242 inplace = validate_bool_kwarg(inplace, "inplace") 

7243 if inplace: 

7244 if not CHAINED_WARNING_DISABLED: 

7245 if sys.getrefcount( 

7246 self 

7247 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

7248 warnings.warn( 

7249 _chained_assignment_method_msg, 

7250 ChainedAssignmentError, 

7251 stacklevel=2, 

7252 ) 

7253 

7254 return self._pad_or_backfill( 

7255 "ffill", 

7256 axis=axis, 

7257 inplace=inplace, 

7258 limit=limit, 

7259 limit_area=limit_area, 

7260 ) 

7261 

7262 @final 

7263 def bfill( 

7264 self, 

7265 *, 

7266 axis: None | Axis = None, 

7267 inplace: bool = False, 

7268 limit: None | int = None, 

7269 limit_area: Literal["inside", "outside"] | None = None, 

7270 ) -> Self: 

7271 """ 

7272 Fill NA/NaN values by using the next valid observation to fill the gap. 

7273 

7274 This method fills missing values in a backward direction along the 

7275 specified axis, propagating non-null values from later positions to 

7276 earlier positions containing NaN. 

7277 

7278 Parameters 

7279 ---------- 

7280 axis : {0 or 'index'} for Series, {0 or 'index', 1 or 'columns'} for DataFrame 

7281 Axis along which to fill missing values. For `Series` 

7282 this parameter is unused and defaults to 0. 

7283 inplace : bool, default False 

7284 If True, fill in-place. Note: this will modify any 

7285 other views on this object (e.g., a no-copy slice for a column in a 

7286 DataFrame). 

7287 limit : int, default None 

7288 If method is specified, this is the maximum number of consecutive 

7289 NaN values to forward/backward fill. In other words, if there is 

7290 a gap with more than this number of consecutive NaNs, it will only 

7291 be partially filled. If method is not specified, this is the 

7292 maximum number of entries along the entire axis where NaNs will be 

7293 filled. Must be greater than 0 if not None. 

7294 limit_area : {`None`, 'inside', 'outside'}, default None 

7295 If limit is specified, consecutive NaNs will be filled with this 

7296 restriction. 

7297 

7298 * ``None``: No fill restriction. 

7299 * 'inside': Only fill NaNs surrounded by valid values 

7300 (interpolate). 

7301 * 'outside': Only fill NaNs outside valid values (extrapolate). 

7302 

7303 .. versionadded:: 2.2.0 

7304 

7305 Returns 

7306 ------- 

7307 Series/DataFrame 

7308 Object with missing values filled. 

7309 

7310 See Also 

7311 -------- 

7312 DataFrame.ffill : Fill NA/NaN values by propagating the last valid 

7313 observation to next valid. 

7314 

7315 Examples 

7316 -------- 

7317 For Series: 

7318 

7319 >>> s = pd.Series([1, None, None, 2]) 

7320 >>> s.bfill() 

7321 0 1.0 

7322 1 2.0 

7323 2 2.0 

7324 3 2.0 

7325 dtype: float64 

7326 >>> s.bfill(limit=1) 

7327 0 1.0 

7328 1 NaN 

7329 2 2.0 

7330 3 2.0 

7331 dtype: float64 

7332 

7333 With DataFrame: 

7334 

7335 >>> df = pd.DataFrame({"A": [1, None, None, 4], "B": [None, 5, None, 7]}) 

7336 >>> df 

7337 A B 

7338 0 1.0 NaN 

7339 1 NaN 5.0 

7340 2 NaN NaN 

7341 3 4.0 7.0 

7342 >>> df.bfill() 

7343 A B 

7344 0 1.0 5.0 

7345 1 4.0 5.0 

7346 2 4.0 7.0 

7347 3 4.0 7.0 

7348 >>> df.bfill(limit=1) 

7349 A B 

7350 0 1.0 5.0 

7351 1 NaN 5.0 

7352 2 4.0 7.0 

7353 3 4.0 7.0 

7354 """ 

7355 inplace = validate_bool_kwarg(inplace, "inplace") 

7356 if inplace: 

7357 if not CHAINED_WARNING_DISABLED: 

7358 if sys.getrefcount( 

7359 self 

7360 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

7361 warnings.warn( 

7362 _chained_assignment_method_msg, 

7363 ChainedAssignmentError, 

7364 stacklevel=2, 

7365 ) 

7366 

7367 return self._pad_or_backfill( 

7368 "bfill", 

7369 axis=axis, 

7370 inplace=inplace, 

7371 limit=limit, 

7372 limit_area=limit_area, 

7373 ) 

7374 

7375 @final 

7376 def replace( 

7377 self, 

7378 to_replace=None, 

7379 value=lib.no_default, 

7380 *, 

7381 inplace: bool = False, 

7382 regex: bool = False, 

7383 ) -> Self: 

7384 """ 

7385 Replace values given in `to_replace` with `value`. 

7386 

7387 Values of the Series/DataFrame are replaced with other values dynamically. 

7388 This differs from updating with ``.loc`` or ``.iloc``, which require 

7389 you to specify a location to update with some value. 

7390 

7391 Parameters 

7392 ---------- 

7393 to_replace : str, regex, list, dict, Series, int, float, or None 

7394 How to find the values that will be replaced. 

7395 

7396 * numeric, str or regex: 

7397 

7398 - numeric: numeric values equal to `to_replace` will be 

7399 replaced with `value` 

7400 - str: string exactly matching `to_replace` will be replaced 

7401 with `value` 

7402 - regex: regexes matching `to_replace` will be replaced with 

7403 `value` 

7404 

7405 * list of str, regex, or numeric: 

7406 

7407 - First, if `to_replace` and `value` are both lists, they 

7408 **must** be the same length. 

7409 - Second, if ``regex=True`` then all of the strings in **both** 

7410 lists will be interpreted as regexes otherwise they will match 

7411 directly. This doesn't matter much for `value` since there 

7412 are only a few possible substitution regexes you can use. 

7413 - str, regex and numeric rules apply as above. 

7414 

7415 * dict: 

7416 

7417 - Dicts can be used to specify different replacement values 

7418 for different existing values. For example, 

7419 ``{'a': 'b', 'y': 'z'}`` replaces the value 'a' with 'b' and 

7420 'y' with 'z'. To use a dict in this way, the optional `value` 

7421 parameter should not be given. 

7422 - For a DataFrame a dict can specify that different values 

7423 should be replaced in different columns. For example, 

7424 ``{'a': 1, 'b': 'z'}`` looks for the value 1 in column 'a' 

7425 and the value 'z' in column 'b' and replaces these values 

7426 with whatever is specified in `value`. The `value` parameter 

7427 should not be ``None`` in this case. You can treat this as a 

7428 special case of passing two lists except that you are 

7429 specifying the column to search in. 

7430 - For a DataFrame nested dictionaries, e.g., 

7431 ``{'a': {'b': np.nan}}``, are read as follows: look in column 

7432 'a' for the value 'b' and replace it with NaN. The optional `value` 

7433 parameter should not be specified to use a nested dict in this 

7434 way. You can nest regular expressions as well. Note that 

7435 column names (the top-level dictionary keys in a nested 

7436 dictionary) **cannot** be regular expressions. 

7437 

7438 * None: 

7439 

7440 - This means that the `regex` argument must be a string, 

7441 compiled regular expression, or list, dict, ndarray or 

7442 Series of such elements. If `value` is also ``None`` then 

7443 this **must** be a nested dictionary or Series. 

7444 

7445 See the examples section for examples of each of these. 

7446 value : scalar, dict, list, str, regex, default None 

7447 Value to replace any values matching `to_replace` with. 

7448 For a DataFrame a dict of values can be used to specify which 

7449 value to use for each column (columns not in the dict will not be 

7450 filled). Regular expressions, strings and lists or dicts of such 

7451 objects are also allowed. 

7452 

7453 inplace : bool, default False 

7454 If True, performs operation inplace. 

7455 regex : bool or same types as `to_replace`, default False 

7456 Whether to interpret `to_replace` and/or `value` as regular 

7457 expressions. Alternatively, this could be a regular expression or a 

7458 list, dict, or array of regular expressions in which case 

7459 `to_replace` must be ``None``. 

7460 

7461 Returns 

7462 ------- 

7463 Series/DataFrame 

7464 Object after replacement. 

7465 

7466 Raises 

7467 ------ 

7468 AssertionError 

7469 * If `regex` is not a ``bool`` and `to_replace` is not 

7470 ``None``. 

7471 

7472 TypeError 

7473 * If `to_replace` is not a scalar, array-like, ``dict``, or ``None`` 

7474 * If `to_replace` is a ``dict`` and `value` is not a ``list``, 

7475 ``dict``, ``ndarray``, or ``Series`` 

7476 * If `to_replace` is ``None`` and `regex` is not compilable 

7477 into a regular expression or is a list, dict, ndarray, or 

7478 Series. 

7479 * When replacing multiple ``bool`` or ``datetime64`` objects and 

7480 the arguments to `to_replace` does not match the type of the 

7481 value being replaced 

7482 

7483 ValueError 

7484 * If a ``list`` or an ``ndarray`` is passed to `to_replace` and 

7485 `value` but they are not the same length. 

7486 

7487 See Also 

7488 -------- 

7489 Series.fillna : Fill NA values. 

7490 DataFrame.fillna : Fill NA values. 

7491 Series.where : Replace values based on boolean condition. 

7492 DataFrame.where : Replace values based on boolean condition. 

7493 DataFrame.map: Apply a function to a Dataframe elementwise. 

7494 Series.map: Map values of Series according to an input mapping or function. 

7495 Series.str.replace : Simple string replacement. 

7496 

7497 Notes 

7498 ----- 

7499 * Regex substitution is performed under the hood with ``re.sub``. The 

7500 rules for substitution for ``re.sub`` are the same. 

7501 * Regular expressions will only substitute on strings, meaning you 

7502 cannot provide, for example, a regular expression matching floating 

7503 point numbers and expect the columns in your frame that have a 

7504 numeric dtype to be matched. However, if those floating point 

7505 numbers *are* strings, then you can do this. 

7506 * This method has *a lot* of options. You are encouraged to experiment 

7507 and play with this method to gain intuition about how it works. 

7508 * When dict is used as the `to_replace` value, it is like 

7509 key(s) in the dict are the to_replace part and 

7510 value(s) in the dict are the value parameter. 

7511 

7512 Examples 

7513 -------- 

7514 

7515 **Scalar `to_replace` and `value`** 

7516 

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

7518 >>> s.replace(1, 5) 

7519 0 5 

7520 1 2 

7521 2 3 

7522 3 4 

7523 4 5 

7524 dtype: int64 

7525 

7526 >>> df = pd.DataFrame( 

7527 ... { 

7528 ... "A": [0, 1, 2, 3, 4], 

7529 ... "B": [5, 6, 7, 8, 9], 

7530 ... "C": ["a", "b", "c", "d", "e"], 

7531 ... } 

7532 ... ) 

7533 >>> df.replace(0, 5) 

7534 A B C 

7535 0 5 5 a 

7536 1 1 6 b 

7537 2 2 7 c 

7538 3 3 8 d 

7539 4 4 9 e 

7540 

7541 **List-like `to_replace`** 

7542 

7543 >>> df.replace([0, 1, 2, 3], 4) 

7544 A B C 

7545 0 4 5 a 

7546 1 4 6 b 

7547 2 4 7 c 

7548 3 4 8 d 

7549 4 4 9 e 

7550 

7551 >>> df.replace([0, 1, 2, 3], [4, 3, 2, 1]) 

7552 A B C 

7553 0 4 5 a 

7554 1 3 6 b 

7555 2 2 7 c 

7556 3 1 8 d 

7557 4 4 9 e 

7558 

7559 **dict-like `to_replace`** 

7560 

7561 >>> df.replace({0: 10, 1: 100}) 

7562 A B C 

7563 0 10 5 a 

7564 1 100 6 b 

7565 2 2 7 c 

7566 3 3 8 d 

7567 4 4 9 e 

7568 

7569 >>> df.replace({"A": 0, "B": 5}, 100) 

7570 A B C 

7571 0 100 100 a 

7572 1 1 6 b 

7573 2 2 7 c 

7574 3 3 8 d 

7575 4 4 9 e 

7576 

7577 >>> df.replace({"A": {0: 100, 4: 400}}) 

7578 A B C 

7579 0 100 5 a 

7580 1 1 6 b 

7581 2 2 7 c 

7582 3 3 8 d 

7583 4 400 9 e 

7584 

7585 **Regular expression `to_replace`** 

7586 

7587 >>> df = pd.DataFrame({"A": ["bat", "foo", "bait"], "B": ["abc", "bar", "xyz"]}) 

7588 >>> df.replace(to_replace=r"^ba.$", value="new", regex=True) 

7589 A B 

7590 0 new abc 

7591 1 foo new 

7592 2 bait xyz 

7593 

7594 >>> df.replace({"A": r"^ba.$"}, {"A": "new"}, regex=True) 

7595 A B 

7596 0 new abc 

7597 1 foo bar 

7598 2 bait xyz 

7599 

7600 >>> df.replace(regex=r"^ba.$", value="new") 

7601 A B 

7602 0 new abc 

7603 1 foo new 

7604 2 bait xyz 

7605 

7606 >>> df.replace(regex={r"^ba.$": "new", "foo": "xyz"}) 

7607 A B 

7608 0 new abc 

7609 1 xyz new 

7610 2 bait xyz 

7611 

7612 >>> df.replace(regex=[r"^ba.$", "foo"], value="new") 

7613 A B 

7614 0 new abc 

7615 1 new new 

7616 2 bait xyz 

7617 

7618 Compare the behavior of ``s.replace({'a': None})`` and 

7619 ``s.replace('a', None)`` to understand the peculiarities 

7620 of the `to_replace` parameter: 

7621 

7622 >>> s = pd.Series([10, "a", "a", "b", "a"]) 

7623 

7624 When one uses a dict as the `to_replace` value, it is like the 

7625 value(s) in the dict are equal to the `value` parameter. 

7626 ``s.replace({'a': None})`` is equivalent to 

7627 ``s.replace(to_replace={'a': None}, value=None)``: 

7628 

7629 >>> s.replace({"a": None}) 

7630 0 10 

7631 1 None 

7632 2 None 

7633 3 b 

7634 4 None 

7635 dtype: object 

7636 

7637 If ``None`` is explicitly passed for ``value``, it will be respected: 

7638 

7639 >>> s.replace("a", None) 

7640 0 10 

7641 1 None 

7642 2 None 

7643 3 b 

7644 4 None 

7645 dtype: object 

7646 

7647 When ``regex=True``, ``value`` is not ``None`` and `to_replace` is a string, 

7648 the replacement will be applied in all columns of the DataFrame. 

7649 

7650 >>> df = pd.DataFrame( 

7651 ... { 

7652 ... "A": [0, 1, 2, 3, 4], 

7653 ... "B": ["a", "b", "c", "d", "e"], 

7654 ... "C": ["f", "g", "h", "i", "j"], 

7655 ... } 

7656 ... ) 

7657 

7658 >>> df.replace(to_replace="^[a-g]", value="e", regex=True) 

7659 A B C 

7660 0 0 e e 

7661 1 1 e e 

7662 2 2 e h 

7663 3 3 e i 

7664 4 4 e j 

7665 

7666 If ``value`` is not ``None`` and `to_replace` is a dictionary, the dictionary 

7667 keys will be the DataFrame columns that the replacement will be applied. 

7668 

7669 >>> df.replace(to_replace={"B": "^[a-c]", "C": "^[h-j]"}, value="e", regex=True) 

7670 A B C 

7671 0 0 e f 

7672 1 1 e g 

7673 2 2 e e 

7674 3 3 d e 

7675 4 4 e e 

7676 """ 

7677 if not is_bool(regex) and to_replace is not None: 

7678 raise ValueError("'to_replace' must be 'None' if 'regex' is not a bool") 

7679 

7680 if not ( 

7681 is_scalar(to_replace) 

7682 or is_re_compilable(to_replace) 

7683 or is_list_like(to_replace) 

7684 ): 

7685 raise TypeError( 

7686 "Expecting 'to_replace' to be either a scalar, array-like, " 

7687 "dict or None, got invalid type " 

7688 f"{type(to_replace).__name__!r}" 

7689 ) 

7690 

7691 if value is lib.no_default and not ( 

7692 is_dict_like(to_replace) or is_dict_like(regex) 

7693 ): 

7694 raise ValueError( 

7695 # GH#33302 

7696 f"{type(self).__name__}.replace must specify either 'value', " 

7697 "a dict-like 'to_replace', or dict-like 'regex'." 

7698 ) 

7699 

7700 inplace = validate_bool_kwarg(inplace, "inplace") 

7701 if inplace: 

7702 if not CHAINED_WARNING_DISABLED: 

7703 if sys.getrefcount( 

7704 self 

7705 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

7706 warnings.warn( 

7707 _chained_assignment_method_msg, 

7708 ChainedAssignmentError, 

7709 stacklevel=2, 

7710 ) 

7711 

7712 if value is lib.no_default: 

7713 if not is_dict_like(to_replace): 

7714 # In this case we have checked above that 

7715 # 1) regex is dict-like and 2) to_replace is None 

7716 to_replace = regex 

7717 regex = True 

7718 

7719 items = list(to_replace.items()) 

7720 if items: 

7721 keys, values = zip(*items, strict=True) 

7722 else: 

7723 keys, values = ([], []) # type: ignore[assignment] 

7724 

7725 are_mappings = [is_dict_like(v) for v in values] 

7726 

7727 if any(are_mappings): 

7728 if not all(are_mappings): 

7729 raise TypeError( 

7730 "If a nested mapping is passed, all values " 

7731 "of the top level mapping must be mappings" 

7732 ) 

7733 # passed a nested dict/Series 

7734 to_rep_dict = {} 

7735 value_dict = {} 

7736 

7737 for k, v in items: 

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

7739 # "list[Never]", variable has type "tuple[Any, ...]") 

7740 keys, values = list(zip(*v.items(), strict=True)) or ( # type: ignore[assignment] 

7741 [], 

7742 [], 

7743 ) 

7744 

7745 to_rep_dict[k] = list(keys) 

7746 value_dict[k] = list(values) 

7747 

7748 to_replace, value = to_rep_dict, value_dict 

7749 else: 

7750 to_replace, value = keys, values 

7751 

7752 return self.replace(to_replace, value, inplace=inplace, regex=regex) 

7753 else: 

7754 # need a non-zero len on all axes 

7755 if not self.size: 

7756 return self if inplace else self.copy(deep=False) 

7757 if is_dict_like(to_replace): 

7758 if is_dict_like(value): # {'A' : NA} -> {'A' : 0} 

7759 if isinstance(self, ABCSeries): 

7760 raise ValueError( 

7761 "to_replace and value cannot be dict-like for " 

7762 "Series.replace" 

7763 ) 

7764 # Note: Checking below for `in foo.keys()` instead of 

7765 # `in foo` is needed for when we have a Series and not dict 

7766 mapping = { 

7767 col: (to_replace[col], value[col]) 

7768 for col in to_replace.keys() 

7769 if col in value.keys() and col in self 

7770 } 

7771 return self._replace_columnwise(mapping, inplace, regex) 

7772 

7773 # {'A': NA} -> 0 

7774 elif not is_list_like(value): 

7775 # Operate column-wise 

7776 if self.ndim == 1: 

7777 raise ValueError( 

7778 "Series.replace cannot specify both a dict-like " 

7779 "'to_replace' and a 'value'" 

7780 ) 

7781 mapping = { 

7782 col: (to_rep, value) for col, to_rep in to_replace.items() 

7783 } 

7784 return self._replace_columnwise(mapping, inplace, regex) 

7785 else: 

7786 raise TypeError("value argument must be scalar, dict, or Series") 

7787 

7788 elif is_list_like(to_replace): 

7789 if not is_list_like(value): 

7790 # e.g. to_replace = [NA, ''] and value is 0, 

7791 # so we replace NA with 0 and then replace '' with 0 

7792 value = [value] * len(to_replace) 

7793 

7794 # e.g. we have to_replace = [NA, ''] and value = [0, 'missing'] 

7795 if len(to_replace) != len(value): 

7796 raise ValueError( 

7797 f"Replacement lists must match in length. " 

7798 f"Expecting {len(to_replace)} got {len(value)} " 

7799 ) 

7800 new_data = self._mgr.replace_list( 

7801 src_list=to_replace, 

7802 dest_list=value, 

7803 inplace=inplace, 

7804 regex=regex, 

7805 ) 

7806 

7807 elif to_replace is None: 

7808 if not ( 

7809 is_re_compilable(regex) 

7810 or is_list_like(regex) 

7811 or is_dict_like(regex) 

7812 ): 

7813 raise TypeError( 

7814 f"'regex' must be a string or a compiled regular expression " 

7815 f"or a list or dict of strings or regular expressions, " 

7816 f"you passed a {type(regex).__name__!r}" 

7817 ) 

7818 return self.replace(regex, value, inplace=inplace, regex=True) 

7819 # dest iterable dict-like 

7820 elif is_dict_like(value): # NA -> {'A' : 0, 'B' : -1} 

7821 # Operate column-wise 

7822 if self.ndim == 1: 

7823 raise ValueError( 

7824 "Series.replace cannot use dict-value and non-None to_replace" 

7825 ) 

7826 mapping = {col: (to_replace, val) for col, val in value.items()} 

7827 return self._replace_columnwise(mapping, inplace, regex) 

7828 

7829 elif not is_list_like(value): # NA -> 0 

7830 regex = should_use_regex(regex, to_replace) 

7831 if regex: 

7832 new_data = self._mgr.replace_regex( 

7833 to_replace=to_replace, 

7834 value=value, 

7835 inplace=inplace, 

7836 ) 

7837 else: 

7838 new_data = self._mgr.replace( 

7839 to_replace=to_replace, value=value, inplace=inplace 

7840 ) 

7841 else: 

7842 raise TypeError( 

7843 f'Invalid "to_replace" type: {type(to_replace).__name__!r}' 

7844 ) 

7845 

7846 result = self._constructor_from_mgr(new_data, axes=new_data.axes) 

7847 if inplace: 

7848 self._update_inplace(result) 

7849 return self 

7850 else: 

7851 return result.__finalize__(self, method="replace") 

7852 

7853 @final 

7854 def interpolate( 

7855 self, 

7856 method: InterpolateOptions = "linear", 

7857 *, 

7858 axis: Axis = 0, 

7859 limit: int | None = None, 

7860 inplace: bool = False, 

7861 limit_direction: Literal["forward", "backward", "both"] | None = None, 

7862 limit_area: Literal["inside", "outside"] | None = None, 

7863 **kwargs, 

7864 ) -> Self: 

7865 """ 

7866 Fill NaN values using an interpolation method. 

7867 

7868 Please note that only ``method='linear'`` is supported for 

7869 DataFrame/Series with a MultiIndex. 

7870 

7871 Parameters 

7872 ---------- 

7873 method : str, default 'linear' 

7874 Interpolation technique to use. One of: 

7875 

7876 * 'linear': Ignore the index and treat the values as equally 

7877 spaced. This is the only method supported on MultiIndexes. 

7878 * 'time': Works on daily and higher resolution data to interpolate 

7879 given length of interval. This interpolates values based on 

7880 time interval between observations. 

7881 * 'index': The interpolation uses the numerical values 

7882 of the DataFrame's index to linearly calculate missing values. 

7883 * 'values': Interpolation based on the numerical values 

7884 in the DataFrame, treating them as equally spaced along the index. 

7885 * 'nearest', 'zero', 'slinear', 'quadratic', 'cubic', 

7886 'barycentric', 'polynomial': Passed to 

7887 `scipy.interpolate.interp1d`, whereas 'spline' is passed to 

7888 `scipy.interpolate.UnivariateSpline`. These methods use the numerical 

7889 values of the index. Both 'polynomial' and 'spline' require that 

7890 you also specify an `order` (int), e.g. 

7891 ``df.interpolate(method='polynomial', order=5)``. Note that, 

7892 `slinear` method in Pandas refers to the Scipy first order `spline` 

7893 instead of Pandas first order `spline`. 

7894 * 'krogh', 'piecewise_polynomial', 'spline', 'pchip', 'akima', 

7895 'cubicspline': Wrappers around the SciPy interpolation methods of 

7896 similar names. See `Notes`. 

7897 * 'from_derivatives': Refers to 

7898 `scipy.interpolate.BPoly.from_derivatives`. 

7899 

7900 axis : {0 or 'index', 1 or 'columns', None}, default None 

7901 Axis to interpolate along. For `Series` this parameter is unused 

7902 and defaults to 0. 

7903 limit : int, optional 

7904 Maximum number of consecutive NaNs to fill. Must be greater than 

7905 0. 

7906 inplace : bool, default False 

7907 Update the data in place if possible. 

7908 limit_direction : {'forward', 'backward', 'both'}, optional, default 'forward' 

7909 Consecutive NaNs will be filled in this direction. 

7910 

7911 limit_area : {`None`, 'inside', 'outside'}, default None 

7912 If limit is specified, consecutive NaNs will be filled with this 

7913 restriction. 

7914 

7915 * ``None``: No fill restriction. 

7916 * 'inside': Only fill NaNs surrounded by valid values 

7917 (interpolate). 

7918 * 'outside': Only fill NaNs outside valid values (extrapolate). 

7919 

7920 **kwargs : optional 

7921 Keyword arguments to pass on to the interpolating function. 

7922 

7923 Returns 

7924 ------- 

7925 Series or DataFrame 

7926 Returns the same object type as the caller, interpolated at 

7927 some or all ``NaN`` values. 

7928 

7929 See Also 

7930 -------- 

7931 fillna : Fill missing values using different methods. 

7932 scipy.interpolate.Akima1DInterpolator : Piecewise cubic polynomials 

7933 (Akima interpolator). 

7934 scipy.interpolate.BPoly.from_derivatives : Piecewise polynomial in the 

7935 Bernstein basis. 

7936 scipy.interpolate.interp1d : Interpolate a 1-D function. 

7937 scipy.interpolate.KroghInterpolator : Interpolate polynomial (Krogh 

7938 interpolator). 

7939 scipy.interpolate.PchipInterpolator : PCHIP 1-d monotonic cubic 

7940 interpolation. 

7941 scipy.interpolate.CubicSpline : Cubic spline data interpolator. 

7942 

7943 Notes 

7944 ----- 

7945 The 'krogh', 'piecewise_polynomial', 'spline', 'pchip' and 'akima' 

7946 methods are wrappers around the respective SciPy implementations of 

7947 similar names. These use the actual numerical values of the index. 

7948 For more information on their behavior, see the 

7949 `SciPy documentation 

7950 <https://docs.scipy.org/doc/scipy/reference/interpolate.html#univariate-interpolation>`__. 

7951 

7952 Examples 

7953 -------- 

7954 Filling in ``NaN`` in a :class:`~pandas.Series` via linear 

7955 interpolation. 

7956 

7957 >>> s = pd.Series([0, 1, np.nan, 3]) 

7958 >>> s 

7959 0 0.0 

7960 1 1.0 

7961 2 NaN 

7962 3 3.0 

7963 dtype: float64 

7964 >>> s.interpolate() 

7965 0 0.0 

7966 1 1.0 

7967 2 2.0 

7968 3 3.0 

7969 dtype: float64 

7970 

7971 Filling in ``NaN`` in a Series via polynomial interpolation or splines: 

7972 Both 'polynomial' and 'spline' methods require that you also specify 

7973 an ``order`` (int). 

7974 

7975 >>> s = pd.Series([0, 2, np.nan, 8]) 

7976 >>> s.interpolate(method="polynomial", order=2) 

7977 0 0.000000 

7978 1 2.000000 

7979 2 4.666667 

7980 3 8.000000 

7981 dtype: float64 

7982 

7983 Fill the DataFrame forward (that is, going down) along each column 

7984 using linear interpolation. 

7985 

7986 Note how the last entry in column 'a' is interpolated differently, 

7987 because there is no entry after it to use for interpolation. 

7988 Note how the first entry in column 'b' remains ``NaN``, because there 

7989 is no entry before it to use for interpolation. 

7990 

7991 >>> df = pd.DataFrame( 

7992 ... [ 

7993 ... (0.0, np.nan, -1.0, 1.0), 

7994 ... (np.nan, 2.0, np.nan, np.nan), 

7995 ... (2.0, 3.0, np.nan, 9.0), 

7996 ... (np.nan, 4.0, -4.0, 16.0), 

7997 ... ], 

7998 ... columns=list("abcd"), 

7999 ... ) 

8000 >>> df 

8001 a b c d 

8002 0 0.0 NaN -1.0 1.0 

8003 1 NaN 2.0 NaN NaN 

8004 2 2.0 3.0 NaN 9.0 

8005 3 NaN 4.0 -4.0 16.0 

8006 >>> df.interpolate(method="linear", limit_direction="forward", axis=0) 

8007 a b c d 

8008 0 0.0 NaN -1.0 1.0 

8009 1 1.0 2.0 -2.0 5.0 

8010 2 2.0 3.0 -3.0 9.0 

8011 3 2.0 4.0 -4.0 16.0 

8012 

8013 Using polynomial interpolation. 

8014 

8015 >>> df["d"].interpolate(method="polynomial", order=2) 

8016 0 1.0 

8017 1 4.0 

8018 2 9.0 

8019 3 16.0 

8020 Name: d, dtype: float64 

8021 """ 

8022 inplace = validate_bool_kwarg(inplace, "inplace") 

8023 

8024 if inplace: 

8025 if not CHAINED_WARNING_DISABLED: 

8026 if sys.getrefcount( 

8027 self 

8028 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

8029 warnings.warn( 

8030 _chained_assignment_method_msg, 

8031 ChainedAssignmentError, 

8032 stacklevel=2, 

8033 ) 

8034 

8035 axis = self._get_axis_number(axis) 

8036 

8037 if self.empty: 

8038 return self if inplace else self.copy() 

8039 

8040 if not isinstance(method, str): 

8041 raise ValueError("'method' should be a string, not None.") 

8042 

8043 obj, should_transpose = (self.T, True) if axis == 1 else (self, False) 

8044 

8045 if isinstance(obj.index, MultiIndex) and method != "linear": 

8046 raise ValueError( 

8047 "Only `method=linear` interpolation is supported on MultiIndexes." 

8048 ) 

8049 

8050 limit_direction = missing.infer_limit_direction(limit_direction, method) 

8051 

8052 index = missing.get_interp_index(method, obj.index) 

8053 new_data = obj._mgr.interpolate( 

8054 method=method, 

8055 index=index, 

8056 limit=limit, 

8057 limit_direction=limit_direction, 

8058 limit_area=limit_area, 

8059 inplace=inplace, 

8060 **kwargs, 

8061 ) 

8062 

8063 result = self._constructor_from_mgr(new_data, axes=new_data.axes) 

8064 if should_transpose: 

8065 result = result.T 

8066 if inplace: 

8067 self._update_inplace(result) 

8068 return self 

8069 else: 

8070 return result.__finalize__(self, method="interpolate") 

8071 

8072 # ---------------------------------------------------------------------- 

8073 # Timeseries methods Methods 

8074 

8075 @final 

8076 def asof(self, where, subset=None): 

8077 """ 

8078 Return the last row(s) without any NaNs before `where`. 

8079 

8080 The last row (for each element in `where`, if list) without any 

8081 NaN is taken. 

8082 In case of a :class:`~pandas.DataFrame`, the last row without NaN 

8083 considering only the subset of columns (if not `None`) 

8084 

8085 If there is no good value, NaN is returned for a Series or 

8086 a Series of NaN values for a DataFrame 

8087 

8088 Parameters 

8089 ---------- 

8090 where : date or array-like of dates 

8091 Date(s) before which the last row(s) are returned. 

8092 subset : str or array-like of str, default `None` 

8093 For DataFrame, if not `None`, only use these columns to 

8094 check for NaNs. 

8095 

8096 Returns 

8097 ------- 

8098 scalar, Series, or DataFrame 

8099 

8100 The return can be: 

8101 

8102 * scalar : when `self` is a Series and `where` is a scalar 

8103 * Series: when `self` is a Series and `where` is an array-like, 

8104 or when `self` is a DataFrame and `where` is a scalar 

8105 * DataFrame : when `self` is a DataFrame and `where` is an 

8106 array-like 

8107 

8108 See Also 

8109 -------- 

8110 merge_asof : Perform an asof merge. Similar to left join. 

8111 

8112 Notes 

8113 ----- 

8114 Dates are assumed to be sorted. Raises if this is not the case. 

8115 

8116 Examples 

8117 -------- 

8118 A Series and a scalar `where`. 

8119 

8120 >>> s = pd.Series([1, 2, np.nan, 4], index=[10, 20, 30, 40]) 

8121 >>> s 

8122 10 1.0 

8123 20 2.0 

8124 30 NaN 

8125 40 4.0 

8126 dtype: float64 

8127 

8128 >>> s.asof(20) 

8129 np.float64(2.0) 

8130 

8131 For a sequence `where`, a Series is returned. The first value is 

8132 NaN, because the first element of `where` is before the first 

8133 index value. 

8134 

8135 >>> s.asof([5, 20]) 

8136 5 NaN 

8137 20 2.0 

8138 dtype: float64 

8139 

8140 Missing values are not considered. The following is ``2.0``, not 

8141 NaN, even though NaN is at the index location for ``30``. 

8142 

8143 >>> s.asof(30) 

8144 np.float64(2.0) 

8145 

8146 Take all columns into consideration 

8147 

8148 >>> df = pd.DataFrame( 

8149 ... { 

8150 ... "a": [10.0, 20.0, 30.0, 40.0, 50.0], 

8151 ... "b": [None, None, None, None, 500], 

8152 ... }, 

8153 ... index=pd.DatetimeIndex( 

8154 ... [ 

8155 ... "2018-02-27 09:01:00", 

8156 ... "2018-02-27 09:02:00", 

8157 ... "2018-02-27 09:03:00", 

8158 ... "2018-02-27 09:04:00", 

8159 ... "2018-02-27 09:05:00", 

8160 ... ] 

8161 ... ), 

8162 ... ) 

8163 >>> df.asof(pd.DatetimeIndex(["2018-02-27 09:03:30", "2018-02-27 09:04:30"])) 

8164 a b 

8165 2018-02-27 09:03:30 NaN NaN 

8166 2018-02-27 09:04:30 NaN NaN 

8167 

8168 Take a single column into consideration 

8169 

8170 >>> df.asof( 

8171 ... pd.DatetimeIndex(["2018-02-27 09:03:30", "2018-02-27 09:04:30"]), 

8172 ... subset=["a"], 

8173 ... ) 

8174 a b 

8175 2018-02-27 09:03:30 30.0 NaN 

8176 2018-02-27 09:04:30 40.0 NaN 

8177 """ 

8178 if isinstance(where, str): 

8179 where = Timestamp(where) 

8180 

8181 if not self.index.is_monotonic_increasing: 

8182 raise ValueError("asof requires a sorted index") 

8183 

8184 is_series = isinstance(self, ABCSeries) 

8185 if is_series: 

8186 if subset is not None: 

8187 raise ValueError("subset is not valid for Series") 

8188 else: 

8189 if subset is None: 

8190 subset = self.columns 

8191 if not is_list_like(subset): 

8192 subset = [subset] 

8193 

8194 is_list = is_list_like(where) 

8195 if not is_list: 

8196 start = self.index[0] 

8197 if isinstance(self.index, PeriodIndex): 

8198 where = Period(where, freq=self.index.freq) 

8199 

8200 if where < start: 

8201 if not is_series: 

8202 return self._constructor_sliced( 

8203 index=self.columns, name=where, dtype=np.float64 

8204 ) 

8205 return np.nan 

8206 

8207 # It's always much faster to use a *while* loop here for 

8208 # Series than pre-computing all the NAs. However a 

8209 # *while* loop is extremely expensive for DataFrame 

8210 # so we later pre-compute all the NAs and use the same 

8211 # code path whether *where* is a scalar or list. 

8212 # See PR: https://github.com/pandas-dev/pandas/pull/14476 

8213 if is_series: 

8214 loc = self.index.searchsorted(where, side="right") 

8215 if loc > 0: 

8216 loc -= 1 

8217 

8218 values = self._values 

8219 while loc > 0 and isna(values[loc]): 

8220 loc -= 1 

8221 return values[loc] 

8222 

8223 if not isinstance(where, Index): 

8224 where = Index(where) if is_list else Index([where]) 

8225 

8226 nulls = self.isna() if is_series else self[subset].isna().any(axis=1) 

8227 if nulls.all(): 

8228 if is_series: 

8229 self = cast("Series", self) 

8230 return self._constructor(np.nan, index=where, name=self.name) 

8231 elif is_list: 

8232 self = cast("DataFrame", self) 

8233 return self._constructor(np.nan, index=where, columns=self.columns) 

8234 else: 

8235 self = cast("DataFrame", self) 

8236 return self._constructor_sliced( 

8237 np.nan, index=self.columns, name=where[0] 

8238 ) 

8239 

8240 # error: Unsupported operand type for 

8241 # ~ ("ExtensionArray | ndarray[Any, Any] | Any") 

8242 locs = self.index.asof_locs(where, ~nulls._values) # type: ignore[operator] 

8243 

8244 # mask the missing 

8245 mask = locs == -1 

8246 data = self.take(locs) 

8247 data.index = where 

8248 if mask.any(): 

8249 # GH#16063 only do this setting when necessary, otherwise 

8250 # we'd cast e.g. bools to floats 

8251 data.loc[mask] = np.nan 

8252 return data if is_list else data.iloc[-1] 

8253 

8254 # ---------------------------------------------------------------------- 

8255 # Action Methods 

8256 

8257 def isna(self) -> Self: 

8258 """ 

8259 Detect missing values. 

8260 

8261 Return a boolean same-sized object indicating if the values are NA. 

8262 NA values, such as None or :attr:`numpy.NaN`, gets mapped to True 

8263 values. 

8264 Everything else gets mapped to False values. Characters such as empty 

8265 strings ``''`` or :attr:`numpy.inf` are not considered NA values. 

8266 

8267 Returns 

8268 ------- 

8269 Series/DataFrame 

8270 Mask of bool values for each element in Series/DataFrame 

8271 that indicates whether an element is an NA value. 

8272 

8273 See Also 

8274 -------- 

8275 Series.isnull : Alias of isna. 

8276 DataFrame.isnull : Alias of isna. 

8277 Series.notna : Boolean inverse of isna. 

8278 DataFrame.notna : Boolean inverse of isna. 

8279 Series.dropna : Omit axes labels with missing values. 

8280 DataFrame.dropna : Omit axes labels with missing values. 

8281 isna : Top-level isna. 

8282 

8283 Examples 

8284 -------- 

8285 Show which entries in a DataFrame are NA. 

8286 

8287 >>> df = pd.DataFrame( 

8288 ... dict( 

8289 ... age=[5, 6, np.nan], 

8290 ... born=[ 

8291 ... pd.NaT, 

8292 ... pd.Timestamp("1939-05-27"), 

8293 ... pd.Timestamp("1940-04-25"), 

8294 ... ], 

8295 ... name=["Alfred", "Batman", ""], 

8296 ... toy=[None, "Batmobile", "Joker"], 

8297 ... ) 

8298 ... ) 

8299 >>> df 

8300 age born name toy 

8301 0 5.0 NaT Alfred NaN 

8302 1 6.0 1939-05-27 Batman Batmobile 

8303 2 NaN 1940-04-25 Joker 

8304 

8305 >>> df.isna() 

8306 age born name toy 

8307 0 False True False True 

8308 1 False False False False 

8309 2 True False False False 

8310 

8311 Show which entries in a Series are NA. 

8312 

8313 >>> ser = pd.Series([5, 6, np.nan]) 

8314 >>> ser 

8315 0 5.0 

8316 1 6.0 

8317 2 NaN 

8318 dtype: float64 

8319 

8320 >>> ser.isna() 

8321 0 False 

8322 1 False 

8323 2 True 

8324 dtype: bool 

8325 """ 

8326 return isna(self).__finalize__(self, method="isna") 

8327 

8328 def isnull(self) -> Self: 

8329 """ 

8330 Detect missing values. 

8331 

8332 Return a boolean same-sized object indicating if the values are NA. 

8333 NA values, such as None or :attr:`numpy.NaN`, gets mapped to True 

8334 values. 

8335 Everything else gets mapped to False values. Characters such as empty 

8336 strings ``''`` or :attr:`numpy.inf` are not considered NA values. 

8337 

8338 Returns 

8339 ------- 

8340 Series/DataFrame 

8341 Mask of bool values for each element in Series/DataFrame 

8342 that indicates whether an element is an NA value. 

8343 

8344 See Also 

8345 -------- 

8346 Series.isna : Alias of isnull. 

8347 DataFrame.isna : Alias of isnull. 

8348 Series.notna : Boolean inverse of isnull. 

8349 DataFrame.notna : Boolean inverse of isnull. 

8350 Series.dropna : Omit axes labels with missing values. 

8351 DataFrame.dropna : Omit axes labels with missing values. 

8352 isna : Top-level isna. 

8353 

8354 Examples 

8355 -------- 

8356 Show which entries in a DataFrame are NA. 

8357 

8358 >>> df = pd.DataFrame( 

8359 ... dict( 

8360 ... age=[5, 6, np.nan], 

8361 ... born=[ 

8362 ... pd.NaT, 

8363 ... pd.Timestamp("1939-05-27"), 

8364 ... pd.Timestamp("1940-04-25"), 

8365 ... ], 

8366 ... name=["Alfred", "Batman", ""], 

8367 ... toy=[None, "Batmobile", "Joker"], 

8368 ... ) 

8369 ... ) 

8370 >>> df 

8371 age born name toy 

8372 0 5.0 NaT Alfred NaN 

8373 1 6.0 1939-05-27 Batman Batmobile 

8374 2 NaN 1940-04-25 Joker 

8375 

8376 >>> df.isna() 

8377 age born name toy 

8378 0 False True False True 

8379 1 False False False False 

8380 2 True False False False 

8381 

8382 Show which entries in a Series are NA. 

8383 

8384 >>> ser = pd.Series([5, 6, np.nan]) 

8385 >>> ser 

8386 0 5.0 

8387 1 6.0 

8388 2 NaN 

8389 dtype: float64 

8390 

8391 >>> ser.isna() 

8392 0 False 

8393 1 False 

8394 2 True 

8395 dtype: bool 

8396 """ 

8397 return isna(self).__finalize__(self, method="isnull") 

8398 

8399 def notna(self) -> Self: 

8400 """ 

8401 Detect existing (non-missing) values. 

8402 

8403 Return a boolean same-sized object indicating if the values are not NA. 

8404 Non-missing values get mapped to True. Characters such as empty 

8405 strings ``''`` or :attr:`numpy.inf` are not considered NA values. 

8406 NA values, such as None or :attr:`numpy.NaN`, get mapped to False 

8407 values. 

8408 

8409 Returns 

8410 ------- 

8411 Series/DataFrame 

8412 Mask of bool values for each element in Series/DataFrame 

8413 that indicates whether an element is not an NA value. 

8414 

8415 See Also 

8416 -------- 

8417 Series.notnull : Alias of notna. 

8418 DataFrame.notnull : Alias of notna. 

8419 Series.isna : Boolean inverse of notna. 

8420 DataFrame.isna : Boolean inverse of notna. 

8421 Series.dropna : Omit axes labels with missing values. 

8422 DataFrame.dropna : Omit axes labels with missing values. 

8423 notna : Top-level notna. 

8424 

8425 Examples 

8426 -------- 

8427 Show which entries in a DataFrame are not NA. 

8428 

8429 >>> df = pd.DataFrame( 

8430 ... dict( 

8431 ... age=[5, 6, np.nan], 

8432 ... born=[ 

8433 ... pd.NaT, 

8434 ... pd.Timestamp("1939-05-27"), 

8435 ... pd.Timestamp("1940-04-25"), 

8436 ... ], 

8437 ... name=["Alfred", "Batman", ""], 

8438 ... toy=[None, "Batmobile", "Joker"], 

8439 ... ) 

8440 ... ) 

8441 >>> df 

8442 age born name toy 

8443 0 5.0 NaT Alfred NaN 

8444 1 6.0 1939-05-27 Batman Batmobile 

8445 2 NaN 1940-04-25 Joker 

8446 

8447 >>> df.notna() 

8448 age born name toy 

8449 0 True False True False 

8450 1 True True True True 

8451 2 False True True True 

8452 

8453 Show which entries in a Series are not NA. 

8454 

8455 >>> ser = pd.Series([5, 6, np.nan]) 

8456 >>> ser 

8457 0 5.0 

8458 1 6.0 

8459 2 NaN 

8460 dtype: float64 

8461 

8462 >>> ser.notna() 

8463 0 True 

8464 1 True 

8465 2 False 

8466 dtype: bool 

8467 """ 

8468 return notna(self).__finalize__(self, method="notna") 

8469 

8470 def notnull(self) -> Self: 

8471 """ 

8472 Detect existing (non-missing) values. 

8473 

8474 Return a boolean same-sized object indicating if the values are not NA. 

8475 Non-missing values get mapped to True. Characters such as empty 

8476 strings ``''`` or :attr:`numpy.inf` are not considered NA values. 

8477 NA values, such as None or :attr:`numpy.NaN`, get mapped to False 

8478 values. 

8479 

8480 Returns 

8481 ------- 

8482 Series/DataFrame 

8483 Mask of bool values for each element in Series/DataFrame 

8484 that indicates whether an element is not an NA value. 

8485 

8486 See Also 

8487 -------- 

8488 Series.notnull : Alias of notna. 

8489 DataFrame.notnull : Alias of notna. 

8490 Series.isna : Boolean inverse of notna. 

8491 DataFrame.isna : Boolean inverse of notna. 

8492 Series.dropna : Omit axes labels with missing values. 

8493 DataFrame.dropna : Omit axes labels with missing values. 

8494 notna : Top-level notna. 

8495 

8496 Examples 

8497 -------- 

8498 Show which entries in a DataFrame are not NA. 

8499 

8500 >>> df = pd.DataFrame( 

8501 ... dict( 

8502 ... age=[5, 6, np.nan], 

8503 ... born=[ 

8504 ... pd.NaT, 

8505 ... pd.Timestamp("1939-05-27"), 

8506 ... pd.Timestamp("1940-04-25"), 

8507 ... ], 

8508 ... name=["Alfred", "Batman", ""], 

8509 ... toy=[None, "Batmobile", "Joker"], 

8510 ... ) 

8511 ... ) 

8512 >>> df 

8513 age born name toy 

8514 0 5.0 NaT Alfred NaN 

8515 1 6.0 1939-05-27 Batman Batmobile 

8516 2 NaN 1940-04-25 Joker 

8517 

8518 >>> df.notna() 

8519 age born name toy 

8520 0 True False True False 

8521 1 True True True True 

8522 2 False True True True 

8523 

8524 Show which entries in a Series are not NA. 

8525 

8526 >>> ser = pd.Series([5, 6, np.nan]) 

8527 >>> ser 

8528 0 5.0 

8529 1 6.0 

8530 2 NaN 

8531 dtype: float64 

8532 

8533 >>> ser.notna() 

8534 0 True 

8535 1 True 

8536 2 False 

8537 dtype: bool 

8538 """ 

8539 return notna(self).__finalize__(self, method="notnull") 

8540 

8541 @final 

8542 def _clip_with_scalar(self, lower, upper, inplace: bool = False): 

8543 if (lower is not None and np.any(isna(lower))) or ( 

8544 upper is not None and np.any(isna(upper)) 

8545 ): 

8546 raise ValueError("Cannot use an NA value as a clip threshold") 

8547 

8548 result = self 

8549 mask = self.isna() 

8550 

8551 if lower is not None: 

8552 cond = mask | (self >= lower) 

8553 result = result.where(cond, lower, inplace=inplace) 

8554 if upper is not None: 

8555 cond = mask | (self <= upper) 

8556 result = result.where(cond, upper, inplace=inplace) 

8557 

8558 return result 

8559 

8560 @final 

8561 def _clip_with_one_bound(self, threshold, method, axis, inplace): 

8562 if axis is not None: 

8563 axis = self._get_axis_number(axis) 

8564 

8565 # method is self.le for upper bound and self.ge for lower bound 

8566 if is_scalar(threshold) and is_number(threshold): 

8567 if method.__name__ == "le": 

8568 return self._clip_with_scalar(None, threshold, inplace=inplace) 

8569 return self._clip_with_scalar(threshold, None, inplace=inplace) 

8570 

8571 # GH #15390 

8572 # In order for where method to work, the threshold must 

8573 # be transformed to NDFrame from other array like structure. 

8574 if (not isinstance(threshold, ABCSeries)) and is_list_like(threshold): 

8575 if isinstance(self, ABCSeries): 

8576 threshold = self._constructor(threshold, index=self.index) 

8577 else: 

8578 threshold = self._align_for_op(threshold, axis, flex=None)[1] 

8579 

8580 # GH 40420 

8581 # Treat missing thresholds as no bounds, not clipping the values 

8582 if is_list_like(threshold): 

8583 fill_value = np.inf if method.__name__ == "le" else -np.inf 

8584 threshold_inf = threshold.fillna(fill_value) 

8585 else: 

8586 threshold_inf = threshold 

8587 

8588 subset = method(threshold_inf, axis=axis) | isna(self) 

8589 

8590 # GH 40420 

8591 return self.where(subset, threshold, axis=axis, inplace=inplace) 

8592 

8593 @final 

8594 def clip( 

8595 self, 

8596 lower=None, 

8597 upper=None, 

8598 *, 

8599 axis: Axis | None = None, 

8600 inplace: bool = False, 

8601 **kwargs, 

8602 ) -> Self: 

8603 """ 

8604 Trim values at input threshold(s). 

8605 

8606 Assigns values outside boundary to boundary values. Thresholds 

8607 can be singular values or array like, and in the latter case 

8608 the clipping is performed element-wise in the specified axis. 

8609 

8610 Parameters 

8611 ---------- 

8612 lower : float or array-like, default None 

8613 Minimum threshold value. All values below this 

8614 threshold will be set to it. A missing 

8615 threshold (e.g `NA`) will not clip the value. 

8616 upper : float or array-like, default None 

8617 Maximum threshold value. All values above this 

8618 threshold will be set to it. A missing 

8619 threshold (e.g `NA`) will not clip the value. 

8620 axis : {0 or 'index', 1 or 'columns', None}, default None 

8621 Align object with lower and upper along the given axis. 

8622 For `Series` this parameter is unused and defaults to `None`. 

8623 inplace : bool, default False 

8624 Whether to perform the operation in place on the data. 

8625 **kwargs 

8626 Additional keywords have no effect but might be accepted 

8627 for compatibility with numpy. 

8628 

8629 Returns 

8630 ------- 

8631 Series or DataFrame 

8632 Same type as calling object with the values outside the 

8633 clip boundaries replaced. 

8634 

8635 See Also 

8636 -------- 

8637 Series.clip : Trim values at input threshold in series. 

8638 DataFrame.clip : Trim values at input threshold in DataFrame. 

8639 numpy.clip : Clip (limit) the values in an array. 

8640 

8641 Examples 

8642 -------- 

8643 >>> data = {"col_0": [9, -3, 0, -1, 5], "col_1": [-2, -7, 6, 8, -5]} 

8644 >>> df = pd.DataFrame(data) 

8645 >>> df 

8646 col_0 col_1 

8647 0 9 -2 

8648 1 -3 -7 

8649 2 0 6 

8650 3 -1 8 

8651 4 5 -5 

8652 

8653 Clips per column using lower and upper thresholds: 

8654 

8655 >>> df.clip(-4, 6) 

8656 col_0 col_1 

8657 0 6 -2 

8658 1 -3 -4 

8659 2 0 6 

8660 3 -1 6 

8661 4 5 -4 

8662 

8663 Clips using specific lower and upper thresholds per column: 

8664 

8665 >>> df.clip([-2, -1], [4, 5]) 

8666 col_0 col_1 

8667 0 4 -1 

8668 1 -2 -1 

8669 2 0 5 

8670 3 -1 5 

8671 4 4 -1 

8672 

8673 Clips using specific lower and upper thresholds per column element: 

8674 

8675 >>> t = pd.Series([2, -4, -1, 6, 3]) 

8676 >>> t 

8677 0 2 

8678 1 -4 

8679 2 -1 

8680 3 6 

8681 4 3 

8682 dtype: int64 

8683 

8684 >>> df.clip(t, t + 4, axis=0) 

8685 col_0 col_1 

8686 0 6 2 

8687 1 -3 -4 

8688 2 0 3 

8689 3 6 8 

8690 4 5 3 

8691 

8692 Clips using specific lower threshold per column element, with missing values: 

8693 

8694 >>> t = pd.Series([2, -4, np.nan, 6, 3]) 

8695 >>> t 

8696 0 2.0 

8697 1 -4.0 

8698 2 NaN 

8699 3 6.0 

8700 4 3.0 

8701 dtype: float64 

8702 

8703 >>> df.clip(t, axis=0) 

8704 col_0 col_1 

8705 0 9.0 2.0 

8706 1 -3.0 -4.0 

8707 2 0.0 6.0 

8708 3 6.0 8.0 

8709 4 5.0 3.0 

8710 """ 

8711 inplace = validate_bool_kwarg(inplace, "inplace") 

8712 

8713 if inplace: 

8714 if not CHAINED_WARNING_DISABLED: 

8715 if sys.getrefcount( 

8716 self 

8717 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

8718 warnings.warn( 

8719 _chained_assignment_method_msg, 

8720 ChainedAssignmentError, 

8721 stacklevel=2, 

8722 ) 

8723 

8724 axis = nv.validate_clip_with_axis(axis, (), kwargs) 

8725 if axis is not None: 

8726 axis = self._get_axis_number(axis) 

8727 

8728 # GH 17276 

8729 # numpy doesn't like NaN as a clip value 

8730 # so ignore 

8731 # GH 19992 

8732 # numpy doesn't drop a list-like bound containing NaN 

8733 isna_lower = isna(lower) 

8734 if not is_list_like(lower): 

8735 if np.any(isna_lower): 

8736 lower = None 

8737 elif np.all(isna_lower): 

8738 lower = None 

8739 isna_upper = isna(upper) 

8740 if not is_list_like(upper): 

8741 if np.any(isna_upper): 

8742 upper = None 

8743 elif np.all(isna_upper): 

8744 upper = None 

8745 

8746 # GH 2747 (arguments were reversed) 

8747 if ( 

8748 lower is not None 

8749 and upper is not None 

8750 and is_scalar(lower) 

8751 and is_scalar(upper) 

8752 ): 

8753 lower, upper = min(lower, upper), max(lower, upper) 

8754 

8755 # fast-path for scalars 

8756 if (lower is None or is_number(lower)) and (upper is None or is_number(upper)): 

8757 return self._clip_with_scalar(lower, upper, inplace=inplace) 

8758 

8759 result = self 

8760 if lower is not None: 

8761 result = result._clip_with_one_bound( 

8762 lower, method=self.ge, axis=axis, inplace=inplace 

8763 ) 

8764 if upper is not None: 

8765 if inplace: 

8766 result = self 

8767 result = result._clip_with_one_bound( 

8768 upper, method=self.le, axis=axis, inplace=inplace 

8769 ) 

8770 

8771 return result 

8772 

8773 @final 

8774 def asfreq( 

8775 self, 

8776 freq: Frequency, 

8777 method: FillnaOptions | None = None, 

8778 how: Literal["start", "end"] | None = None, 

8779 normalize: bool = False, 

8780 fill_value: Hashable | None = None, 

8781 ) -> Self: 

8782 """ 

8783 Convert time series to specified frequency. 

8784 

8785 Returns the original data conformed to a new index with the specified 

8786 frequency. 

8787 

8788 If the index of this Series/DataFrame is a :class:`~pandas.PeriodIndex`, the 

8789 new index is the result of transforming the original index with 

8790 :meth:`PeriodIndex.asfreq <pandas.PeriodIndex.asfreq>` (so the original index 

8791 will map one-to-one to the new index). 

8792 

8793 Otherwise, the new index will be equivalent to ``pd.date_range(start, end, 

8794 freq=freq)`` where ``start`` and ``end`` are, respectively, the min and 

8795 max entries in the original index (see :func:`pandas.date_range`). The 

8796 values corresponding to any timesteps in the new index which were not present 

8797 in the original index will be null (``NaN``), unless a method for filling 

8798 such unknowns is provided (see the ``method`` parameter below). 

8799 

8800 The :meth:`resample` method is more appropriate if an operation on each group of 

8801 timesteps (such as an aggregate) is necessary to represent the data at the new 

8802 frequency. 

8803 

8804 Parameters 

8805 ---------- 

8806 freq : DateOffset or str 

8807 Frequency DateOffset or string. 

8808 method : {'backfill'/'bfill', 'pad'/'ffill'}, default None 

8809 Method to use for filling holes in reindexed Series (note this 

8810 does not fill NaNs that already were present): 

8811 

8812 * 'pad' / 'ffill': propagate last valid observation forward to next 

8813 valid based on the order of the index 

8814 * 'backfill' / 'bfill': use NEXT valid observation to fill. 

8815 how : {'start', 'end'}, default end 

8816 For PeriodIndex only (see PeriodIndex.asfreq). 

8817 normalize : bool, default False 

8818 Whether to reset output index to midnight. 

8819 fill_value : scalar, optional 

8820 Value to use for missing values, applied during upsampling (note 

8821 this does not fill NaNs that already were present). 

8822 

8823 Returns 

8824 ------- 

8825 Series/DataFrame 

8826 Series/DataFrame object reindexed to the specified frequency. 

8827 

8828 See Also 

8829 -------- 

8830 reindex : Conform DataFrame to new index with optional filling logic. 

8831 

8832 Notes 

8833 ----- 

8834 To learn more about the frequency strings, please see 

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

8836 

8837 Examples 

8838 -------- 

8839 Start by creating a series with 4 one minute timestamps. 

8840 

8841 >>> index = pd.date_range("1/1/2000", periods=4, freq="min") 

8842 >>> series = pd.Series([0.0, None, 2.0, 3.0], index=index) 

8843 >>> df = pd.DataFrame({"s": series}) 

8844 >>> df 

8845 s 

8846 2000-01-01 00:00:00 0.0 

8847 2000-01-01 00:01:00 NaN 

8848 2000-01-01 00:02:00 2.0 

8849 2000-01-01 00:03:00 3.0 

8850 

8851 Upsample the series into 30 second bins. 

8852 

8853 >>> df.asfreq(freq="30s") 

8854 s 

8855 2000-01-01 00:00:00 0.0 

8856 2000-01-01 00:00:30 NaN 

8857 2000-01-01 00:01:00 NaN 

8858 2000-01-01 00:01:30 NaN 

8859 2000-01-01 00:02:00 2.0 

8860 2000-01-01 00:02:30 NaN 

8861 2000-01-01 00:03:00 3.0 

8862 

8863 Upsample again, providing a ``fill value``. 

8864 

8865 >>> df.asfreq(freq="30s", fill_value=9.0) 

8866 s 

8867 2000-01-01 00:00:00 0.0 

8868 2000-01-01 00:00:30 9.0 

8869 2000-01-01 00:01:00 NaN 

8870 2000-01-01 00:01:30 9.0 

8871 2000-01-01 00:02:00 2.0 

8872 2000-01-01 00:02:30 9.0 

8873 2000-01-01 00:03:00 3.0 

8874 

8875 Upsample again, providing a ``method``. 

8876 

8877 >>> df.asfreq(freq="30s", method="bfill") 

8878 s 

8879 2000-01-01 00:00:00 0.0 

8880 2000-01-01 00:00:30 NaN 

8881 2000-01-01 00:01:00 NaN 

8882 2000-01-01 00:01:30 2.0 

8883 2000-01-01 00:02:00 2.0 

8884 2000-01-01 00:02:30 3.0 

8885 2000-01-01 00:03:00 3.0 

8886 """ 

8887 from pandas.core.resample import asfreq 

8888 

8889 return asfreq( 

8890 self, 

8891 freq, 

8892 method=method, 

8893 how=how, 

8894 normalize=normalize, 

8895 fill_value=fill_value, 

8896 ) 

8897 

8898 @final 

8899 def at_time(self, time, asof: bool = False, axis: Axis | None = None) -> Self: 

8900 """ 

8901 Select values at particular time of day (e.g., 9:30AM). 

8902 

8903 Parameters 

8904 ---------- 

8905 time : datetime.time or str 

8906 The values to select. 

8907 asof : bool, default False 

8908 This parameter is currently not supported. 

8909 axis : {0 or 'index', 1 or 'columns'}, default 0 

8910 For `Series` this parameter is unused and defaults to 0. 

8911 

8912 Returns 

8913 ------- 

8914 Series or DataFrame 

8915 The values with the specified time. 

8916 

8917 Raises 

8918 ------ 

8919 TypeError 

8920 If the index is not a :class:`DatetimeIndex` 

8921 

8922 See Also 

8923 -------- 

8924 between_time : Select values between particular times of the day. 

8925 first : Select initial periods of time series based on a date offset. 

8926 last : Select final periods of time series based on a date offset. 

8927 DatetimeIndex.indexer_at_time : Get just the index locations for 

8928 values at particular time of the day. 

8929 

8930 Examples 

8931 -------- 

8932 >>> i = pd.date_range("2018-04-09", periods=4, freq="12h") 

8933 >>> ts = pd.DataFrame({"A": [1, 2, 3, 4]}, index=i) 

8934 >>> ts 

8935 A 

8936 2018-04-09 00:00:00 1 

8937 2018-04-09 12:00:00 2 

8938 2018-04-10 00:00:00 3 

8939 2018-04-10 12:00:00 4 

8940 

8941 >>> ts.at_time("12:00") 

8942 A 

8943 2018-04-09 12:00:00 2 

8944 2018-04-10 12:00:00 4 

8945 """ 

8946 if axis is None: 

8947 axis = 0 

8948 axis = self._get_axis_number(axis) 

8949 

8950 index = self._get_axis(axis) 

8951 

8952 if not isinstance(index, DatetimeIndex): 

8953 raise TypeError("Index must be DatetimeIndex") 

8954 

8955 indexer = index.indexer_at_time(time, asof=asof) 

8956 return self.take(indexer, axis=axis) 

8957 

8958 @final 

8959 def between_time( 

8960 self, 

8961 start_time, 

8962 end_time, 

8963 inclusive: IntervalClosedType = "both", 

8964 axis: Axis | None = None, 

8965 ) -> Self: 

8966 """ 

8967 Select values between particular times of the day (e.g., 9:00-9:30 AM). 

8968 

8969 By setting ``start_time`` to be later than ``end_time``, 

8970 you can get the times that are *not* between the two times. 

8971 

8972 Parameters 

8973 ---------- 

8974 start_time : datetime.time or str 

8975 Initial time as a time filter limit. 

8976 end_time : datetime.time or str 

8977 End time as a time filter limit. 

8978 inclusive : {"both", "neither", "left", "right"}, default "both" 

8979 Include boundaries; whether to set each bound as closed or open. 

8980 axis : {0 or 'index', 1 or 'columns'}, default 0 

8981 Determine range time on index or columns value. 

8982 For `Series` this parameter is unused and defaults to 0. 

8983 

8984 Returns 

8985 ------- 

8986 Series or DataFrame 

8987 Data from the original object filtered to the specified dates range. 

8988 

8989 Raises 

8990 ------ 

8991 TypeError 

8992 If the index is not a :class:`DatetimeIndex` 

8993 

8994 See Also 

8995 -------- 

8996 at_time : Select values at a particular time of the day. 

8997 first : Select initial periods of time series based on a date offset. 

8998 last : Select final periods of time series based on a date offset. 

8999 DatetimeIndex.indexer_between_time : Get just the index locations for 

9000 values between particular times of the day. 

9001 

9002 Examples 

9003 -------- 

9004 >>> i = pd.date_range("2018-04-09", periods=4, freq="1D20min") 

9005 >>> ts = pd.DataFrame({"A": [1, 2, 3, 4]}, index=i) 

9006 >>> ts 

9007 A 

9008 2018-04-09 00:00:00 1 

9009 2018-04-10 00:20:00 2 

9010 2018-04-11 00:40:00 3 

9011 2018-04-12 01:00:00 4 

9012 

9013 >>> ts.between_time("0:15", "0:45") 

9014 A 

9015 2018-04-10 00:20:00 2 

9016 2018-04-11 00:40:00 3 

9017 

9018 You get the times that are *not* between two times by setting 

9019 ``start_time`` later than ``end_time``: 

9020 

9021 >>> ts.between_time("0:45", "0:15") 

9022 A 

9023 2018-04-09 00:00:00 1 

9024 2018-04-12 01:00:00 4 

9025 """ 

9026 if axis is None: 

9027 axis = 0 

9028 axis = self._get_axis_number(axis) 

9029 

9030 index = self._get_axis(axis) 

9031 if not isinstance(index, DatetimeIndex): 

9032 raise TypeError("Index must be DatetimeIndex") 

9033 

9034 left_inclusive, right_inclusive = validate_inclusive(inclusive) 

9035 indexer = index.indexer_between_time( 

9036 start_time, 

9037 end_time, 

9038 include_start=left_inclusive, 

9039 include_end=right_inclusive, 

9040 ) 

9041 return self.take(indexer, axis=axis) 

9042 

9043 @final 

9044 def resample( 

9045 self, 

9046 rule, 

9047 closed: Literal["right", "left"] | None = None, 

9048 label: Literal["right", "left"] | None = None, 

9049 convention: Literal["start", "end", "s", "e"] = "start", 

9050 on: Level | None = None, 

9051 level: Level | None = None, 

9052 origin: str | TimestampConvertibleTypes = "start_day", 

9053 offset: TimedeltaConvertibleTypes | None = None, 

9054 group_keys: bool = False, 

9055 ) -> Resampler: 

9056 """ 

9057 Resample time-series data. 

9058 

9059 Convenience method for frequency conversion and resampling of time series. 

9060 The object must have a datetime-like index (`DatetimeIndex`, `PeriodIndex`, 

9061 or `TimedeltaIndex`), or the caller must pass the label of a datetime-like 

9062 series/index to the ``on``/``level`` keyword parameter. 

9063 

9064 Parameters 

9065 ---------- 

9066 rule : DateOffset, Timedelta or str 

9067 The offset string or object representing target conversion. 

9068 closed : {'right', 'left'}, default None 

9069 Which side of bin interval is closed. The default is 'left' 

9070 for all frequency offsets except for 'ME', 'YE', 'QE', 'BME', 

9071 'BA', 'BQE', and 'W' which all have a default of 'right'. 

9072 label : {'right', 'left'}, default None 

9073 Which bin edge label to label bucket with. The default is 'left' 

9074 for all frequency offsets except for 'ME', 'YE', 'QE', 'BME', 

9075 'BA', 'BQE', and 'W' which all have a default of 'right'. 

9076 convention : {'start', 'end', 's', 'e'}, default 'start' 

9077 For `PeriodIndex` only, controls whether to use the start or 

9078 end of `rule`. 

9079 on : str, optional 

9080 For a DataFrame, column to use instead of index for resampling. 

9081 Column must be datetime-like. 

9082 level : str or int, optional 

9083 For a MultiIndex, level (name or number) to use for 

9084 resampling. `level` must be datetime-like. 

9085 origin : Timestamp or str, default 'start_day' 

9086 The timestamp on which to adjust the grouping. The timezone of origin 

9087 must match the timezone of the index. 

9088 If string, must be Timestamp convertible or one of the following: 

9089 

9090 - 'epoch': `origin` is 1970-01-01 

9091 - 'start': `origin` is the first value of the timeseries 

9092 - 'start_day': `origin` is the first day at midnight of the timeseries 

9093 

9094 - 'end': `origin` is the last value of the timeseries 

9095 - 'end_day': `origin` is the ceiling midnight of the last day 

9096 

9097 .. note:: 

9098 

9099 Only takes effect for Tick-frequencies (i.e. fixed frequencies like 

9100 days, hours, and minutes, rather than months or quarters). 

9101 offset : Timedelta or str, default is None 

9102 An offset timedelta added to the origin. 

9103 

9104 group_keys : bool, default False 

9105 Whether to include the group keys in the result index when using 

9106 ``.apply()`` on the resampled object. 

9107 

9108 .. versionchanged:: 2.0.0 

9109 

9110 ``group_keys`` now defaults to ``False``. 

9111 

9112 Returns 

9113 ------- 

9114 pandas.api.typing.Resampler 

9115 :class:`~pandas.core.Resampler` object. 

9116 

9117 See Also 

9118 -------- 

9119 Series.resample : Resample a Series. 

9120 DataFrame.resample : Resample a DataFrame. 

9121 groupby : Group Series/DataFrame by mapping, function, label, or list of labels. 

9122 asfreq : Reindex a Series/DataFrame with the given frequency without grouping. 

9123 

9124 Notes 

9125 ----- 

9126 See the `user guide 

9127 <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#resampling>`__ 

9128 for more. 

9129 

9130 To learn more about the offset strings, please see `this link 

9131 <https://pandas.pydata.org/pandas-docs/stable/user_guide/timeseries.html#dateoffset-objects>`__. 

9132 

9133 Examples 

9134 -------- 

9135 Start by creating a series with 9 one minute timestamps. 

9136 

9137 >>> index = pd.date_range("1/1/2000", periods=9, freq="min") 

9138 >>> series = pd.Series(range(9), index=index) 

9139 >>> series 

9140 2000-01-01 00:00:00 0 

9141 2000-01-01 00:01:00 1 

9142 2000-01-01 00:02:00 2 

9143 2000-01-01 00:03:00 3 

9144 2000-01-01 00:04:00 4 

9145 2000-01-01 00:05:00 5 

9146 2000-01-01 00:06:00 6 

9147 2000-01-01 00:07:00 7 

9148 2000-01-01 00:08:00 8 

9149 Freq: min, dtype: int64 

9150 

9151 Downsample the series into 3 minute bins and sum the values 

9152 of the timestamps falling into a bin. 

9153 

9154 >>> series.resample("3min").sum() 

9155 2000-01-01 00:00:00 3 

9156 2000-01-01 00:03:00 12 

9157 2000-01-01 00:06:00 21 

9158 Freq: 3min, dtype: int64 

9159 

9160 Downsample the series into 3 minute bins as above, but label each 

9161 bin using the right edge instead of the left. Please note that the 

9162 value in the bucket used as the label is not included in the bucket, 

9163 which it labels. For example, in the original series the 

9164 bucket ``2000-01-01 00:03:00`` contains the value 3, but the summed 

9165 value in the resampled bucket with the label ``2000-01-01 00:03:00`` 

9166 does not include 3 (if it did, the summed value would be 6, not 3). 

9167 

9168 >>> series.resample("3min", label="right").sum() 

9169 2000-01-01 00:03:00 3 

9170 2000-01-01 00:06:00 12 

9171 2000-01-01 00:09:00 21 

9172 Freq: 3min, dtype: int64 

9173 

9174 To include this value close the right side of the bin interval, 

9175 as shown below. 

9176 

9177 >>> series.resample("3min", label="right", closed="right").sum() 

9178 2000-01-01 00:00:00 0 

9179 2000-01-01 00:03:00 6 

9180 2000-01-01 00:06:00 15 

9181 2000-01-01 00:09:00 15 

9182 Freq: 3min, dtype: int64 

9183 

9184 Upsample the series into 30 second bins. 

9185 

9186 >>> series.resample("30s").asfreq()[0:5] # Select first 5 rows 

9187 2000-01-01 00:00:00 0.0 

9188 2000-01-01 00:00:30 NaN 

9189 2000-01-01 00:01:00 1.0 

9190 2000-01-01 00:01:30 NaN 

9191 2000-01-01 00:02:00 2.0 

9192 Freq: 30s, dtype: float64 

9193 

9194 Upsample the series into 30 second bins and fill the ``NaN`` 

9195 values using the ``ffill`` method. 

9196 

9197 >>> series.resample("30s").ffill()[0:5] 

9198 2000-01-01 00:00:00 0 

9199 2000-01-01 00:00:30 0 

9200 2000-01-01 00:01:00 1 

9201 2000-01-01 00:01:30 1 

9202 2000-01-01 00:02:00 2 

9203 Freq: 30s, dtype: int64 

9204 

9205 Upsample the series into 30 second bins and fill the 

9206 ``NaN`` values using the ``bfill`` method. 

9207 

9208 >>> series.resample("30s").bfill()[0:5] 

9209 2000-01-01 00:00:00 0 

9210 2000-01-01 00:00:30 1 

9211 2000-01-01 00:01:00 1 

9212 2000-01-01 00:01:30 2 

9213 2000-01-01 00:02:00 2 

9214 Freq: 30s, dtype: int64 

9215 

9216 Pass a custom function via ``apply`` 

9217 

9218 >>> def custom_resampler(arraylike): 

9219 ... return np.sum(arraylike) + 5 

9220 >>> series.resample("3min").apply(custom_resampler) 

9221 2000-01-01 00:00:00 8 

9222 2000-01-01 00:03:00 17 

9223 2000-01-01 00:06:00 26 

9224 Freq: 3min, dtype: int64 

9225 

9226 For a Series with a PeriodIndex, the keyword `convention` can be 

9227 used to control whether to use the start or end of `rule`. 

9228 

9229 Resample a year by quarter using 'start' `convention`. Values are 

9230 assigned to the first quarter of the period. 

9231 

9232 >>> s = pd.Series( 

9233 ... [1, 2], index=pd.period_range("2012-01-01", freq="Y", periods=2) 

9234 ... ) 

9235 >>> s 

9236 2012 1 

9237 2013 2 

9238 Freq: Y-DEC, dtype: int64 

9239 >>> s.resample("Q", convention="start").asfreq() 

9240 2012Q1 1.0 

9241 2012Q2 NaN 

9242 2012Q3 NaN 

9243 2012Q4 NaN 

9244 2013Q1 2.0 

9245 2013Q2 NaN 

9246 2013Q3 NaN 

9247 2013Q4 NaN 

9248 Freq: Q-DEC, dtype: float64 

9249 

9250 Resample quarters by month using 'end' `convention`. Values are 

9251 assigned to the last month of the period. 

9252 

9253 >>> q = pd.Series( 

9254 ... [1, 2, 3, 4], index=pd.period_range("2018-01-01", freq="Q", periods=4) 

9255 ... ) 

9256 >>> q 

9257 2018Q1 1 

9258 2018Q2 2 

9259 2018Q3 3 

9260 2018Q4 4 

9261 Freq: Q-DEC, dtype: int64 

9262 >>> q.resample("M", convention="end").asfreq() 

9263 2018-03 1.0 

9264 2018-04 NaN 

9265 2018-05 NaN 

9266 2018-06 2.0 

9267 2018-07 NaN 

9268 2018-08 NaN 

9269 2018-09 3.0 

9270 2018-10 NaN 

9271 2018-11 NaN 

9272 2018-12 4.0 

9273 Freq: M, dtype: float64 

9274 

9275 For DataFrame objects, the keyword `on` can be used to specify the 

9276 column instead of the index for resampling. 

9277 

9278 >>> df = pd.DataFrame([10, 11, 9, 13, 14, 18, 17, 19], columns=["price"]) 

9279 >>> df["volume"] = [50, 60, 40, 100, 50, 100, 40, 50] 

9280 >>> df["week_starting"] = pd.date_range("01/01/2018", periods=8, freq="W") 

9281 >>> df 

9282 price volume week_starting 

9283 0 10 50 2018-01-07 

9284 1 11 60 2018-01-14 

9285 2 9 40 2018-01-21 

9286 3 13 100 2018-01-28 

9287 4 14 50 2018-02-04 

9288 5 18 100 2018-02-11 

9289 6 17 40 2018-02-18 

9290 7 19 50 2018-02-25 

9291 >>> df.resample("ME", on="week_starting").mean() 

9292 price volume 

9293 week_starting 

9294 2018-01-31 10.75 62.5 

9295 2018-02-28 17.00 60.0 

9296 

9297 For a DataFrame with MultiIndex, the keyword `level` can be used to 

9298 specify on which level the resampling needs to take place. 

9299 

9300 >>> days = pd.date_range("1/1/2000", periods=4, freq="D") 

9301 >>> df2 = pd.DataFrame( 

9302 ... [ 

9303 ... [10, 50], 

9304 ... [11, 60], 

9305 ... [9, 40], 

9306 ... [13, 100], 

9307 ... [14, 50], 

9308 ... [18, 100], 

9309 ... [17, 40], 

9310 ... [19, 50], 

9311 ... ], 

9312 ... columns=["price", "volume"], 

9313 ... index=pd.MultiIndex.from_product([days, ["morning", "afternoon"]]), 

9314 ... ) 

9315 >>> df2 

9316 price volume 

9317 2000-01-01 morning 10 50 

9318 afternoon 11 60 

9319 2000-01-02 morning 9 40 

9320 afternoon 13 100 

9321 2000-01-03 morning 14 50 

9322 afternoon 18 100 

9323 2000-01-04 morning 17 40 

9324 afternoon 19 50 

9325 >>> df2.resample("D", level=0).sum() 

9326 price volume 

9327 2000-01-01 21 110 

9328 2000-01-02 22 140 

9329 2000-01-03 32 150 

9330 2000-01-04 36 90 

9331 

9332 If you want to adjust the start of the bins based on a fixed timestamp: 

9333 

9334 >>> start, end = "2000-10-01 23:30:00", "2000-10-02 00:30:00" 

9335 >>> rng = pd.date_range(start, end, freq="7min") 

9336 >>> ts = pd.Series(np.arange(len(rng)) * 3, index=rng) 

9337 >>> ts 

9338 2000-10-01 23:30:00 0 

9339 2000-10-01 23:37:00 3 

9340 2000-10-01 23:44:00 6 

9341 2000-10-01 23:51:00 9 

9342 2000-10-01 23:58:00 12 

9343 2000-10-02 00:05:00 15 

9344 2000-10-02 00:12:00 18 

9345 2000-10-02 00:19:00 21 

9346 2000-10-02 00:26:00 24 

9347 Freq: 7min, dtype: int64 

9348 

9349 >>> ts.resample("17min").sum() 

9350 2000-10-01 23:14:00 0 

9351 2000-10-01 23:31:00 9 

9352 2000-10-01 23:48:00 21 

9353 2000-10-02 00:05:00 54 

9354 2000-10-02 00:22:00 24 

9355 Freq: 17min, dtype: int64 

9356 

9357 >>> ts.resample("17min", origin="epoch").sum() 

9358 2000-10-01 23:18:00 0 

9359 2000-10-01 23:35:00 18 

9360 2000-10-01 23:52:00 27 

9361 2000-10-02 00:09:00 39 

9362 2000-10-02 00:26:00 24 

9363 Freq: 17min, dtype: int64 

9364 

9365 >>> ts.resample("17min", origin="2000-01-01").sum() 

9366 2000-10-01 23:24:00 3 

9367 2000-10-01 23:41:00 15 

9368 2000-10-01 23:58:00 45 

9369 2000-10-02 00:15:00 45 

9370 Freq: 17min, dtype: int64 

9371 

9372 If you want to adjust the start of the bins with an `offset` Timedelta, the two 

9373 following lines are equivalent: 

9374 

9375 >>> ts.resample("17min", origin="start").sum() 

9376 2000-10-01 23:30:00 9 

9377 2000-10-01 23:47:00 21 

9378 2000-10-02 00:04:00 54 

9379 2000-10-02 00:21:00 24 

9380 Freq: 17min, dtype: int64 

9381 

9382 >>> ts.resample("17min", offset="23h30min").sum() 

9383 2000-10-01 23:30:00 9 

9384 2000-10-01 23:47:00 21 

9385 2000-10-02 00:04:00 54 

9386 2000-10-02 00:21:00 24 

9387 Freq: 17min, dtype: int64 

9388 

9389 If you want to take the largest Timestamp as the end of the bins: 

9390 

9391 >>> ts.resample("17min", origin="end").sum() 

9392 2000-10-01 23:35:00 0 

9393 2000-10-01 23:52:00 18 

9394 2000-10-02 00:09:00 27 

9395 2000-10-02 00:26:00 63 

9396 Freq: 17min, dtype: int64 

9397 

9398 In contrast with the `start_day`, you can use `end_day` to take the ceiling 

9399 midnight of the largest Timestamp as the end of the bins and drop the bins 

9400 not containing data: 

9401 

9402 >>> ts.resample("17min", origin="end_day").sum() 

9403 2000-10-01 23:38:00 3 

9404 2000-10-01 23:55:00 15 

9405 2000-10-02 00:12:00 45 

9406 2000-10-02 00:29:00 45 

9407 Freq: 17min, dtype: int64 

9408 """ 

9409 from pandas.core.resample import get_resampler 

9410 

9411 return get_resampler( 

9412 cast("Series | DataFrame", self), 

9413 freq=rule, 

9414 label=label, 

9415 closed=closed, 

9416 convention=convention, 

9417 key=on, 

9418 level=level, 

9419 origin=origin, 

9420 offset=offset, 

9421 group_keys=group_keys, 

9422 ) 

9423 

9424 @final 

9425 def rank( 

9426 self, 

9427 axis: Axis = 0, 

9428 method: Literal["average", "min", "max", "first", "dense"] = "average", 

9429 numeric_only: bool = False, 

9430 na_option: Literal["keep", "top", "bottom"] = "keep", 

9431 ascending: bool = True, 

9432 pct: bool = False, 

9433 ) -> Self: 

9434 """ 

9435 Compute numerical data ranks (1 through n) along axis. 

9436 

9437 By default, equal values are assigned a rank that is the average of the 

9438 ranks of those values. 

9439 

9440 Parameters 

9441 ---------- 

9442 axis : {0 or 'index', 1 or 'columns'}, default 0 

9443 Index to direct ranking. 

9444 For `Series` this parameter is unused and defaults to 0. 

9445 method : {'average', 'min', 'max', 'first', 'dense'}, default 'average' 

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

9447 

9448 * average: average rank of the group 

9449 * min: lowest rank in the group 

9450 * max: highest rank in the group 

9451 * first: ranks assigned in order they appear in the array 

9452 * dense: like 'min', but rank always increases by 1 between groups. 

9453 

9454 numeric_only : bool, default False 

9455 For DataFrame objects, rank only numeric columns if set to True. 

9456 

9457 .. versionchanged:: 2.0.0 

9458 The default value of ``numeric_only`` is now ``False``. 

9459 

9460 na_option : {'keep', 'top', 'bottom'}, default 'keep' 

9461 How to rank NaN values: 

9462 

9463 * keep: assign NaN rank to NaN values 

9464 * top: assign lowest rank to NaN values 

9465 * bottom: assign highest rank to NaN values 

9466 

9467 ascending : bool, default True 

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

9469 pct : bool, default False 

9470 Whether or not to display the returned rankings in percentile 

9471 form. 

9472 

9473 Returns 

9474 ------- 

9475 same type as caller 

9476 Return a Series or DataFrame with data ranks as values. 

9477 

9478 See Also 

9479 -------- 

9480 core.groupby.DataFrameGroupBy.rank : Rank of values within each group. 

9481 core.groupby.SeriesGroupBy.rank : Rank of values within each group. 

9482 

9483 Examples 

9484 -------- 

9485 >>> df = pd.DataFrame( 

9486 ... data={ 

9487 ... "Animal": ["cat", "penguin", "dog", "spider", "snake"], 

9488 ... "Number_legs": [4, 2, 4, 8, np.nan], 

9489 ... } 

9490 ... ) 

9491 >>> df 

9492 Animal Number_legs 

9493 0 cat 4.0 

9494 1 penguin 2.0 

9495 2 dog 4.0 

9496 3 spider 8.0 

9497 4 snake NaN 

9498 

9499 Ties are assigned the mean of the ranks (by default) for the group. 

9500 

9501 >>> s = pd.Series(range(5), index=list("abcde")) 

9502 >>> s["d"] = s["b"] 

9503 >>> s.rank() 

9504 a 1.0 

9505 b 2.5 

9506 c 4.0 

9507 d 2.5 

9508 e 5.0 

9509 dtype: float64 

9510 

9511 The following example shows how the method behaves with the above 

9512 parameters: 

9513 

9514 * default_rank: this is the default behaviour obtained without using 

9515 any parameter. 

9516 * max_rank: setting ``method = 'max'`` the records that have the 

9517 same values are ranked using the highest rank (e.g.: since 'cat' 

9518 and 'dog' are both in the 2nd and 3rd position, rank 3 is assigned.) 

9519 * NA_bottom: choosing ``na_option = 'bottom'``, if there are records 

9520 with NaN values they are placed at the bottom of the ranking. 

9521 * pct_rank: when setting ``pct = True``, the ranking is expressed as 

9522 percentile rank. 

9523 

9524 >>> df["default_rank"] = df["Number_legs"].rank() 

9525 >>> df["max_rank"] = df["Number_legs"].rank(method="max") 

9526 >>> df["NA_bottom"] = df["Number_legs"].rank(na_option="bottom") 

9527 >>> df["pct_rank"] = df["Number_legs"].rank(pct=True) 

9528 >>> df 

9529 Animal Number_legs default_rank max_rank NA_bottom pct_rank 

9530 0 cat 4.0 2.5 3.0 2.5 0.625 

9531 1 penguin 2.0 1.0 1.0 1.0 0.250 

9532 2 dog 4.0 2.5 3.0 2.5 0.625 

9533 3 spider 8.0 4.0 4.0 4.0 1.000 

9534 4 snake NaN NaN NaN 5.0 NaN 

9535 """ 

9536 axis_int = self._get_axis_number(axis) 

9537 

9538 if na_option not in {"keep", "top", "bottom"}: 

9539 msg = "na_option must be one of 'keep', 'top', or 'bottom'" 

9540 raise ValueError(msg) 

9541 

9542 def ranker(data): 

9543 if data.ndim == 2: 

9544 # i.e. DataFrame, we cast to ndarray 

9545 values = data.values 

9546 else: 

9547 # i.e. Series, can dispatch to EA 

9548 values = data._values 

9549 

9550 if isinstance(values, ExtensionArray): 

9551 ranks = values._rank( 

9552 axis=axis_int, 

9553 method=method, 

9554 ascending=ascending, 

9555 na_option=na_option, 

9556 pct=pct, 

9557 ) 

9558 else: 

9559 ranks = algos.rank( 

9560 values, 

9561 axis=axis_int, 

9562 method=method, 

9563 ascending=ascending, 

9564 na_option=na_option, 

9565 pct=pct, 

9566 ) 

9567 

9568 ranks_obj = self._constructor(ranks, **data._construct_axes_dict()) 

9569 return ranks_obj.__finalize__(self, method="rank") 

9570 

9571 if numeric_only: 

9572 if self.ndim == 1 and not is_numeric_dtype(self.dtype): 

9573 # GH#47500 

9574 raise TypeError( 

9575 "Series.rank does not allow numeric_only=True with " 

9576 "non-numeric dtype." 

9577 ) 

9578 data = self._get_numeric_data() 

9579 else: 

9580 data = self 

9581 

9582 return ranker(data) 

9583 

9584 def compare( 

9585 self, 

9586 other: Self, 

9587 align_axis: Axis = 1, 

9588 keep_shape: bool = False, 

9589 keep_equal: bool = False, 

9590 result_names: Suffixes = ("self", "other"), 

9591 ): 

9592 """ 

9593 Compare to another Series/DataFrame and show the differences. 

9594 

9595 Parameters 

9596 ---------- 

9597 other : Series/DataFrame 

9598 Object to compare with. 

9599 

9600 align_axis : {0 or 'index', 1 or 'columns'}, default 1 

9601 Determine which axis to align the comparison on. 

9602 

9603 * 0, or 'index' : Resulting differences are stacked vertically 

9604 with rows drawn alternately from self and other. 

9605 * 1, or 'columns' : Resulting differences are aligned horizontally 

9606 with columns drawn alternately from self and other. 

9607 

9608 keep_shape : bool, default False 

9609 If true, all rows and columns are kept. 

9610 Otherwise, only the ones with different values are kept. 

9611 

9612 keep_equal : bool, default False 

9613 If true, the result keeps values that are equal. 

9614 Otherwise, equal values are shown as NaNs. 

9615 

9616 result_names : tuple, default ('self', 'other') 

9617 Set the dataframes names in the comparison. 

9618 """ 

9619 if type(self) is not type(other): 

9620 cls_self, cls_other = type(self).__name__, type(other).__name__ 

9621 raise TypeError( 

9622 f"can only compare '{cls_self}' (not '{cls_other}') with '{cls_self}'" 

9623 ) 

9624 

9625 # error: Unsupported left operand type for & ("Self") 

9626 mask = ~((self == other) | (self.isna() & other.isna())) # type: ignore[operator] 

9627 mask.fillna(True, inplace=True) 

9628 

9629 if not keep_equal: 

9630 self = self.where(mask) 

9631 other = other.where(mask) 

9632 

9633 if not keep_shape: 

9634 if isinstance(self, ABCDataFrame): 

9635 cmask = mask.any() 

9636 rmask = mask.any(axis=1) 

9637 self = self.loc[rmask, cmask] 

9638 other = other.loc[rmask, cmask] 

9639 else: 

9640 self = self[mask] 

9641 other = other[mask] 

9642 if not isinstance(result_names, tuple): 

9643 raise TypeError( 

9644 f"Passing 'result_names' as a {type(result_names)} is not " 

9645 "supported. Provide 'result_names' as a tuple instead." 

9646 ) 

9647 

9648 if align_axis in (1, "columns"): # This is needed for Series 

9649 axis = 1 

9650 else: 

9651 axis = self._get_axis_number(align_axis) 

9652 

9653 # error: List item 0 has incompatible type "NDFrame"; expected 

9654 # "Union[Series, DataFrame]" 

9655 diff = concat( 

9656 [self, other], # type: ignore[list-item] 

9657 axis=axis, 

9658 keys=result_names, 

9659 ) 

9660 

9661 if axis >= self.ndim: 

9662 # No need to reorganize data if stacking on new axis 

9663 # This currently applies for stacking two Series on columns 

9664 return diff 

9665 

9666 ax = diff._get_axis(axis) 

9667 ax_names = np.array(ax.names) 

9668 

9669 # set index names to positions to avoid confusion 

9670 ax.names = np.arange(len(ax_names)) 

9671 

9672 # bring self-other to inner level 

9673 order = [*range(1, ax.nlevels), 0] 

9674 if isinstance(diff, ABCDataFrame): 

9675 diff = diff.reorder_levels(order, axis=axis) 

9676 else: 

9677 diff = diff.reorder_levels(order) 

9678 

9679 # restore the index names in order 

9680 diff._get_axis(axis=axis).names = ax_names[order] 

9681 

9682 # reorder axis to keep things organized 

9683 indices = ( 

9684 np.arange(diff.shape[axis]) 

9685 .reshape([2, diff.shape[axis] // 2]) 

9686 .T.reshape(-1) 

9687 ) 

9688 diff = diff.take(indices, axis=axis) 

9689 

9690 return diff 

9691 

9692 @final 

9693 def align( 

9694 self, 

9695 other: NDFrameT, 

9696 join: AlignJoin = "outer", 

9697 axis: Axis | None = None, 

9698 level: Level | None = None, 

9699 copy: bool | lib.NoDefault = lib.no_default, 

9700 fill_value: Hashable | None = None, 

9701 ) -> tuple[Self, NDFrameT]: 

9702 """ 

9703 Align two objects on their axes with the specified join method. 

9704 

9705 Join method is specified for each axis Index. 

9706 

9707 Parameters 

9708 ---------- 

9709 other : DataFrame or Series 

9710 The object to align with. 

9711 join : {'outer', 'inner', 'left', 'right'}, default 'outer' 

9712 Type of alignment to be performed. 

9713 

9714 * left: use only keys from left frame, preserve key order. 

9715 * right: use only keys from right frame, preserve key order. 

9716 * outer: use union of keys from both frames, sort keys lexicographically. 

9717 * inner: use intersection of keys from both frames, 

9718 preserve the order of the left keys. 

9719 

9720 axis : allowed axis of the other object, default None 

9721 Align on index (0), columns (1), or both (None). 

9722 level : int or level name, default None 

9723 Broadcast across a level, matching Index values on the 

9724 passed MultiIndex level. 

9725 copy : bool, default False 

9726 This keyword is now ignored; changing its value will have no 

9727 impact on the method. 

9728 

9729 .. deprecated:: 3.0.0 

9730 

9731 This keyword is ignored and will be removed in pandas 4.0. Since 

9732 pandas 3.0, this method always returns a new object using a lazy 

9733 copy mechanism that defers copies until necessary 

9734 (Copy-on-Write). See the `user guide on Copy-on-Write 

9735 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

9736 for more details. 

9737 

9738 fill_value : scalar, default np.nan 

9739 Value to use for missing values. Defaults to NaN, but can be any 

9740 "compatible" value. 

9741 

9742 Returns 

9743 ------- 

9744 tuple of (Series/DataFrame, type of other) 

9745 Aligned objects. 

9746 

9747 See Also 

9748 -------- 

9749 Series.align : Align two objects on their axes with specified join method. 

9750 DataFrame.align : Align two objects on their axes with specified join method. 

9751 

9752 Examples 

9753 -------- 

9754 >>> df = pd.DataFrame( 

9755 ... [[1, 2, 3, 4], [6, 7, 8, 9]], columns=["D", "B", "E", "A"], index=[1, 2] 

9756 ... ) 

9757 >>> other = pd.DataFrame( 

9758 ... [[10, 20, 30, 40], [60, 70, 80, 90], [600, 700, 800, 900]], 

9759 ... columns=["A", "B", "C", "D"], 

9760 ... index=[2, 3, 4], 

9761 ... ) 

9762 >>> df 

9763 D B E A 

9764 1 1 2 3 4 

9765 2 6 7 8 9 

9766 >>> other 

9767 A B C D 

9768 2 10 20 30 40 

9769 3 60 70 80 90 

9770 4 600 700 800 900 

9771 

9772 Align on columns: 

9773 

9774 >>> left, right = df.align(other, join="outer", axis=1) 

9775 >>> left 

9776 A B C D E 

9777 1 4 2 NaN 1 3 

9778 2 9 7 NaN 6 8 

9779 >>> right 

9780 A B C D E 

9781 2 10 20 30 40 NaN 

9782 3 60 70 80 90 NaN 

9783 4 600 700 800 900 NaN 

9784 

9785 We can also align on the index: 

9786 

9787 >>> left, right = df.align(other, join="outer", axis=0) 

9788 >>> left 

9789 D B E A 

9790 1 1.0 2.0 3.0 4.0 

9791 2 6.0 7.0 8.0 9.0 

9792 3 NaN NaN NaN NaN 

9793 4 NaN NaN NaN NaN 

9794 >>> right 

9795 A B C D 

9796 1 NaN NaN NaN NaN 

9797 2 10.0 20.0 30.0 40.0 

9798 3 60.0 70.0 80.0 90.0 

9799 4 600.0 700.0 800.0 900.0 

9800 

9801 Finally, the default `axis=None` will align on both index and columns: 

9802 

9803 >>> left, right = df.align(other, join="outer", axis=None) 

9804 >>> left 

9805 A B C D E 

9806 1 4.0 2.0 NaN 1.0 3.0 

9807 2 9.0 7.0 NaN 6.0 8.0 

9808 3 NaN NaN NaN NaN NaN 

9809 4 NaN NaN NaN NaN NaN 

9810 >>> right 

9811 A B C D E 

9812 1 NaN NaN NaN NaN NaN 

9813 2 10.0 20.0 30.0 40.0 NaN 

9814 3 60.0 70.0 80.0 90.0 NaN 

9815 4 600.0 700.0 800.0 900.0 NaN 

9816 """ 

9817 self._check_copy_deprecation(copy) 

9818 

9819 _right: DataFrame | Series 

9820 if axis is not None: 

9821 axis = self._get_axis_number(axis) 

9822 if isinstance(other, ABCDataFrame): 

9823 left, _right, join_index = self._align_frame( 

9824 other, 

9825 join=join, 

9826 axis=axis, 

9827 level=level, 

9828 fill_value=fill_value, 

9829 ) 

9830 

9831 elif isinstance(other, ABCSeries): 

9832 left, _right, join_index = self._align_series( 

9833 other, 

9834 join=join, 

9835 axis=axis, 

9836 level=level, 

9837 fill_value=fill_value, 

9838 ) 

9839 else: # pragma: no cover 

9840 raise TypeError(f"unsupported type: {type(other)}") 

9841 

9842 right = cast(NDFrameT, _right) 

9843 if self.ndim == 1 or axis == 0: 

9844 # If we are aligning timezone-aware DatetimeIndexes and the timezones 

9845 # do not match, convert both to UTC. 

9846 if isinstance(left.index.dtype, DatetimeTZDtype): 

9847 if left.index.tz != right.index.tz: 

9848 if join_index is not None: 

9849 # GH#33671 copy to ensure we don't change the index on 

9850 # our original Series 

9851 left = left.copy(deep=False) 

9852 right = right.copy(deep=False) 

9853 left.index = join_index 

9854 right.index = join_index 

9855 

9856 left = left.__finalize__(self) 

9857 right = right.__finalize__(other) 

9858 return left, right 

9859 

9860 @final 

9861 def _align_frame( 

9862 self, 

9863 other: DataFrame, 

9864 join: AlignJoin = "outer", 

9865 axis: Axis | None = None, 

9866 level=None, 

9867 fill_value=None, 

9868 ) -> tuple[Self, DataFrame, Index | None]: 

9869 # defaults 

9870 join_index, join_columns = None, None 

9871 ilidx, iridx = None, None 

9872 clidx, cridx = None, None 

9873 

9874 is_series = isinstance(self, ABCSeries) 

9875 

9876 if (axis is None or axis == 0) and not self.index.equals(other.index): 

9877 join_index, ilidx, iridx = self.index.join( 

9878 other.index, how=join, level=level, return_indexers=True 

9879 ) 

9880 

9881 if ( 

9882 (axis is None or axis == 1) 

9883 and not is_series 

9884 and not self.columns.equals(other.columns) 

9885 ): 

9886 join_columns, clidx, cridx = self.columns.join( 

9887 other.columns, how=join, level=level, return_indexers=True 

9888 ) 

9889 

9890 if is_series: 

9891 reindexers = {0: [join_index, ilidx]} 

9892 else: 

9893 reindexers = {0: [join_index, ilidx], 1: [join_columns, clidx]} 

9894 

9895 left = self._reindex_with_indexers( 

9896 reindexers, fill_value=fill_value, allow_dups=True 

9897 ) 

9898 # other must be always DataFrame 

9899 right = other._reindex_with_indexers( 

9900 {0: [join_index, iridx], 1: [join_columns, cridx]}, 

9901 fill_value=fill_value, 

9902 allow_dups=True, 

9903 ) 

9904 return left, right, join_index 

9905 

9906 @final 

9907 def _align_series( 

9908 self, 

9909 other: Series, 

9910 join: AlignJoin = "outer", 

9911 axis: Axis | None = None, 

9912 level=None, 

9913 fill_value=None, 

9914 ) -> tuple[Self, Series, Index | None]: 

9915 is_series = isinstance(self, ABCSeries) 

9916 

9917 if (not is_series and axis is None) or axis not in [None, 0, 1]: 

9918 raise ValueError("Must specify axis=0 or 1") 

9919 

9920 if is_series and axis == 1: 

9921 raise ValueError("cannot align series to a series other than axis 0") 

9922 

9923 # series/series compat, other must always be a Series 

9924 if not axis: 

9925 # equal 

9926 if self.index.equals(other.index): 

9927 join_index, lidx, ridx = None, None, None 

9928 else: 

9929 join_index, lidx, ridx = self.index.join( 

9930 other.index, how=join, level=level, return_indexers=True 

9931 ) 

9932 

9933 if is_series: 

9934 left = self._reindex_indexer(join_index, lidx) 

9935 elif lidx is None or join_index is None: 

9936 left = self.copy(deep=False) 

9937 else: 

9938 new_mgr = self._mgr.reindex_indexer(join_index, lidx, axis=1) 

9939 left = self._constructor_from_mgr(new_mgr, axes=new_mgr.axes) 

9940 

9941 right = other._reindex_indexer(join_index, ridx) 

9942 

9943 else: 

9944 # one has > 1 ndim 

9945 fdata = self._mgr 

9946 join_index = self.axes[1] 

9947 lidx, ridx = None, None 

9948 if not join_index.equals(other.index): 

9949 join_index, lidx, ridx = join_index.join( 

9950 other.index, how=join, level=level, return_indexers=True 

9951 ) 

9952 

9953 if lidx is not None: 

9954 bm_axis = self._get_block_manager_axis(1) 

9955 fdata = fdata.reindex_indexer(join_index, lidx, axis=bm_axis) 

9956 

9957 left = self._constructor_from_mgr(fdata, axes=fdata.axes) 

9958 

9959 right = other._reindex_indexer(join_index, ridx) 

9960 

9961 # fill 

9962 fill_na = notna(fill_value) 

9963 if fill_na: 

9964 left = left.fillna(fill_value) 

9965 right = right.fillna(fill_value) 

9966 

9967 return left, right, join_index 

9968 

9969 @final 

9970 def _where( 

9971 self, 

9972 cond, 

9973 other=lib.no_default, 

9974 *, 

9975 inplace: bool = False, 

9976 axis: Axis | None = None, 

9977 level=None, 

9978 ) -> Self: 

9979 """ 

9980 Equivalent to public method `where`, except that `other` is not 

9981 applied as a function even if callable. Used in __setitem__. 

9982 """ 

9983 inplace = validate_bool_kwarg(inplace, "inplace") 

9984 

9985 if axis is not None: 

9986 axis = self._get_axis_number(axis) 

9987 

9988 # align the cond to same shape as myself 

9989 cond = common.apply_if_callable(cond, self) 

9990 if isinstance(cond, NDFrame): 

9991 # CoW: Make sure reference is not kept alive 

9992 if cond.ndim == 1 and self.ndim == 2: 

9993 cond = cond._constructor_expanddim( 

9994 dict.fromkeys(range(len(self.columns)), cond), 

9995 copy=False, 

9996 ) 

9997 cond.columns = self.columns 

9998 cond = cond.align(self, join="right")[0] 

9999 else: 

10000 if not hasattr(cond, "shape"): 

10001 cond = np.asanyarray(cond) 

10002 if cond.shape != self.shape: 

10003 raise ValueError("Array conditional must be same shape as self") 

10004 cond = self._constructor(cond, **self._construct_axes_dict(), copy=False) 

10005 

10006 # make sure we are boolean 

10007 fill_value = bool(inplace) 

10008 cond = cond.fillna(fill_value) 

10009 cond = cond.infer_objects() 

10010 

10011 msg = "Boolean array expected for the condition, not {dtype}" 

10012 

10013 if not cond.empty: 

10014 if not isinstance(cond, ABCDataFrame): 

10015 # This is a single-dimensional object. 

10016 if not is_bool_dtype(cond): 

10017 raise TypeError(msg.format(dtype=cond.dtype)) 

10018 else: 

10019 for block in cond._mgr.blocks: 

10020 if not is_bool_dtype(block.dtype): 

10021 raise TypeError(msg.format(dtype=block.dtype)) 

10022 if cond._mgr.any_extension_types: 

10023 # GH51574: avoid object ndarray conversion later on 

10024 cond = cond._constructor( 

10025 cond.to_numpy(dtype=bool, na_value=fill_value), 

10026 **cond._construct_axes_dict(), 

10027 ) 

10028 else: 

10029 # GH#21947 we have an empty DataFrame/Series, could be object-dtype 

10030 cond = cond.astype(bool) 

10031 

10032 cond = -cond if inplace else cond 

10033 cond = cond.reindex(self._info_axis, axis=self._info_axis_number) 

10034 

10035 # try to align with other 

10036 if isinstance(other, NDFrame): 

10037 # align with me 

10038 if other.ndim <= self.ndim: 

10039 # CoW: Make sure reference is not kept alive 

10040 other = self.align( 

10041 other, 

10042 join="left", 

10043 axis=axis, 

10044 level=level, 

10045 fill_value=None, 

10046 )[1] 

10047 

10048 # if we are NOT aligned, raise as we cannot where index 

10049 if axis is None and not other._indexed_same(self): 

10050 raise InvalidIndexError 

10051 

10052 if other.ndim < self.ndim: 

10053 other = other._values 

10054 if isinstance(other, np.ndarray): 

10055 # TODO(EA2D): could also do this for NDArrayBackedEA cases? 

10056 if axis == 0: 

10057 other = np.reshape(other, (-1, 1)) 

10058 elif axis == 1: 

10059 other = np.reshape(other, (1, -1)) 

10060 

10061 other = np.broadcast_to(other, self.shape) 

10062 else: 

10063 # GH#38729, GH#62038 avoid lossy casting or object-casting 

10064 if axis == 0: 

10065 res_cols = [ 

10066 self.iloc[:, i]._where( 

10067 cond.iloc[:, i], 

10068 other, 

10069 ) 

10070 for i in range(self.shape[1]) 

10071 ] 

10072 elif axis == 1: 

10073 # TODO: can we use a zero-copy alternative to "repeat"? 

10074 res_cols = [ 

10075 self.iloc[:, i]._where( 

10076 cond.iloc[:, i], 

10077 other[i : i + 1].repeat(len(self)), 

10078 ) 

10079 for i in range(self.shape[1]) 

10080 ] 

10081 res = self._constructor(dict(enumerate(res_cols))) 

10082 res.index = self.index 

10083 res.columns = self.columns 

10084 if inplace: 

10085 self._update_inplace(res) 

10086 return self 

10087 return res.__finalize__(self) 

10088 

10089 # slice me out of the other 

10090 else: 

10091 raise NotImplementedError( 

10092 "cannot align with a higher dimensional NDFrame" 

10093 ) 

10094 

10095 elif not isinstance(other, (MultiIndex, NDFrame)): 

10096 # mainly just catching Index here 

10097 other = extract_array(other, extract_numpy=True) 

10098 

10099 if isinstance(other, (np.ndarray, ExtensionArray)): 

10100 if other.shape != self.shape: 

10101 if self.ndim != 1: 

10102 # In the ndim == 1 case we may have 

10103 # other length 1, which we treat as scalar (GH#2745, GH#4192) 

10104 # or len(other) == icond.sum(), which we treat like 

10105 # __setitem__ (GH#3235) 

10106 raise ValueError( 

10107 "other must be the same shape as self when an ndarray" 

10108 ) 

10109 

10110 # we are the same shape, so create an actual object for alignment 

10111 else: 

10112 other = self._constructor( 

10113 other, **self._construct_axes_dict(), copy=False 

10114 ) 

10115 

10116 if axis is None: 

10117 axis = 0 

10118 

10119 if self.ndim == getattr(other, "ndim", 0): 

10120 align = True 

10121 else: 

10122 align = self._get_axis_number(axis) == 1 

10123 

10124 if inplace: 

10125 # we may have different type blocks come out of putmask, so 

10126 # reconstruct the block manager 

10127 

10128 new_data = self._mgr.putmask(mask=cond, new=other, align=align) 

10129 result = self._constructor_from_mgr(new_data, axes=new_data.axes) 

10130 self._update_inplace(result) 

10131 return self 

10132 

10133 else: 

10134 new_data = self._mgr.where( 

10135 other=other, 

10136 cond=cond, 

10137 align=align, 

10138 ) 

10139 result = self._constructor_from_mgr(new_data, axes=new_data.axes) 

10140 return result.__finalize__(self) 

10141 

10142 @final 

10143 def where( 

10144 self, 

10145 cond, 

10146 other=lib.no_default, 

10147 *, 

10148 inplace: bool = False, 

10149 axis: Axis | None = None, 

10150 level: Level | None = None, 

10151 ) -> Self: 

10152 """ 

10153 Replace values where the condition is False. 

10154 

10155 This method allows conditional replacement of values. Where the 

10156 condition evaluates to True, the original values are retained; where 

10157 it evaluates to False, values are replaced with corresponding entries 

10158 from ``other``. 

10159 

10160 Parameters 

10161 ---------- 

10162 cond : bool Series/DataFrame, array-like, or callable 

10163 Where `cond` is True, keep the original value. Where 

10164 False, replace with corresponding value from `other`. 

10165 If `cond` is callable, it is computed on the Series/DataFrame and 

10166 should return boolean Series/DataFrame or array. The callable must 

10167 not change input Series/DataFrame (though pandas doesn't check it). 

10168 other : scalar, Series/DataFrame, or callable 

10169 Entries where `cond` is False are replaced with 

10170 corresponding value from `other`. 

10171 If other is callable, it is computed on the Series/DataFrame and 

10172 should return scalar or Series/DataFrame. The callable must not 

10173 change input Series/DataFrame (though pandas doesn't check it). 

10174 If not specified, entries will be filled with the corresponding 

10175 NULL value (``np.nan`` for numpy dtypes, ``pd.NA`` for extension 

10176 dtypes). 

10177 inplace : bool, default False 

10178 Whether to perform the operation in place on the data. 

10179 axis : int, default None 

10180 Alignment axis if needed. For `Series` this parameter is 

10181 unused and defaults to 0. 

10182 level : int, default None 

10183 Alignment level if needed. 

10184 

10185 Returns 

10186 ------- 

10187 Series or DataFrame 

10188 When applied to a Series, the function will return a Series, 

10189 and when applied to a DataFrame, it will return a DataFrame. 

10190 

10191 See Also 

10192 -------- 

10193 :func:`DataFrame.mask` : Return an object of same shape as caller. 

10194 :func:`Series.mask` : Return an object of same shape as caller. 

10195 

10196 Notes 

10197 ----- 

10198 The where method is an application of the if-then idiom. For each 

10199 element in the caller, if ``cond`` is ``True`` the 

10200 element is used; otherwise the corresponding element from 

10201 ``other`` is used. If the axis of ``other`` does not align with axis of 

10202 ``cond`` Series/DataFrame, the values of ``cond`` on misaligned index positions 

10203 will be filled with False. 

10204 

10205 The signature for :func:`Series.where` or 

10206 :func:`DataFrame.where` differs from :func:`numpy.where`. 

10207 Roughly ``df1.where(m, df2)`` is equivalent to ``np.where(m, df1, df2)``. 

10208 

10209 For further details and examples see the ``where`` documentation in 

10210 :ref:`indexing <indexing.where_mask>`. 

10211 

10212 The dtype of the object takes precedence. The fill value is casted to 

10213 the object's dtype, if this can be done losslessly. 

10214 

10215 Examples 

10216 -------- 

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

10218 >>> s.where(s > 0) 

10219 0 NaN 

10220 1 1.0 

10221 2 2.0 

10222 3 3.0 

10223 4 4.0 

10224 dtype: float64 

10225 >>> s.mask(s > 0) 

10226 0 0.0 

10227 1 NaN 

10228 2 NaN 

10229 3 NaN 

10230 4 NaN 

10231 dtype: float64 

10232 

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

10234 >>> t = pd.Series([True, False]) 

10235 >>> s.where(t, 99) 

10236 0 0 

10237 1 99 

10238 2 99 

10239 3 99 

10240 4 99 

10241 dtype: int64 

10242 >>> s.mask(t, 99) 

10243 0 99 

10244 1 1 

10245 2 99 

10246 3 99 

10247 4 99 

10248 dtype: int64 

10249 

10250 >>> s.where(s > 1, 10) 

10251 0 10 

10252 1 10 

10253 2 2 

10254 3 3 

10255 4 4 

10256 dtype: int64 

10257 >>> s.mask(s > 1, 10) 

10258 0 0 

10259 1 1 

10260 2 10 

10261 3 10 

10262 4 10 

10263 dtype: int64 

10264 

10265 >>> df = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=["A", "B"]) 

10266 >>> df 

10267 A B 

10268 0 0 1 

10269 1 2 3 

10270 2 4 5 

10271 3 6 7 

10272 4 8 9 

10273 >>> m = df % 3 == 0 

10274 >>> df.where(m, -df) 

10275 A B 

10276 0 0 -1 

10277 1 -2 3 

10278 2 -4 -5 

10279 3 6 -7 

10280 4 -8 9 

10281 >>> df.where(m, -df) == np.where(m, df, -df) 

10282 A B 

10283 0 True True 

10284 1 True True 

10285 2 True True 

10286 3 True True 

10287 4 True True 

10288 >>> df.where(m, -df) == df.mask(~m, -df) 

10289 A B 

10290 0 True True 

10291 1 True True 

10292 2 True True 

10293 3 True True 

10294 4 True True 

10295 """ 

10296 inplace = validate_bool_kwarg(inplace, "inplace") 

10297 if inplace: 

10298 if not CHAINED_WARNING_DISABLED: 

10299 if sys.getrefcount( 

10300 self 

10301 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

10302 warnings.warn( 

10303 _chained_assignment_method_msg, 

10304 ChainedAssignmentError, 

10305 stacklevel=2, 

10306 ) 

10307 

10308 other = common.apply_if_callable(other, self) 

10309 return self._where(cond, other, inplace=inplace, axis=axis, level=level) 

10310 

10311 @final 

10312 def mask( 

10313 self, 

10314 cond, 

10315 other=lib.no_default, 

10316 *, 

10317 inplace: bool = False, 

10318 axis: Axis | None = None, 

10319 level: Level | None = None, 

10320 ) -> Self: 

10321 """ 

10322 Replace values where the condition is True. 

10323 

10324 Parameters 

10325 ---------- 

10326 cond : bool Series/DataFrame, array-like, or callable 

10327 Where `cond` is False, keep the original value. Where 

10328 True, replace with corresponding value from `other`. 

10329 If `cond` is callable, it is computed on the Series/DataFrame and 

10330 should return boolean Series/DataFrame or array. The callable must 

10331 not change input Series/DataFrame (though pandas doesn't check it). 

10332 other : scalar, Series/DataFrame, or callable 

10333 Entries where `cond` is True are replaced with 

10334 corresponding value from `other`. 

10335 If other is callable, it is computed on the Series/DataFrame and 

10336 should return scalar or Series/DataFrame. The callable must not 

10337 change input Series/DataFrame (though pandas doesn't check it). 

10338 If not specified, entries will be filled with the corresponding 

10339 NULL value (``np.nan`` for numpy dtypes, ``pd.NA`` for extension 

10340 dtypes). 

10341 inplace : bool, default False 

10342 Whether to perform the operation in place on the data. 

10343 axis : int, default None 

10344 Alignment axis if needed. For `Series` this parameter is 

10345 unused and defaults to 0. 

10346 level : int, default None 

10347 Alignment level if needed. 

10348 

10349 Returns 

10350 ------- 

10351 Series or DataFrame 

10352 When applied to a Series, the function will return a Series, 

10353 and when applied to a DataFrame, it will return a DataFrame. 

10354 

10355 See Also 

10356 -------- 

10357 :func:`DataFrame.where` : Return an object of same shape as caller. 

10358 :func:`Series.where` : Return an object of same shape as caller. 

10359 

10360 Notes 

10361 ----- 

10362 The mask method is an application of the if-then idiom. For each 

10363 element in the caller, if ``cond`` is ``False`` the 

10364 element is used; otherwise the corresponding element from 

10365 ``other`` is used. If the axis of ``other`` does not align with axis of 

10366 ``cond`` Series/DataFrame, the values of ``cond`` on misaligned index positions 

10367 will be filled with True. 

10368 

10369 The signature for :func:`Series.where` or 

10370 :func:`DataFrame.where` differs from :func:`numpy.where`. 

10371 Roughly ``df1.where(m, df2)`` is equivalent to ``np.where(m, df1, df2)``. 

10372 

10373 For further details and examples see the ``mask`` documentation in 

10374 :ref:`indexing <indexing.where_mask>`. 

10375 

10376 The dtype of the object takes precedence. The fill value is casted to 

10377 the object's dtype, if this can be done losslessly. 

10378 

10379 Examples 

10380 -------- 

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

10382 >>> s.where(s > 0) 

10383 0 NaN 

10384 1 1.0 

10385 2 2.0 

10386 3 3.0 

10387 4 4.0 

10388 dtype: float64 

10389 >>> s.mask(s > 0) 

10390 0 0.0 

10391 1 NaN 

10392 2 NaN 

10393 3 NaN 

10394 4 NaN 

10395 dtype: float64 

10396 

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

10398 >>> t = pd.Series([True, False]) 

10399 >>> s.where(t, 99) 

10400 0 0 

10401 1 99 

10402 2 99 

10403 3 99 

10404 4 99 

10405 dtype: int64 

10406 >>> s.mask(t, 99) 

10407 0 99 

10408 1 1 

10409 2 99 

10410 3 99 

10411 4 99 

10412 dtype: int64 

10413 

10414 >>> s.where(s > 1, 10) 

10415 0 10 

10416 1 10 

10417 2 2 

10418 3 3 

10419 4 4 

10420 dtype: int64 

10421 >>> s.mask(s > 1, 10) 

10422 0 0 

10423 1 1 

10424 2 10 

10425 3 10 

10426 4 10 

10427 dtype: int64 

10428 

10429 >>> df = pd.DataFrame(np.arange(10).reshape(-1, 2), columns=["A", "B"]) 

10430 >>> df 

10431 A B 

10432 0 0 1 

10433 1 2 3 

10434 2 4 5 

10435 3 6 7 

10436 4 8 9 

10437 >>> m = df % 3 == 0 

10438 >>> df.where(m, -df) 

10439 A B 

10440 0 0 -1 

10441 1 -2 3 

10442 2 -4 -5 

10443 3 6 -7 

10444 4 -8 9 

10445 >>> df.where(m, -df) == np.where(m, df, -df) 

10446 A B 

10447 0 True True 

10448 1 True True 

10449 2 True True 

10450 3 True True 

10451 4 True True 

10452 >>> df.where(m, -df) == df.mask(~m, -df) 

10453 A B 

10454 0 True True 

10455 1 True True 

10456 2 True True 

10457 3 True True 

10458 4 True True 

10459 """ 

10460 inplace = validate_bool_kwarg(inplace, "inplace") 

10461 if inplace: 

10462 if not CHAINED_WARNING_DISABLED: 

10463 if sys.getrefcount( 

10464 self 

10465 ) <= REF_COUNT_METHOD and not common.is_local_in_caller_frame(self): 

10466 warnings.warn( 

10467 _chained_assignment_method_msg, 

10468 ChainedAssignmentError, 

10469 stacklevel=2, 

10470 ) 

10471 

10472 cond = common.apply_if_callable(cond, self) 

10473 other = common.apply_if_callable(other, self) 

10474 

10475 # see gh-21891 

10476 if not hasattr(cond, "__invert__"): 

10477 cond = np.array(cond) 

10478 

10479 return self._where( 

10480 ~cond, 

10481 other=other, 

10482 inplace=inplace, 

10483 axis=axis, 

10484 level=level, 

10485 ) 

10486 

10487 def shift( 

10488 self, 

10489 periods: int | Sequence[int] = 1, 

10490 freq=None, 

10491 axis: Axis = 0, 

10492 fill_value: Hashable = lib.no_default, 

10493 suffix: str | None = None, 

10494 ) -> Self | DataFrame: 

10495 """ 

10496 Shift index by desired number of periods with an optional time `freq`. 

10497 

10498 When `freq` is not passed, shift the index without realigning the data. 

10499 If `freq` is passed (in this case, the index must be date or datetime, 

10500 or it will raise a `NotImplementedError`), the index will be 

10501 increased using the periods and the `freq`. `freq` can be inferred 

10502 when specified as "infer" as long as either freq or inferred_freq 

10503 attribute is set in the index. 

10504 

10505 Parameters 

10506 ---------- 

10507 periods : int or Sequence 

10508 Number of periods to shift. Can be positive or negative. 

10509 If an iterable of ints, the data will be shifted once by each int. 

10510 This is equivalent to shifting by one value at a time and 

10511 concatenating all resulting frames. The resulting columns will have 

10512 the shift suffixed to their column names. For multiple periods, 

10513 axis must not be 1. 

10514 freq : DateOffset, tseries.offsets, timedelta, or str, optional 

10515 Offset to use from the tseries module or time rule (e.g. 'EOM'). 

10516 If `freq` is specified then the index values are shifted but the 

10517 data is not realigned. That is, use `freq` if you would like to 

10518 extend the index when shifting and preserve the original data. 

10519 If `freq` is specified as "infer" then it will be inferred from 

10520 the freq or inferred_freq attributes of the index. If neither of 

10521 those attributes exist, a ValueError is thrown. 

10522 axis : {0 or 'index', 1 or 'columns', None}, default None 

10523 Shift direction. For `Series` this parameter is unused and defaults to 0. 

10524 fill_value : object, optional 

10525 The scalar value to use for newly introduced missing values. 

10526 the default depends on the dtype of `self`. 

10527 For Boolean and numeric NumPy data types, ``np.nan`` is used. 

10528 For datetime, timedelta, or period data, etc. :attr:`NaT` is used. 

10529 For extension dtypes, ``self.dtype.na_value`` is used. 

10530 suffix : str, optional 

10531 If str and periods is an iterable, this is added after the column 

10532 name and before the shift value for each shifted column name. 

10533 For `Series` this parameter is unused and defaults to `None`. 

10534 

10535 Returns 

10536 ------- 

10537 Series/DataFrame 

10538 Copy of input object, shifted. 

10539 

10540 See Also 

10541 -------- 

10542 Index.shift : Shift values of Index. 

10543 DatetimeIndex.shift : Shift values of DatetimeIndex. 

10544 PeriodIndex.shift : Shift values of PeriodIndex. 

10545 

10546 Examples 

10547 -------- 

10548 >>> df = pd.DataFrame( 

10549 ... [[10, 13, 17], [20, 23, 27], [15, 18, 22], [30, 33, 37], [45, 48, 52]], 

10550 ... columns=["Col1", "Col2", "Col3"], 

10551 ... index=pd.date_range("2020-01-01", "2020-01-05"), 

10552 ... ) 

10553 >>> df 

10554 Col1 Col2 Col3 

10555 2020-01-01 10 13 17 

10556 2020-01-02 20 23 27 

10557 2020-01-03 15 18 22 

10558 2020-01-04 30 33 37 

10559 2020-01-05 45 48 52 

10560 

10561 >>> df.shift(periods=3) 

10562 Col1 Col2 Col3 

10563 2020-01-01 NaN NaN NaN 

10564 2020-01-02 NaN NaN NaN 

10565 2020-01-03 NaN NaN NaN 

10566 2020-01-04 10.0 13.0 17.0 

10567 2020-01-05 20.0 23.0 27.0 

10568 

10569 >>> df.shift(periods=1, axis="columns") 

10570 Col1 Col2 Col3 

10571 2020-01-01 NaN 10 13 

10572 2020-01-02 NaN 20 23 

10573 2020-01-03 NaN 15 18 

10574 2020-01-04 NaN 30 33 

10575 2020-01-05 NaN 45 48 

10576 

10577 >>> df.shift(periods=3, fill_value=0) 

10578 Col1 Col2 Col3 

10579 2020-01-01 0 0 0 

10580 2020-01-02 0 0 0 

10581 2020-01-03 0 0 0 

10582 2020-01-04 10 13 17 

10583 2020-01-05 20 23 27 

10584 

10585 >>> df.shift(periods=3, freq="D") 

10586 Col1 Col2 Col3 

10587 2020-01-04 10 13 17 

10588 2020-01-05 20 23 27 

10589 2020-01-06 15 18 22 

10590 2020-01-07 30 33 37 

10591 2020-01-08 45 48 52 

10592 

10593 >>> df.shift(periods=3, freq="infer") 

10594 Col1 Col2 Col3 

10595 2020-01-04 10 13 17 

10596 2020-01-05 20 23 27 

10597 2020-01-06 15 18 22 

10598 2020-01-07 30 33 37 

10599 2020-01-08 45 48 52 

10600 

10601 >>> df["Col1"].shift(periods=[0, 1, 2]) 

10602 Col1_0 Col1_1 Col1_2 

10603 2020-01-01 10 NaN NaN 

10604 2020-01-02 20 10.0 NaN 

10605 2020-01-03 15 20.0 10.0 

10606 2020-01-04 30 15.0 20.0 

10607 2020-01-05 45 30.0 15.0 

10608 """ 

10609 axis = self._get_axis_number(axis) 

10610 

10611 if freq is not None and fill_value is not lib.no_default: 

10612 # GH#53832 

10613 raise ValueError( 

10614 "Passing a 'freq' together with a 'fill_value' is not allowed." 

10615 ) 

10616 

10617 if periods == 0: 

10618 return self.copy(deep=False) 

10619 

10620 if is_list_like(periods) and isinstance(self, ABCSeries): 

10621 return self.to_frame().shift( 

10622 periods=periods, freq=freq, axis=axis, fill_value=fill_value 

10623 ) 

10624 periods = cast(int, periods) 

10625 

10626 if freq is None: 

10627 # when freq is None, data is shifted, index is not 

10628 axis = self._get_axis_number(axis) 

10629 assert axis == 0 # axis == 1 cases handled in DataFrame.shift 

10630 new_data = self._mgr.shift(periods=periods, fill_value=fill_value) 

10631 return self._constructor_from_mgr( 

10632 new_data, axes=new_data.axes 

10633 ).__finalize__(self, method="shift") 

10634 

10635 return self._shift_with_freq(periods, axis, freq) 

10636 

10637 @final 

10638 def _shift_with_freq(self, periods: int, axis: int, freq) -> Self: 

10639 # see shift.__doc__ 

10640 # when freq is given, index is shifted, data is not 

10641 index = self._get_axis(axis) 

10642 

10643 if freq == "infer": 

10644 freq = getattr(index, "freq", None) 

10645 

10646 if freq is None: 

10647 freq = getattr(index, "inferred_freq", None) 

10648 

10649 if freq is None: 

10650 msg = "Freq was not set in the index hence cannot be inferred" 

10651 raise ValueError(msg) 

10652 

10653 elif isinstance(freq, str): 

10654 is_period = isinstance(index, PeriodIndex) 

10655 freq = to_offset(freq, is_period=is_period) 

10656 

10657 if isinstance(index, PeriodIndex): 

10658 orig_freq = to_offset(index.freq) 

10659 if freq != orig_freq: 

10660 assert orig_freq is not None # for mypy 

10661 raise ValueError( 

10662 f"Given freq {PeriodDtype(freq)._freqstr} " 

10663 f"does not match PeriodIndex freq " 

10664 f"{PeriodDtype(orig_freq)._freqstr}" 

10665 ) 

10666 new_ax: Index = index.shift(periods) 

10667 else: 

10668 new_ax = index.shift(periods, freq) 

10669 

10670 result = self.set_axis(new_ax, axis=axis) 

10671 return result.__finalize__(self, method="shift") 

10672 

10673 @final 

10674 def truncate( 

10675 self, 

10676 before=None, 

10677 after=None, 

10678 axis: Axis | None = None, 

10679 copy: bool | lib.NoDefault = lib.no_default, 

10680 ) -> Self: 

10681 """ 

10682 Truncate a Series or DataFrame before and after some index value. 

10683 

10684 This is a useful shorthand for boolean indexing based on index 

10685 values above or below certain thresholds. 

10686 

10687 Parameters 

10688 ---------- 

10689 before : date, str, int 

10690 Truncate all rows before this index value. 

10691 after : date, str, int 

10692 Truncate all rows after this index value. 

10693 axis : {0 or 'index', 1 or 'columns'}, optional 

10694 Axis to truncate. Truncates the index (rows) by default. 

10695 For `Series` this parameter is unused and defaults to 0. 

10696 copy : bool, default False 

10697 This keyword is now ignored; changing its value will have no 

10698 impact on the method. 

10699 

10700 .. deprecated:: 3.0.0 

10701 

10702 This keyword is ignored and will be removed in pandas 4.0. Since 

10703 pandas 3.0, this method always returns a new object using a lazy 

10704 copy mechanism that defers copies until necessary 

10705 (Copy-on-Write). See the `user guide on Copy-on-Write 

10706 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

10707 for more details. 

10708 

10709 Returns 

10710 ------- 

10711 type of caller 

10712 The truncated Series or DataFrame. 

10713 

10714 See Also 

10715 -------- 

10716 DataFrame.loc : Select a subset of a DataFrame by label. 

10717 DataFrame.iloc : Select a subset of a DataFrame by position. 

10718 

10719 Notes 

10720 ----- 

10721 If the index being truncated contains only datetime values, 

10722 `before` and `after` may be specified as strings instead of 

10723 Timestamps. 

10724 

10725 Examples 

10726 -------- 

10727 >>> df = pd.DataFrame( 

10728 ... { 

10729 ... "A": ["a", "b", "c", "d", "e"], 

10730 ... "B": ["f", "g", "h", "i", "j"], 

10731 ... "C": ["k", "l", "m", "n", "o"], 

10732 ... }, 

10733 ... index=[1, 2, 3, 4, 5], 

10734 ... ) 

10735 >>> df 

10736 A B C 

10737 1 a f k 

10738 2 b g l 

10739 3 c h m 

10740 4 d i n 

10741 5 e j o 

10742 

10743 >>> df.truncate(before=2, after=4) 

10744 A B C 

10745 2 b g l 

10746 3 c h m 

10747 4 d i n 

10748 

10749 The columns of a DataFrame can be truncated. 

10750 

10751 >>> df.truncate(before="A", after="B", axis="columns") 

10752 A B 

10753 1 a f 

10754 2 b g 

10755 3 c h 

10756 4 d i 

10757 5 e j 

10758 

10759 For Series, only rows can be truncated. 

10760 

10761 >>> df["A"].truncate(before=2, after=4) 

10762 2 b 

10763 3 c 

10764 4 d 

10765 Name: A, dtype: str 

10766 

10767 The index values in ``truncate`` can be datetimes or string 

10768 dates. 

10769 

10770 >>> dates = pd.date_range("2016-01-01", "2016-02-01", freq="s") 

10771 >>> df = pd.DataFrame(index=dates, data={"A": 1}) 

10772 >>> df.tail() 

10773 A 

10774 2016-01-31 23:59:56 1 

10775 2016-01-31 23:59:57 1 

10776 2016-01-31 23:59:58 1 

10777 2016-01-31 23:59:59 1 

10778 2016-02-01 00:00:00 1 

10779 

10780 >>> df.truncate( 

10781 ... before=pd.Timestamp("2016-01-05"), after=pd.Timestamp("2016-01-10") 

10782 ... ).tail() 

10783 A 

10784 2016-01-09 23:59:56 1 

10785 2016-01-09 23:59:57 1 

10786 2016-01-09 23:59:58 1 

10787 2016-01-09 23:59:59 1 

10788 2016-01-10 00:00:00 1 

10789 

10790 Because the index is a DatetimeIndex containing only dates, we can 

10791 specify `before` and `after` as strings. They will be coerced to 

10792 Timestamps before truncation. 

10793 

10794 >>> df.truncate("2016-01-05", "2016-01-10").tail() 

10795 A 

10796 2016-01-09 23:59:56 1 

10797 2016-01-09 23:59:57 1 

10798 2016-01-09 23:59:58 1 

10799 2016-01-09 23:59:59 1 

10800 2016-01-10 00:00:00 1 

10801 

10802 Note that ``truncate`` assumes a 0 value for any unspecified time 

10803 component (midnight). This differs from partial string slicing, which 

10804 returns any partially matching dates. 

10805 

10806 >>> df.loc["2016-01-05":"2016-01-10", :].tail() 

10807 A 

10808 2016-01-10 23:59:55 1 

10809 2016-01-10 23:59:56 1 

10810 2016-01-10 23:59:57 1 

10811 2016-01-10 23:59:58 1 

10812 2016-01-10 23:59:59 1 

10813 """ 

10814 self._check_copy_deprecation(copy) 

10815 

10816 if axis is None: 

10817 axis = 0 

10818 axis = self._get_axis_number(axis) 

10819 ax = self._get_axis(axis) 

10820 

10821 # GH 17935 

10822 # Check that index is sorted 

10823 if not ax.is_monotonic_increasing and not ax.is_monotonic_decreasing: 

10824 raise ValueError("truncate requires a sorted index") 

10825 

10826 # if we have a date index, convert to dates, otherwise 

10827 # treat like a slice 

10828 if ax._is_all_dates: 

10829 from pandas.core.tools.datetimes import to_datetime 

10830 

10831 if before is not None: 

10832 # Avoid converting to NaT 

10833 before = to_datetime(before) 

10834 if after is not None: 

10835 # Avoid converting to NaT 

10836 after = to_datetime(after) 

10837 

10838 if before is not None and after is not None and before > after: 

10839 raise ValueError(f"Truncate: {after} must be after {before}") 

10840 

10841 if len(ax) > 1 and ax.is_monotonic_decreasing and ax.nunique() > 1: 

10842 before, after = after, before 

10843 

10844 slicer = [slice(None, None)] * self._AXIS_LEN 

10845 slicer[axis] = slice(before, after) 

10846 result = self.loc[tuple(slicer)] 

10847 

10848 if isinstance(ax, MultiIndex): 

10849 setattr(result, self._get_axis_name(axis), ax.truncate(before, after)) 

10850 

10851 result = result.copy(deep=False) 

10852 

10853 return result 

10854 

10855 @final 

10856 def tz_convert( 

10857 self, 

10858 tz, 

10859 axis: Axis = 0, 

10860 level=None, 

10861 copy: bool | lib.NoDefault = lib.no_default, 

10862 ) -> Self: 

10863 """ 

10864 Convert tz-aware axis to target time zone. 

10865 

10866 Parameters 

10867 ---------- 

10868 tz : str or tzinfo object or None 

10869 Target time zone. Passing ``None`` will convert to 

10870 UTC and remove the timezone information. 

10871 axis : {0 or 'index', 1 or 'columns'}, default 0 

10872 The axis to convert 

10873 level : int, str, default None 

10874 If axis is a MultiIndex, convert a specific level. Otherwise 

10875 must be None. 

10876 copy : bool, default False 

10877 This keyword is now ignored; changing its value will have no 

10878 impact on the method. 

10879 

10880 .. deprecated:: 3.0.0 

10881 

10882 This keyword is ignored and will be removed in pandas 4.0. Since 

10883 pandas 3.0, this method always returns a new object using a lazy 

10884 copy mechanism that defers copies until necessary 

10885 (Copy-on-Write). See the `user guide on Copy-on-Write 

10886 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

10887 for more details. 

10888 

10889 Returns 

10890 ------- 

10891 Series/DataFrame 

10892 Object with time zone converted axis. 

10893 

10894 Raises 

10895 ------ 

10896 TypeError 

10897 If the axis is tz-naive. 

10898 

10899 See Also 

10900 -------- 

10901 DataFrame.tz_localize: Localize tz-naive index of DataFrame to target time zone. 

10902 Series.tz_localize: Localize tz-naive index of Series to target time zone. 

10903 

10904 Examples 

10905 -------- 

10906 Change to another time zone: 

10907 

10908 >>> s = pd.Series( 

10909 ... [1], 

10910 ... index=pd.DatetimeIndex(["2018-09-15 01:30:00+02:00"]), 

10911 ... ) 

10912 >>> s.tz_convert("Asia/Shanghai") 

10913 2018-09-15 07:30:00+08:00 1 

10914 dtype: int64 

10915 

10916 Pass None to convert to UTC and get a tz-naive index: 

10917 

10918 >>> s = pd.Series([1], index=pd.DatetimeIndex(["2018-09-15 01:30:00+02:00"])) 

10919 >>> s.tz_convert(None) 

10920 2018-09-14 23:30:00 1 

10921 dtype: int64 

10922 """ 

10923 self._check_copy_deprecation(copy) 

10924 axis = self._get_axis_number(axis) 

10925 ax = self._get_axis(axis) 

10926 

10927 def _tz_convert(ax, tz): 

10928 if not hasattr(ax, "tz_convert"): 

10929 if len(ax) > 0: 

10930 ax_name = self._get_axis_name(axis) 

10931 raise TypeError( 

10932 f"{ax_name} is not a valid DatetimeIndex or PeriodIndex" 

10933 ) 

10934 ax = DatetimeIndex([], tz=tz) 

10935 else: 

10936 ax = ax.tz_convert(tz) 

10937 return ax 

10938 

10939 # if a level is given it must be a MultiIndex level or 

10940 # equivalent to the axis name 

10941 if isinstance(ax, MultiIndex): 

10942 level = ax._get_level_number(level) 

10943 new_level = _tz_convert(ax.levels[level], tz) 

10944 ax = ax.set_levels(new_level, level=level) 

10945 else: 

10946 if level not in (None, 0, ax.name): 

10947 raise ValueError(f"The level {level} is not valid") 

10948 ax = _tz_convert(ax, tz) 

10949 

10950 result = self.copy(deep=False) 

10951 result = result.set_axis(ax, axis=axis) 

10952 return result.__finalize__(self, method="tz_convert") 

10953 

10954 @final 

10955 def tz_localize( 

10956 self, 

10957 tz, 

10958 axis: Axis = 0, 

10959 level=None, 

10960 copy: bool | lib.NoDefault = lib.no_default, 

10961 ambiguous: TimeAmbiguous = "raise", 

10962 nonexistent: TimeNonexistent = "raise", 

10963 ) -> Self: 

10964 """ 

10965 Localize time zone naive index of a Series or DataFrame to target time zone. 

10966 

10967 This operation localizes the Index. To localize the values in a 

10968 time zone naive Series, use :meth:`Series.dt.tz_localize`. 

10969 

10970 Parameters 

10971 ---------- 

10972 tz : str or tzinfo or None 

10973 Time zone to localize. Passing ``None`` will remove the 

10974 time zone information and preserve local time. 

10975 axis : {0 or 'index', 1 or 'columns'}, default 0 

10976 The axis to localize 

10977 level : int, str, default None 

10978 If axis ia a MultiIndex, localize a specific level. Otherwise 

10979 must be None. 

10980 copy : bool, default False 

10981 This keyword is now ignored; changing its value will have no 

10982 impact on the method. 

10983 

10984 .. deprecated:: 3.0.0 

10985 

10986 This keyword is ignored and will be removed in pandas 4.0. Since 

10987 pandas 3.0, this method always returns a new object using a lazy 

10988 copy mechanism that defers copies until necessary 

10989 (Copy-on-Write). See the `user guide on Copy-on-Write 

10990 <https://pandas.pydata.org/docs/dev/user_guide/copy_on_write.html>`__ 

10991 for more details. 

10992 

10993 ambiguous : 'infer', bool, bool-ndarray, 'NaT', default 'raise' 

10994 When clocks moved backward due to DST, ambiguous times may arise. 

10995 For example in Central European Time (UTC+01), when going from 

10996 03:00 DST to 02:00 non-DST, 02:30:00 local time occurs both at 

10997 00:30:00 UTC and at 01:30:00 UTC. In such a situation, the 

10998 `ambiguous` parameter dictates how ambiguous times should be 

10999 handled. 

11000 

11001 - 'infer' will attempt to infer fall dst-transition hours based on 

11002 order 

11003 - bool (or bool-ndarray) where True signifies a DST time, False designates 

11004 a non-DST time (note that this flag is only applicable for 

11005 ambiguous times) 

11006 - 'NaT' will return NaT where there are ambiguous times 

11007 - 'raise' will raise a ValueError if there are ambiguous 

11008 times. 

11009 nonexistent : str, default 'raise' 

11010 A nonexistent time does not exist in a particular timezone 

11011 where clocks moved forward due to DST. Valid values are: 

11012 

11013 - 'shift_forward' will shift the nonexistent time forward to the 

11014 closest existing time 

11015 - 'shift_backward' will shift the nonexistent time backward to the 

11016 closest existing time 

11017 - 'NaT' will return NaT where there are nonexistent times 

11018 - timedelta objects will shift nonexistent times by the timedelta 

11019 - 'raise' will raise a ValueError if there are 

11020 nonexistent times. 

11021 

11022 Returns 

11023 ------- 

11024 Series/DataFrame 

11025 Same type as the input, with time zone naive or aware index, depending on 

11026 ``tz``. 

11027 

11028 Raises 

11029 ------ 

11030 TypeError 

11031 If the TimeSeries is tz-aware and tz is not None. 

11032 

11033 See Also 

11034 -------- 

11035 Series.dt.tz_localize: Localize the values in a time zone naive Series. 

11036 Timestamp.tz_localize: Localize the Timestamp to a timezone. 

11037 

11038 Examples 

11039 -------- 

11040 Localize local times: 

11041 

11042 >>> s = pd.Series( 

11043 ... [1], 

11044 ... index=pd.DatetimeIndex(["2018-09-15 01:30:00"]), 

11045 ... ) 

11046 >>> s.tz_localize("CET") 

11047 2018-09-15 01:30:00+02:00 1 

11048 dtype: int64 

11049 

11050 Pass None to convert to tz-naive index and preserve local time: 

11051 

11052 >>> s = pd.Series([1], index=pd.DatetimeIndex(["2018-09-15 01:30:00+02:00"])) 

11053 >>> s.tz_localize(None) 

11054 2018-09-15 01:30:00 1 

11055 dtype: int64 

11056 

11057 Be careful with DST changes. When there is sequential data, pandas 

11058 can infer the DST time: 

11059 

11060 >>> s = pd.Series( 

11061 ... range(7), 

11062 ... index=pd.DatetimeIndex( 

11063 ... [ 

11064 ... "2018-10-28 01:30:00", 

11065 ... "2018-10-28 02:00:00", 

11066 ... "2018-10-28 02:30:00", 

11067 ... "2018-10-28 02:00:00", 

11068 ... "2018-10-28 02:30:00", 

11069 ... "2018-10-28 03:00:00", 

11070 ... "2018-10-28 03:30:00", 

11071 ... ] 

11072 ... ), 

11073 ... ) 

11074 >>> s.tz_localize("CET", ambiguous="infer") 

11075 2018-10-28 01:30:00+02:00 0 

11076 2018-10-28 02:00:00+02:00 1 

11077 2018-10-28 02:30:00+02:00 2 

11078 2018-10-28 02:00:00+01:00 3 

11079 2018-10-28 02:30:00+01:00 4 

11080 2018-10-28 03:00:00+01:00 5 

11081 2018-10-28 03:30:00+01:00 6 

11082 dtype: int64 

11083 

11084 In some cases, inferring the DST is impossible. In such cases, you can 

11085 pass an ndarray to the ambiguous parameter to set the DST explicitly 

11086 

11087 >>> s = pd.Series( 

11088 ... range(3), 

11089 ... index=pd.DatetimeIndex( 

11090 ... [ 

11091 ... "2018-10-28 01:20:00", 

11092 ... "2018-10-28 02:36:00", 

11093 ... "2018-10-28 03:46:00", 

11094 ... ] 

11095 ... ), 

11096 ... ) 

11097 >>> s.tz_localize("CET", ambiguous=np.array([True, True, False])) 

11098 2018-10-28 01:20:00+02:00 0 

11099 2018-10-28 02:36:00+02:00 1 

11100 2018-10-28 03:46:00+01:00 2 

11101 dtype: int64 

11102 

11103 If the DST transition causes nonexistent times, you can shift these 

11104 dates forward or backward with a timedelta object or `'shift_forward'` 

11105 or `'shift_backward'`. 

11106 

11107 >>> dti = pd.DatetimeIndex( 

11108 ... ["2015-03-29 02:30:00", "2015-03-29 03:30:00"], dtype="M8[ns]" 

11109 ... ) 

11110 >>> s = pd.Series(range(2), index=dti) 

11111 >>> s.tz_localize("Europe/Warsaw", nonexistent="shift_forward") 

11112 2015-03-29 03:00:00+02:00 0 

11113 2015-03-29 03:30:00+02:00 1 

11114 dtype: int64 

11115 >>> s.tz_localize("Europe/Warsaw", nonexistent="shift_backward") 

11116 2015-03-29 01:59:59.999999999+01:00 0 

11117 2015-03-29 03:30:00+02:00 1 

11118 dtype: int64 

11119 >>> s.tz_localize("Europe/Warsaw", nonexistent=pd.Timedelta("1h")) 

11120 2015-03-29 03:30:00+02:00 0 

11121 2015-03-29 03:30:00+02:00 1 

11122 dtype: int64 

11123 """ 

11124 self._check_copy_deprecation(copy) 

11125 nonexistent_options = ("raise", "NaT", "shift_forward", "shift_backward") 

11126 if nonexistent not in nonexistent_options and not isinstance( 

11127 nonexistent, dt.timedelta 

11128 ): 

11129 raise ValueError( 

11130 "The nonexistent argument must be one of 'raise', " 

11131 "'NaT', 'shift_forward', 'shift_backward' or " 

11132 "a timedelta object" 

11133 ) 

11134 

11135 axis = self._get_axis_number(axis) 

11136 ax = self._get_axis(axis) 

11137 

11138 def _tz_localize(ax, tz, ambiguous, nonexistent): 

11139 if not hasattr(ax, "tz_localize"): 

11140 if len(ax) > 0: 

11141 ax_name = self._get_axis_name(axis) 

11142 raise TypeError( 

11143 f"{ax_name} is not a valid DatetimeIndex or PeriodIndex" 

11144 ) 

11145 ax = DatetimeIndex([], tz=tz) 

11146 else: 

11147 ax = ax.tz_localize(tz, ambiguous=ambiguous, nonexistent=nonexistent) 

11148 return ax 

11149 

11150 # if a level is given it must be a MultiIndex level or 

11151 # equivalent to the axis name 

11152 if isinstance(ax, MultiIndex): 

11153 level = ax._get_level_number(level) 

11154 new_level = _tz_localize(ax.levels[level], tz, ambiguous, nonexistent) 

11155 ax = ax.set_levels(new_level, level=level) 

11156 else: 

11157 if level not in (None, 0, ax.name): 

11158 raise ValueError(f"The level {level} is not valid") 

11159 ax = _tz_localize(ax, tz, ambiguous, nonexistent) 

11160 

11161 result = self.copy(deep=False) 

11162 result = result.set_axis(ax, axis=axis) 

11163 return result.__finalize__(self, method="tz_localize") 

11164 

11165 # ---------------------------------------------------------------------- 

11166 # Numeric Methods 

11167 

11168 @final 

11169 def describe( 

11170 self, 

11171 percentiles=None, 

11172 include=None, 

11173 exclude=None, 

11174 ) -> Self: 

11175 """ 

11176 Generate descriptive statistics. 

11177 

11178 Descriptive statistics include those that summarize the central 

11179 tendency, dispersion and shape of a 

11180 dataset's distribution, excluding ``NaN`` values. 

11181 

11182 Analyzes both numeric and object series, as well 

11183 as ``DataFrame`` column sets of mixed data types. The output 

11184 will vary depending on what is provided. Refer to the notes 

11185 below for more detail. 

11186 

11187 Parameters 

11188 ---------- 

11189 percentiles : list-like of numbers, optional 

11190 The percentiles to include in the output. All should 

11191 fall between 0 and 1. The default, ``None``, will automatically 

11192 return the 25th, 50th, and 75th percentiles. 

11193 include : 'all', list-like of dtypes or None (default), optional 

11194 A white list of data types to include in the result. Ignored 

11195 for ``Series``. Here are the options: 

11196 

11197 - 'all' : All columns of the input will be included in the output. 

11198 - A list-like of dtypes : Limits the results to the 

11199 provided data types. 

11200 To limit the result to numeric types submit 

11201 ``numpy.number``. To limit it instead to object columns submit 

11202 the ``numpy.object`` data type. Strings 

11203 can also be used in the style of 

11204 ``select_dtypes`` (e.g. ``df.describe(include=['O'])``). To 

11205 select pandas categorical columns, use ``'category'`` 

11206 - None (default) : The result will include all numeric columns. 

11207 exclude : list-like of dtypes or None (default), optional, 

11208 A black list of data types to omit from the result. Ignored 

11209 for ``Series``. Here are the options: 

11210 

11211 - A list-like of dtypes : Excludes the provided data types 

11212 from the result. To exclude numeric types submit 

11213 ``numpy.number``. To exclude object columns submit the data 

11214 type ``numpy.object``. Strings can also be used in the style of 

11215 ``select_dtypes`` (e.g. ``df.describe(exclude=['O'])``). To 

11216 exclude pandas categorical columns, use ``'category'`` 

11217 - None (default) : The result will exclude nothing. 

11218 

11219 Returns 

11220 ------- 

11221 Series or DataFrame 

11222 Summary statistics of the Series or Dataframe provided. 

11223 

11224 See Also 

11225 -------- 

11226 DataFrame.count: Count number of non-NA/null observations. 

11227 DataFrame.max: Maximum of the values in the object. 

11228 DataFrame.min: Minimum of the values in the object. 

11229 DataFrame.mean: Mean of the values. 

11230 DataFrame.std: Standard deviation of the observations. 

11231 DataFrame.select_dtypes: Subset of a DataFrame including/excluding 

11232 columns based on their dtype. 

11233 

11234 Notes 

11235 ----- 

11236 For numeric data, the result's index will include ``count``, 

11237 ``mean``, ``std``, ``min``, ``max`` as well as lower, ``50`` and 

11238 upper percentiles. By default the lower percentile is ``25`` and the 

11239 upper percentile is ``75``. The ``50`` percentile is the 

11240 same as the median. 

11241 

11242 For object data (e.g. strings), the result's index 

11243 will include ``count``, ``unique``, ``top``, and ``freq``. The ``top`` 

11244 is the most common value. The ``freq`` is the most common value's 

11245 frequency. 

11246 

11247 If multiple object values have the highest count, then the 

11248 ``count`` and ``top`` results will be arbitrarily chosen from 

11249 among those with the highest count. 

11250 

11251 For mixed data types provided via a ``DataFrame``, the default is to 

11252 return only an analysis of numeric columns. If the DataFrame consists 

11253 only of object and categorical data without any numeric columns, the 

11254 default is to return an analysis of both the object and categorical 

11255 columns. If ``include='all'`` is provided as an option, the result 

11256 will include a union of attributes of each type. 

11257 

11258 The `include` and `exclude` parameters can be used to limit 

11259 which columns in a ``DataFrame`` are analyzed for the output. 

11260 The parameters are ignored when analyzing a ``Series``. 

11261 

11262 Examples 

11263 -------- 

11264 Describing a numeric ``Series``. 

11265 

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

11267 >>> s.describe() 

11268 count 3.0 

11269 mean 2.0 

11270 std 1.0 

11271 min 1.0 

11272 25% 1.5 

11273 50% 2.0 

11274 75% 2.5 

11275 max 3.0 

11276 dtype: float64 

11277 

11278 Describing a categorical ``Series``. 

11279 

11280 >>> s = pd.Series(["a", "a", "b", "c"]) 

11281 >>> s.describe() 

11282 count 4 

11283 unique 3 

11284 top a 

11285 freq 2 

11286 dtype: object 

11287 

11288 Describing a timestamp ``Series``. 

11289 

11290 >>> s = pd.Series( 

11291 ... [ 

11292 ... np.datetime64("2000-01-01"), 

11293 ... np.datetime64("2010-01-01"), 

11294 ... np.datetime64("2010-01-01"), 

11295 ... ] 

11296 ... ) 

11297 >>> s.describe() 

11298 count 3 

11299 mean 2006-09-01 08:00:00 

11300 min 2000-01-01 00:00:00 

11301 25% 2004-12-31 12:00:00 

11302 50% 2010-01-01 00:00:00 

11303 75% 2010-01-01 00:00:00 

11304 max 2010-01-01 00:00:00 

11305 dtype: object 

11306 

11307 Describing a ``DataFrame``. By default only numeric fields 

11308 are returned. 

11309 

11310 >>> df = pd.DataFrame( 

11311 ... { 

11312 ... "categorical": pd.Categorical(["d", "e", "f"]), 

11313 ... "numeric": [1, 2, 3], 

11314 ... "object": ["a", "b", "c"], 

11315 ... } 

11316 ... ) 

11317 >>> df.describe() 

11318 numeric 

11319 count 3.0 

11320 mean 2.0 

11321 std 1.0 

11322 min 1.0 

11323 25% 1.5 

11324 50% 2.0 

11325 75% 2.5 

11326 max 3.0 

11327 

11328 Describing all columns of a ``DataFrame`` regardless of data type. 

11329 

11330 >>> df.describe(include="all") # doctest: +SKIP 

11331 categorical numeric object 

11332 count 3 3.0 3 

11333 unique 3 NaN 3 

11334 top f NaN a 

11335 freq 1 NaN 1 

11336 mean NaN 2.0 NaN 

11337 std NaN 1.0 NaN 

11338 min NaN 1.0 NaN 

11339 25% NaN 1.5 NaN 

11340 50% NaN 2.0 NaN 

11341 75% NaN 2.5 NaN 

11342 max NaN 3.0 NaN 

11343 

11344 Describing a column from a ``DataFrame`` by accessing it as 

11345 an attribute. 

11346 

11347 >>> df.numeric.describe() 

11348 count 3.0 

11349 mean 2.0 

11350 std 1.0 

11351 min 1.0 

11352 25% 1.5 

11353 50% 2.0 

11354 75% 2.5 

11355 max 3.0 

11356 Name: numeric, dtype: float64 

11357 

11358 Including only numeric columns in a ``DataFrame`` description. 

11359 

11360 >>> df.describe(include=[np.number]) 

11361 numeric 

11362 count 3.0 

11363 mean 2.0 

11364 std 1.0 

11365 min 1.0 

11366 25% 1.5 

11367 50% 2.0 

11368 75% 2.5 

11369 max 3.0 

11370 

11371 Including only string columns in a ``DataFrame`` description. 

11372 

11373 >>> df.describe(include=[object]) # doctest: +SKIP 

11374 object 

11375 count 3 

11376 unique 3 

11377 top a 

11378 freq 1 

11379 

11380 Including only categorical columns from a ``DataFrame`` description. 

11381 

11382 >>> df.describe(include=["category"]) 

11383 categorical 

11384 count 3 

11385 unique 3 

11386 top d 

11387 freq 1 

11388 

11389 Excluding numeric columns from a ``DataFrame`` description. 

11390 

11391 >>> df.describe(exclude=[np.number]) # doctest: +SKIP 

11392 categorical object 

11393 count 3 3 

11394 unique 3 3 

11395 top f a 

11396 freq 1 1 

11397 

11398 Excluding object columns from a ``DataFrame`` description. 

11399 

11400 >>> df.describe(exclude=[object]) # doctest: +SKIP 

11401 categorical numeric 

11402 count 3 3.0 

11403 unique 3 NaN 

11404 top f NaN 

11405 freq 1 NaN 

11406 mean NaN 2.0 

11407 std NaN 1.0 

11408 min NaN 1.0 

11409 25% NaN 1.5 

11410 50% NaN 2.0 

11411 75% NaN 2.5 

11412 max NaN 3.0 

11413 """ 

11414 return describe_ndframe( 

11415 obj=self, 

11416 include=include, 

11417 exclude=exclude, 

11418 percentiles=percentiles, 

11419 ).__finalize__(self, method="describe") 

11420 

11421 @final 

11422 def pct_change( 

11423 self, 

11424 periods: int = 1, 

11425 fill_method: None = None, 

11426 freq=None, 

11427 **kwargs, 

11428 ) -> Self: 

11429 """ 

11430 Fractional change between the current and a prior element. 

11431 

11432 Computes the fractional change from the immediately previous row by 

11433 default. This is useful in comparing the fraction of change in a time 

11434 series of elements. 

11435 

11436 .. note:: 

11437 

11438 Despite the name of this method, it calculates fractional change 

11439 (also known as per unit change or relative change) and not 

11440 percentage change. If you need the percentage change, multiply 

11441 these values by 100. 

11442 

11443 Parameters 

11444 ---------- 

11445 periods : int, default 1 

11446 Periods to shift for forming percent change. 

11447 fill_method : None 

11448 Must be None. This argument will be removed in a future version of pandas. 

11449 freq : DateOffset, timedelta, or str, optional 

11450 Increment to use from time series API (e.g. 'ME' or BDay()). 

11451 **kwargs 

11452 Additional keyword arguments are passed into 

11453 `DataFrame.shift` or `Series.shift`. 

11454 

11455 Returns 

11456 ------- 

11457 Series or DataFrame 

11458 The same type as the calling object. 

11459 

11460 See Also 

11461 -------- 

11462 Series.diff : Compute the difference of two elements in a Series. 

11463 DataFrame.diff : Compute the difference of two elements in a DataFrame. 

11464 Series.shift : Shift the index by some number of periods. 

11465 DataFrame.shift : Shift the index by some number of periods. 

11466 

11467 Examples 

11468 -------- 

11469 **Series** 

11470 

11471 >>> s = pd.Series([90, 91, 85]) 

11472 >>> s 

11473 0 90 

11474 1 91 

11475 2 85 

11476 dtype: int64 

11477 

11478 >>> s.pct_change() 

11479 0 NaN 

11480 1 0.011111 

11481 2 -0.065934 

11482 dtype: float64 

11483 

11484 >>> s.pct_change(periods=2) 

11485 0 NaN 

11486 1 NaN 

11487 2 -0.055556 

11488 dtype: float64 

11489 

11490 See the percentage change in a Series where filling NAs with last 

11491 valid observation forward to next valid. 

11492 

11493 >>> s = pd.Series([90, 91, None, 85]) 

11494 >>> s 

11495 0 90.0 

11496 1 91.0 

11497 2 NaN 

11498 3 85.0 

11499 dtype: float64 

11500 

11501 >>> s.ffill().pct_change() 

11502 0 NaN 

11503 1 0.011111 

11504 2 0.000000 

11505 3 -0.065934 

11506 dtype: float64 

11507 

11508 **DataFrame** 

11509 

11510 Percentage change in French franc, Deutsche Mark, and Italian lira from 

11511 1980-01-01 to 1980-03-01. 

11512 

11513 >>> df = pd.DataFrame( 

11514 ... { 

11515 ... "FR": [4.0405, 4.0963, 4.3149], 

11516 ... "GR": [1.7246, 1.7482, 1.8519], 

11517 ... "IT": [804.74, 810.01, 860.13], 

11518 ... }, 

11519 ... index=["1980-01-01", "1980-02-01", "1980-03-01"], 

11520 ... ) 

11521 >>> df 

11522 FR GR IT 

11523 1980-01-01 4.0405 1.7246 804.74 

11524 1980-02-01 4.0963 1.7482 810.01 

11525 1980-03-01 4.3149 1.8519 860.13 

11526 

11527 >>> df.pct_change() 

11528 FR GR IT 

11529 1980-01-01 NaN NaN NaN 

11530 1980-02-01 0.013810 0.013684 0.006549 

11531 1980-03-01 0.053365 0.059318 0.061876 

11532 

11533 Percentage of change in GOOG and APPL stock volume. Shows computing 

11534 the percentage change between columns. 

11535 

11536 >>> df = pd.DataFrame( 

11537 ... { 

11538 ... "2016": [1769950, 30586265], 

11539 ... "2015": [1500923, 40912316], 

11540 ... "2014": [1371819, 41403351], 

11541 ... }, 

11542 ... index=["GOOG", "APPL"], 

11543 ... ) 

11544 >>> df 

11545 2016 2015 2014 

11546 GOOG 1769950 1500923 1371819 

11547 APPL 30586265 40912316 41403351 

11548 

11549 >>> df.pct_change(axis="columns", periods=-1) 

11550 2016 2015 2014 

11551 GOOG 0.179241 0.094112 NaN 

11552 APPL -0.252395 -0.011860 NaN 

11553 """ 

11554 # GH#53491 

11555 if fill_method is not None: 

11556 raise ValueError(f"fill_method must be None; got {fill_method=}.") 

11557 

11558 axis = self._get_axis_number(kwargs.pop("axis", "index")) 

11559 shifted = self.shift(periods=periods, freq=freq, axis=axis, **kwargs) 

11560 # Unsupported left operand type for / ("Self") 

11561 rs = self / shifted - 1 # type: ignore[operator] 

11562 if freq is not None: 

11563 # Shift method is implemented differently when freq is not None 

11564 # We want to restore the original index 

11565 rs = rs.loc[~rs.index.duplicated()] 

11566 rs = rs.reindex_like(self) 

11567 return rs.__finalize__(self, method="pct_change") 

11568 

11569 @final 

11570 def _logical_func( 

11571 self, 

11572 name: str, 

11573 func, 

11574 axis: Axis | None = 0, 

11575 bool_only: bool = False, 

11576 skipna: bool = True, 

11577 **kwargs, 

11578 ) -> Series | bool: 

11579 nv.validate_logical_func((), kwargs, fname=name) 

11580 validate_bool_kwarg(skipna, "skipna", none_allowed=False) 

11581 

11582 if self.ndim > 1 and axis is None: 

11583 # Reduce along one dimension then the other, to simplify DataFrame._reduce 

11584 res = self._logical_func( 

11585 name, func, axis=0, bool_only=bool_only, skipna=skipna, **kwargs 

11586 ) 

11587 # error: Item "bool" of "Series | bool" has no attribute "_logical_func" 

11588 return res._logical_func( # type: ignore[union-attr] 

11589 name, func, skipna=skipna, **kwargs 

11590 ) 

11591 elif axis is None: 

11592 axis = 0 

11593 

11594 if ( 

11595 self.ndim > 1 

11596 and axis == 1 

11597 and len(self._mgr.blocks) > 1 

11598 # TODO(EA2D): special-case not needed 

11599 and all(block.values.ndim == 2 for block in self._mgr.blocks) 

11600 and not kwargs 

11601 ): 

11602 # Fastpath avoiding potentially expensive transpose 

11603 obj = self 

11604 if bool_only: 

11605 obj = self._get_bool_data() 

11606 return obj._reduce_axis1(name, func, skipna=skipna) 

11607 

11608 return self._reduce( 

11609 func, 

11610 name=name, 

11611 axis=axis, 

11612 skipna=skipna, 

11613 numeric_only=bool_only, 

11614 filter_type="bool", 

11615 ) 

11616 

11617 def any( 

11618 self, 

11619 *, 

11620 axis: Axis | None = 0, 

11621 bool_only: bool = False, 

11622 skipna: bool = True, 

11623 **kwargs, 

11624 ) -> Series | bool: 

11625 return self._logical_func( 

11626 "any", nanops.nanany, axis, bool_only, skipna, **kwargs 

11627 ) 

11628 

11629 def all( 

11630 self, 

11631 *, 

11632 axis: Axis = 0, 

11633 bool_only: bool = False, 

11634 skipna: bool = True, 

11635 **kwargs, 

11636 ) -> Series | bool: 

11637 return self._logical_func( 

11638 "all", nanops.nanall, axis, bool_only, skipna, **kwargs 

11639 ) 

11640 

11641 @final 

11642 def _accum_func( 

11643 self, 

11644 name: str, 

11645 func, 

11646 axis: Axis | None = None, 

11647 skipna: bool = True, 

11648 *args, 

11649 **kwargs, 

11650 ): 

11651 skipna = nv.validate_cum_func_with_skipna(skipna, args, kwargs, name) 

11652 if axis is None: 

11653 axis = 0 

11654 else: 

11655 axis = self._get_axis_number(axis) 

11656 

11657 if axis == 1: 

11658 return self.T._accum_func( 

11659 name, 

11660 func, 

11661 axis=0, 

11662 skipna=skipna, 

11663 *args, # noqa: B026 

11664 **kwargs, 

11665 ).T 

11666 

11667 def block_accum_func(blk_values): 

11668 values = blk_values.T if hasattr(blk_values, "T") else blk_values 

11669 

11670 result: np.ndarray | ExtensionArray 

11671 if isinstance(values, ExtensionArray): 

11672 result = values._accumulate(name, skipna=skipna, **kwargs) 

11673 else: 

11674 result = nanops.na_accum_func(values, func, skipna=skipna) 

11675 

11676 result = result.T if hasattr(result, "T") else result 

11677 return result 

11678 

11679 result = self._mgr.apply(block_accum_func) 

11680 

11681 return self._constructor_from_mgr(result, axes=result.axes).__finalize__( 

11682 self, method=name 

11683 ) 

11684 

11685 def cummax(self, axis: Axis = 0, skipna: bool = True, *args, **kwargs) -> Self: 

11686 return self._accum_func( 

11687 "cummax", np.maximum.accumulate, axis, skipna, *args, **kwargs 

11688 ) 

11689 

11690 def cummin(self, axis: Axis = 0, skipna: bool = True, *args, **kwargs) -> Self: 

11691 return self._accum_func( 

11692 "cummin", np.minimum.accumulate, axis, skipna, *args, **kwargs 

11693 ) 

11694 

11695 def cumsum(self, axis: Axis = 0, skipna: bool = True, *args, **kwargs) -> Self: 

11696 return self._accum_func("cumsum", np.cumsum, axis, skipna, *args, **kwargs) 

11697 

11698 def cumprod(self, axis: Axis = 0, skipna: bool = True, *args, **kwargs) -> Self: 

11699 return self._accum_func("cumprod", np.cumprod, axis, skipna, *args, **kwargs) 

11700 

11701 @final 

11702 def _stat_function_ddof( 

11703 self, 

11704 name: str, 

11705 func, 

11706 axis: Axis | None = 0, 

11707 skipna: bool = True, 

11708 ddof: int = 1, 

11709 numeric_only: bool = False, 

11710 **kwargs, 

11711 ) -> Series | float: 

11712 nv.validate_stat_ddof_func((), kwargs, fname=name) 

11713 validate_bool_kwarg(skipna, "skipna", none_allowed=False) 

11714 

11715 return self._reduce( 

11716 func, name, axis=axis, numeric_only=numeric_only, skipna=skipna, ddof=ddof 

11717 ) 

11718 

11719 def sem( 

11720 self, 

11721 *, 

11722 axis: Axis | None = 0, 

11723 skipna: bool = True, 

11724 ddof: int = 1, 

11725 numeric_only: bool = False, 

11726 **kwargs, 

11727 ) -> Series | float: 

11728 return self._stat_function_ddof( 

11729 "sem", nanops.nansem, axis, skipna, ddof, numeric_only, **kwargs 

11730 ) 

11731 

11732 def var( 

11733 self, 

11734 *, 

11735 axis: Axis | None = 0, 

11736 skipna: bool = True, 

11737 ddof: int = 1, 

11738 numeric_only: bool = False, 

11739 **kwargs, 

11740 ) -> Series | float: 

11741 return self._stat_function_ddof( 

11742 "var", nanops.nanvar, axis, skipna, ddof, numeric_only, **kwargs 

11743 ) 

11744 

11745 def std( 

11746 self, 

11747 *, 

11748 axis: Axis | None = 0, 

11749 skipna: bool = True, 

11750 ddof: int = 1, 

11751 numeric_only: bool = False, 

11752 **kwargs, 

11753 ) -> Series | float: 

11754 return self._stat_function_ddof( 

11755 "std", nanops.nanstd, axis, skipna, ddof, numeric_only, **kwargs 

11756 ) 

11757 

11758 @final 

11759 def _stat_function( 

11760 self, 

11761 name: str, 

11762 func, 

11763 axis: Axis | None = 0, 

11764 skipna: bool = True, 

11765 numeric_only: bool = False, 

11766 **kwargs, 

11767 ): 

11768 assert name in ["median", "mean", "min", "max", "kurt", "skew"], name 

11769 nv.validate_func(name, (), kwargs) 

11770 

11771 validate_bool_kwarg(skipna, "skipna", none_allowed=False) 

11772 

11773 return self._reduce( 

11774 func, name=name, axis=axis, skipna=skipna, numeric_only=numeric_only 

11775 ) 

11776 

11777 def min( 

11778 self, 

11779 *, 

11780 axis: Axis | None = 0, 

11781 skipna: bool = True, 

11782 numeric_only: bool = False, 

11783 **kwargs, 

11784 ): 

11785 return self._stat_function( 

11786 "min", 

11787 nanops.nanmin, 

11788 axis, 

11789 skipna, 

11790 numeric_only, 

11791 **kwargs, 

11792 ) 

11793 

11794 def max( 

11795 self, 

11796 *, 

11797 axis: Axis | None = 0, 

11798 skipna: bool = True, 

11799 numeric_only: bool = False, 

11800 **kwargs, 

11801 ): 

11802 return self._stat_function( 

11803 "max", 

11804 nanops.nanmax, 

11805 axis, 

11806 skipna, 

11807 numeric_only, 

11808 **kwargs, 

11809 ) 

11810 

11811 def mean( 

11812 self, 

11813 *, 

11814 axis: Axis | None = 0, 

11815 skipna: bool = True, 

11816 numeric_only: bool = False, 

11817 **kwargs, 

11818 ) -> Series | float: 

11819 return self._stat_function( 

11820 "mean", nanops.nanmean, axis, skipna, numeric_only, **kwargs 

11821 ) 

11822 

11823 def median( 

11824 self, 

11825 *, 

11826 axis: Axis | None = 0, 

11827 skipna: bool = True, 

11828 numeric_only: bool = False, 

11829 **kwargs, 

11830 ) -> Series | float: 

11831 return self._stat_function( 

11832 "median", nanops.nanmedian, axis, skipna, numeric_only, **kwargs 

11833 ) 

11834 

11835 def skew( 

11836 self, 

11837 *, 

11838 axis: Axis | None = 0, 

11839 skipna: bool = True, 

11840 numeric_only: bool = False, 

11841 **kwargs, 

11842 ) -> Series | float: 

11843 return self._stat_function( 

11844 "skew", nanops.nanskew, axis, skipna, numeric_only, **kwargs 

11845 ) 

11846 

11847 def kurt( 

11848 self, 

11849 *, 

11850 axis: Axis | None = 0, 

11851 skipna: bool = True, 

11852 numeric_only: bool = False, 

11853 **kwargs, 

11854 ) -> Series | float: 

11855 return self._stat_function( 

11856 "kurt", nanops.nankurt, axis, skipna, numeric_only, **kwargs 

11857 ) 

11858 

11859 kurtosis = kurt 

11860 

11861 @final 

11862 def _min_count_stat_function( 

11863 self, 

11864 name: str, 

11865 func, 

11866 axis: Axis | None = 0, 

11867 skipna: bool = True, 

11868 numeric_only: bool = False, 

11869 min_count: int = 0, 

11870 **kwargs, 

11871 ): 

11872 assert name in ["sum", "prod"], name 

11873 nv.validate_func(name, (), kwargs) 

11874 

11875 validate_bool_kwarg(skipna, "skipna", none_allowed=False) 

11876 

11877 return self._reduce( 

11878 func, 

11879 name=name, 

11880 axis=axis, 

11881 skipna=skipna, 

11882 numeric_only=numeric_only, 

11883 min_count=min_count, 

11884 ) 

11885 

11886 def sum( 

11887 self, 

11888 *, 

11889 axis: Axis | None = 0, 

11890 skipna: bool = True, 

11891 numeric_only: bool = False, 

11892 min_count: int = 0, 

11893 **kwargs, 

11894 ): 

11895 return self._min_count_stat_function( 

11896 "sum", nanops.nansum, axis, skipna, numeric_only, min_count, **kwargs 

11897 ) 

11898 

11899 def prod( 

11900 self, 

11901 *, 

11902 axis: Axis | None = 0, 

11903 skipna: bool = True, 

11904 numeric_only: bool = False, 

11905 min_count: int = 0, 

11906 **kwargs, 

11907 ): 

11908 return self._min_count_stat_function( 

11909 "prod", 

11910 nanops.nanprod, 

11911 axis, 

11912 skipna, 

11913 numeric_only, 

11914 min_count, 

11915 **kwargs, 

11916 ) 

11917 

11918 product = prod 

11919 

11920 @final 

11921 def rolling( 

11922 self, 

11923 window: int | dt.timedelta | str | BaseOffset | BaseIndexer, 

11924 min_periods: int | None = None, 

11925 center: bool = False, 

11926 win_type: str | None = None, 

11927 on: str | None = None, 

11928 closed: IntervalClosedType | None = None, 

11929 step: int | None = None, 

11930 method: str = "single", 

11931 ) -> Window | Rolling: 

11932 """ 

11933 Provide rolling window calculations. 

11934 

11935 Parameters 

11936 ---------- 

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

11938 Interval of the moving window. 

11939 

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

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

11942 

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

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

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

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

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

11948 

11949 If a BaseIndexer subclass, the window boundaries 

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

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

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

11953 

11954 min_periods : int, default None 

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

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

11957 

11958 For a window that is specified by an offset, ``min_periods`` will default 

11959 to 1. 

11960 

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

11962 to the size of the window. 

11963 

11964 center : bool, default False 

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

11966 

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

11968 

11969 win_type : str, default None 

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

11971 

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

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

11974 

11975 Certain Scipy window types require additional parameters to be passed 

11976 in the aggregation function. The additional parameters must match 

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

11978 

11979 on : str, optional 

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

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

11982 

11983 Provided integer column is ignored and excluded from result since 

11984 an integer index is not used to calculate the rolling window. 

11985 

11986 closed : str, default None 

11987 Determines the inclusivity of points in the window 

11988 

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

11990 is included in the calculations. 

11991 

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

11993 is included in the calculations. 

11994 

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

11996 the window are included in the calculations. 

11997 

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

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

12000 

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

12002 notation respetively. 

12003 

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

12005 

12006 step : int, default None 

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

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

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

12010 

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

12012 

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

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

12015 

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

12017 in the method call. 

12018 

12019 Returns 

12020 ------- 

12021 pandas.api.typing.Window or pandas.api.typing.Rolling 

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

12023 an instance of Rolling is returned. 

12024 

12025 See Also 

12026 -------- 

12027 expanding : Provides expanding transformations. 

12028 ewm : Provides exponential weighted functions. 

12029 

12030 Notes 

12031 ----- 

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

12033 and examples. 

12034 

12035 Examples 

12036 -------- 

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

12038 >>> df 

12039 B 

12040 0 0.0 

12041 1 1.0 

12042 2 2.0 

12043 3 NaN 

12044 4 4.0 

12045 

12046 **window** 

12047 

12048 Rolling sum with a window length of 2 observations. 

12049 

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

12051 B 

12052 0 NaN 

12053 1 1.0 

12054 2 3.0 

12055 3 NaN 

12056 4 NaN 

12057 

12058 Rolling sum with a window span of 2 seconds. 

12059 

12060 >>> df_time = pd.DataFrame( 

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

12062 ... index=[ 

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

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

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

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

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

12068 ... ], 

12069 ... ) 

12070 

12071 >>> df_time 

12072 B 

12073 2013-01-01 09:00:00 0.0 

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

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

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

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

12078 

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

12080 B 

12081 2013-01-01 09:00:00 0.0 

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

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

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

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

12086 

12087 Rolling sum with forward looking windows with 2 observations. 

12088 

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

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

12091 B 

12092 0 1.0 

12093 1 3.0 

12094 2 2.0 

12095 3 4.0 

12096 4 4.0 

12097 

12098 **min_periods** 

12099 

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

12101 of 1 observation to calculate a value. 

12102 

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

12104 B 

12105 0 0.0 

12106 1 1.0 

12107 2 3.0 

12108 3 2.0 

12109 4 4.0 

12110 

12111 **center** 

12112 

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

12114 

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

12116 B 

12117 0 1.0 

12118 1 3.0 

12119 2 3.0 

12120 3 6.0 

12121 4 4.0 

12122 

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

12124 B 

12125 0 0.0 

12126 1 1.0 

12127 2 3.0 

12128 3 3.0 

12129 4 6.0 

12130 

12131 **step** 

12132 

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

12134 calculate a value, and a step of 2. 

12135 

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

12137 B 

12138 0 0.0 

12139 2 3.0 

12140 4 4.0 

12141 

12142 **win_type** 

12143 

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

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

12146 

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

12148 B 

12149 0 NaN 

12150 1 0.986207 

12151 2 2.958621 

12152 3 NaN 

12153 4 NaN 

12154 

12155 **on** 

12156 

12157 Rolling sum with a window length of 2 days. 

12158 

12159 >>> df = pd.DataFrame( 

12160 ... { 

12161 ... "A": [ 

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

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

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

12165 ... ], 

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

12167 ... }, 

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

12169 ... ) 

12170 

12171 >>> df 

12172 A B 

12173 2020-01-01 2020-01-01 1 

12174 2020-01-02 2020-01-01 2 

12175 2020-01-03 2020-01-02 3 

12176 

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

12178 A B 

12179 2020-01-01 2020-01-01 1.0 

12180 2020-01-02 2020-01-01 3.0 

12181 2020-01-03 2020-01-02 6.0 

12182 """ 

12183 if win_type is not None: 

12184 return Window( 

12185 self, 

12186 window=window, 

12187 min_periods=min_periods, 

12188 center=center, 

12189 win_type=win_type, 

12190 on=on, 

12191 closed=closed, 

12192 step=step, 

12193 method=method, 

12194 ) 

12195 

12196 return Rolling( 

12197 self, 

12198 window=window, 

12199 min_periods=min_periods, 

12200 center=center, 

12201 win_type=win_type, 

12202 on=on, 

12203 closed=closed, 

12204 step=step, 

12205 method=method, 

12206 ) 

12207 

12208 @final 

12209 def expanding( 

12210 self, 

12211 min_periods: int = 1, 

12212 method: Literal["single", "table"] = "single", 

12213 ) -> Expanding: 

12214 """ 

12215 Provide expanding window calculations. 

12216 

12217 An expanding window yields the value of an aggregation statistic with all 

12218 the data available up to that point in time. 

12219 

12220 Parameters 

12221 ---------- 

12222 min_periods : int, default 1 

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

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

12225 

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

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

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

12229 

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

12231 in the method call. 

12232 

12233 Returns 

12234 ------- 

12235 pandas.api.typing.Expanding 

12236 An instance of Expanding for further expanding window calculations, 

12237 e.g. using the ``sum`` method. 

12238 

12239 See Also 

12240 -------- 

12241 rolling : Provides rolling window calculations. 

12242 ewm : Provides exponential weighted functions. 

12243 

12244 Notes 

12245 ----- 

12246 See :ref:`Windowing Operations <window.expanding>` for further usage details 

12247 and examples. 

12248 

12249 Examples 

12250 -------- 

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

12252 >>> df 

12253 B 

12254 0 0.0 

12255 1 1.0 

12256 2 2.0 

12257 3 NaN 

12258 4 4.0 

12259 

12260 **min_periods** 

12261 

12262 Expanding sum with 1 vs 3 observations needed to calculate a value. 

12263 

12264 >>> df.expanding(1).sum() 

12265 B 

12266 0 0.0 

12267 1 1.0 

12268 2 3.0 

12269 3 3.0 

12270 4 7.0 

12271 >>> df.expanding(3).sum() 

12272 B 

12273 0 NaN 

12274 1 NaN 

12275 2 3.0 

12276 3 3.0 

12277 4 7.0 

12278 """ 

12279 return Expanding(self, min_periods=min_periods, method=method) 

12280 

12281 @final 

12282 @doc(ExponentialMovingWindow) 

12283 def ewm( 

12284 self, 

12285 com: float | None = None, 

12286 span: float | None = None, 

12287 halflife: float | TimedeltaConvertibleTypes | None = None, 

12288 alpha: float | None = None, 

12289 min_periods: int | None = 0, 

12290 adjust: bool = True, 

12291 ignore_na: bool = False, 

12292 times: np.ndarray | DataFrame | Series | None = None, 

12293 method: Literal["single", "table"] = "single", 

12294 ) -> ExponentialMovingWindow: 

12295 return ExponentialMovingWindow( 

12296 self, 

12297 com=com, 

12298 span=span, 

12299 halflife=halflife, 

12300 alpha=alpha, 

12301 min_periods=min_periods, 

12302 adjust=adjust, 

12303 ignore_na=ignore_na, 

12304 times=times, 

12305 method=method, 

12306 ) 

12307 

12308 # ---------------------------------------------------------------------- 

12309 # Arithmetic Methods 

12310 

12311 @final 

12312 def _inplace_method(self, other, op) -> Self: 

12313 """ 

12314 Wrap arithmetic method to operate inplace. 

12315 """ 

12316 result = op(self, other) 

12317 

12318 # this makes sure that we are aligned like the input 

12319 # we are updating inplace 

12320 self._update_inplace(result.reindex_like(self)) 

12321 return self 

12322 

12323 @final 

12324 def __iadd__(self, other) -> Self: 

12325 # error: Unsupported left operand type for + ("Type[NDFrame]") 

12326 return self._inplace_method(other, type(self).__add__) # type: ignore[operator] 

12327 

12328 @final 

12329 def __isub__(self, other) -> Self: 

12330 # error: Unsupported left operand type for - ("Type[NDFrame]") 

12331 return self._inplace_method(other, type(self).__sub__) # type: ignore[operator] 

12332 

12333 @final 

12334 def __imul__(self, other) -> Self: 

12335 # error: Unsupported left operand type for * ("Type[NDFrame]") 

12336 return self._inplace_method(other, type(self).__mul__) # type: ignore[operator] 

12337 

12338 @final 

12339 def __itruediv__(self, other) -> Self: 

12340 # error: Unsupported left operand type for / ("Type[NDFrame]") 

12341 return self._inplace_method( 

12342 other, 

12343 type(self).__truediv__, # type: ignore[operator] 

12344 ) 

12345 

12346 @final 

12347 def __ifloordiv__(self, other) -> Self: 

12348 # error: Unsupported left operand type for // ("Type[NDFrame]") 

12349 return self._inplace_method( 

12350 other, 

12351 type(self).__floordiv__, # type: ignore[operator] 

12352 ) 

12353 

12354 @final 

12355 def __imod__(self, other) -> Self: 

12356 # error: Unsupported left operand type for % ("Type[NDFrame]") 

12357 return self._inplace_method(other, type(self).__mod__) # type: ignore[operator] 

12358 

12359 @final 

12360 def __ipow__(self, other) -> Self: 

12361 # error: Unsupported left operand type for ** ("Type[NDFrame]") 

12362 return self._inplace_method(other, type(self).__pow__) # type: ignore[operator] 

12363 

12364 @final 

12365 def __iand__(self, other) -> Self: 

12366 # error: Unsupported left operand type for & ("Type[NDFrame]") 

12367 return self._inplace_method(other, type(self).__and__) # type: ignore[operator] 

12368 

12369 @final 

12370 def __ior__(self, other) -> Self: 

12371 return self._inplace_method(other, type(self).__or__) 

12372 

12373 @final 

12374 def __ixor__(self, other) -> Self: 

12375 # error: Unsupported left operand type for ^ ("Type[NDFrame]") 

12376 return self._inplace_method(other, type(self).__xor__) # type: ignore[operator] 

12377 

12378 # ---------------------------------------------------------------------- 

12379 # Misc methods 

12380 

12381 @final 

12382 def _find_valid_index(self, *, how: str) -> Hashable: 

12383 """ 

12384 Retrieves the index of the first valid value. 

12385 

12386 Parameters 

12387 ---------- 

12388 how : {'first', 'last'} 

12389 Use this parameter to change between the first or last valid index. 

12390 

12391 Returns 

12392 ------- 

12393 idx_first_valid : type of index 

12394 """ 

12395 is_valid = self.notna().values 

12396 idxpos = find_valid_index(how=how, is_valid=is_valid) 

12397 if idxpos is None: 

12398 return None 

12399 return self.index[idxpos] 

12400 

12401 @final 

12402 def first_valid_index(self) -> Hashable: 

12403 """ 

12404 Return index for first non-missing value or None, if no value is found. 

12405 

12406 See the :ref:`User Guide <missing_data>` for more information 

12407 on which values are considered missing. 

12408 

12409 Returns 

12410 ------- 

12411 type of index 

12412 Index of first non-missing value. 

12413 

12414 See Also 

12415 -------- 

12416 DataFrame.last_valid_index : Return index for last non-NA value or None, if 

12417 no non-NA value is found. 

12418 Series.last_valid_index : Return index for last non-NA value or None, if no 

12419 non-NA value is found. 

12420 DataFrame.isna : Detect missing values. 

12421 

12422 Examples 

12423 -------- 

12424 For Series: 

12425 

12426 >>> s = pd.Series([None, 3, 4]) 

12427 >>> s.first_valid_index() 

12428 1 

12429 >>> s.last_valid_index() 

12430 2 

12431 

12432 >>> s = pd.Series([None, None]) 

12433 >>> print(s.first_valid_index()) 

12434 None 

12435 >>> print(s.last_valid_index()) 

12436 None 

12437 

12438 If all elements in Series are NA/null, returns None. 

12439 

12440 >>> s = pd.Series() 

12441 >>> print(s.first_valid_index()) 

12442 None 

12443 >>> print(s.last_valid_index()) 

12444 None 

12445 

12446 If Series is empty, returns None. 

12447 

12448 For DataFrame: 

12449 

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

12451 >>> df 

12452 A B 

12453 0 NaN NaN 

12454 1 NaN 3.0 

12455 2 2.0 4.0 

12456 >>> df.first_valid_index() 

12457 1 

12458 >>> df.last_valid_index() 

12459 2 

12460 

12461 >>> df = pd.DataFrame({"A": [None, None, None], "B": [None, None, None]}) 

12462 >>> df 

12463 A B 

12464 0 None None 

12465 1 None None 

12466 2 None None 

12467 >>> print(df.first_valid_index()) 

12468 None 

12469 >>> print(df.last_valid_index()) 

12470 None 

12471 

12472 If all elements in DataFrame are NA/null, returns None. 

12473 

12474 >>> df = pd.DataFrame() 

12475 >>> df 

12476 Empty DataFrame 

12477 Columns: [] 

12478 Index: [] 

12479 >>> print(df.first_valid_index()) 

12480 None 

12481 >>> print(df.last_valid_index()) 

12482 None 

12483 

12484 If DataFrame is empty, returns None. 

12485 """ 

12486 return self._find_valid_index(how="first") 

12487 

12488 @final 

12489 def last_valid_index(self) -> Hashable: 

12490 """ 

12491 Return index for last non-missing value or None, if no value is found. 

12492 

12493 See the :ref:`User Guide <missing_data>` for more information 

12494 on which values are considered missing. 

12495 

12496 Returns 

12497 ------- 

12498 type of index 

12499 Index of last non-missing value. 

12500 

12501 See Also 

12502 -------- 

12503 DataFrame.first_valid_index : Return index for first non-NA value or None, if 

12504 no non-NA value is found. 

12505 Series.first_valid_index : Return index for first non-NA value or None, if no 

12506 non-NA value is found. 

12507 DataFrame.isna : Detect missing values. 

12508 

12509 Examples 

12510 -------- 

12511 For Series: 

12512 

12513 >>> s = pd.Series([None, 3, 4]) 

12514 >>> s.first_valid_index() 

12515 1 

12516 >>> s.last_valid_index() 

12517 2 

12518 

12519 >>> s = pd.Series([None, None]) 

12520 >>> print(s.first_valid_index()) 

12521 None 

12522 >>> print(s.last_valid_index()) 

12523 None 

12524 

12525 If all elements in Series are NA/null, returns None. 

12526 

12527 >>> s = pd.Series() 

12528 >>> print(s.first_valid_index()) 

12529 None 

12530 >>> print(s.last_valid_index()) 

12531 None 

12532 

12533 If Series is empty, returns None. 

12534 

12535 For DataFrame: 

12536 

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

12538 >>> df 

12539 A B 

12540 0 NaN NaN 

12541 1 NaN 3.0 

12542 2 2.0 4.0 

12543 >>> df.first_valid_index() 

12544 1 

12545 >>> df.last_valid_index() 

12546 2 

12547 

12548 >>> df = pd.DataFrame({"A": [None, None, None], "B": [None, None, None]}) 

12549 >>> df 

12550 A B 

12551 0 None None 

12552 1 None None 

12553 2 None None 

12554 >>> print(df.first_valid_index()) 

12555 None 

12556 >>> print(df.last_valid_index()) 

12557 None 

12558 

12559 If all elements in DataFrame are NA/null, returns None. 

12560 

12561 >>> df = pd.DataFrame() 

12562 >>> df 

12563 Empty DataFrame 

12564 Columns: [] 

12565 Index: [] 

12566 >>> print(df.first_valid_index()) 

12567 None 

12568 >>> print(df.last_valid_index()) 

12569 None 

12570 

12571 If DataFrame is empty, returns None. 

12572 """ 

12573 return self._find_valid_index(how="last") 

12574 

12575 

12576_num_doc = """ 

12577{desc} 

12578 

12579Parameters 

12580---------- 

12581axis : {axis_descr} 

12582 Axis for the function to be applied on. 

12583 For `Series` this parameter is unused and defaults to 0. 

12584 

12585 For DataFrames, specifying ``axis=None`` will apply the aggregation 

12586 across both axes. 

12587 

12588 .. versionadded:: 2.0.0 

12589 

12590skipna : bool, default True 

12591 Exclude NA/null values when computing the result. 

12592numeric_only : bool, default False 

12593 Include only float, int, boolean columns. 

12594 

12595{min_count}\ 

12596**kwargs 

12597 Additional keyword arguments to be passed to the function. 

12598 

12599Returns 

12600------- 

12601{name1} or scalar\ 

12602 

12603 Value containing the calculation referenced in the description.\ 

12604{see_also}\ 

12605{examples} 

12606""" 

12607 

12608_sum_prod_doc = """ 

12609{desc} 

12610 

12611Parameters 

12612---------- 

12613axis : {axis_descr} 

12614 Axis for the function to be applied on. 

12615 For `Series` this parameter is unused and defaults to 0. 

12616 

12617 .. warning:: 

12618 

12619 The behavior of DataFrame.{name} with ``axis=None`` is deprecated, 

12620 in a future version this will reduce over both axes and return a scalar 

12621 To retain the old behavior, pass axis=0 (or do not pass axis). 

12622 

12623 .. versionadded:: 2.0.0 

12624 

12625skipna : bool, default True 

12626 Exclude NA/null values when computing the result. 

12627numeric_only : bool, default False 

12628 Include only float, int, boolean columns. Not implemented for Series. 

12629 

12630{min_count}\ 

12631**kwargs 

12632 Additional keyword arguments to be passed to the function. 

12633 

12634Returns 

12635------- 

12636{name1} or scalar\ 

12637 

12638 Value containing the calculation referenced in the description.\ 

12639{see_also}\ 

12640{examples} 

12641""" 

12642 

12643_num_ddof_doc = """ 

12644{desc} 

12645 

12646Parameters 

12647---------- 

12648axis : {axis_descr} 

12649 For `Series` this parameter is unused and defaults to 0. 

12650 

12651 .. warning:: 

12652 

12653 The behavior of DataFrame.{name} with ``axis=None`` is deprecated, 

12654 in a future version this will reduce over both axes and return a scalar 

12655 To retain the old behavior, pass axis=0 (or do not pass axis). 

12656 

12657skipna : bool, default True 

12658 Exclude NA/null values. If an entire row/column is NA, the result 

12659 will be NA. 

12660ddof : int, default 1 

12661 Delta Degrees of Freedom. The divisor used in calculations is N - ddof, 

12662 where N represents the number of elements. 

12663numeric_only : bool, default False 

12664 Include only float, int, boolean columns. Not implemented for Series. 

12665**kwargs : 

12666 Additional keywords have no effect but might be accepted 

12667 for compatibility with NumPy. 

12668 

12669Returns 

12670------- 

12671{name1} or {name2} (if level specified) 

12672 {return_desc} 

12673 

12674See Also 

12675-------- 

12676{see_also}\ 

12677{notes}\ 

12678{examples} 

12679""" 

12680 

12681_sem_see_also = """\ 

12682scipy.stats.sem : Compute standard error of the mean. 

12683{name2}.std : Return sample standard deviation over requested axis. 

12684{name2}.var : Return unbiased variance over requested axis. 

12685{name2}.mean : Return the mean of the values over the requested axis. 

12686{name2}.median : Return the median of the values over the requested axis. 

12687{name2}.mode : Return the mode(s) of the Series.""" 

12688 

12689_sem_return_desc = """\ 

12690Unbiased standard error of the mean over requested axis.""" 

12691 

12692_std_see_also = """\ 

12693numpy.std : Compute the standard deviation along the specified axis. 

12694{name2}.var : Return unbiased variance over requested axis. 

12695{name2}.sem : Return unbiased standard error of the mean over requested axis. 

12696{name2}.mean : Return the mean of the values over the requested axis. 

12697{name2}.median : Return the median of the values over the requested axis. 

12698{name2}.mode : Return the mode(s) of the Series.""" 

12699 

12700_std_return_desc = """\ 

12701Standard deviation over requested axis.""" 

12702 

12703_std_notes = """ 

12704 

12705Notes 

12706----- 

12707To have the same behaviour as `numpy.std`, use `ddof=0` (instead of the 

12708default `ddof=1`)""" 

12709 

12710_std_examples = """ 

12711 

12712Examples 

12713-------- 

12714>>> df = pd.DataFrame({'person_id': [0, 1, 2, 3], 

12715... 'age': [21, 25, 62, 43], 

12716... 'height': [1.61, 1.87, 1.49, 2.01]} 

12717... ).set_index('person_id') 

12718>>> df 

12719 age height 

12720person_id 

127210 21 1.61 

127221 25 1.87 

127232 62 1.49 

127243 43 2.01 

12725 

12726The standard deviation of the columns can be found as follows: 

12727 

12728>>> df.std() 

12729age 18.786076 

12730height 0.237417 

12731dtype: float64 

12732 

12733Alternatively, `ddof=0` can be set to normalize by N instead of N-1: 

12734 

12735>>> df.std(ddof=0) 

12736age 16.269219 

12737height 0.205609 

12738dtype: float64""" 

12739 

12740_var_examples = """ 

12741 

12742Examples 

12743-------- 

12744>>> df = pd.DataFrame({'person_id': [0, 1, 2, 3], 

12745... 'age': [21, 25, 62, 43], 

12746... 'height': [1.61, 1.87, 1.49, 2.01]} 

12747... ).set_index('person_id') 

12748>>> df 

12749 age height 

12750person_id 

127510 21 1.61 

127521 25 1.87 

127532 62 1.49 

127543 43 2.01 

12755 

12756>>> df.var() 

12757age 352.916667 

12758height 0.056367 

12759dtype: float64 

12760 

12761Alternatively, ``ddof=0`` can be set to normalize by N instead of N-1: 

12762 

12763>>> df.var(ddof=0) 

12764age 264.687500 

12765height 0.042275 

12766dtype: float64""" 

12767 

12768_bool_doc = """ 

12769{desc} 

12770 

12771Parameters 

12772---------- 

12773axis : {{0 or 'index', 1 or 'columns', None}}, default 0 

12774 Indicate which axis or axes should be reduced. For `Series` this parameter 

12775 is unused and defaults to 0. 

12776 

12777 * 0 / 'index' : reduce the index, return a Series whose index is the 

12778 original column labels. 

12779 * 1 / 'columns' : reduce the columns, return a Series whose index is the 

12780 original index. 

12781 * None : reduce all axes, return a scalar. 

12782 

12783bool_only : bool, default False 

12784 Include only boolean columns. Not implemented for Series. 

12785skipna : bool, default True 

12786 Exclude NA/null values. If the entire row/column is NA and skipna is 

12787 True, then the result will be {empty_value}, as for an empty row/column. 

12788 If skipna is False, then NA are treated as True, because these are not 

12789 equal to zero. 

12790**kwargs : any, default None 

12791 Additional keywords have no effect but might be accepted for 

12792 compatibility with NumPy. 

12793 

12794Returns 

12795------- 

12796{name2} or {name1} 

12797 If axis=None, then a scalar boolean is returned. 

12798 Otherwise a Series is returned with index matching the index argument. 

12799 

12800{see_also} 

12801{examples}""" 

12802 

12803_all_desc = """\ 

12804Return whether all elements are True, potentially over an axis. 

12805 

12806Returns True unless there at least one element within a series or 

12807along a Dataframe axis that is False or equivalent (e.g. zero or 

12808empty).""" 

12809 

12810_all_examples = """\ 

12811Examples 

12812-------- 

12813**Series** 

12814 

12815>>> pd.Series([True, True]).all() 

12816True 

12817>>> pd.Series([True, False]).all() 

12818False 

12819>>> pd.Series([], dtype="float64").all() 

12820True 

12821>>> pd.Series([np.nan]).all() 

12822True 

12823>>> pd.Series([np.nan]).all(skipna=False) 

12824True 

12825 

12826**DataFrames** 

12827 

12828Create a DataFrame from a dictionary. 

12829 

12830>>> df = pd.DataFrame({'col1': [True, True], 'col2': [True, False]}) 

12831>>> df 

12832 col1 col2 

128330 True True 

128341 True False 

12835 

12836Default behaviour checks if values in each column all return True. 

12837 

12838>>> df.all() 

12839col1 True 

12840col2 False 

12841dtype: bool 

12842 

12843Specify ``axis='columns'`` to check if values in each row all return True. 

12844 

12845>>> df.all(axis='columns') 

128460 True 

128471 False 

12848dtype: bool 

12849 

12850Or ``axis=None`` for whether every value is True. 

12851 

12852>>> df.all(axis=None) 

12853False 

12854""" 

12855 

12856_all_see_also = """\ 

12857See Also 

12858-------- 

12859Series.all : Return True if all elements are True. 

12860DataFrame.any : Return True if one (or more) elements are True. 

12861""" 

12862 

12863_cnum_pd_doc = """ 

12864Return cumulative {desc} over a DataFrame or Series axis. 

12865 

12866Returns a DataFrame or Series of the same size containing the cumulative 

12867{desc}. 

12868 

12869Parameters 

12870---------- 

12871axis : {{0 or 'index', 1 or 'columns'}}, default 0 

12872 The index or the name of the axis. 0 is equivalent to None or 'index'. 

12873 For `Series` this parameter is unused and defaults to 0. 

12874skipna : bool, default True 

12875 Exclude NA/null values. If an entire row/column is NA, the result 

12876 will be NA. 

12877numeric_only : bool, default False 

12878 Include only float, int, boolean columns. 

12879*args, **kwargs 

12880 Additional keywords have no effect but might be accepted for 

12881 compatibility with NumPy. 

12882 

12883Returns 

12884------- 

12885{name1} or {name2} 

12886 Return cumulative {desc} of {name1} or {name2}. 

12887 

12888See Also 

12889-------- 

12890core.window.expanding.Expanding.{accum_func_name} : Similar functionality 

12891 but ignores ``NaN`` values. 

12892{name2}.{accum_func_name} : Return the {desc} over 

12893 {name2} axis. 

12894{name2}.cummax : Return cumulative maximum over {name2} axis. 

12895{name2}.cummin : Return cumulative minimum over {name2} axis. 

12896{name2}.cumsum : Return cumulative sum over {name2} axis. 

12897{name2}.cumprod : Return cumulative product over {name2} axis. 

12898 

12899{examples}""" 

12900 

12901_cnum_series_doc = """ 

12902Return cumulative {desc} over a DataFrame or Series axis. 

12903 

12904Returns a DataFrame or Series of the same size containing the cumulative 

12905{desc}. 

12906 

12907Parameters 

12908---------- 

12909axis : {{0 or 'index', 1 or 'columns'}}, default 0 

12910 The index or the name of the axis. 0 is equivalent to None or 'index'. 

12911 For `Series` this parameter is unused and defaults to 0. 

12912skipna : bool, default True 

12913 Exclude NA/null values. If an entire row/column is NA, the result 

12914 will be NA. 

12915*args, **kwargs 

12916 Additional keywords have no effect but might be accepted for 

12917 compatibility with NumPy. 

12918 

12919Returns 

12920------- 

12921{name1} or {name2} 

12922 Return cumulative {desc} of {name1} or {name2}. 

12923 

12924See Also 

12925-------- 

12926core.window.expanding.Expanding.{accum_func_name} : Similar functionality 

12927 but ignores ``NaN`` values. 

12928{name2}.{accum_func_name} : Return the {desc} over 

12929 {name2} axis. 

12930{name2}.cummax : Return cumulative maximum over {name2} axis. 

12931{name2}.cummin : Return cumulative minimum over {name2} axis. 

12932{name2}.cumsum : Return cumulative sum over {name2} axis. 

12933{name2}.cumprod : Return cumulative product over {name2} axis. 

12934 

12935{examples}""" 

12936 

12937_cummin_examples = """\ 

12938Examples 

12939-------- 

12940**Series** 

12941 

12942>>> s = pd.Series([2, np.nan, 5, -1, 0]) 

12943>>> s 

129440 2.0 

129451 NaN 

129462 5.0 

129473 -1.0 

129484 0.0 

12949dtype: float64 

12950 

12951By default, NA values are ignored. 

12952 

12953>>> s.cummin() 

129540 2.0 

129551 NaN 

129562 2.0 

129573 -1.0 

129584 -1.0 

12959dtype: float64 

12960 

12961To include NA values in the operation, use ``skipna=False`` 

12962 

12963>>> s.cummin(skipna=False) 

129640 2.0 

129651 NaN 

129662 NaN 

129673 NaN 

129684 NaN 

12969dtype: float64 

12970 

12971**DataFrame** 

12972 

12973>>> df = pd.DataFrame([[2.0, 1.0], 

12974... [3.0, np.nan], 

12975... [1.0, 0.0]], 

12976... columns=list('AB')) 

12977>>> df 

12978 A B 

129790 2.0 1.0 

129801 3.0 NaN 

129812 1.0 0.0 

12982 

12983By default, iterates over rows and finds the minimum 

12984in each column. This is equivalent to ``axis=None`` or ``axis='index'``. 

12985 

12986>>> df.cummin() 

12987 A B 

129880 2.0 1.0 

129891 2.0 NaN 

129902 1.0 0.0 

12991 

12992To iterate over columns and find the minimum in each row, 

12993use ``axis=1`` 

12994 

12995>>> df.cummin(axis=1) 

12996 A B 

129970 2.0 1.0 

129981 3.0 NaN 

129992 1.0 0.0 

13000""" 

13001 

13002_cumsum_examples = """\ 

13003Examples 

13004-------- 

13005**Series** 

13006 

13007>>> s = pd.Series([2, np.nan, 5, -1, 0]) 

13008>>> s 

130090 2.0 

130101 NaN 

130112 5.0 

130123 -1.0 

130134 0.0 

13014dtype: float64 

13015 

13016By default, NA values are ignored. 

13017 

13018>>> s.cumsum() 

130190 2.0 

130201 NaN 

130212 7.0 

130223 6.0 

130234 6.0 

13024dtype: float64 

13025 

13026To include NA values in the operation, use ``skipna=False`` 

13027 

13028>>> s.cumsum(skipna=False) 

130290 2.0 

130301 NaN 

130312 NaN 

130323 NaN 

130334 NaN 

13034dtype: float64 

13035 

13036**DataFrame** 

13037 

13038>>> df = pd.DataFrame([[2.0, 1.0], 

13039... [3.0, np.nan], 

13040... [1.0, 0.0]], 

13041... columns=list('AB')) 

13042>>> df 

13043 A B 

130440 2.0 1.0 

130451 3.0 NaN 

130462 1.0 0.0 

13047 

13048By default, iterates over rows and finds the sum 

13049in each column. This is equivalent to ``axis=None`` or ``axis='index'``. 

13050 

13051>>> df.cumsum() 

13052 A B 

130530 2.0 1.0 

130541 5.0 NaN 

130552 6.0 1.0 

13056 

13057To iterate over columns and find the sum in each row, 

13058use ``axis=1`` 

13059 

13060>>> df.cumsum(axis=1) 

13061 A B 

130620 2.0 3.0 

130631 3.0 NaN 

130642 1.0 1.0 

13065""" 

13066 

13067_cumprod_examples = """\ 

13068Examples 

13069-------- 

13070**Series** 

13071 

13072>>> s = pd.Series([2, np.nan, 5, -1, 0]) 

13073>>> s 

130740 2.0 

130751 NaN 

130762 5.0 

130773 -1.0 

130784 0.0 

13079dtype: float64 

13080 

13081By default, NA values are ignored. 

13082 

13083>>> s.cumprod() 

130840 2.0 

130851 NaN 

130862 10.0 

130873 -10.0 

130884 -0.0 

13089dtype: float64 

13090 

13091To include NA values in the operation, use ``skipna=False`` 

13092 

13093>>> s.cumprod(skipna=False) 

130940 2.0 

130951 NaN 

130962 NaN 

130973 NaN 

130984 NaN 

13099dtype: float64 

13100 

13101**DataFrame** 

13102 

13103>>> df = pd.DataFrame([[2.0, 1.0], 

13104... [3.0, np.nan], 

13105... [1.0, 0.0]], 

13106... columns=list('AB')) 

13107>>> df 

13108 A B 

131090 2.0 1.0 

131101 3.0 NaN 

131112 1.0 0.0 

13112 

13113By default, iterates over rows and finds the product 

13114in each column. This is equivalent to ``axis=None`` or ``axis='index'``. 

13115 

13116>>> df.cumprod() 

13117 A B 

131180 2.0 1.0 

131191 6.0 NaN 

131202 6.0 0.0 

13121 

13122To iterate over columns and find the product in each row, 

13123use ``axis=1`` 

13124 

13125>>> df.cumprod(axis=1) 

13126 A B 

131270 2.0 2.0 

131281 3.0 NaN 

131292 1.0 0.0 

13130""" 

13131 

13132_cummax_examples = """\ 

13133Examples 

13134-------- 

13135**Series** 

13136 

13137>>> s = pd.Series([2, np.nan, 5, -1, 0]) 

13138>>> s 

131390 2.0 

131401 NaN 

131412 5.0 

131423 -1.0 

131434 0.0 

13144dtype: float64 

13145 

13146By default, NA values are ignored. 

13147 

13148>>> s.cummax() 

131490 2.0 

131501 NaN 

131512 5.0 

131523 5.0 

131534 5.0 

13154dtype: float64 

13155 

13156To include NA values in the operation, use ``skipna=False`` 

13157 

13158>>> s.cummax(skipna=False) 

131590 2.0 

131601 NaN 

131612 NaN 

131623 NaN 

131634 NaN 

13164dtype: float64 

13165 

13166**DataFrame** 

13167 

13168>>> df = pd.DataFrame([[2.0, 1.0], 

13169... [3.0, np.nan], 

13170... [1.0, 0.0]], 

13171... columns=list('AB')) 

13172>>> df 

13173 A B 

131740 2.0 1.0 

131751 3.0 NaN 

131762 1.0 0.0 

13177 

13178By default, iterates over rows and finds the maximum 

13179in each column. This is equivalent to ``axis=None`` or ``axis='index'``. 

13180 

13181>>> df.cummax() 

13182 A B 

131830 2.0 1.0 

131841 3.0 NaN 

131852 3.0 1.0 

13186 

13187To iterate over columns and find the maximum in each row, 

13188use ``axis=1`` 

13189 

13190>>> df.cummax(axis=1) 

13191 A B 

131920 2.0 2.0 

131931 3.0 NaN 

131942 1.0 1.0 

13195""" 

13196 

13197_any_see_also = """\ 

13198See Also 

13199-------- 

13200numpy.any : Numpy version of this method. 

13201Series.any : Return whether any element is True. 

13202Series.all : Return whether all elements are True. 

13203DataFrame.any : Return whether any element is True over requested axis. 

13204DataFrame.all : Return whether all elements are True over requested axis. 

13205""" 

13206 

13207_any_desc = """\ 

13208Return whether any element is True, potentially over an axis. 

13209 

13210Returns False unless there is at least one element within a series or 

13211along a Dataframe axis that is True or equivalent (e.g. non-zero or 

13212non-empty).""" 

13213 

13214_any_examples = """\ 

13215Examples 

13216-------- 

13217**Series** 

13218 

13219For Series input, the output is a scalar indicating whether any element 

13220is True. 

13221 

13222>>> pd.Series([False, False]).any() 

13223False 

13224>>> pd.Series([True, False]).any() 

13225True 

13226>>> pd.Series([], dtype="float64").any() 

13227False 

13228>>> pd.Series([np.nan]).any() 

13229False 

13230>>> pd.Series([np.nan]).any(skipna=False) 

13231True 

13232 

13233**DataFrame** 

13234 

13235Whether each column contains at least one True element (the default). 

13236 

13237>>> df = pd.DataFrame({"A": [1, 2], "B": [0, 2], "C": [0, 0]}) 

13238>>> df 

13239 A B C 

132400 1 0 0 

132411 2 2 0 

13242 

13243>>> df.any() 

13244A True 

13245B True 

13246C False 

13247dtype: bool 

13248 

13249Aggregating over the columns. 

13250 

13251>>> df = pd.DataFrame({"A": [True, False], "B": [1, 2]}) 

13252>>> df 

13253 A B 

132540 True 1 

132551 False 2 

13256 

13257>>> df.any(axis='columns') 

132580 True 

132591 True 

13260dtype: bool 

13261 

13262>>> df = pd.DataFrame({"A": [True, False], "B": [1, 0]}) 

13263>>> df 

13264 A B 

132650 True 1 

132661 False 0 

13267 

13268>>> df.any(axis='columns') 

132690 True 

132701 False 

13271dtype: bool 

13272 

13273Aggregating over the entire DataFrame with ``axis=None``. 

13274 

13275>>> df.any(axis=None) 

13276True 

13277 

13278`any` for an empty DataFrame is an empty Series. 

13279 

13280>>> pd.DataFrame([]).any() 

13281Series([], dtype: bool) 

13282""" 

13283 

13284_shared_docs["stat_func_example"] = """ 

13285 

13286Examples 

13287-------- 

13288>>> idx = pd.MultiIndex.from_arrays([ 

13289... ['warm', 'warm', 'cold', 'cold'], 

13290... ['dog', 'falcon', 'fish', 'spider']], 

13291... names=['blooded', 'animal']) 

13292>>> s = pd.Series([4, 2, 0, 8], name='legs', index=idx) 

13293>>> s 

13294blooded animal 

13295warm dog 4 

13296 falcon 2 

13297cold fish 0 

13298 spider 8 

13299Name: legs, dtype: int64 

13300 

13301>>> s.{stat_func}() 

13302{default_output}""" 

13303 

13304_sum_examples = _shared_docs["stat_func_example"].format( 

13305 stat_func="sum", verb="Sum", default_output=14, level_output_0=6, level_output_1=8 

13306) 

13307 

13308_sum_examples += """ 

13309 

13310By default, the sum of an empty or all-NA Series is ``0``. 

13311 

13312>>> pd.Series([], dtype="float64").sum() # min_count=0 is the default 

133130.0 

13314 

13315This can be controlled with the ``min_count`` parameter. For example, if 

13316you'd like the sum of an empty series to be NaN, pass ``min_count=1``. 

13317 

13318>>> pd.Series([], dtype="float64").sum(min_count=1) 

13319nan 

13320 

13321Thanks to the ``skipna`` parameter, ``min_count`` handles all-NA and 

13322empty series identically. 

13323 

13324>>> pd.Series([np.nan]).sum() 

133250.0 

13326 

13327>>> pd.Series([np.nan]).sum(min_count=1) 

13328nan""" 

13329 

13330_max_examples: str = _shared_docs["stat_func_example"].format( 

13331 stat_func="max", verb="Max", default_output=8, level_output_0=4, level_output_1=8 

13332) 

13333 

13334_min_examples: str = _shared_docs["stat_func_example"].format( 

13335 stat_func="min", verb="Min", default_output=0, level_output_0=2, level_output_1=0 

13336) 

13337 

13338_skew_see_also = """ 

13339 

13340See Also 

13341-------- 

13342Series.skew : Return unbiased skew over requested axis. 

13343Series.var : Return unbiased variance over requested axis. 

13344Series.std : Return unbiased standard deviation over requested axis.""" 

13345 

13346_stat_func_see_also = """ 

13347 

13348See Also 

13349-------- 

13350Series.sum : Return the sum. 

13351Series.min : Return the minimum. 

13352Series.max : Return the maximum. 

13353Series.idxmin : Return the index of the minimum. 

13354Series.idxmax : Return the index of the maximum. 

13355DataFrame.sum : Return the sum over the requested axis. 

13356DataFrame.min : Return the minimum over the requested axis. 

13357DataFrame.max : Return the maximum over the requested axis. 

13358DataFrame.idxmin : Return the index of the minimum over the requested axis. 

13359DataFrame.idxmax : Return the index of the maximum over the requested axis.""" 

13360 

13361_prod_examples = """ 

13362 

13363Examples 

13364-------- 

13365By default, the product of an empty or all-NA Series is ``1`` 

13366 

13367>>> pd.Series([], dtype="float64").prod() 

133681.0 

13369 

13370This can be controlled with the ``min_count`` parameter 

13371 

13372>>> pd.Series([], dtype="float64").prod(min_count=1) 

13373nan 

13374 

13375Thanks to the ``skipna`` parameter, ``min_count`` handles all-NA and 

13376empty series identically. 

13377 

13378>>> pd.Series([np.nan]).prod() 

133791.0 

13380 

13381>>> pd.Series([np.nan]).prod(min_count=1) 

13382nan""" 

13383 

13384_min_count_stub = """\ 

13385min_count : int, default 0 

13386 The required number of valid values to perform the operation. If fewer than 

13387 ``min_count`` non-NA values are present the result will be NA. 

13388""" 

13389 

13390 

13391def make_doc(name: str, ndim: int) -> str: 

13392 """ 

13393 Generate the docstring for a Series/DataFrame reduction. 

13394 """ 

13395 if ndim == 1: 

13396 name1 = "scalar" 

13397 name2 = "Series" 

13398 axis_descr = "{index (0)}" 

13399 else: 

13400 name1 = "Series" 

13401 name2 = "DataFrame" 

13402 axis_descr = "{index (0), columns (1)}" 

13403 

13404 if name == "any": 

13405 base_doc = _bool_doc 

13406 desc = _any_desc 

13407 see_also = _any_see_also 

13408 examples = _any_examples 

13409 kwargs = {"empty_value": "False"} 

13410 elif name == "all": 

13411 base_doc = _bool_doc 

13412 desc = _all_desc 

13413 see_also = _all_see_also 

13414 examples = _all_examples 

13415 kwargs = {"empty_value": "True"} 

13416 elif name == "min": 

13417 base_doc = _num_doc 

13418 desc = ( 

13419 "Return the minimum of the values over the requested axis.\n\n" 

13420 "If you want the *index* of the minimum, use ``idxmin``. This is " 

13421 "the equivalent of the ``numpy.ndarray`` method ``argmin``." 

13422 ) 

13423 see_also = _stat_func_see_also 

13424 examples = _min_examples 

13425 kwargs = {"min_count": ""} 

13426 elif name == "max": 

13427 base_doc = _num_doc 

13428 desc = ( 

13429 "Return the maximum of the values over the requested axis.\n\n" 

13430 "If you want the *index* of the maximum, use ``idxmax``. This is " 

13431 "the equivalent of the ``numpy.ndarray`` method ``argmax``." 

13432 ) 

13433 see_also = _stat_func_see_also 

13434 examples = _max_examples 

13435 kwargs = {"min_count": ""} 

13436 

13437 elif name == "sum": 

13438 base_doc = _sum_prod_doc 

13439 desc = ( 

13440 "Return the sum of the values over the requested axis.\n\n" 

13441 "This is equivalent to the method ``numpy.sum``." 

13442 ) 

13443 see_also = _stat_func_see_also 

13444 examples = _sum_examples 

13445 kwargs = {"min_count": _min_count_stub} 

13446 

13447 elif name == "prod": 

13448 base_doc = _sum_prod_doc 

13449 desc = "Return the product of the values over the requested axis." 

13450 see_also = _stat_func_see_also 

13451 examples = _prod_examples 

13452 kwargs = {"min_count": _min_count_stub} 

13453 

13454 elif name == "median": 

13455 base_doc = _num_doc 

13456 desc = "Return the median of the values over the requested axis." 

13457 see_also = _stat_func_see_also 

13458 examples = """ 

13459 

13460 Examples 

13461 -------- 

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

13463 >>> s.median() 

13464 2.0 

13465 

13466 With a DataFrame 

13467 

13468 >>> df = pd.DataFrame({'a': [1, 2], 'b': [2, 3]}, index=['tiger', 'zebra']) 

13469 >>> df 

13470 a b 

13471 tiger 1 2 

13472 zebra 2 3 

13473 >>> df.median() 

13474 a 1.5 

13475 b 2.5 

13476 dtype: float64 

13477 

13478 Using axis=1 

13479 

13480 >>> df.median(axis=1) 

13481 tiger 1.5 

13482 zebra 2.5 

13483 dtype: float64 

13484 

13485 In this case, `numeric_only` should be set to `True` 

13486 to avoid getting an error. 

13487 

13488 >>> df = pd.DataFrame({'a': [1, 2], 'b': ['T', 'Z']}, 

13489 ... index=['tiger', 'zebra']) 

13490 >>> df.median(numeric_only=True) 

13491 a 1.5 

13492 dtype: float64""" 

13493 kwargs = {"min_count": ""} 

13494 

13495 elif name == "mean": 

13496 base_doc = _num_doc 

13497 desc = "Return the mean of the values over the requested axis." 

13498 see_also = _stat_func_see_also 

13499 examples = """ 

13500 

13501 Examples 

13502 -------- 

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

13504 >>> s.mean() 

13505 2.0 

13506 

13507 With a DataFrame 

13508 

13509 >>> df = pd.DataFrame({'a': [1, 2], 'b': [2, 3]}, index=['tiger', 'zebra']) 

13510 >>> df 

13511 a b 

13512 tiger 1 2 

13513 zebra 2 3 

13514 >>> df.mean() 

13515 a 1.5 

13516 b 2.5 

13517 dtype: float64 

13518 

13519 Using axis=1 

13520 

13521 >>> df.mean(axis=1) 

13522 tiger 1.5 

13523 zebra 2.5 

13524 dtype: float64 

13525 

13526 In this case, `numeric_only` should be set to `True` to avoid 

13527 getting an error. 

13528 

13529 >>> df = pd.DataFrame({'a': [1, 2], 'b': ['T', 'Z']}, 

13530 ... index=['tiger', 'zebra']) 

13531 >>> df.mean(numeric_only=True) 

13532 a 1.5 

13533 dtype: float64""" 

13534 kwargs = {"min_count": ""} 

13535 

13536 elif name == "var": 

13537 base_doc = _num_ddof_doc 

13538 desc = ( 

13539 "Return unbiased variance over requested axis.\n\nNormalized by " 

13540 "N-1 by default. This can be changed using the ddof argument." 

13541 ) 

13542 examples = _var_examples 

13543 see_also = "" 

13544 kwargs = {"notes": ""} 

13545 

13546 elif name == "std": 

13547 base_doc = _num_ddof_doc 

13548 desc = ( 

13549 "Return sample standard deviation over requested axis." 

13550 "\n\nNormalized by N-1 by default. This can be changed using the " 

13551 "ddof argument." 

13552 ) 

13553 examples = _std_examples 

13554 see_also = _std_see_also.format(name2=name2) 

13555 kwargs = {"notes": "", "return_desc": _std_return_desc} 

13556 

13557 elif name == "sem": 

13558 base_doc = _num_ddof_doc 

13559 desc = ( 

13560 "Return unbiased standard error of the mean over requested " 

13561 "axis.\n\nNormalized by N-1 by default. This can be changed " 

13562 "using the ddof argument" 

13563 ) 

13564 examples = """ 

13565 

13566 Examples 

13567 -------- 

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

13569 >>> round(s.sem(), 6) 

13570 0.57735 

13571 

13572 With a DataFrame 

13573 

13574 >>> df = pd.DataFrame({'a': [1, 2], 'b': [2, 3]}, index=['tiger', 'zebra']) 

13575 >>> df 

13576 a b 

13577 tiger 1 2 

13578 zebra 2 3 

13579 >>> df.sem() 

13580 a 0.5 

13581 b 0.5 

13582 dtype: float64 

13583 

13584 Using axis=1 

13585 

13586 >>> df.sem(axis=1) 

13587 tiger 0.5 

13588 zebra 0.5 

13589 dtype: float64 

13590 

13591 In this case, `numeric_only` should be set to `True` 

13592 to avoid getting an error. 

13593 

13594 >>> df = pd.DataFrame({'a': [1, 2], 'b': ['T', 'Z']}, 

13595 ... index=['tiger', 'zebra']) 

13596 >>> df.sem(numeric_only=True) 

13597 a 0.5 

13598 dtype: float64""" 

13599 see_also = _sem_see_also.format(name2=name2) 

13600 kwargs = {"notes": "", "return_desc": _sem_return_desc} 

13601 

13602 elif name == "skew": 

13603 base_doc = _num_doc 

13604 desc = "Return unbiased skew over requested axis.\n\nNormalized by N-1." 

13605 see_also = _skew_see_also 

13606 examples = """ 

13607 

13608 Examples 

13609 -------- 

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

13611 >>> s.skew() 

13612 0.0 

13613 

13614 With a DataFrame 

13615 

13616 >>> df = pd.DataFrame({'a': [1, 2, 3], 'b': [2, 3, 4], 'c': [1, 3, 5]}, 

13617 ... index=['tiger', 'zebra', 'cow']) 

13618 >>> df 

13619 a b c 

13620 tiger 1 2 1 

13621 zebra 2 3 3 

13622 cow 3 4 5 

13623 >>> df.skew() 

13624 a 0.0 

13625 b 0.0 

13626 c 0.0 

13627 dtype: float64 

13628 

13629 Using axis=1 

13630 

13631 >>> df.skew(axis=1) 

13632 tiger 1.732051 

13633 zebra -1.732051 

13634 cow 0.000000 

13635 dtype: float64 

13636 

13637 In this case, `numeric_only` should be set to `True` to avoid 

13638 getting an error. 

13639 

13640 >>> df = pd.DataFrame({'a': [1, 2, 3], 'b': ['T', 'Z', 'X']}, 

13641 ... index=['tiger', 'zebra', 'cow']) 

13642 >>> df.skew(numeric_only=True) 

13643 a 0.0 

13644 dtype: float64""" 

13645 kwargs = {"min_count": ""} 

13646 

13647 elif name == "kurt": 

13648 base_doc = _num_doc 

13649 desc = ( 

13650 "Return unbiased kurtosis over requested axis.\n\n" 

13651 "Kurtosis obtained using Fisher's definition of\n" 

13652 "kurtosis (kurtosis of normal == 0.0). Normalized " 

13653 "by N-1." 

13654 ) 

13655 see_also = "" 

13656 examples = """ 

13657 

13658 Examples 

13659 -------- 

13660 >>> s = pd.Series([1, 2, 2, 3], index=['cat', 'dog', 'dog', 'mouse']) 

13661 >>> s 

13662 cat 1 

13663 dog 2 

13664 dog 2 

13665 mouse 3 

13666 dtype: int64 

13667 >>> s.kurt() 

13668 1.5 

13669 

13670 With a DataFrame 

13671 

13672 >>> df = pd.DataFrame({'a': [1, 2, 2, 3], 'b': [3, 4, 4, 4]}, 

13673 ... index=['cat', 'dog', 'dog', 'mouse']) 

13674 >>> df 

13675 a b 

13676 cat 1 3 

13677 dog 2 4 

13678 dog 2 4 

13679 mouse 3 4 

13680 >>> df.kurt() 

13681 a 1.5 

13682 b 4.0 

13683 dtype: float64 

13684 

13685 With axis=None 

13686 

13687 >>> df.kurt(axis=None) 

13688 -0.9886927196984727 

13689 

13690 Using axis=1 

13691 

13692 >>> df = pd.DataFrame({'a': [1, 2], 'b': [3, 4], 'c': [3, 4], 'd': [1, 2]}, 

13693 ... index=['cat', 'dog']) 

13694 >>> df.kurt(axis=1) 

13695 cat -6.0 

13696 dog -6.0 

13697 dtype: float64""" 

13698 kwargs = {"min_count": ""} 

13699 

13700 elif name == "cumsum": 

13701 if ndim == 1: 

13702 base_doc = _cnum_series_doc 

13703 else: 

13704 base_doc = _cnum_pd_doc 

13705 

13706 desc = "sum" 

13707 see_also = "" 

13708 examples = _cumsum_examples 

13709 kwargs = {"accum_func_name": "sum"} 

13710 

13711 elif name == "cumprod": 

13712 if ndim == 1: 

13713 base_doc = _cnum_series_doc 

13714 else: 

13715 base_doc = _cnum_pd_doc 

13716 

13717 desc = "product" 

13718 see_also = "" 

13719 examples = _cumprod_examples 

13720 kwargs = {"accum_func_name": "prod"} 

13721 

13722 elif name == "cummin": 

13723 if ndim == 1: 

13724 base_doc = _cnum_series_doc 

13725 else: 

13726 base_doc = _cnum_pd_doc 

13727 

13728 desc = "minimum" 

13729 see_also = "" 

13730 examples = _cummin_examples 

13731 kwargs = {"accum_func_name": "min"} 

13732 

13733 elif name == "cummax": 

13734 if ndim == 1: 

13735 base_doc = _cnum_series_doc 

13736 else: 

13737 base_doc = _cnum_pd_doc 

13738 

13739 desc = "maximum" 

13740 see_also = "" 

13741 examples = _cummax_examples 

13742 kwargs = {"accum_func_name": "max"} 

13743 

13744 else: 

13745 raise NotImplementedError 

13746 

13747 docstr = base_doc.format( 

13748 desc=desc, 

13749 name=name, 

13750 name1=name1, 

13751 name2=name2, 

13752 axis_descr=axis_descr, 

13753 see_also=see_also, 

13754 examples=examples, 

13755 **kwargs, 

13756 ) 

13757 return docstr