Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/pandas/core/series.py: 41%

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

1309 statements  

1""" 

2Data structure for 1-dimensional cross-sectional and time series data 

3""" 

4from __future__ import annotations 

5 

6from collections.abc import ( 

7 Hashable, 

8 Iterable, 

9 Mapping, 

10 Sequence, 

11) 

12import operator 

13import sys 

14from textwrap import dedent 

15from typing import ( 

16 IO, 

17 TYPE_CHECKING, 

18 Any, 

19 Callable, 

20 Literal, 

21 cast, 

22 overload, 

23) 

24import warnings 

25import weakref 

26 

27import numpy as np 

28 

29from pandas._config import ( 

30 using_copy_on_write, 

31 warn_copy_on_write, 

32) 

33from pandas._config.config import _get_option 

34 

35from pandas._libs import ( 

36 lib, 

37 properties, 

38 reshape, 

39) 

40from pandas._libs.lib import is_range_indexer 

41from pandas.compat import PYPY 

42from pandas.compat._constants import REF_COUNT 

43from pandas.compat._optional import import_optional_dependency 

44from pandas.compat.numpy import function as nv 

45from pandas.errors import ( 

46 ChainedAssignmentError, 

47 InvalidIndexError, 

48 _chained_assignment_method_msg, 

49 _chained_assignment_msg, 

50 _chained_assignment_warning_method_msg, 

51 _chained_assignment_warning_msg, 

52 _check_cacher, 

53) 

54from pandas.util._decorators import ( 

55 Appender, 

56 Substitution, 

57 deprecate_nonkeyword_arguments, 

58 doc, 

59) 

60from pandas.util._exceptions import find_stack_level 

61from pandas.util._validators import ( 

62 validate_ascending, 

63 validate_bool_kwarg, 

64 validate_percentile, 

65) 

66 

67from pandas.core.dtypes.astype import astype_is_view 

68from pandas.core.dtypes.cast import ( 

69 LossySetitemError, 

70 construct_1d_arraylike_from_scalar, 

71 find_common_type, 

72 infer_dtype_from, 

73 maybe_box_native, 

74 maybe_cast_pointwise_result, 

75) 

76from pandas.core.dtypes.common import ( 

77 is_dict_like, 

78 is_integer, 

79 is_iterator, 

80 is_list_like, 

81 is_object_dtype, 

82 is_scalar, 

83 pandas_dtype, 

84 validate_all_hashable, 

85) 

86from pandas.core.dtypes.dtypes import ( 

87 CategoricalDtype, 

88 ExtensionDtype, 

89 SparseDtype, 

90) 

91from pandas.core.dtypes.generic import ( 

92 ABCDataFrame, 

93 ABCSeries, 

94) 

95from pandas.core.dtypes.inference import is_hashable 

96from pandas.core.dtypes.missing import ( 

97 isna, 

98 na_value_for_dtype, 

99 notna, 

100 remove_na_arraylike, 

101) 

102 

103from pandas.core import ( 

104 algorithms, 

105 base, 

106 common as com, 

107 missing, 

108 nanops, 

109 ops, 

110 roperator, 

111) 

112from pandas.core.accessor import CachedAccessor 

113from pandas.core.apply import SeriesApply 

114from pandas.core.arrays import ExtensionArray 

115from pandas.core.arrays.arrow import ( 

116 ListAccessor, 

117 StructAccessor, 

118) 

119from pandas.core.arrays.categorical import CategoricalAccessor 

120from pandas.core.arrays.sparse import SparseAccessor 

121from pandas.core.arrays.string_ import StringDtype 

122from pandas.core.construction import ( 

123 array as pd_array, 

124 extract_array, 

125 sanitize_array, 

126) 

127from pandas.core.generic import ( 

128 NDFrame, 

129 make_doc, 

130) 

131from pandas.core.indexers import ( 

132 disallow_ndim_indexing, 

133 unpack_1tuple, 

134) 

135from pandas.core.indexes.accessors import CombinedDatetimelikeProperties 

136from pandas.core.indexes.api import ( 

137 DatetimeIndex, 

138 Index, 

139 MultiIndex, 

140 PeriodIndex, 

141 default_index, 

142 ensure_index, 

143) 

144import pandas.core.indexes.base as ibase 

145from pandas.core.indexes.multi import maybe_droplevels 

146from pandas.core.indexing import ( 

147 check_bool_indexer, 

148 check_dict_or_set_indexers, 

149) 

150from pandas.core.internals import ( 

151 SingleArrayManager, 

152 SingleBlockManager, 

153) 

154from pandas.core.methods import selectn 

155from pandas.core.shared_docs import _shared_docs 

156from pandas.core.sorting import ( 

157 ensure_key_mapped, 

158 nargsort, 

159) 

160from pandas.core.strings.accessor import StringMethods 

161from pandas.core.tools.datetimes import to_datetime 

162 

163import pandas.io.formats.format as fmt 

164from pandas.io.formats.info import ( 

165 INFO_DOCSTRING, 

166 SeriesInfo, 

167 series_sub_kwargs, 

168) 

169import pandas.plotting 

170 

171if TYPE_CHECKING: 

172 from pandas._libs.internals import BlockValuesRefs 

173 from pandas._typing import ( 

174 AggFuncType, 

175 AnyAll, 

176 AnyArrayLike, 

177 ArrayLike, 

178 Axis, 

179 AxisInt, 

180 CorrelationMethod, 

181 DropKeep, 

182 Dtype, 

183 DtypeObj, 

184 FilePath, 

185 Frequency, 

186 IgnoreRaise, 

187 IndexKeyFunc, 

188 IndexLabel, 

189 Level, 

190 MutableMappingT, 

191 NaPosition, 

192 NumpySorter, 

193 NumpyValueArrayLike, 

194 QuantileInterpolation, 

195 ReindexMethod, 

196 Renamer, 

197 Scalar, 

198 Self, 

199 SingleManager, 

200 SortKind, 

201 StorageOptions, 

202 Suffixes, 

203 ValueKeyFunc, 

204 WriteBuffer, 

205 npt, 

206 ) 

207 

208 from pandas.core.frame import DataFrame 

209 from pandas.core.groupby.generic import SeriesGroupBy 

210 

211__all__ = ["Series"] 

212 

213_shared_doc_kwargs = { 

214 "axes": "index", 

215 "klass": "Series", 

216 "axes_single_arg": "{0 or 'index'}", 

217 "axis": """axis : {0 or 'index'} 

218 Unused. Parameter needed for compatibility with DataFrame.""", 

219 "inplace": """inplace : bool, default False 

220 If True, performs operation inplace and returns None.""", 

221 "unique": "np.ndarray", 

222 "duplicated": "Series", 

223 "optional_by": "", 

224 "optional_reindex": """ 

225index : array-like, optional 

226 New labels for the index. Preferably an Index object to avoid 

227 duplicating data. 

228axis : int or str, optional 

229 Unused.""", 

230} 

231 

232 

233def _coerce_method(converter): 

234 """ 

235 Install the scalar coercion methods. 

236 """ 

237 

238 def wrapper(self): 

239 if len(self) == 1: 

240 warnings.warn( 

241 f"Calling {converter.__name__} on a single element Series is " 

242 "deprecated and will raise a TypeError in the future. " 

243 f"Use {converter.__name__}(ser.iloc[0]) instead", 

244 FutureWarning, 

245 stacklevel=find_stack_level(), 

246 ) 

247 return converter(self.iloc[0]) 

248 raise TypeError(f"cannot convert the series to {converter}") 

249 

250 wrapper.__name__ = f"__{converter.__name__}__" 

251 return wrapper 

252 

253 

254# ---------------------------------------------------------------------- 

255# Series class 

256 

257 

258# error: Cannot override final attribute "ndim" (previously declared in base 

259# class "NDFrame") 

260# error: Cannot override final attribute "size" (previously declared in base 

261# class "NDFrame") 

262# definition in base class "NDFrame" 

263class Series(base.IndexOpsMixin, NDFrame): # type: ignore[misc] 

264 """ 

265 One-dimensional ndarray with axis labels (including time series). 

266 

267 Labels need not be unique but must be a hashable type. The object 

268 supports both integer- and label-based indexing and provides a host of 

269 methods for performing operations involving the index. Statistical 

270 methods from ndarray have been overridden to automatically exclude 

271 missing data (currently represented as NaN). 

272 

273 Operations between Series (+, -, /, \\*, \\*\\*) align values based on their 

274 associated index values-- they need not be the same length. The result 

275 index will be the sorted union of the two indexes. 

276 

277 Parameters 

278 ---------- 

279 data : array-like, Iterable, dict, or scalar value 

280 Contains data stored in Series. If data is a dict, argument order is 

281 maintained. 

282 index : array-like or Index (1d) 

283 Values must be hashable and have the same length as `data`. 

284 Non-unique index values are allowed. Will default to 

285 RangeIndex (0, 1, 2, ..., n) if not provided. If data is dict-like 

286 and index is None, then the keys in the data are used as the index. If the 

287 index is not None, the resulting Series is reindexed with the index values. 

288 dtype : str, numpy.dtype, or ExtensionDtype, optional 

289 Data type for the output Series. If not specified, this will be 

290 inferred from `data`. 

291 See the :ref:`user guide <basics.dtypes>` for more usages. 

292 name : Hashable, default None 

293 The name to give to the Series. 

294 copy : bool, default False 

295 Copy input data. Only affects Series or 1d ndarray input. See examples. 

296 

297 Notes 

298 ----- 

299 Please reference the :ref:`User Guide <basics.series>` for more information. 

300 

301 Examples 

302 -------- 

303 Constructing Series from a dictionary with an Index specified 

304 

305 >>> d = {'a': 1, 'b': 2, 'c': 3} 

306 >>> ser = pd.Series(data=d, index=['a', 'b', 'c']) 

307 >>> ser 

308 a 1 

309 b 2 

310 c 3 

311 dtype: int64 

312 

313 The keys of the dictionary match with the Index values, hence the Index 

314 values have no effect. 

315 

316 >>> d = {'a': 1, 'b': 2, 'c': 3} 

317 >>> ser = pd.Series(data=d, index=['x', 'y', 'z']) 

318 >>> ser 

319 x NaN 

320 y NaN 

321 z NaN 

322 dtype: float64 

323 

324 Note that the Index is first build with the keys from the dictionary. 

325 After this the Series is reindexed with the given Index values, hence we 

326 get all NaN as a result. 

327 

328 Constructing Series from a list with `copy=False`. 

329 

330 >>> r = [1, 2] 

331 >>> ser = pd.Series(r, copy=False) 

332 >>> ser.iloc[0] = 999 

333 >>> r 

334 [1, 2] 

335 >>> ser 

336 0 999 

337 1 2 

338 dtype: int64 

339 

340 Due to input data type the Series has a `copy` of 

341 the original data even though `copy=False`, so 

342 the data is unchanged. 

343 

344 Constructing Series from a 1d ndarray with `copy=False`. 

345 

346 >>> r = np.array([1, 2]) 

347 >>> ser = pd.Series(r, copy=False) 

348 >>> ser.iloc[0] = 999 

349 >>> r 

350 array([999, 2]) 

351 >>> ser 

352 0 999 

353 1 2 

354 dtype: int64 

355 

356 Due to input data type the Series has a `view` on 

357 the original data, so 

358 the data is changed as well. 

359 """ 

360 

361 _typ = "series" 

362 _HANDLED_TYPES = (Index, ExtensionArray, np.ndarray) 

363 

364 _name: Hashable 

365 _metadata: list[str] = ["_name"] 

366 _internal_names_set = {"index", "name"} | NDFrame._internal_names_set 

367 _accessors = {"dt", "cat", "str", "sparse"} 

368 _hidden_attrs = ( 

369 base.IndexOpsMixin._hidden_attrs | NDFrame._hidden_attrs | frozenset([]) 

370 ) 

371 

372 # similar to __array_priority__, positions Series after DataFrame 

373 # but before Index and ExtensionArray. Should NOT be overridden by subclasses. 

374 __pandas_priority__ = 3000 

375 

376 # Override cache_readonly bc Series is mutable 

377 # error: Incompatible types in assignment (expression has type "property", 

378 # base class "IndexOpsMixin" defined the type as "Callable[[IndexOpsMixin], bool]") 

379 hasnans = property( # type: ignore[assignment] 

380 # error: "Callable[[IndexOpsMixin], bool]" has no attribute "fget" 

381 base.IndexOpsMixin.hasnans.fget, # type: ignore[attr-defined] 

382 doc=base.IndexOpsMixin.hasnans.__doc__, 

383 ) 

384 _mgr: SingleManager 

385 

386 # ---------------------------------------------------------------------- 

387 # Constructors 

388 

389 def __init__( 

390 self, 

391 data=None, 

392 index=None, 

393 dtype: Dtype | None = None, 

394 name=None, 

395 copy: bool | None = None, 

396 fastpath: bool | lib.NoDefault = lib.no_default, 

397 ) -> None: 

398 if fastpath is not lib.no_default: 

399 warnings.warn( 

400 "The 'fastpath' keyword in pd.Series is deprecated and will " 

401 "be removed in a future version.", 

402 DeprecationWarning, 

403 stacklevel=find_stack_level(), 

404 ) 

405 else: 

406 fastpath = False 

407 

408 allow_mgr = False 

409 if ( 

410 isinstance(data, (SingleBlockManager, SingleArrayManager)) 

411 and index is None 

412 and dtype is None 

413 and (copy is False or copy is None) 

414 ): 

415 if not allow_mgr: 

416 # GH#52419 

417 warnings.warn( 

418 f"Passing a {type(data).__name__} to {type(self).__name__} " 

419 "is deprecated and will raise in a future version. " 

420 "Use public APIs instead.", 

421 DeprecationWarning, 

422 stacklevel=2, 

423 ) 

424 if using_copy_on_write(): 

425 data = data.copy(deep=False) 

426 # GH#33357 called with just the SingleBlockManager 

427 NDFrame.__init__(self, data) 

428 if fastpath: 

429 # e.g. from _box_col_values, skip validation of name 

430 object.__setattr__(self, "_name", name) 

431 else: 

432 self.name = name 

433 return 

434 

435 is_pandas_object = isinstance(data, (Series, Index, ExtensionArray)) 

436 data_dtype = getattr(data, "dtype", None) 

437 original_dtype = dtype 

438 

439 if isinstance(data, (ExtensionArray, np.ndarray)): 

440 if copy is not False and using_copy_on_write(): 

441 if dtype is None or astype_is_view(data.dtype, pandas_dtype(dtype)): 

442 data = data.copy() 

443 if copy is None: 

444 copy = False 

445 

446 # we are called internally, so short-circuit 

447 if fastpath: 

448 # data is a ndarray, index is defined 

449 if not isinstance(data, (SingleBlockManager, SingleArrayManager)): 

450 manager = _get_option("mode.data_manager", silent=True) 

451 if manager == "block": 

452 data = SingleBlockManager.from_array(data, index) 

453 elif manager == "array": 

454 data = SingleArrayManager.from_array(data, index) 

455 allow_mgr = True 

456 elif using_copy_on_write() and not copy: 

457 data = data.copy(deep=False) 

458 

459 if not allow_mgr: 

460 warnings.warn( 

461 f"Passing a {type(data).__name__} to {type(self).__name__} " 

462 "is deprecated and will raise in a future version. " 

463 "Use public APIs instead.", 

464 DeprecationWarning, 

465 stacklevel=2, 

466 ) 

467 

468 if copy: 

469 data = data.copy() 

470 # skips validation of the name 

471 object.__setattr__(self, "_name", name) 

472 NDFrame.__init__(self, data) 

473 return 

474 

475 if isinstance(data, SingleBlockManager) and using_copy_on_write() and not copy: 

476 data = data.copy(deep=False) 

477 

478 if not allow_mgr: 

479 warnings.warn( 

480 f"Passing a {type(data).__name__} to {type(self).__name__} " 

481 "is deprecated and will raise in a future version. " 

482 "Use public APIs instead.", 

483 DeprecationWarning, 

484 stacklevel=2, 

485 ) 

486 

487 name = ibase.maybe_extract_name(name, data, type(self)) 

488 

489 if index is not None: 

490 index = ensure_index(index) 

491 

492 if dtype is not None: 

493 dtype = self._validate_dtype(dtype) 

494 

495 if data is None: 

496 index = index if index is not None else default_index(0) 

497 if len(index) or dtype is not None: 

498 data = na_value_for_dtype(pandas_dtype(dtype), compat=False) 

499 else: 

500 data = [] 

501 

502 if isinstance(data, MultiIndex): 

503 raise NotImplementedError( 

504 "initializing a Series from a MultiIndex is not supported" 

505 ) 

506 

507 refs = None 

508 if isinstance(data, Index): 

509 if dtype is not None: 

510 data = data.astype(dtype, copy=False) 

511 

512 if using_copy_on_write(): 

513 refs = data._references 

514 data = data._values 

515 else: 

516 # GH#24096 we need to ensure the index remains immutable 

517 data = data._values.copy() 

518 copy = False 

519 

520 elif isinstance(data, np.ndarray): 

521 if len(data.dtype): 

522 # GH#13296 we are dealing with a compound dtype, which 

523 # should be treated as 2D 

524 raise ValueError( 

525 "Cannot construct a Series from an ndarray with " 

526 "compound dtype. Use DataFrame instead." 

527 ) 

528 elif isinstance(data, Series): 

529 if index is None: 

530 index = data.index 

531 data = data._mgr.copy(deep=False) 

532 else: 

533 data = data.reindex(index, copy=copy) 

534 copy = False 

535 data = data._mgr 

536 elif isinstance(data, Mapping): 

537 data, index = self._init_dict(data, index, dtype) 

538 dtype = None 

539 copy = False 

540 elif isinstance(data, (SingleBlockManager, SingleArrayManager)): 

541 if index is None: 

542 index = data.index 

543 elif not data.index.equals(index) or copy: 

544 # GH#19275 SingleBlockManager input should only be called 

545 # internally 

546 raise AssertionError( 

547 "Cannot pass both SingleBlockManager " 

548 "`data` argument and a different " 

549 "`index` argument. `copy` must be False." 

550 ) 

551 

552 if not allow_mgr: 

553 warnings.warn( 

554 f"Passing a {type(data).__name__} to {type(self).__name__} " 

555 "is deprecated and will raise in a future version. " 

556 "Use public APIs instead.", 

557 DeprecationWarning, 

558 stacklevel=2, 

559 ) 

560 allow_mgr = True 

561 

562 elif isinstance(data, ExtensionArray): 

563 pass 

564 else: 

565 data = com.maybe_iterable_to_list(data) 

566 if is_list_like(data) and not len(data) and dtype is None: 

567 # GH 29405: Pre-2.0, this defaulted to float. 

568 dtype = np.dtype(object) 

569 

570 if index is None: 

571 if not is_list_like(data): 

572 data = [data] 

573 index = default_index(len(data)) 

574 elif is_list_like(data): 

575 com.require_length_match(data, index) 

576 

577 # create/copy the manager 

578 if isinstance(data, (SingleBlockManager, SingleArrayManager)): 

579 if dtype is not None: 

580 data = data.astype(dtype=dtype, errors="ignore", copy=copy) 

581 elif copy: 

582 data = data.copy() 

583 else: 

584 data = sanitize_array(data, index, dtype, copy) 

585 

586 manager = _get_option("mode.data_manager", silent=True) 

587 if manager == "block": 

588 data = SingleBlockManager.from_array(data, index, refs=refs) 

589 elif manager == "array": 

590 data = SingleArrayManager.from_array(data, index) 

591 

592 NDFrame.__init__(self, data) 

593 self.name = name 

594 self._set_axis(0, index) 

595 

596 if original_dtype is None and is_pandas_object and data_dtype == np.object_: 

597 if self.dtype != data_dtype: 

598 warnings.warn( 

599 "Dtype inference on a pandas object " 

600 "(Series, Index, ExtensionArray) is deprecated. The Series " 

601 "constructor will keep the original dtype in the future. " 

602 "Call `infer_objects` on the result to get the old behavior.", 

603 FutureWarning, 

604 stacklevel=find_stack_level(), 

605 ) 

606 

607 def _init_dict( 

608 self, data: Mapping, index: Index | None = None, dtype: DtypeObj | None = None 

609 ): 

610 """ 

611 Derive the "_mgr" and "index" attributes of a new Series from a 

612 dictionary input. 

613 

614 Parameters 

615 ---------- 

616 data : dict or dict-like 

617 Data used to populate the new Series. 

618 index : Index or None, default None 

619 Index for the new Series: if None, use dict keys. 

620 dtype : np.dtype, ExtensionDtype, or None, default None 

621 The dtype for the new Series: if None, infer from data. 

622 

623 Returns 

624 ------- 

625 _data : BlockManager for the new Series 

626 index : index for the new Series 

627 """ 

628 keys: Index | tuple 

629 

630 # Looking for NaN in dict doesn't work ({np.nan : 1}[float('nan')] 

631 # raises KeyError), so we iterate the entire dict, and align 

632 if data: 

633 # GH:34717, issue was using zip to extract key and values from data. 

634 # using generators in effects the performance. 

635 # Below is the new way of extracting the keys and values 

636 

637 keys = tuple(data.keys()) 

638 values = list(data.values()) # Generating list of values- faster way 

639 elif index is not None: 

640 # fastpath for Series(data=None). Just use broadcasting a scalar 

641 # instead of reindexing. 

642 if len(index) or dtype is not None: 

643 values = na_value_for_dtype(pandas_dtype(dtype), compat=False) 

644 else: 

645 values = [] 

646 keys = index 

647 else: 

648 keys, values = default_index(0), [] 

649 

650 # Input is now list-like, so rely on "standard" construction: 

651 s = Series(values, index=keys, dtype=dtype) 

652 

653 # Now we just make sure the order is respected, if any 

654 if data and index is not None: 

655 s = s.reindex(index, copy=False) 

656 return s._mgr, s.index 

657 

658 # ---------------------------------------------------------------------- 

659 

660 @property 

661 def _constructor(self) -> Callable[..., Series]: 

662 return Series 

663 

664 def _constructor_from_mgr(self, mgr, axes): 

665 ser = Series._from_mgr(mgr, axes=axes) 

666 ser._name = None # caller is responsible for setting real name 

667 

668 if type(self) is Series: 

669 # This would also work `if self._constructor is Series`, but 

670 # this check is slightly faster, benefiting the most-common case. 

671 return ser 

672 

673 # We assume that the subclass __init__ knows how to handle a 

674 # pd.Series object. 

675 return self._constructor(ser) 

676 

677 @property 

678 def _constructor_expanddim(self) -> Callable[..., DataFrame]: 

679 """ 

680 Used when a manipulation result has one higher dimension as the 

681 original, such as Series.to_frame() 

682 """ 

683 from pandas.core.frame import DataFrame 

684 

685 return DataFrame 

686 

687 def _constructor_expanddim_from_mgr(self, mgr, axes): 

688 from pandas.core.frame import DataFrame 

689 

690 df = DataFrame._from_mgr(mgr, axes=mgr.axes) 

691 

692 if type(self) is Series: 

693 # This would also work `if self._constructor_expanddim is DataFrame`, 

694 # but this check is slightly faster, benefiting the most-common case. 

695 return df 

696 

697 # We assume that the subclass __init__ knows how to handle a 

698 # pd.DataFrame object. 

699 return self._constructor_expanddim(df) 

700 

701 # types 

702 @property 

703 def _can_hold_na(self) -> bool: 

704 return self._mgr._can_hold_na 

705 

706 # ndarray compatibility 

707 @property 

708 def dtype(self) -> DtypeObj: 

709 """ 

710 Return the dtype object of the underlying data. 

711 

712 Examples 

713 -------- 

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

715 >>> s.dtype 

716 dtype('int64') 

717 """ 

718 return self._mgr.dtype 

719 

720 @property 

721 def dtypes(self) -> DtypeObj: 

722 """ 

723 Return the dtype object of the underlying data. 

724 

725 Examples 

726 -------- 

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

728 >>> s.dtypes 

729 dtype('int64') 

730 """ 

731 # DataFrame compatibility 

732 return self.dtype 

733 

734 @property 

735 def name(self) -> Hashable: 

736 """ 

737 Return the name of the Series. 

738 

739 The name of a Series becomes its index or column name if it is used 

740 to form a DataFrame. It is also used whenever displaying the Series 

741 using the interpreter. 

742 

743 Returns 

744 ------- 

745 label (hashable object) 

746 The name of the Series, also the column name if part of a DataFrame. 

747 

748 See Also 

749 -------- 

750 Series.rename : Sets the Series name when given a scalar input. 

751 Index.name : Corresponding Index property. 

752 

753 Examples 

754 -------- 

755 The Series name can be set initially when calling the constructor. 

756 

757 >>> s = pd.Series([1, 2, 3], dtype=np.int64, name='Numbers') 

758 >>> s 

759 0 1 

760 1 2 

761 2 3 

762 Name: Numbers, dtype: int64 

763 >>> s.name = "Integers" 

764 >>> s 

765 0 1 

766 1 2 

767 2 3 

768 Name: Integers, dtype: int64 

769 

770 The name of a Series within a DataFrame is its column name. 

771 

772 >>> df = pd.DataFrame([[1, 2], [3, 4], [5, 6]], 

773 ... columns=["Odd Numbers", "Even Numbers"]) 

774 >>> df 

775 Odd Numbers Even Numbers 

776 0 1 2 

777 1 3 4 

778 2 5 6 

779 >>> df["Even Numbers"].name 

780 'Even Numbers' 

781 """ 

782 return self._name 

783 

784 @name.setter 

785 def name(self, value: Hashable) -> None: 

786 validate_all_hashable(value, error_name=f"{type(self).__name__}.name") 

787 object.__setattr__(self, "_name", value) 

788 

789 @property 

790 def values(self): 

791 """ 

792 Return Series as ndarray or ndarray-like depending on the dtype. 

793 

794 .. warning:: 

795 

796 We recommend using :attr:`Series.array` or 

797 :meth:`Series.to_numpy`, depending on whether you need 

798 a reference to the underlying data or a NumPy array. 

799 

800 Returns 

801 ------- 

802 numpy.ndarray or ndarray-like 

803 

804 See Also 

805 -------- 

806 Series.array : Reference to the underlying data. 

807 Series.to_numpy : A NumPy array representing the underlying data. 

808 

809 Examples 

810 -------- 

811 >>> pd.Series([1, 2, 3]).values 

812 array([1, 2, 3]) 

813 

814 >>> pd.Series(list('aabc')).values 

815 array(['a', 'a', 'b', 'c'], dtype=object) 

816 

817 >>> pd.Series(list('aabc')).astype('category').values 

818 ['a', 'a', 'b', 'c'] 

819 Categories (3, object): ['a', 'b', 'c'] 

820 

821 Timezone aware datetime data is converted to UTC: 

822 

823 >>> pd.Series(pd.date_range('20130101', periods=3, 

824 ... tz='US/Eastern')).values 

825 array(['2013-01-01T05:00:00.000000000', 

826 '2013-01-02T05:00:00.000000000', 

827 '2013-01-03T05:00:00.000000000'], dtype='datetime64[ns]') 

828 """ 

829 return self._mgr.external_values() 

830 

831 @property 

832 def _values(self): 

833 """ 

834 Return the internal repr of this data (defined by Block.interval_values). 

835 This are the values as stored in the Block (ndarray or ExtensionArray 

836 depending on the Block class), with datetime64[ns] and timedelta64[ns] 

837 wrapped in ExtensionArrays to match Index._values behavior. 

838 

839 Differs from the public ``.values`` for certain data types, because of 

840 historical backwards compatibility of the public attribute (e.g. period 

841 returns object ndarray and datetimetz a datetime64[ns] ndarray for 

842 ``.values`` while it returns an ExtensionArray for ``._values`` in those 

843 cases). 

844 

845 Differs from ``.array`` in that this still returns the numpy array if 

846 the Block is backed by a numpy array (except for datetime64 and 

847 timedelta64 dtypes), while ``.array`` ensures to always return an 

848 ExtensionArray. 

849 

850 Overview: 

851 

852 dtype | values | _values | array | 

853 ----------- | ------------- | ------------- | --------------------- | 

854 Numeric | ndarray | ndarray | NumpyExtensionArray | 

855 Category | Categorical | Categorical | Categorical | 

856 dt64[ns] | ndarray[M8ns] | DatetimeArray | DatetimeArray | 

857 dt64[ns tz] | ndarray[M8ns] | DatetimeArray | DatetimeArray | 

858 td64[ns] | ndarray[m8ns] | TimedeltaArray| TimedeltaArray | 

859 Period | ndarray[obj] | PeriodArray | PeriodArray | 

860 Nullable | EA | EA | EA | 

861 

862 """ 

863 return self._mgr.internal_values() 

864 

865 @property 

866 def _references(self) -> BlockValuesRefs | None: 

867 if isinstance(self._mgr, SingleArrayManager): 

868 return None 

869 return self._mgr._block.refs 

870 

871 # error: Decorated property not supported 

872 @Appender(base.IndexOpsMixin.array.__doc__) # type: ignore[misc] 

873 @property 

874 def array(self) -> ExtensionArray: 

875 return self._mgr.array_values() 

876 

877 # ops 

878 def ravel(self, order: str = "C") -> ArrayLike: 

879 """ 

880 Return the flattened underlying data as an ndarray or ExtensionArray. 

881 

882 .. deprecated:: 2.2.0 

883 Series.ravel is deprecated. The underlying array is already 1D, so 

884 ravel is not necessary. Use :meth:`to_numpy` for conversion to a numpy 

885 array instead. 

886 

887 Returns 

888 ------- 

889 numpy.ndarray or ExtensionArray 

890 Flattened data of the Series. 

891 

892 See Also 

893 -------- 

894 numpy.ndarray.ravel : Return a flattened array. 

895 

896 Examples 

897 -------- 

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

899 >>> s.ravel() # doctest: +SKIP 

900 array([1, 2, 3]) 

901 """ 

902 warnings.warn( 

903 "Series.ravel is deprecated. The underlying array is already 1D, so " 

904 "ravel is not necessary. Use `to_numpy()` for conversion to a numpy " 

905 "array instead.", 

906 FutureWarning, 

907 stacklevel=2, 

908 ) 

909 arr = self._values.ravel(order=order) 

910 if isinstance(arr, np.ndarray) and using_copy_on_write(): 

911 arr.flags.writeable = False 

912 return arr 

913 

914 def __len__(self) -> int: 

915 """ 

916 Return the length of the Series. 

917 """ 

918 return len(self._mgr) 

919 

920 def view(self, dtype: Dtype | None = None) -> Series: 

921 """ 

922 Create a new view of the Series. 

923 

924 .. deprecated:: 2.2.0 

925 ``Series.view`` is deprecated and will be removed in a future version. 

926 Use :meth:`Series.astype` as an alternative to change the dtype. 

927 

928 This function will return a new Series with a view of the same 

929 underlying values in memory, optionally reinterpreted with a new data 

930 type. The new data type must preserve the same size in bytes as to not 

931 cause index misalignment. 

932 

933 Parameters 

934 ---------- 

935 dtype : data type 

936 Data type object or one of their string representations. 

937 

938 Returns 

939 ------- 

940 Series 

941 A new Series object as a view of the same data in memory. 

942 

943 See Also 

944 -------- 

945 numpy.ndarray.view : Equivalent numpy function to create a new view of 

946 the same data in memory. 

947 

948 Notes 

949 ----- 

950 Series are instantiated with ``dtype=float64`` by default. While 

951 ``numpy.ndarray.view()`` will return a view with the same data type as 

952 the original array, ``Series.view()`` (without specified dtype) 

953 will try using ``float64`` and may fail if the original data type size 

954 in bytes is not the same. 

955 

956 Examples 

957 -------- 

958 Use ``astype`` to change the dtype instead. 

959 """ 

960 warnings.warn( 

961 "Series.view is deprecated and will be removed in a future version. " 

962 "Use ``astype`` as an alternative to change the dtype.", 

963 FutureWarning, 

964 stacklevel=2, 

965 ) 

966 # self.array instead of self._values so we piggyback on NumpyExtensionArray 

967 # implementation 

968 res_values = self.array.view(dtype) 

969 res_ser = self._constructor(res_values, index=self.index, copy=False) 

970 if isinstance(res_ser._mgr, SingleBlockManager): 

971 blk = res_ser._mgr._block 

972 blk.refs = cast("BlockValuesRefs", self._references) 

973 blk.refs.add_reference(blk) 

974 return res_ser.__finalize__(self, method="view") 

975 

976 # ---------------------------------------------------------------------- 

977 # NDArray Compat 

978 def __array__( 

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

980 ) -> np.ndarray: 

981 """ 

982 Return the values as a NumPy array. 

983 

984 Users should not call this directly. Rather, it is invoked by 

985 :func:`numpy.array` and :func:`numpy.asarray`. 

986 

987 Parameters 

988 ---------- 

989 dtype : str or numpy.dtype, optional 

990 The dtype to use for the resulting NumPy array. By default, 

991 the dtype is inferred from the data. 

992 

993 copy : bool or None, optional 

994 Unused. 

995 

996 Returns 

997 ------- 

998 numpy.ndarray 

999 The values in the series converted to a :class:`numpy.ndarray` 

1000 with the specified `dtype`. 

1001 

1002 See Also 

1003 -------- 

1004 array : Create a new array from data. 

1005 Series.array : Zero-copy view to the array backing the Series. 

1006 Series.to_numpy : Series method for similar behavior. 

1007 

1008 Examples 

1009 -------- 

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

1011 >>> np.asarray(ser) 

1012 array([1, 2, 3]) 

1013 

1014 For timezone-aware data, the timezones may be retained with 

1015 ``dtype='object'`` 

1016 

1017 >>> tzser = pd.Series(pd.date_range('2000', periods=2, tz="CET")) 

1018 >>> np.asarray(tzser, dtype="object") 

1019 array([Timestamp('2000-01-01 00:00:00+0100', tz='CET'), 

1020 Timestamp('2000-01-02 00:00:00+0100', tz='CET')], 

1021 dtype=object) 

1022 

1023 Or the values may be localized to UTC and the tzinfo discarded with 

1024 ``dtype='datetime64[ns]'`` 

1025 

1026 >>> np.asarray(tzser, dtype="datetime64[ns]") # doctest: +ELLIPSIS 

1027 array(['1999-12-31T23:00:00.000000000', ...], 

1028 dtype='datetime64[ns]') 

1029 """ 

1030 values = self._values 

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

1032 if using_copy_on_write() and astype_is_view(values.dtype, arr.dtype): 

1033 arr = arr.view() 

1034 arr.flags.writeable = False 

1035 return arr 

1036 

1037 # ---------------------------------------------------------------------- 

1038 

1039 def __column_consortium_standard__(self, *, api_version: str | None = None) -> Any: 

1040 """ 

1041 Provide entry point to the Consortium DataFrame Standard API. 

1042 

1043 This is developed and maintained outside of pandas. 

1044 Please report any issues to https://github.com/data-apis/dataframe-api-compat. 

1045 """ 

1046 dataframe_api_compat = import_optional_dependency("dataframe_api_compat") 

1047 return ( 

1048 dataframe_api_compat.pandas_standard.convert_to_standard_compliant_column( 

1049 self, api_version=api_version 

1050 ) 

1051 ) 

1052 

1053 # ---------------------------------------------------------------------- 

1054 # Unary Methods 

1055 

1056 # coercion 

1057 __float__ = _coerce_method(float) 

1058 __int__ = _coerce_method(int) 

1059 

1060 # ---------------------------------------------------------------------- 

1061 

1062 # indexers 

1063 @property 

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

1065 """ 

1066 Return a list of the row axis labels. 

1067 """ 

1068 return [self.index] 

1069 

1070 # ---------------------------------------------------------------------- 

1071 # Indexing Methods 

1072 

1073 def _ixs(self, i: int, axis: AxisInt = 0) -> Any: 

1074 """ 

1075 Return the i-th value or values in the Series by location. 

1076 

1077 Parameters 

1078 ---------- 

1079 i : int 

1080 

1081 Returns 

1082 ------- 

1083 scalar 

1084 """ 

1085 return self._values[i] 

1086 

1087 def _slice(self, slobj: slice, axis: AxisInt = 0) -> Series: 

1088 # axis kwarg is retained for compat with NDFrame method 

1089 # _slice is *always* positional 

1090 mgr = self._mgr.get_slice(slobj, axis=axis) 

1091 out = self._constructor_from_mgr(mgr, axes=mgr.axes) 

1092 out._name = self._name 

1093 return out.__finalize__(self) 

1094 

1095 def __getitem__(self, key): 

1096 check_dict_or_set_indexers(key) 

1097 key = com.apply_if_callable(key, self) 

1098 

1099 if key is Ellipsis: 

1100 if using_copy_on_write() or warn_copy_on_write(): 

1101 return self.copy(deep=False) 

1102 return self 

1103 

1104 key_is_scalar = is_scalar(key) 

1105 if isinstance(key, (list, tuple)): 

1106 key = unpack_1tuple(key) 

1107 

1108 if is_integer(key) and self.index._should_fallback_to_positional: 

1109 warnings.warn( 

1110 # GH#50617 

1111 "Series.__getitem__ treating keys as positions is deprecated. " 

1112 "In a future version, integer keys will always be treated " 

1113 "as labels (consistent with DataFrame behavior). To access " 

1114 "a value by position, use `ser.iloc[pos]`", 

1115 FutureWarning, 

1116 stacklevel=find_stack_level(), 

1117 ) 

1118 return self._values[key] 

1119 

1120 elif key_is_scalar: 

1121 return self._get_value(key) 

1122 

1123 # Convert generator to list before going through hashable part 

1124 # (We will iterate through the generator there to check for slices) 

1125 if is_iterator(key): 

1126 key = list(key) 

1127 

1128 if is_hashable(key) and not isinstance(key, slice): 

1129 # Otherwise index.get_value will raise InvalidIndexError 

1130 try: 

1131 # For labels that don't resolve as scalars like tuples and frozensets 

1132 result = self._get_value(key) 

1133 

1134 return result 

1135 

1136 except (KeyError, TypeError, InvalidIndexError): 

1137 # InvalidIndexError for e.g. generator 

1138 # see test_series_getitem_corner_generator 

1139 if isinstance(key, tuple) and isinstance(self.index, MultiIndex): 

1140 # We still have the corner case where a tuple is a key 

1141 # in the first level of our MultiIndex 

1142 return self._get_values_tuple(key) 

1143 

1144 if isinstance(key, slice): 

1145 # Do slice check before somewhat-costly is_bool_indexer 

1146 return self._getitem_slice(key) 

1147 

1148 if com.is_bool_indexer(key): 

1149 key = check_bool_indexer(self.index, key) 

1150 key = np.asarray(key, dtype=bool) 

1151 return self._get_rows_with_mask(key) 

1152 

1153 return self._get_with(key) 

1154 

1155 def _get_with(self, key): 

1156 # other: fancy integer or otherwise 

1157 if isinstance(key, ABCDataFrame): 

1158 raise TypeError( 

1159 "Indexing a Series with DataFrame is not " 

1160 "supported, use the appropriate DataFrame column" 

1161 ) 

1162 elif isinstance(key, tuple): 

1163 return self._get_values_tuple(key) 

1164 

1165 elif not is_list_like(key): 

1166 # e.g. scalars that aren't recognized by lib.is_scalar, GH#32684 

1167 return self.loc[key] 

1168 

1169 if not isinstance(key, (list, np.ndarray, ExtensionArray, Series, Index)): 

1170 key = list(key) 

1171 

1172 key_type = lib.infer_dtype(key, skipna=False) 

1173 

1174 # Note: The key_type == "boolean" case should be caught by the 

1175 # com.is_bool_indexer check in __getitem__ 

1176 if key_type == "integer": 

1177 # We need to decide whether to treat this as a positional indexer 

1178 # (i.e. self.iloc) or label-based (i.e. self.loc) 

1179 if not self.index._should_fallback_to_positional: 

1180 return self.loc[key] 

1181 else: 

1182 warnings.warn( 

1183 # GH#50617 

1184 "Series.__getitem__ treating keys as positions is deprecated. " 

1185 "In a future version, integer keys will always be treated " 

1186 "as labels (consistent with DataFrame behavior). To access " 

1187 "a value by position, use `ser.iloc[pos]`", 

1188 FutureWarning, 

1189 stacklevel=find_stack_level(), 

1190 ) 

1191 return self.iloc[key] 

1192 

1193 # handle the dup indexing case GH#4246 

1194 return self.loc[key] 

1195 

1196 def _get_values_tuple(self, key: tuple): 

1197 # mpl hackaround 

1198 if com.any_none(*key): 

1199 # mpl compat if we look up e.g. ser[:, np.newaxis]; 

1200 # see tests.series.timeseries.test_mpl_compat_hack 

1201 # the asarray is needed to avoid returning a 2D DatetimeArray 

1202 result = np.asarray(self._values[key]) 

1203 disallow_ndim_indexing(result) 

1204 return result 

1205 

1206 if not isinstance(self.index, MultiIndex): 

1207 raise KeyError("key of type tuple not found and not a MultiIndex") 

1208 

1209 # If key is contained, would have returned by now 

1210 indexer, new_index = self.index.get_loc_level(key) 

1211 new_ser = self._constructor(self._values[indexer], index=new_index, copy=False) 

1212 if isinstance(indexer, slice): 

1213 new_ser._mgr.add_references(self._mgr) # type: ignore[arg-type] 

1214 return new_ser.__finalize__(self) 

1215 

1216 def _get_rows_with_mask(self, indexer: npt.NDArray[np.bool_]) -> Series: 

1217 new_mgr = self._mgr.get_rows_with_mask(indexer) 

1218 return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__(self) 

1219 

1220 def _get_value(self, label, takeable: bool = False): 

1221 """ 

1222 Quickly retrieve single value at passed index label. 

1223 

1224 Parameters 

1225 ---------- 

1226 label : object 

1227 takeable : interpret the index as indexers, default False 

1228 

1229 Returns 

1230 ------- 

1231 scalar value 

1232 """ 

1233 if takeable: 

1234 return self._values[label] 

1235 

1236 # Similar to Index.get_value, but we do not fall back to positional 

1237 loc = self.index.get_loc(label) 

1238 

1239 if is_integer(loc): 

1240 return self._values[loc] 

1241 

1242 if isinstance(self.index, MultiIndex): 

1243 mi = self.index 

1244 new_values = self._values[loc] 

1245 if len(new_values) == 1 and mi.nlevels == 1: 

1246 # If more than one level left, we can not return a scalar 

1247 return new_values[0] 

1248 

1249 new_index = mi[loc] 

1250 new_index = maybe_droplevels(new_index, label) 

1251 new_ser = self._constructor( 

1252 new_values, index=new_index, name=self.name, copy=False 

1253 ) 

1254 if isinstance(loc, slice): 

1255 new_ser._mgr.add_references(self._mgr) # type: ignore[arg-type] 

1256 return new_ser.__finalize__(self) 

1257 

1258 else: 

1259 return self.iloc[loc] 

1260 

1261 def __setitem__(self, key, value) -> None: 

1262 warn = True 

1263 if not PYPY and using_copy_on_write(): 

1264 if sys.getrefcount(self) <= 3: 

1265 warnings.warn( 

1266 _chained_assignment_msg, ChainedAssignmentError, stacklevel=2 

1267 ) 

1268 elif not PYPY and not using_copy_on_write(): 

1269 ctr = sys.getrefcount(self) 

1270 ref_count = 3 

1271 if not warn_copy_on_write() and _check_cacher(self): 

1272 # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 

1273 ref_count += 1 

1274 if ctr <= ref_count and ( 

1275 warn_copy_on_write() 

1276 or ( 

1277 not warn_copy_on_write() 

1278 and self._mgr.blocks[0].refs.has_reference() # type: ignore[union-attr] 

1279 ) 

1280 ): 

1281 warn = False 

1282 warnings.warn( 

1283 _chained_assignment_warning_msg, FutureWarning, stacklevel=2 

1284 ) 

1285 

1286 check_dict_or_set_indexers(key) 

1287 key = com.apply_if_callable(key, self) 

1288 cacher_needs_updating = self._check_is_chained_assignment_possible() 

1289 

1290 if key is Ellipsis: 

1291 key = slice(None) 

1292 

1293 if isinstance(key, slice): 

1294 indexer = self.index._convert_slice_indexer(key, kind="getitem") 

1295 return self._set_values(indexer, value, warn=warn) 

1296 

1297 try: 

1298 self._set_with_engine(key, value, warn=warn) 

1299 except KeyError: 

1300 # We have a scalar (or for MultiIndex or object-dtype, scalar-like) 

1301 # key that is not present in self.index. 

1302 if is_integer(key): 

1303 if not self.index._should_fallback_to_positional: 

1304 # GH#33469 

1305 self.loc[key] = value 

1306 else: 

1307 # positional setter 

1308 # can't use _mgr.setitem_inplace yet bc could have *both* 

1309 # KeyError and then ValueError, xref GH#45070 

1310 warnings.warn( 

1311 # GH#50617 

1312 "Series.__setitem__ treating keys as positions is deprecated. " 

1313 "In a future version, integer keys will always be treated " 

1314 "as labels (consistent with DataFrame behavior). To set " 

1315 "a value by position, use `ser.iloc[pos] = value`", 

1316 FutureWarning, 

1317 stacklevel=find_stack_level(), 

1318 ) 

1319 self._set_values(key, value) 

1320 else: 

1321 # GH#12862 adding a new key to the Series 

1322 self.loc[key] = value 

1323 

1324 except (TypeError, ValueError, LossySetitemError): 

1325 # The key was OK, but we cannot set the value losslessly 

1326 indexer = self.index.get_loc(key) 

1327 self._set_values(indexer, value) 

1328 

1329 except InvalidIndexError as err: 

1330 if isinstance(key, tuple) and not isinstance(self.index, MultiIndex): 

1331 # cases with MultiIndex don't get here bc they raise KeyError 

1332 # e.g. test_basic_getitem_setitem_corner 

1333 raise KeyError( 

1334 "key of type tuple not found and not a MultiIndex" 

1335 ) from err 

1336 

1337 if com.is_bool_indexer(key): 

1338 key = check_bool_indexer(self.index, key) 

1339 key = np.asarray(key, dtype=bool) 

1340 

1341 if ( 

1342 is_list_like(value) 

1343 and len(value) != len(self) 

1344 and not isinstance(value, Series) 

1345 and not is_object_dtype(self.dtype) 

1346 ): 

1347 # Series will be reindexed to have matching length inside 

1348 # _where call below 

1349 # GH#44265 

1350 indexer = key.nonzero()[0] 

1351 self._set_values(indexer, value) 

1352 return 

1353 

1354 # otherwise with listlike other we interpret series[mask] = other 

1355 # as series[mask] = other[mask] 

1356 try: 

1357 self._where(~key, value, inplace=True, warn=warn) 

1358 except InvalidIndexError: 

1359 # test_where_dups 

1360 self.iloc[key] = value 

1361 return 

1362 

1363 else: 

1364 self._set_with(key, value, warn=warn) 

1365 

1366 if cacher_needs_updating: 

1367 self._maybe_update_cacher(inplace=True) 

1368 

1369 def _set_with_engine(self, key, value, warn: bool = True) -> None: 

1370 loc = self.index.get_loc(key) 

1371 

1372 # this is equivalent to self._values[key] = value 

1373 self._mgr.setitem_inplace(loc, value, warn=warn) 

1374 

1375 def _set_with(self, key, value, warn: bool = True) -> None: 

1376 # We got here via exception-handling off of InvalidIndexError, so 

1377 # key should always be listlike at this point. 

1378 assert not isinstance(key, tuple) 

1379 

1380 if is_iterator(key): 

1381 # Without this, the call to infer_dtype will consume the generator 

1382 key = list(key) 

1383 

1384 if not self.index._should_fallback_to_positional: 

1385 # Regardless of the key type, we're treating it as labels 

1386 self._set_labels(key, value, warn=warn) 

1387 

1388 else: 

1389 # Note: key_type == "boolean" should not occur because that 

1390 # should be caught by the is_bool_indexer check in __setitem__ 

1391 key_type = lib.infer_dtype(key, skipna=False) 

1392 

1393 if key_type == "integer": 

1394 warnings.warn( 

1395 # GH#50617 

1396 "Series.__setitem__ treating keys as positions is deprecated. " 

1397 "In a future version, integer keys will always be treated " 

1398 "as labels (consistent with DataFrame behavior). To set " 

1399 "a value by position, use `ser.iloc[pos] = value`", 

1400 FutureWarning, 

1401 stacklevel=find_stack_level(), 

1402 ) 

1403 self._set_values(key, value, warn=warn) 

1404 else: 

1405 self._set_labels(key, value, warn=warn) 

1406 

1407 def _set_labels(self, key, value, warn: bool = True) -> None: 

1408 key = com.asarray_tuplesafe(key) 

1409 indexer: np.ndarray = self.index.get_indexer(key) 

1410 mask = indexer == -1 

1411 if mask.any(): 

1412 raise KeyError(f"{key[mask]} not in index") 

1413 self._set_values(indexer, value, warn=warn) 

1414 

1415 def _set_values(self, key, value, warn: bool = True) -> None: 

1416 if isinstance(key, (Index, Series)): 

1417 key = key._values 

1418 

1419 self._mgr = self._mgr.setitem(indexer=key, value=value, warn=warn) 

1420 self._maybe_update_cacher() 

1421 

1422 def _set_value(self, label, value, takeable: bool = False) -> None: 

1423 """ 

1424 Quickly set single value at passed label. 

1425 

1426 If label is not contained, a new object is created with the label 

1427 placed at the end of the result index. 

1428 

1429 Parameters 

1430 ---------- 

1431 label : object 

1432 Partial indexing with MultiIndex not allowed. 

1433 value : object 

1434 Scalar value. 

1435 takeable : interpret the index as indexers, default False 

1436 """ 

1437 if not takeable: 

1438 try: 

1439 loc = self.index.get_loc(label) 

1440 except KeyError: 

1441 # set using a non-recursive method 

1442 self.loc[label] = value 

1443 return 

1444 else: 

1445 loc = label 

1446 

1447 self._set_values(loc, value) 

1448 

1449 # ---------------------------------------------------------------------- 

1450 # Lookup Caching 

1451 

1452 @property 

1453 def _is_cached(self) -> bool: 

1454 """Return boolean indicating if self is cached or not.""" 

1455 return getattr(self, "_cacher", None) is not None 

1456 

1457 def _get_cacher(self): 

1458 """return my cacher or None""" 

1459 cacher = getattr(self, "_cacher", None) 

1460 if cacher is not None: 

1461 cacher = cacher[1]() 

1462 return cacher 

1463 

1464 def _reset_cacher(self) -> None: 

1465 """ 

1466 Reset the cacher. 

1467 """ 

1468 if hasattr(self, "_cacher"): 

1469 del self._cacher 

1470 

1471 def _set_as_cached(self, item, cacher) -> None: 

1472 """ 

1473 Set the _cacher attribute on the calling object with a weakref to 

1474 cacher. 

1475 """ 

1476 if using_copy_on_write(): 

1477 return 

1478 self._cacher = (item, weakref.ref(cacher)) 

1479 

1480 def _clear_item_cache(self) -> None: 

1481 # no-op for Series 

1482 pass 

1483 

1484 def _check_is_chained_assignment_possible(self) -> bool: 

1485 """ 

1486 See NDFrame._check_is_chained_assignment_possible.__doc__ 

1487 """ 

1488 if self._is_view and self._is_cached: 

1489 ref = self._get_cacher() 

1490 if ref is not None and ref._is_mixed_type: 

1491 self._check_setitem_copy(t="referent", force=True) 

1492 return True 

1493 return super()._check_is_chained_assignment_possible() 

1494 

1495 def _maybe_update_cacher( 

1496 self, clear: bool = False, verify_is_copy: bool = True, inplace: bool = False 

1497 ) -> None: 

1498 """ 

1499 See NDFrame._maybe_update_cacher.__doc__ 

1500 """ 

1501 # for CoW, we never want to update the parent DataFrame cache 

1502 # if the Series changed, but don't keep track of any cacher 

1503 if using_copy_on_write(): 

1504 return 

1505 cacher = getattr(self, "_cacher", None) 

1506 if cacher is not None: 

1507 ref: DataFrame = cacher[1]() 

1508 

1509 # we are trying to reference a dead referent, hence 

1510 # a copy 

1511 if ref is None: 

1512 del self._cacher 

1513 elif len(self) == len(ref) and self.name in ref.columns: 

1514 # GH#42530 self.name must be in ref.columns 

1515 # to ensure column still in dataframe 

1516 # otherwise, either self or ref has swapped in new arrays 

1517 ref._maybe_cache_changed(cacher[0], self, inplace=inplace) 

1518 else: 

1519 # GH#33675 we have swapped in a new array, so parent 

1520 # reference to self is now invalid 

1521 ref._item_cache.pop(cacher[0], None) 

1522 

1523 super()._maybe_update_cacher( 

1524 clear=clear, verify_is_copy=verify_is_copy, inplace=inplace 

1525 ) 

1526 

1527 # ---------------------------------------------------------------------- 

1528 # Unsorted 

1529 

1530 def repeat(self, repeats: int | Sequence[int], axis: None = None) -> Series: 

1531 """ 

1532 Repeat elements of a Series. 

1533 

1534 Returns a new Series where each element of the current Series 

1535 is repeated consecutively a given number of times. 

1536 

1537 Parameters 

1538 ---------- 

1539 repeats : int or array of ints 

1540 The number of repetitions for each element. This should be a 

1541 non-negative integer. Repeating 0 times will return an empty 

1542 Series. 

1543 axis : None 

1544 Unused. Parameter needed for compatibility with DataFrame. 

1545 

1546 Returns 

1547 ------- 

1548 Series 

1549 Newly created Series with repeated elements. 

1550 

1551 See Also 

1552 -------- 

1553 Index.repeat : Equivalent function for Index. 

1554 numpy.repeat : Similar method for :class:`numpy.ndarray`. 

1555 

1556 Examples 

1557 -------- 

1558 >>> s = pd.Series(['a', 'b', 'c']) 

1559 >>> s 

1560 0 a 

1561 1 b 

1562 2 c 

1563 dtype: object 

1564 >>> s.repeat(2) 

1565 0 a 

1566 0 a 

1567 1 b 

1568 1 b 

1569 2 c 

1570 2 c 

1571 dtype: object 

1572 >>> s.repeat([1, 2, 3]) 

1573 0 a 

1574 1 b 

1575 1 b 

1576 2 c 

1577 2 c 

1578 2 c 

1579 dtype: object 

1580 """ 

1581 nv.validate_repeat((), {"axis": axis}) 

1582 new_index = self.index.repeat(repeats) 

1583 new_values = self._values.repeat(repeats) 

1584 return self._constructor(new_values, index=new_index, copy=False).__finalize__( 

1585 self, method="repeat" 

1586 ) 

1587 

1588 @overload 

1589 def reset_index( 

1590 self, 

1591 level: IndexLabel = ..., 

1592 *, 

1593 drop: Literal[False] = ..., 

1594 name: Level = ..., 

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

1596 allow_duplicates: bool = ..., 

1597 ) -> DataFrame: 

1598 ... 

1599 

1600 @overload 

1601 def reset_index( 

1602 self, 

1603 level: IndexLabel = ..., 

1604 *, 

1605 drop: Literal[True], 

1606 name: Level = ..., 

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

1608 allow_duplicates: bool = ..., 

1609 ) -> Series: 

1610 ... 

1611 

1612 @overload 

1613 def reset_index( 

1614 self, 

1615 level: IndexLabel = ..., 

1616 *, 

1617 drop: bool = ..., 

1618 name: Level = ..., 

1619 inplace: Literal[True], 

1620 allow_duplicates: bool = ..., 

1621 ) -> None: 

1622 ... 

1623 

1624 def reset_index( 

1625 self, 

1626 level: IndexLabel | None = None, 

1627 *, 

1628 drop: bool = False, 

1629 name: Level = lib.no_default, 

1630 inplace: bool = False, 

1631 allow_duplicates: bool = False, 

1632 ) -> DataFrame | Series | None: 

1633 """ 

1634 Generate a new DataFrame or Series with the index reset. 

1635 

1636 This is useful when the index needs to be treated as a column, or 

1637 when the index is meaningless and needs to be reset to the default 

1638 before another operation. 

1639 

1640 Parameters 

1641 ---------- 

1642 level : int, str, tuple, or list, default optional 

1643 For a Series with a MultiIndex, only remove the specified levels 

1644 from the index. Removes all levels by default. 

1645 drop : bool, default False 

1646 Just reset the index, without inserting it as a column in 

1647 the new DataFrame. 

1648 name : object, optional 

1649 The name to use for the column containing the original Series 

1650 values. Uses ``self.name`` by default. This argument is ignored 

1651 when `drop` is True. 

1652 inplace : bool, default False 

1653 Modify the Series in place (do not create a new object). 

1654 allow_duplicates : bool, default False 

1655 Allow duplicate column labels to be created. 

1656 

1657 .. versionadded:: 1.5.0 

1658 

1659 Returns 

1660 ------- 

1661 Series or DataFrame or None 

1662 When `drop` is False (the default), a DataFrame is returned. 

1663 The newly created columns will come first in the DataFrame, 

1664 followed by the original Series values. 

1665 When `drop` is True, a `Series` is returned. 

1666 In either case, if ``inplace=True``, no value is returned. 

1667 

1668 See Also 

1669 -------- 

1670 DataFrame.reset_index: Analogous function for DataFrame. 

1671 

1672 Examples 

1673 -------- 

1674 >>> s = pd.Series([1, 2, 3, 4], name='foo', 

1675 ... index=pd.Index(['a', 'b', 'c', 'd'], name='idx')) 

1676 

1677 Generate a DataFrame with default index. 

1678 

1679 >>> s.reset_index() 

1680 idx foo 

1681 0 a 1 

1682 1 b 2 

1683 2 c 3 

1684 3 d 4 

1685 

1686 To specify the name of the new column use `name`. 

1687 

1688 >>> s.reset_index(name='values') 

1689 idx values 

1690 0 a 1 

1691 1 b 2 

1692 2 c 3 

1693 3 d 4 

1694 

1695 To generate a new Series with the default set `drop` to True. 

1696 

1697 >>> s.reset_index(drop=True) 

1698 0 1 

1699 1 2 

1700 2 3 

1701 3 4 

1702 Name: foo, dtype: int64 

1703 

1704 The `level` parameter is interesting for Series with a multi-level 

1705 index. 

1706 

1707 >>> arrays = [np.array(['bar', 'bar', 'baz', 'baz']), 

1708 ... np.array(['one', 'two', 'one', 'two'])] 

1709 >>> s2 = pd.Series( 

1710 ... range(4), name='foo', 

1711 ... index=pd.MultiIndex.from_arrays(arrays, 

1712 ... names=['a', 'b'])) 

1713 

1714 To remove a specific level from the Index, use `level`. 

1715 

1716 >>> s2.reset_index(level='a') 

1717 a foo 

1718 b 

1719 one bar 0 

1720 two bar 1 

1721 one baz 2 

1722 two baz 3 

1723 

1724 If `level` is not set, all levels are removed from the Index. 

1725 

1726 >>> s2.reset_index() 

1727 a b foo 

1728 0 bar one 0 

1729 1 bar two 1 

1730 2 baz one 2 

1731 3 baz two 3 

1732 """ 

1733 inplace = validate_bool_kwarg(inplace, "inplace") 

1734 if drop: 

1735 new_index = default_index(len(self)) 

1736 if level is not None: 

1737 level_list: Sequence[Hashable] 

1738 if not isinstance(level, (tuple, list)): 

1739 level_list = [level] 

1740 else: 

1741 level_list = level 

1742 level_list = [self.index._get_level_number(lev) for lev in level_list] 

1743 if len(level_list) < self.index.nlevels: 

1744 new_index = self.index.droplevel(level_list) 

1745 

1746 if inplace: 

1747 self.index = new_index 

1748 elif using_copy_on_write(): 

1749 new_ser = self.copy(deep=False) 

1750 new_ser.index = new_index 

1751 return new_ser.__finalize__(self, method="reset_index") 

1752 else: 

1753 return self._constructor( 

1754 self._values.copy(), index=new_index, copy=False, dtype=self.dtype 

1755 ).__finalize__(self, method="reset_index") 

1756 elif inplace: 

1757 raise TypeError( 

1758 "Cannot reset_index inplace on a Series to create a DataFrame" 

1759 ) 

1760 else: 

1761 if name is lib.no_default: 

1762 # For backwards compatibility, keep columns as [0] instead of 

1763 # [None] when self.name is None 

1764 if self.name is None: 

1765 name = 0 

1766 else: 

1767 name = self.name 

1768 

1769 df = self.to_frame(name) 

1770 return df.reset_index( 

1771 level=level, drop=drop, allow_duplicates=allow_duplicates 

1772 ) 

1773 return None 

1774 

1775 # ---------------------------------------------------------------------- 

1776 # Rendering Methods 

1777 

1778 def __repr__(self) -> str: 

1779 """ 

1780 Return a string representation for a particular Series. 

1781 """ 

1782 # pylint: disable=invalid-repr-returned 

1783 repr_params = fmt.get_series_repr_params() 

1784 return self.to_string(**repr_params) 

1785 

1786 @overload 

1787 def to_string( 

1788 self, 

1789 buf: None = ..., 

1790 na_rep: str = ..., 

1791 float_format: str | None = ..., 

1792 header: bool = ..., 

1793 index: bool = ..., 

1794 length: bool = ..., 

1795 dtype=..., 

1796 name=..., 

1797 max_rows: int | None = ..., 

1798 min_rows: int | None = ..., 

1799 ) -> str: 

1800 ... 

1801 

1802 @overload 

1803 def to_string( 

1804 self, 

1805 buf: FilePath | WriteBuffer[str], 

1806 na_rep: str = ..., 

1807 float_format: str | None = ..., 

1808 header: bool = ..., 

1809 index: bool = ..., 

1810 length: bool = ..., 

1811 dtype=..., 

1812 name=..., 

1813 max_rows: int | None = ..., 

1814 min_rows: int | None = ..., 

1815 ) -> None: 

1816 ... 

1817 

1818 def to_string( 

1819 self, 

1820 buf: FilePath | WriteBuffer[str] | None = None, 

1821 na_rep: str = "NaN", 

1822 float_format: str | None = None, 

1823 header: bool = True, 

1824 index: bool = True, 

1825 length: bool = False, 

1826 dtype: bool = False, 

1827 name: bool = False, 

1828 max_rows: int | None = None, 

1829 min_rows: int | None = None, 

1830 ) -> str | None: 

1831 """ 

1832 Render a string representation of the Series. 

1833 

1834 Parameters 

1835 ---------- 

1836 buf : StringIO-like, optional 

1837 Buffer to write to. 

1838 na_rep : str, optional 

1839 String representation of NaN to use, default 'NaN'. 

1840 float_format : one-parameter function, optional 

1841 Formatter function to apply to columns' elements if they are 

1842 floats, default None. 

1843 header : bool, default True 

1844 Add the Series header (index name). 

1845 index : bool, optional 

1846 Add index (row) labels, default True. 

1847 length : bool, default False 

1848 Add the Series length. 

1849 dtype : bool, default False 

1850 Add the Series dtype. 

1851 name : bool, default False 

1852 Add the Series name if not None. 

1853 max_rows : int, optional 

1854 Maximum number of rows to show before truncating. If None, show 

1855 all. 

1856 min_rows : int, optional 

1857 The number of rows to display in a truncated repr (when number 

1858 of rows is above `max_rows`). 

1859 

1860 Returns 

1861 ------- 

1862 str or None 

1863 String representation of Series if ``buf=None``, otherwise None. 

1864 

1865 Examples 

1866 -------- 

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

1868 >>> ser 

1869 '0 1\\n1 2\\n2 3' 

1870 """ 

1871 formatter = fmt.SeriesFormatter( 

1872 self, 

1873 name=name, 

1874 length=length, 

1875 header=header, 

1876 index=index, 

1877 dtype=dtype, 

1878 na_rep=na_rep, 

1879 float_format=float_format, 

1880 min_rows=min_rows, 

1881 max_rows=max_rows, 

1882 ) 

1883 result = formatter.to_string() 

1884 

1885 # catch contract violations 

1886 if not isinstance(result, str): 

1887 raise AssertionError( 

1888 "result must be of type str, type " 

1889 f"of result is {repr(type(result).__name__)}" 

1890 ) 

1891 

1892 if buf is None: 

1893 return result 

1894 else: 

1895 if hasattr(buf, "write"): 

1896 buf.write(result) 

1897 else: 

1898 with open(buf, "w", encoding="utf-8") as f: 

1899 f.write(result) 

1900 return None 

1901 

1902 @doc( 

1903 klass=_shared_doc_kwargs["klass"], 

1904 storage_options=_shared_docs["storage_options"], 

1905 examples=dedent( 

1906 """Examples 

1907 -------- 

1908 >>> s = pd.Series(["elk", "pig", "dog", "quetzal"], name="animal") 

1909 >>> print(s.to_markdown()) 

1910 | | animal | 

1911 |---:|:---------| 

1912 | 0 | elk | 

1913 | 1 | pig | 

1914 | 2 | dog | 

1915 | 3 | quetzal | 

1916 

1917 Output markdown with a tabulate option. 

1918 

1919 >>> print(s.to_markdown(tablefmt="grid")) 

1920 +----+----------+ 

1921 | | animal | 

1922 +====+==========+ 

1923 | 0 | elk | 

1924 +----+----------+ 

1925 | 1 | pig | 

1926 +----+----------+ 

1927 | 2 | dog | 

1928 +----+----------+ 

1929 | 3 | quetzal | 

1930 +----+----------+""" 

1931 ), 

1932 ) 

1933 def to_markdown( 

1934 self, 

1935 buf: IO[str] | None = None, 

1936 mode: str = "wt", 

1937 index: bool = True, 

1938 storage_options: StorageOptions | None = None, 

1939 **kwargs, 

1940 ) -> str | None: 

1941 """ 

1942 Print {klass} in Markdown-friendly format. 

1943 

1944 Parameters 

1945 ---------- 

1946 buf : str, Path or StringIO-like, optional, default None 

1947 Buffer to write to. If None, the output is returned as a string. 

1948 mode : str, optional 

1949 Mode in which file is opened, "wt" by default. 

1950 index : bool, optional, default True 

1951 Add index (row) labels. 

1952 

1953 {storage_options} 

1954 

1955 **kwargs 

1956 These parameters will be passed to `tabulate \ 

1957 <https://pypi.org/project/tabulate>`_. 

1958 

1959 Returns 

1960 ------- 

1961 str 

1962 {klass} in Markdown-friendly format. 

1963 

1964 Notes 

1965 ----- 

1966 Requires the `tabulate <https://pypi.org/project/tabulate>`_ package. 

1967 

1968 {examples} 

1969 """ 

1970 return self.to_frame().to_markdown( 

1971 buf, mode=mode, index=index, storage_options=storage_options, **kwargs 

1972 ) 

1973 

1974 # ---------------------------------------------------------------------- 

1975 

1976 def items(self) -> Iterable[tuple[Hashable, Any]]: 

1977 """ 

1978 Lazily iterate over (index, value) tuples. 

1979 

1980 This method returns an iterable tuple (index, value). This is 

1981 convenient if you want to create a lazy iterator. 

1982 

1983 Returns 

1984 ------- 

1985 iterable 

1986 Iterable of tuples containing the (index, value) pairs from a 

1987 Series. 

1988 

1989 See Also 

1990 -------- 

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

1992 DataFrame.iterrows : Iterate over DataFrame rows as (index, Series) pairs. 

1993 

1994 Examples 

1995 -------- 

1996 >>> s = pd.Series(['A', 'B', 'C']) 

1997 >>> for index, value in s.items(): 

1998 ... print(f"Index : {index}, Value : {value}") 

1999 Index : 0, Value : A 

2000 Index : 1, Value : B 

2001 Index : 2, Value : C 

2002 """ 

2003 return zip(iter(self.index), iter(self)) 

2004 

2005 # ---------------------------------------------------------------------- 

2006 # Misc public methods 

2007 

2008 def keys(self) -> Index: 

2009 """ 

2010 Return alias for index. 

2011 

2012 Returns 

2013 ------- 

2014 Index 

2015 Index of the Series. 

2016 

2017 Examples 

2018 -------- 

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

2020 >>> s.keys() 

2021 Index([0, 1, 2], dtype='int64') 

2022 """ 

2023 return self.index 

2024 

2025 @overload 

2026 def to_dict( 

2027 self, *, into: type[MutableMappingT] | MutableMappingT 

2028 ) -> MutableMappingT: 

2029 ... 

2030 

2031 @overload 

2032 def to_dict(self, *, into: type[dict] = ...) -> dict: 

2033 ... 

2034 

2035 # error: Incompatible default for argument "into" (default has type "type[ 

2036 # dict[Any, Any]]", argument has type "type[MutableMappingT] | MutableMappingT") 

2037 @deprecate_nonkeyword_arguments( 

2038 version="3.0", allowed_args=["self"], name="to_dict" 

2039 ) 

2040 def to_dict( 

2041 self, 

2042 into: type[MutableMappingT] 

2043 | MutableMappingT = dict, # type: ignore[assignment] 

2044 ) -> MutableMappingT: 

2045 """ 

2046 Convert Series to {label -> value} dict or dict-like object. 

2047 

2048 Parameters 

2049 ---------- 

2050 into : class, default dict 

2051 The collections.abc.MutableMapping subclass to use as the return 

2052 object. Can be the actual class or an empty instance of the mapping 

2053 type you want. If you want a collections.defaultdict, you must 

2054 pass it initialized. 

2055 

2056 Returns 

2057 ------- 

2058 collections.abc.MutableMapping 

2059 Key-value representation of Series. 

2060 

2061 Examples 

2062 -------- 

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

2064 >>> s.to_dict() 

2065 {0: 1, 1: 2, 2: 3, 3: 4} 

2066 >>> from collections import OrderedDict, defaultdict 

2067 >>> s.to_dict(into=OrderedDict) 

2068 OrderedDict([(0, 1), (1, 2), (2, 3), (3, 4)]) 

2069 >>> dd = defaultdict(list) 

2070 >>> s.to_dict(into=dd) 

2071 defaultdict(<class 'list'>, {0: 1, 1: 2, 2: 3, 3: 4}) 

2072 """ 

2073 # GH16122 

2074 into_c = com.standardize_mapping(into) 

2075 

2076 if is_object_dtype(self.dtype) or isinstance(self.dtype, ExtensionDtype): 

2077 return into_c((k, maybe_box_native(v)) for k, v in self.items()) 

2078 else: 

2079 # Not an object dtype => all types will be the same so let the default 

2080 # indexer return native python type 

2081 return into_c(self.items()) 

2082 

2083 def to_frame(self, name: Hashable = lib.no_default) -> DataFrame: 

2084 """ 

2085 Convert Series to DataFrame. 

2086 

2087 Parameters 

2088 ---------- 

2089 name : object, optional 

2090 The passed name should substitute for the series name (if it has 

2091 one). 

2092 

2093 Returns 

2094 ------- 

2095 DataFrame 

2096 DataFrame representation of Series. 

2097 

2098 Examples 

2099 -------- 

2100 >>> s = pd.Series(["a", "b", "c"], 

2101 ... name="vals") 

2102 >>> s.to_frame() 

2103 vals 

2104 0 a 

2105 1 b 

2106 2 c 

2107 """ 

2108 columns: Index 

2109 if name is lib.no_default: 

2110 name = self.name 

2111 if name is None: 

2112 # default to [0], same as we would get with DataFrame(self) 

2113 columns = default_index(1) 

2114 else: 

2115 columns = Index([name]) 

2116 else: 

2117 columns = Index([name]) 

2118 

2119 mgr = self._mgr.to_2d_mgr(columns) 

2120 df = self._constructor_expanddim_from_mgr(mgr, axes=mgr.axes) 

2121 return df.__finalize__(self, method="to_frame") 

2122 

2123 def _set_name( 

2124 self, name, inplace: bool = False, deep: bool | None = None 

2125 ) -> Series: 

2126 """ 

2127 Set the Series name. 

2128 

2129 Parameters 

2130 ---------- 

2131 name : str 

2132 inplace : bool 

2133 Whether to modify `self` directly or return a copy. 

2134 deep : bool|None, default None 

2135 Whether to do a deep copy, a shallow copy, or Copy on Write(None) 

2136 """ 

2137 inplace = validate_bool_kwarg(inplace, "inplace") 

2138 ser = self if inplace else self.copy(deep and not using_copy_on_write()) 

2139 ser.name = name 

2140 return ser 

2141 

2142 @Appender( 

2143 dedent( 

2144 """ 

2145 Examples 

2146 -------- 

2147 >>> ser = pd.Series([390., 350., 30., 20.], 

2148 ... index=['Falcon', 'Falcon', 'Parrot', 'Parrot'], 

2149 ... name="Max Speed") 

2150 >>> ser 

2151 Falcon 390.0 

2152 Falcon 350.0 

2153 Parrot 30.0 

2154 Parrot 20.0 

2155 Name: Max Speed, dtype: float64 

2156 >>> ser.groupby(["a", "b", "a", "b"]).mean() 

2157 a 210.0 

2158 b 185.0 

2159 Name: Max Speed, dtype: float64 

2160 >>> ser.groupby(level=0).mean() 

2161 Falcon 370.0 

2162 Parrot 25.0 

2163 Name: Max Speed, dtype: float64 

2164 >>> ser.groupby(ser > 100).mean() 

2165 Max Speed 

2166 False 25.0 

2167 True 370.0 

2168 Name: Max Speed, dtype: float64 

2169 

2170 **Grouping by Indexes** 

2171 

2172 We can groupby different levels of a hierarchical index 

2173 using the `level` parameter: 

2174 

2175 >>> arrays = [['Falcon', 'Falcon', 'Parrot', 'Parrot'], 

2176 ... ['Captive', 'Wild', 'Captive', 'Wild']] 

2177 >>> index = pd.MultiIndex.from_arrays(arrays, names=('Animal', 'Type')) 

2178 >>> ser = pd.Series([390., 350., 30., 20.], index=index, name="Max Speed") 

2179 >>> ser 

2180 Animal Type 

2181 Falcon Captive 390.0 

2182 Wild 350.0 

2183 Parrot Captive 30.0 

2184 Wild 20.0 

2185 Name: Max Speed, dtype: float64 

2186 >>> ser.groupby(level=0).mean() 

2187 Animal 

2188 Falcon 370.0 

2189 Parrot 25.0 

2190 Name: Max Speed, dtype: float64 

2191 >>> ser.groupby(level="Type").mean() 

2192 Type 

2193 Captive 210.0 

2194 Wild 185.0 

2195 Name: Max Speed, dtype: float64 

2196 

2197 We can also choose to include `NA` in group keys or not by defining 

2198 `dropna` parameter, the default setting is `True`. 

2199 

2200 >>> ser = pd.Series([1, 2, 3, 3], index=["a", 'a', 'b', np.nan]) 

2201 >>> ser.groupby(level=0).sum() 

2202 a 3 

2203 b 3 

2204 dtype: int64 

2205 

2206 >>> ser.groupby(level=0, dropna=False).sum() 

2207 a 3 

2208 b 3 

2209 NaN 3 

2210 dtype: int64 

2211 

2212 >>> arrays = ['Falcon', 'Falcon', 'Parrot', 'Parrot'] 

2213 >>> ser = pd.Series([390., 350., 30., 20.], index=arrays, name="Max Speed") 

2214 >>> ser.groupby(["a", "b", "a", np.nan]).mean() 

2215 a 210.0 

2216 b 350.0 

2217 Name: Max Speed, dtype: float64 

2218 

2219 >>> ser.groupby(["a", "b", "a", np.nan], dropna=False).mean() 

2220 a 210.0 

2221 b 350.0 

2222 NaN 20.0 

2223 Name: Max Speed, dtype: float64 

2224 """ 

2225 ) 

2226 ) 

2227 @Appender(_shared_docs["groupby"] % _shared_doc_kwargs) 

2228 def groupby( 

2229 self, 

2230 by=None, 

2231 axis: Axis = 0, 

2232 level: IndexLabel | None = None, 

2233 as_index: bool = True, 

2234 sort: bool = True, 

2235 group_keys: bool = True, 

2236 observed: bool | lib.NoDefault = lib.no_default, 

2237 dropna: bool = True, 

2238 ) -> SeriesGroupBy: 

2239 from pandas.core.groupby.generic import SeriesGroupBy 

2240 

2241 if level is None and by is None: 

2242 raise TypeError("You have to supply one of 'by' and 'level'") 

2243 if not as_index: 

2244 raise TypeError("as_index=False only valid with DataFrame") 

2245 axis = self._get_axis_number(axis) 

2246 

2247 return SeriesGroupBy( 

2248 obj=self, 

2249 keys=by, 

2250 axis=axis, 

2251 level=level, 

2252 as_index=as_index, 

2253 sort=sort, 

2254 group_keys=group_keys, 

2255 observed=observed, 

2256 dropna=dropna, 

2257 ) 

2258 

2259 # ---------------------------------------------------------------------- 

2260 # Statistics, overridden ndarray methods 

2261 

2262 # TODO: integrate bottleneck 

2263 def count(self) -> int: 

2264 """ 

2265 Return number of non-NA/null observations in the Series. 

2266 

2267 Returns 

2268 ------- 

2269 int 

2270 Number of non-null values in the Series. 

2271 

2272 See Also 

2273 -------- 

2274 DataFrame.count : Count non-NA cells for each column or row. 

2275 

2276 Examples 

2277 -------- 

2278 >>> s = pd.Series([0.0, 1.0, np.nan]) 

2279 >>> s.count() 

2280 2 

2281 """ 

2282 return notna(self._values).sum().astype("int64") 

2283 

2284 def mode(self, dropna: bool = True) -> Series: 

2285 """ 

2286 Return the mode(s) of the Series. 

2287 

2288 The mode is the value that appears most often. There can be multiple modes. 

2289 

2290 Always returns Series even if only one value is returned. 

2291 

2292 Parameters 

2293 ---------- 

2294 dropna : bool, default True 

2295 Don't consider counts of NaN/NaT. 

2296 

2297 Returns 

2298 ------- 

2299 Series 

2300 Modes of the Series in sorted order. 

2301 

2302 Examples 

2303 -------- 

2304 >>> s = pd.Series([2, 4, 2, 2, 4, None]) 

2305 >>> s.mode() 

2306 0 2.0 

2307 dtype: float64 

2308 

2309 More than one mode: 

2310 

2311 >>> s = pd.Series([2, 4, 8, 2, 4, None]) 

2312 >>> s.mode() 

2313 0 2.0 

2314 1 4.0 

2315 dtype: float64 

2316 

2317 With and without considering null value: 

2318 

2319 >>> s = pd.Series([2, 4, None, None, 4, None]) 

2320 >>> s.mode(dropna=False) 

2321 0 NaN 

2322 dtype: float64 

2323 >>> s = pd.Series([2, 4, None, None, 4, None]) 

2324 >>> s.mode() 

2325 0 4.0 

2326 dtype: float64 

2327 """ 

2328 # TODO: Add option for bins like value_counts() 

2329 values = self._values 

2330 if isinstance(values, np.ndarray): 

2331 res_values = algorithms.mode(values, dropna=dropna) 

2332 else: 

2333 res_values = values._mode(dropna=dropna) 

2334 

2335 # Ensure index is type stable (should always use int index) 

2336 return self._constructor( 

2337 res_values, 

2338 index=range(len(res_values)), 

2339 name=self.name, 

2340 copy=False, 

2341 dtype=self.dtype, 

2342 ).__finalize__(self, method="mode") 

2343 

2344 def unique(self) -> ArrayLike: # pylint: disable=useless-parent-delegation 

2345 """ 

2346 Return unique values of Series object. 

2347 

2348 Uniques are returned in order of appearance. Hash table-based unique, 

2349 therefore does NOT sort. 

2350 

2351 Returns 

2352 ------- 

2353 ndarray or ExtensionArray 

2354 The unique values returned as a NumPy array. See Notes. 

2355 

2356 See Also 

2357 -------- 

2358 Series.drop_duplicates : Return Series with duplicate values removed. 

2359 unique : Top-level unique method for any 1-d array-like object. 

2360 Index.unique : Return Index with unique values from an Index object. 

2361 

2362 Notes 

2363 ----- 

2364 Returns the unique values as a NumPy array. In case of an 

2365 extension-array backed Series, a new 

2366 :class:`~api.extensions.ExtensionArray` of that type with just 

2367 the unique values is returned. This includes 

2368 

2369 * Categorical 

2370 * Period 

2371 * Datetime with Timezone 

2372 * Datetime without Timezone 

2373 * Timedelta 

2374 * Interval 

2375 * Sparse 

2376 * IntegerNA 

2377 

2378 See Examples section. 

2379 

2380 Examples 

2381 -------- 

2382 >>> pd.Series([2, 1, 3, 3], name='A').unique() 

2383 array([2, 1, 3]) 

2384 

2385 >>> pd.Series([pd.Timestamp('2016-01-01') for _ in range(3)]).unique() 

2386 <DatetimeArray> 

2387 ['2016-01-01 00:00:00'] 

2388 Length: 1, dtype: datetime64[ns] 

2389 

2390 >>> pd.Series([pd.Timestamp('2016-01-01', tz='US/Eastern') 

2391 ... for _ in range(3)]).unique() 

2392 <DatetimeArray> 

2393 ['2016-01-01 00:00:00-05:00'] 

2394 Length: 1, dtype: datetime64[ns, US/Eastern] 

2395 

2396 An Categorical will return categories in the order of 

2397 appearance and with the same dtype. 

2398 

2399 >>> pd.Series(pd.Categorical(list('baabc'))).unique() 

2400 ['b', 'a', 'c'] 

2401 Categories (3, object): ['a', 'b', 'c'] 

2402 >>> pd.Series(pd.Categorical(list('baabc'), categories=list('abc'), 

2403 ... ordered=True)).unique() 

2404 ['b', 'a', 'c'] 

2405 Categories (3, object): ['a' < 'b' < 'c'] 

2406 """ 

2407 return super().unique() 

2408 

2409 @overload 

2410 def drop_duplicates( 

2411 self, 

2412 *, 

2413 keep: DropKeep = ..., 

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

2415 ignore_index: bool = ..., 

2416 ) -> Series: 

2417 ... 

2418 

2419 @overload 

2420 def drop_duplicates( 

2421 self, *, keep: DropKeep = ..., inplace: Literal[True], ignore_index: bool = ... 

2422 ) -> None: 

2423 ... 

2424 

2425 @overload 

2426 def drop_duplicates( 

2427 self, *, keep: DropKeep = ..., inplace: bool = ..., ignore_index: bool = ... 

2428 ) -> Series | None: 

2429 ... 

2430 

2431 def drop_duplicates( 

2432 self, 

2433 *, 

2434 keep: DropKeep = "first", 

2435 inplace: bool = False, 

2436 ignore_index: bool = False, 

2437 ) -> Series | None: 

2438 """ 

2439 Return Series with duplicate values removed. 

2440 

2441 Parameters 

2442 ---------- 

2443 keep : {'first', 'last', ``False``}, default 'first' 

2444 Method to handle dropping duplicates: 

2445 

2446 - 'first' : Drop duplicates except for the first occurrence. 

2447 - 'last' : Drop duplicates except for the last occurrence. 

2448 - ``False`` : Drop all duplicates. 

2449 

2450 inplace : bool, default ``False`` 

2451 If ``True``, performs operation inplace and returns None. 

2452 

2453 ignore_index : bool, default ``False`` 

2454 If ``True``, the resulting axis will be labeled 0, 1, …, n - 1. 

2455 

2456 .. versionadded:: 2.0.0 

2457 

2458 Returns 

2459 ------- 

2460 Series or None 

2461 Series with duplicates dropped or None if ``inplace=True``. 

2462 

2463 See Also 

2464 -------- 

2465 Index.drop_duplicates : Equivalent method on Index. 

2466 DataFrame.drop_duplicates : Equivalent method on DataFrame. 

2467 Series.duplicated : Related method on Series, indicating duplicate 

2468 Series values. 

2469 Series.unique : Return unique values as an array. 

2470 

2471 Examples 

2472 -------- 

2473 Generate a Series with duplicated entries. 

2474 

2475 >>> s = pd.Series(['llama', 'cow', 'llama', 'beetle', 'llama', 'hippo'], 

2476 ... name='animal') 

2477 >>> s 

2478 0 llama 

2479 1 cow 

2480 2 llama 

2481 3 beetle 

2482 4 llama 

2483 5 hippo 

2484 Name: animal, dtype: object 

2485 

2486 With the 'keep' parameter, the selection behaviour of duplicated values 

2487 can be changed. The value 'first' keeps the first occurrence for each 

2488 set of duplicated entries. The default value of keep is 'first'. 

2489 

2490 >>> s.drop_duplicates() 

2491 0 llama 

2492 1 cow 

2493 3 beetle 

2494 5 hippo 

2495 Name: animal, dtype: object 

2496 

2497 The value 'last' for parameter 'keep' keeps the last occurrence for 

2498 each set of duplicated entries. 

2499 

2500 >>> s.drop_duplicates(keep='last') 

2501 1 cow 

2502 3 beetle 

2503 4 llama 

2504 5 hippo 

2505 Name: animal, dtype: object 

2506 

2507 The value ``False`` for parameter 'keep' discards all sets of 

2508 duplicated entries. 

2509 

2510 >>> s.drop_duplicates(keep=False) 

2511 1 cow 

2512 3 beetle 

2513 5 hippo 

2514 Name: animal, dtype: object 

2515 """ 

2516 inplace = validate_bool_kwarg(inplace, "inplace") 

2517 result = super().drop_duplicates(keep=keep) 

2518 

2519 if ignore_index: 

2520 result.index = default_index(len(result)) 

2521 

2522 if inplace: 

2523 self._update_inplace(result) 

2524 return None 

2525 else: 

2526 return result 

2527 

2528 def duplicated(self, keep: DropKeep = "first") -> Series: 

2529 """ 

2530 Indicate duplicate Series values. 

2531 

2532 Duplicated values are indicated as ``True`` values in the resulting 

2533 Series. Either all duplicates, all except the first or all except the 

2534 last occurrence of duplicates can be indicated. 

2535 

2536 Parameters 

2537 ---------- 

2538 keep : {'first', 'last', False}, default 'first' 

2539 Method to handle dropping duplicates: 

2540 

2541 - 'first' : Mark duplicates as ``True`` except for the first 

2542 occurrence. 

2543 - 'last' : Mark duplicates as ``True`` except for the last 

2544 occurrence. 

2545 - ``False`` : Mark all duplicates as ``True``. 

2546 

2547 Returns 

2548 ------- 

2549 Series[bool] 

2550 Series indicating whether each value has occurred in the 

2551 preceding values. 

2552 

2553 See Also 

2554 -------- 

2555 Index.duplicated : Equivalent method on pandas.Index. 

2556 DataFrame.duplicated : Equivalent method on pandas.DataFrame. 

2557 Series.drop_duplicates : Remove duplicate values from Series. 

2558 

2559 Examples 

2560 -------- 

2561 By default, for each set of duplicated values, the first occurrence is 

2562 set on False and all others on True: 

2563 

2564 >>> animals = pd.Series(['llama', 'cow', 'llama', 'beetle', 'llama']) 

2565 >>> animals.duplicated() 

2566 0 False 

2567 1 False 

2568 2 True 

2569 3 False 

2570 4 True 

2571 dtype: bool 

2572 

2573 which is equivalent to 

2574 

2575 >>> animals.duplicated(keep='first') 

2576 0 False 

2577 1 False 

2578 2 True 

2579 3 False 

2580 4 True 

2581 dtype: bool 

2582 

2583 By using 'last', the last occurrence of each set of duplicated values 

2584 is set on False and all others on True: 

2585 

2586 >>> animals.duplicated(keep='last') 

2587 0 True 

2588 1 False 

2589 2 True 

2590 3 False 

2591 4 False 

2592 dtype: bool 

2593 

2594 By setting keep on ``False``, all duplicates are True: 

2595 

2596 >>> animals.duplicated(keep=False) 

2597 0 True 

2598 1 False 

2599 2 True 

2600 3 False 

2601 4 True 

2602 dtype: bool 

2603 """ 

2604 res = self._duplicated(keep=keep) 

2605 result = self._constructor(res, index=self.index, copy=False) 

2606 return result.__finalize__(self, method="duplicated") 

2607 

2608 def idxmin(self, axis: Axis = 0, skipna: bool = True, *args, **kwargs) -> Hashable: 

2609 """ 

2610 Return the row label of the minimum value. 

2611 

2612 If multiple values equal the minimum, the first row label with that 

2613 value is returned. 

2614 

2615 Parameters 

2616 ---------- 

2617 axis : {0 or 'index'} 

2618 Unused. Parameter needed for compatibility with DataFrame. 

2619 skipna : bool, default True 

2620 Exclude NA/null values. If the entire Series is NA, the result 

2621 will be NA. 

2622 *args, **kwargs 

2623 Additional arguments and keywords have no effect but might be 

2624 accepted for compatibility with NumPy. 

2625 

2626 Returns 

2627 ------- 

2628 Index 

2629 Label of the minimum value. 

2630 

2631 Raises 

2632 ------ 

2633 ValueError 

2634 If the Series is empty. 

2635 

2636 See Also 

2637 -------- 

2638 numpy.argmin : Return indices of the minimum values 

2639 along the given axis. 

2640 DataFrame.idxmin : Return index of first occurrence of minimum 

2641 over requested axis. 

2642 Series.idxmax : Return index *label* of the first occurrence 

2643 of maximum of values. 

2644 

2645 Notes 

2646 ----- 

2647 This method is the Series version of ``ndarray.argmin``. This method 

2648 returns the label of the minimum, while ``ndarray.argmin`` returns 

2649 the position. To get the position, use ``series.values.argmin()``. 

2650 

2651 Examples 

2652 -------- 

2653 >>> s = pd.Series(data=[1, None, 4, 1], 

2654 ... index=['A', 'B', 'C', 'D']) 

2655 >>> s 

2656 A 1.0 

2657 B NaN 

2658 C 4.0 

2659 D 1.0 

2660 dtype: float64 

2661 

2662 >>> s.idxmin() 

2663 'A' 

2664 

2665 If `skipna` is False and there is an NA value in the data, 

2666 the function returns ``nan``. 

2667 

2668 >>> s.idxmin(skipna=False) 

2669 nan 

2670 """ 

2671 axis = self._get_axis_number(axis) 

2672 with warnings.catch_warnings(): 

2673 # TODO(3.0): this catching/filtering can be removed 

2674 # ignore warning produced by argmin since we will issue a different 

2675 # warning for idxmin 

2676 warnings.simplefilter("ignore") 

2677 i = self.argmin(axis, skipna, *args, **kwargs) 

2678 

2679 if i == -1: 

2680 # GH#43587 give correct NA value for Index. 

2681 warnings.warn( 

2682 f"The behavior of {type(self).__name__}.idxmin with all-NA " 

2683 "values, or any-NA and skipna=False, is deprecated. In a future " 

2684 "version this will raise ValueError", 

2685 FutureWarning, 

2686 stacklevel=find_stack_level(), 

2687 ) 

2688 return self.index._na_value 

2689 return self.index[i] 

2690 

2691 def idxmax(self, axis: Axis = 0, skipna: bool = True, *args, **kwargs) -> Hashable: 

2692 """ 

2693 Return the row label of the maximum value. 

2694 

2695 If multiple values equal the maximum, the first row label with that 

2696 value is returned. 

2697 

2698 Parameters 

2699 ---------- 

2700 axis : {0 or 'index'} 

2701 Unused. Parameter needed for compatibility with DataFrame. 

2702 skipna : bool, default True 

2703 Exclude NA/null values. If the entire Series is NA, the result 

2704 will be NA. 

2705 *args, **kwargs 

2706 Additional arguments and keywords have no effect but might be 

2707 accepted for compatibility with NumPy. 

2708 

2709 Returns 

2710 ------- 

2711 Index 

2712 Label of the maximum value. 

2713 

2714 Raises 

2715 ------ 

2716 ValueError 

2717 If the Series is empty. 

2718 

2719 See Also 

2720 -------- 

2721 numpy.argmax : Return indices of the maximum values 

2722 along the given axis. 

2723 DataFrame.idxmax : Return index of first occurrence of maximum 

2724 over requested axis. 

2725 Series.idxmin : Return index *label* of the first occurrence 

2726 of minimum of values. 

2727 

2728 Notes 

2729 ----- 

2730 This method is the Series version of ``ndarray.argmax``. This method 

2731 returns the label of the maximum, while ``ndarray.argmax`` returns 

2732 the position. To get the position, use ``series.values.argmax()``. 

2733 

2734 Examples 

2735 -------- 

2736 >>> s = pd.Series(data=[1, None, 4, 3, 4], 

2737 ... index=['A', 'B', 'C', 'D', 'E']) 

2738 >>> s 

2739 A 1.0 

2740 B NaN 

2741 C 4.0 

2742 D 3.0 

2743 E 4.0 

2744 dtype: float64 

2745 

2746 >>> s.idxmax() 

2747 'C' 

2748 

2749 If `skipna` is False and there is an NA value in the data, 

2750 the function returns ``nan``. 

2751 

2752 >>> s.idxmax(skipna=False) 

2753 nan 

2754 """ 

2755 axis = self._get_axis_number(axis) 

2756 with warnings.catch_warnings(): 

2757 # TODO(3.0): this catching/filtering can be removed 

2758 # ignore warning produced by argmax since we will issue a different 

2759 # warning for argmax 

2760 warnings.simplefilter("ignore") 

2761 i = self.argmax(axis, skipna, *args, **kwargs) 

2762 

2763 if i == -1: 

2764 # GH#43587 give correct NA value for Index. 

2765 warnings.warn( 

2766 f"The behavior of {type(self).__name__}.idxmax with all-NA " 

2767 "values, or any-NA and skipna=False, is deprecated. In a future " 

2768 "version this will raise ValueError", 

2769 FutureWarning, 

2770 stacklevel=find_stack_level(), 

2771 ) 

2772 return self.index._na_value 

2773 return self.index[i] 

2774 

2775 def round(self, decimals: int = 0, *args, **kwargs) -> Series: 

2776 """ 

2777 Round each value in a Series to the given number of decimals. 

2778 

2779 Parameters 

2780 ---------- 

2781 decimals : int, default 0 

2782 Number of decimal places to round to. If decimals is negative, 

2783 it specifies the number of positions to the left of the decimal point. 

2784 *args, **kwargs 

2785 Additional arguments and keywords have no effect but might be 

2786 accepted for compatibility with NumPy. 

2787 

2788 Returns 

2789 ------- 

2790 Series 

2791 Rounded values of the Series. 

2792 

2793 See Also 

2794 -------- 

2795 numpy.around : Round values of an np.array. 

2796 DataFrame.round : Round values of a DataFrame. 

2797 

2798 Examples 

2799 -------- 

2800 >>> s = pd.Series([0.1, 1.3, 2.7]) 

2801 >>> s.round() 

2802 0 0.0 

2803 1 1.0 

2804 2 3.0 

2805 dtype: float64 

2806 """ 

2807 nv.validate_round(args, kwargs) 

2808 new_mgr = self._mgr.round(decimals=decimals, using_cow=using_copy_on_write()) 

2809 return self._constructor_from_mgr(new_mgr, axes=new_mgr.axes).__finalize__( 

2810 self, method="round" 

2811 ) 

2812 

2813 @overload 

2814 def quantile( 

2815 self, q: float = ..., interpolation: QuantileInterpolation = ... 

2816 ) -> float: 

2817 ... 

2818 

2819 @overload 

2820 def quantile( 

2821 self, 

2822 q: Sequence[float] | AnyArrayLike, 

2823 interpolation: QuantileInterpolation = ..., 

2824 ) -> Series: 

2825 ... 

2826 

2827 @overload 

2828 def quantile( 

2829 self, 

2830 q: float | Sequence[float] | AnyArrayLike = ..., 

2831 interpolation: QuantileInterpolation = ..., 

2832 ) -> float | Series: 

2833 ... 

2834 

2835 def quantile( 

2836 self, 

2837 q: float | Sequence[float] | AnyArrayLike = 0.5, 

2838 interpolation: QuantileInterpolation = "linear", 

2839 ) -> float | Series: 

2840 """ 

2841 Return value at the given quantile. 

2842 

2843 Parameters 

2844 ---------- 

2845 q : float or array-like, default 0.5 (50% quantile) 

2846 The quantile(s) to compute, which can lie in range: 0 <= q <= 1. 

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

2848 This optional parameter specifies the interpolation method to use, 

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

2850 

2851 * linear: `i + (j - i) * (x-i)/(j-i)`, where `(x-i)/(j-i)` is 

2852 the fractional part of the index surrounded by `i > j`. 

2853 * lower: `i`. 

2854 * higher: `j`. 

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

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

2857 

2858 Returns 

2859 ------- 

2860 float or Series 

2861 If ``q`` is an array, a Series will be returned where the 

2862 index is ``q`` and the values are the quantiles, otherwise 

2863 a float will be returned. 

2864 

2865 See Also 

2866 -------- 

2867 core.window.Rolling.quantile : Calculate the rolling quantile. 

2868 numpy.percentile : Returns the q-th percentile(s) of the array elements. 

2869 

2870 Examples 

2871 -------- 

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

2873 >>> s.quantile(.5) 

2874 2.5 

2875 >>> s.quantile([.25, .5, .75]) 

2876 0.25 1.75 

2877 0.50 2.50 

2878 0.75 3.25 

2879 dtype: float64 

2880 """ 

2881 validate_percentile(q) 

2882 

2883 # We dispatch to DataFrame so that core.internals only has to worry 

2884 # about 2D cases. 

2885 df = self.to_frame() 

2886 

2887 result = df.quantile(q=q, interpolation=interpolation, numeric_only=False) 

2888 if result.ndim == 2: 

2889 result = result.iloc[:, 0] 

2890 

2891 if is_list_like(q): 

2892 result.name = self.name 

2893 idx = Index(q, dtype=np.float64) 

2894 return self._constructor(result, index=idx, name=self.name) 

2895 else: 

2896 # scalar 

2897 return result.iloc[0] 

2898 

2899 def corr( 

2900 self, 

2901 other: Series, 

2902 method: CorrelationMethod = "pearson", 

2903 min_periods: int | None = None, 

2904 ) -> float: 

2905 """ 

2906 Compute correlation with `other` Series, excluding missing values. 

2907 

2908 The two `Series` objects are not required to be the same length and will be 

2909 aligned internally before the correlation function is applied. 

2910 

2911 Parameters 

2912 ---------- 

2913 other : Series 

2914 Series with which to compute the correlation. 

2915 method : {'pearson', 'kendall', 'spearman'} or callable 

2916 Method used to compute correlation: 

2917 

2918 - pearson : Standard correlation coefficient 

2919 - kendall : Kendall Tau correlation coefficient 

2920 - spearman : Spearman rank correlation 

2921 - callable: Callable with input two 1d ndarrays and returning a float. 

2922 

2923 .. warning:: 

2924 Note that the returned matrix from corr will have 1 along the 

2925 diagonals and will be symmetric regardless of the callable's 

2926 behavior. 

2927 min_periods : int, optional 

2928 Minimum number of observations needed to have a valid result. 

2929 

2930 Returns 

2931 ------- 

2932 float 

2933 Correlation with other. 

2934 

2935 See Also 

2936 -------- 

2937 DataFrame.corr : Compute pairwise correlation between columns. 

2938 DataFrame.corrwith : Compute pairwise correlation with another 

2939 DataFrame or Series. 

2940 

2941 Notes 

2942 ----- 

2943 Pearson, Kendall and Spearman correlation are currently computed using pairwise complete observations. 

2944 

2945 * `Pearson correlation coefficient <https://en.wikipedia.org/wiki/Pearson_correlation_coefficient>`_ 

2946 * `Kendall rank correlation coefficient <https://en.wikipedia.org/wiki/Kendall_rank_correlation_coefficient>`_ 

2947 * `Spearman's rank correlation coefficient <https://en.wikipedia.org/wiki/Spearman%27s_rank_correlation_coefficient>`_ 

2948 

2949 Automatic data alignment: as with all pandas operations, automatic data alignment is performed for this method. 

2950 ``corr()`` automatically considers values with matching indices. 

2951 

2952 Examples 

2953 -------- 

2954 >>> def histogram_intersection(a, b): 

2955 ... v = np.minimum(a, b).sum().round(decimals=1) 

2956 ... return v 

2957 >>> s1 = pd.Series([.2, .0, .6, .2]) 

2958 >>> s2 = pd.Series([.3, .6, .0, .1]) 

2959 >>> s1.corr(s2, method=histogram_intersection) 

2960 0.3 

2961 

2962 Pandas auto-aligns the values with matching indices 

2963 

2964 >>> s1 = pd.Series([1, 2, 3], index=[0, 1, 2]) 

2965 >>> s2 = pd.Series([1, 2, 3], index=[2, 1, 0]) 

2966 >>> s1.corr(s2) 

2967 -1.0 

2968 """ # noqa: E501 

2969 this, other = self.align(other, join="inner", copy=False) 

2970 if len(this) == 0: 

2971 return np.nan 

2972 

2973 this_values = this.to_numpy(dtype=float, na_value=np.nan, copy=False) 

2974 other_values = other.to_numpy(dtype=float, na_value=np.nan, copy=False) 

2975 

2976 if method in ["pearson", "spearman", "kendall"] or callable(method): 

2977 return nanops.nancorr( 

2978 this_values, other_values, method=method, min_periods=min_periods 

2979 ) 

2980 

2981 raise ValueError( 

2982 "method must be either 'pearson', " 

2983 "'spearman', 'kendall', or a callable, " 

2984 f"'{method}' was supplied" 

2985 ) 

2986 

2987 def cov( 

2988 self, 

2989 other: Series, 

2990 min_periods: int | None = None, 

2991 ddof: int | None = 1, 

2992 ) -> float: 

2993 """ 

2994 Compute covariance with Series, excluding missing values. 

2995 

2996 The two `Series` objects are not required to be the same length and 

2997 will be aligned internally before the covariance is calculated. 

2998 

2999 Parameters 

3000 ---------- 

3001 other : Series 

3002 Series with which to compute the covariance. 

3003 min_periods : int, optional 

3004 Minimum number of observations needed to have a valid result. 

3005 ddof : int, default 1 

3006 Delta degrees of freedom. The divisor used in calculations 

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

3008 

3009 Returns 

3010 ------- 

3011 float 

3012 Covariance between Series and other normalized by N-1 

3013 (unbiased estimator). 

3014 

3015 See Also 

3016 -------- 

3017 DataFrame.cov : Compute pairwise covariance of columns. 

3018 

3019 Examples 

3020 -------- 

3021 >>> s1 = pd.Series([0.90010907, 0.13484424, 0.62036035]) 

3022 >>> s2 = pd.Series([0.12528585, 0.26962463, 0.51111198]) 

3023 >>> s1.cov(s2) 

3024 -0.01685762652715874 

3025 """ 

3026 this, other = self.align(other, join="inner", copy=False) 

3027 if len(this) == 0: 

3028 return np.nan 

3029 this_values = this.to_numpy(dtype=float, na_value=np.nan, copy=False) 

3030 other_values = other.to_numpy(dtype=float, na_value=np.nan, copy=False) 

3031 return nanops.nancov( 

3032 this_values, other_values, min_periods=min_periods, ddof=ddof 

3033 ) 

3034 

3035 @doc( 

3036 klass="Series", 

3037 extra_params="", 

3038 other_klass="DataFrame", 

3039 examples=dedent( 

3040 """ 

3041 Difference with previous row 

3042 

3043 >>> s = pd.Series([1, 1, 2, 3, 5, 8]) 

3044 >>> s.diff() 

3045 0 NaN 

3046 1 0.0 

3047 2 1.0 

3048 3 1.0 

3049 4 2.0 

3050 5 3.0 

3051 dtype: float64 

3052 

3053 Difference with 3rd previous row 

3054 

3055 >>> s.diff(periods=3) 

3056 0 NaN 

3057 1 NaN 

3058 2 NaN 

3059 3 2.0 

3060 4 4.0 

3061 5 6.0 

3062 dtype: float64 

3063 

3064 Difference with following row 

3065 

3066 >>> s.diff(periods=-1) 

3067 0 0.0 

3068 1 -1.0 

3069 2 -1.0 

3070 3 -2.0 

3071 4 -3.0 

3072 5 NaN 

3073 dtype: float64 

3074 

3075 Overflow in input dtype 

3076 

3077 >>> s = pd.Series([1, 0], dtype=np.uint8) 

3078 >>> s.diff() 

3079 0 NaN 

3080 1 255.0 

3081 dtype: float64""" 

3082 ), 

3083 ) 

3084 def diff(self, periods: int = 1) -> Series: 

3085 """ 

3086 First discrete difference of element. 

3087 

3088 Calculates the difference of a {klass} element compared with another 

3089 element in the {klass} (default is element in previous row). 

3090 

3091 Parameters 

3092 ---------- 

3093 periods : int, default 1 

3094 Periods to shift for calculating difference, accepts negative 

3095 values. 

3096 {extra_params} 

3097 Returns 

3098 ------- 

3099 {klass} 

3100 First differences of the Series. 

3101 

3102 See Also 

3103 -------- 

3104 {klass}.pct_change: Percent change over given number of periods. 

3105 {klass}.shift: Shift index by desired number of periods with an 

3106 optional time freq. 

3107 {other_klass}.diff: First discrete difference of object. 

3108 

3109 Notes 

3110 ----- 

3111 For boolean dtypes, this uses :meth:`operator.xor` rather than 

3112 :meth:`operator.sub`. 

3113 The result is calculated according to current dtype in {klass}, 

3114 however dtype of the result is always float64. 

3115 

3116 Examples 

3117 -------- 

3118 {examples} 

3119 """ 

3120 result = algorithms.diff(self._values, periods) 

3121 return self._constructor(result, index=self.index, copy=False).__finalize__( 

3122 self, method="diff" 

3123 ) 

3124 

3125 def autocorr(self, lag: int = 1) -> float: 

3126 """ 

3127 Compute the lag-N autocorrelation. 

3128 

3129 This method computes the Pearson correlation between 

3130 the Series and its shifted self. 

3131 

3132 Parameters 

3133 ---------- 

3134 lag : int, default 1 

3135 Number of lags to apply before performing autocorrelation. 

3136 

3137 Returns 

3138 ------- 

3139 float 

3140 The Pearson correlation between self and self.shift(lag). 

3141 

3142 See Also 

3143 -------- 

3144 Series.corr : Compute the correlation between two Series. 

3145 Series.shift : Shift index by desired number of periods. 

3146 DataFrame.corr : Compute pairwise correlation of columns. 

3147 DataFrame.corrwith : Compute pairwise correlation between rows or 

3148 columns of two DataFrame objects. 

3149 

3150 Notes 

3151 ----- 

3152 If the Pearson correlation is not well defined return 'NaN'. 

3153 

3154 Examples 

3155 -------- 

3156 >>> s = pd.Series([0.25, 0.5, 0.2, -0.05]) 

3157 >>> s.autocorr() # doctest: +ELLIPSIS 

3158 0.10355... 

3159 >>> s.autocorr(lag=2) # doctest: +ELLIPSIS 

3160 -0.99999... 

3161 

3162 If the Pearson correlation is not well defined, then 'NaN' is returned. 

3163 

3164 >>> s = pd.Series([1, 0, 0, 0]) 

3165 >>> s.autocorr() 

3166 nan 

3167 """ 

3168 return self.corr(cast(Series, self.shift(lag))) 

3169 

3170 def dot(self, other: AnyArrayLike) -> Series | np.ndarray: 

3171 """ 

3172 Compute the dot product between the Series and the columns of other. 

3173 

3174 This method computes the dot product between the Series and another 

3175 one, or the Series and each columns of a DataFrame, or the Series and 

3176 each columns of an array. 

3177 

3178 It can also be called using `self @ other`. 

3179 

3180 Parameters 

3181 ---------- 

3182 other : Series, DataFrame or array-like 

3183 The other object to compute the dot product with its columns. 

3184 

3185 Returns 

3186 ------- 

3187 scalar, Series or numpy.ndarray 

3188 Return the dot product of the Series and other if other is a 

3189 Series, the Series of the dot product of Series and each rows of 

3190 other if other is a DataFrame or a numpy.ndarray between the Series 

3191 and each columns of the numpy array. 

3192 

3193 See Also 

3194 -------- 

3195 DataFrame.dot: Compute the matrix product with the DataFrame. 

3196 Series.mul: Multiplication of series and other, element-wise. 

3197 

3198 Notes 

3199 ----- 

3200 The Series and other has to share the same index if other is a Series 

3201 or a DataFrame. 

3202 

3203 Examples 

3204 -------- 

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

3206 >>> other = pd.Series([-1, 2, -3, 4]) 

3207 >>> s.dot(other) 

3208 8 

3209 >>> s @ other 

3210 8 

3211 >>> df = pd.DataFrame([[0, 1], [-2, 3], [4, -5], [6, 7]]) 

3212 >>> s.dot(df) 

3213 0 24 

3214 1 14 

3215 dtype: int64 

3216 >>> arr = np.array([[0, 1], [-2, 3], [4, -5], [6, 7]]) 

3217 >>> s.dot(arr) 

3218 array([24, 14]) 

3219 """ 

3220 if isinstance(other, (Series, ABCDataFrame)): 

3221 common = self.index.union(other.index) 

3222 if len(common) > len(self.index) or len(common) > len(other.index): 

3223 raise ValueError("matrices are not aligned") 

3224 

3225 left = self.reindex(index=common, copy=False) 

3226 right = other.reindex(index=common, copy=False) 

3227 lvals = left.values 

3228 rvals = right.values 

3229 else: 

3230 lvals = self.values 

3231 rvals = np.asarray(other) 

3232 if lvals.shape[0] != rvals.shape[0]: 

3233 raise Exception( 

3234 f"Dot product shape mismatch, {lvals.shape} vs {rvals.shape}" 

3235 ) 

3236 

3237 if isinstance(other, ABCDataFrame): 

3238 return self._constructor( 

3239 np.dot(lvals, rvals), index=other.columns, copy=False 

3240 ).__finalize__(self, method="dot") 

3241 elif isinstance(other, Series): 

3242 return np.dot(lvals, rvals) 

3243 elif isinstance(rvals, np.ndarray): 

3244 return np.dot(lvals, rvals) 

3245 else: # pragma: no cover 

3246 raise TypeError(f"unsupported type: {type(other)}") 

3247 

3248 def __matmul__(self, other): 

3249 """ 

3250 Matrix multiplication using binary `@` operator. 

3251 """ 

3252 return self.dot(other) 

3253 

3254 def __rmatmul__(self, other): 

3255 """ 

3256 Matrix multiplication using binary `@` operator. 

3257 """ 

3258 return self.dot(np.transpose(other)) 

3259 

3260 @doc(base.IndexOpsMixin.searchsorted, klass="Series") 

3261 # Signature of "searchsorted" incompatible with supertype "IndexOpsMixin" 

3262 def searchsorted( # type: ignore[override] 

3263 self, 

3264 value: NumpyValueArrayLike | ExtensionArray, 

3265 side: Literal["left", "right"] = "left", 

3266 sorter: NumpySorter | None = None, 

3267 ) -> npt.NDArray[np.intp] | np.intp: 

3268 return base.IndexOpsMixin.searchsorted(self, value, side=side, sorter=sorter) 

3269 

3270 # ------------------------------------------------------------------- 

3271 # Combination 

3272 

3273 def _append( 

3274 self, to_append, ignore_index: bool = False, verify_integrity: bool = False 

3275 ): 

3276 from pandas.core.reshape.concat import concat 

3277 

3278 if isinstance(to_append, (list, tuple)): 

3279 to_concat = [self] 

3280 to_concat.extend(to_append) 

3281 else: 

3282 to_concat = [self, to_append] 

3283 if any(isinstance(x, (ABCDataFrame,)) for x in to_concat[1:]): 

3284 msg = "to_append should be a Series or list/tuple of Series, got DataFrame" 

3285 raise TypeError(msg) 

3286 return concat( 

3287 to_concat, ignore_index=ignore_index, verify_integrity=verify_integrity 

3288 ) 

3289 

3290 @doc( 

3291 _shared_docs["compare"], 

3292 dedent( 

3293 """ 

3294 Returns 

3295 ------- 

3296 Series or DataFrame 

3297 If axis is 0 or 'index' the result will be a Series. 

3298 The resulting index will be a MultiIndex with 'self' and 'other' 

3299 stacked alternately at the inner level. 

3300 

3301 If axis is 1 or 'columns' the result will be a DataFrame. 

3302 It will have two columns namely 'self' and 'other'. 

3303 

3304 See Also 

3305 -------- 

3306 DataFrame.compare : Compare with another DataFrame and show differences. 

3307 

3308 Notes 

3309 ----- 

3310 Matching NaNs will not appear as a difference. 

3311 

3312 Examples 

3313 -------- 

3314 >>> s1 = pd.Series(["a", "b", "c", "d", "e"]) 

3315 >>> s2 = pd.Series(["a", "a", "c", "b", "e"]) 

3316 

3317 Align the differences on columns 

3318 

3319 >>> s1.compare(s2) 

3320 self other 

3321 1 b a 

3322 3 d b 

3323 

3324 Stack the differences on indices 

3325 

3326 >>> s1.compare(s2, align_axis=0) 

3327 1 self b 

3328 other a 

3329 3 self d 

3330 other b 

3331 dtype: object 

3332 

3333 Keep all original rows 

3334 

3335 >>> s1.compare(s2, keep_shape=True) 

3336 self other 

3337 0 NaN NaN 

3338 1 b a 

3339 2 NaN NaN 

3340 3 d b 

3341 4 NaN NaN 

3342 

3343 Keep all original rows and also all original values 

3344 

3345 >>> s1.compare(s2, keep_shape=True, keep_equal=True) 

3346 self other 

3347 0 a a 

3348 1 b a 

3349 2 c c 

3350 3 d b 

3351 4 e e 

3352 """ 

3353 ), 

3354 klass=_shared_doc_kwargs["klass"], 

3355 ) 

3356 def compare( 

3357 self, 

3358 other: Series, 

3359 align_axis: Axis = 1, 

3360 keep_shape: bool = False, 

3361 keep_equal: bool = False, 

3362 result_names: Suffixes = ("self", "other"), 

3363 ) -> DataFrame | Series: 

3364 return super().compare( 

3365 other=other, 

3366 align_axis=align_axis, 

3367 keep_shape=keep_shape, 

3368 keep_equal=keep_equal, 

3369 result_names=result_names, 

3370 ) 

3371 

3372 def combine( 

3373 self, 

3374 other: Series | Hashable, 

3375 func: Callable[[Hashable, Hashable], Hashable], 

3376 fill_value: Hashable | None = None, 

3377 ) -> Series: 

3378 """ 

3379 Combine the Series with a Series or scalar according to `func`. 

3380 

3381 Combine the Series and `other` using `func` to perform elementwise 

3382 selection for combined Series. 

3383 `fill_value` is assumed when value is missing at some index 

3384 from one of the two objects being combined. 

3385 

3386 Parameters 

3387 ---------- 

3388 other : Series or scalar 

3389 The value(s) to be combined with the `Series`. 

3390 func : function 

3391 Function that takes two scalars as inputs and returns an element. 

3392 fill_value : scalar, optional 

3393 The value to assume when an index is missing from 

3394 one Series or the other. The default specifies to use the 

3395 appropriate NaN value for the underlying dtype of the Series. 

3396 

3397 Returns 

3398 ------- 

3399 Series 

3400 The result of combining the Series with the other object. 

3401 

3402 See Also 

3403 -------- 

3404 Series.combine_first : Combine Series values, choosing the calling 

3405 Series' values first. 

3406 

3407 Examples 

3408 -------- 

3409 Consider 2 Datasets ``s1`` and ``s2`` containing 

3410 highest clocked speeds of different birds. 

3411 

3412 >>> s1 = pd.Series({'falcon': 330.0, 'eagle': 160.0}) 

3413 >>> s1 

3414 falcon 330.0 

3415 eagle 160.0 

3416 dtype: float64 

3417 >>> s2 = pd.Series({'falcon': 345.0, 'eagle': 200.0, 'duck': 30.0}) 

3418 >>> s2 

3419 falcon 345.0 

3420 eagle 200.0 

3421 duck 30.0 

3422 dtype: float64 

3423 

3424 Now, to combine the two datasets and view the highest speeds 

3425 of the birds across the two datasets 

3426 

3427 >>> s1.combine(s2, max) 

3428 duck NaN 

3429 eagle 200.0 

3430 falcon 345.0 

3431 dtype: float64 

3432 

3433 In the previous example, the resulting value for duck is missing, 

3434 because the maximum of a NaN and a float is a NaN. 

3435 So, in the example, we set ``fill_value=0``, 

3436 so the maximum value returned will be the value from some dataset. 

3437 

3438 >>> s1.combine(s2, max, fill_value=0) 

3439 duck 30.0 

3440 eagle 200.0 

3441 falcon 345.0 

3442 dtype: float64 

3443 """ 

3444 if fill_value is None: 

3445 fill_value = na_value_for_dtype(self.dtype, compat=False) 

3446 

3447 if isinstance(other, Series): 

3448 # If other is a Series, result is based on union of Series, 

3449 # so do this element by element 

3450 new_index = self.index.union(other.index) 

3451 new_name = ops.get_op_result_name(self, other) 

3452 new_values = np.empty(len(new_index), dtype=object) 

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

3454 for i, idx in enumerate(new_index): 

3455 lv = self.get(idx, fill_value) 

3456 rv = other.get(idx, fill_value) 

3457 new_values[i] = func(lv, rv) 

3458 else: 

3459 # Assume that other is a scalar, so apply the function for 

3460 # each element in the Series 

3461 new_index = self.index 

3462 new_values = np.empty(len(new_index), dtype=object) 

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

3464 new_values[:] = [func(lv, other) for lv in self._values] 

3465 new_name = self.name 

3466 

3467 # try_float=False is to match agg_series 

3468 npvalues = lib.maybe_convert_objects(new_values, try_float=False) 

3469 # same_dtype here is a kludge to avoid casting e.g. [True, False] to 

3470 # ["True", "False"] 

3471 same_dtype = isinstance(self.dtype, (StringDtype, CategoricalDtype)) 

3472 res_values = maybe_cast_pointwise_result( 

3473 npvalues, self.dtype, same_dtype=same_dtype 

3474 ) 

3475 return self._constructor(res_values, index=new_index, name=new_name, copy=False) 

3476 

3477 def combine_first(self, other) -> Series: 

3478 """ 

3479 Update null elements with value in the same location in 'other'. 

3480 

3481 Combine two Series objects by filling null values in one Series with 

3482 non-null values from the other Series. Result index will be the union 

3483 of the two indexes. 

3484 

3485 Parameters 

3486 ---------- 

3487 other : Series 

3488 The value(s) to be used for filling null values. 

3489 

3490 Returns 

3491 ------- 

3492 Series 

3493 The result of combining the provided Series with the other object. 

3494 

3495 See Also 

3496 -------- 

3497 Series.combine : Perform element-wise operation on two Series 

3498 using a given function. 

3499 

3500 Examples 

3501 -------- 

3502 >>> s1 = pd.Series([1, np.nan]) 

3503 >>> s2 = pd.Series([3, 4, 5]) 

3504 >>> s1.combine_first(s2) 

3505 0 1.0 

3506 1 4.0 

3507 2 5.0 

3508 dtype: float64 

3509 

3510 Null values still persist if the location of that null value 

3511 does not exist in `other` 

3512 

3513 >>> s1 = pd.Series({'falcon': np.nan, 'eagle': 160.0}) 

3514 >>> s2 = pd.Series({'eagle': 200.0, 'duck': 30.0}) 

3515 >>> s1.combine_first(s2) 

3516 duck 30.0 

3517 eagle 160.0 

3518 falcon NaN 

3519 dtype: float64 

3520 """ 

3521 from pandas.core.reshape.concat import concat 

3522 

3523 if self.dtype == other.dtype: 

3524 if self.index.equals(other.index): 

3525 return self.mask(self.isna(), other) 

3526 elif self._can_hold_na and not isinstance(self.dtype, SparseDtype): 

3527 this, other = self.align(other, join="outer") 

3528 return this.mask(this.isna(), other) 

3529 

3530 new_index = self.index.union(other.index) 

3531 

3532 this = self 

3533 # identify the index subset to keep for each series 

3534 keep_other = other.index.difference(this.index[notna(this)]) 

3535 keep_this = this.index.difference(keep_other) 

3536 

3537 this = this.reindex(keep_this, copy=False) 

3538 other = other.reindex(keep_other, copy=False) 

3539 

3540 if this.dtype.kind == "M" and other.dtype.kind != "M": 

3541 other = to_datetime(other) 

3542 combined = concat([this, other]) 

3543 combined = combined.reindex(new_index, copy=False) 

3544 return combined.__finalize__(self, method="combine_first") 

3545 

3546 def update(self, other: Series | Sequence | Mapping) -> None: 

3547 """ 

3548 Modify Series in place using values from passed Series. 

3549 

3550 Uses non-NA values from passed Series to make updates. Aligns 

3551 on index. 

3552 

3553 Parameters 

3554 ---------- 

3555 other : Series, or object coercible into Series 

3556 

3557 Examples 

3558 -------- 

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

3560 >>> s.update(pd.Series([4, 5, 6])) 

3561 >>> s 

3562 0 4 

3563 1 5 

3564 2 6 

3565 dtype: int64 

3566 

3567 >>> s = pd.Series(['a', 'b', 'c']) 

3568 >>> s.update(pd.Series(['d', 'e'], index=[0, 2])) 

3569 >>> s 

3570 0 d 

3571 1 b 

3572 2 e 

3573 dtype: object 

3574 

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

3576 >>> s.update(pd.Series([4, 5, 6, 7, 8])) 

3577 >>> s 

3578 0 4 

3579 1 5 

3580 2 6 

3581 dtype: int64 

3582 

3583 If ``other`` contains NaNs the corresponding values are not updated 

3584 in the original Series. 

3585 

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

3587 >>> s.update(pd.Series([4, np.nan, 6])) 

3588 >>> s 

3589 0 4 

3590 1 2 

3591 2 6 

3592 dtype: int64 

3593 

3594 ``other`` can also be a non-Series object type 

3595 that is coercible into a Series 

3596 

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

3598 >>> s.update([4, np.nan, 6]) 

3599 >>> s 

3600 0 4 

3601 1 2 

3602 2 6 

3603 dtype: int64 

3604 

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

3606 >>> s.update({1: 9}) 

3607 >>> s 

3608 0 1 

3609 1 9 

3610 2 3 

3611 dtype: int64 

3612 """ 

3613 if not PYPY and using_copy_on_write(): 

3614 if sys.getrefcount(self) <= REF_COUNT: 

3615 warnings.warn( 

3616 _chained_assignment_method_msg, 

3617 ChainedAssignmentError, 

3618 stacklevel=2, 

3619 ) 

3620 elif not PYPY and not using_copy_on_write() and self._is_view_after_cow_rules(): 

3621 ctr = sys.getrefcount(self) 

3622 ref_count = REF_COUNT 

3623 if _check_cacher(self): 

3624 # see https://github.com/pandas-dev/pandas/pull/56060#discussion_r1399245221 

3625 ref_count += 1 

3626 if ctr <= ref_count: 

3627 warnings.warn( 

3628 _chained_assignment_warning_method_msg, 

3629 FutureWarning, 

3630 stacklevel=2, 

3631 ) 

3632 

3633 if not isinstance(other, Series): 

3634 other = Series(other) 

3635 

3636 other = other.reindex_like(self) 

3637 mask = notna(other) 

3638 

3639 self._mgr = self._mgr.putmask(mask=mask, new=other) 

3640 self._maybe_update_cacher() 

3641 

3642 # ---------------------------------------------------------------------- 

3643 # Reindexing, sorting 

3644 

3645 @overload 

3646 def sort_values( 

3647 self, 

3648 *, 

3649 axis: Axis = ..., 

3650 ascending: bool | Sequence[bool] = ..., 

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

3652 kind: SortKind = ..., 

3653 na_position: NaPosition = ..., 

3654 ignore_index: bool = ..., 

3655 key: ValueKeyFunc = ..., 

3656 ) -> Series: 

3657 ... 

3658 

3659 @overload 

3660 def sort_values( 

3661 self, 

3662 *, 

3663 axis: Axis = ..., 

3664 ascending: bool | Sequence[bool] = ..., 

3665 inplace: Literal[True], 

3666 kind: SortKind = ..., 

3667 na_position: NaPosition = ..., 

3668 ignore_index: bool = ..., 

3669 key: ValueKeyFunc = ..., 

3670 ) -> None: 

3671 ... 

3672 

3673 @overload 

3674 def sort_values( 

3675 self, 

3676 *, 

3677 axis: Axis = ..., 

3678 ascending: bool | Sequence[bool] = ..., 

3679 inplace: bool = ..., 

3680 kind: SortKind = ..., 

3681 na_position: NaPosition = ..., 

3682 ignore_index: bool = ..., 

3683 key: ValueKeyFunc = ..., 

3684 ) -> Series | None: 

3685 ... 

3686 

3687 def sort_values( 

3688 self, 

3689 *, 

3690 axis: Axis = 0, 

3691 ascending: bool | Sequence[bool] = True, 

3692 inplace: bool = False, 

3693 kind: SortKind = "quicksort", 

3694 na_position: NaPosition = "last", 

3695 ignore_index: bool = False, 

3696 key: ValueKeyFunc | None = None, 

3697 ) -> Series | None: 

3698 """ 

3699 Sort by the values. 

3700 

3701 Sort a Series in ascending or descending order by some 

3702 criterion. 

3703 

3704 Parameters 

3705 ---------- 

3706 axis : {0 or 'index'} 

3707 Unused. Parameter needed for compatibility with DataFrame. 

3708 ascending : bool or list of bools, default True 

3709 If True, sort values in ascending order, otherwise descending. 

3710 inplace : bool, default False 

3711 If True, perform operation in-place. 

3712 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, default 'quicksort' 

3713 Choice of sorting algorithm. See also :func:`numpy.sort` for more 

3714 information. 'mergesort' and 'stable' are the only stable algorithms. 

3715 na_position : {'first' or 'last'}, default 'last' 

3716 Argument 'first' puts NaNs at the beginning, 'last' puts NaNs at 

3717 the end. 

3718 ignore_index : bool, default False 

3719 If True, the resulting axis will be labeled 0, 1, …, n - 1. 

3720 key : callable, optional 

3721 If not None, apply the key function to the series values 

3722 before sorting. This is similar to the `key` argument in the 

3723 builtin :meth:`sorted` function, with the notable difference that 

3724 this `key` function should be *vectorized*. It should expect a 

3725 ``Series`` and return an array-like. 

3726 

3727 Returns 

3728 ------- 

3729 Series or None 

3730 Series ordered by values or None if ``inplace=True``. 

3731 

3732 See Also 

3733 -------- 

3734 Series.sort_index : Sort by the Series indices. 

3735 DataFrame.sort_values : Sort DataFrame by the values along either axis. 

3736 DataFrame.sort_index : Sort DataFrame by indices. 

3737 

3738 Examples 

3739 -------- 

3740 >>> s = pd.Series([np.nan, 1, 3, 10, 5]) 

3741 >>> s 

3742 0 NaN 

3743 1 1.0 

3744 2 3.0 

3745 3 10.0 

3746 4 5.0 

3747 dtype: float64 

3748 

3749 Sort values ascending order (default behaviour) 

3750 

3751 >>> s.sort_values(ascending=True) 

3752 1 1.0 

3753 2 3.0 

3754 4 5.0 

3755 3 10.0 

3756 0 NaN 

3757 dtype: float64 

3758 

3759 Sort values descending order 

3760 

3761 >>> s.sort_values(ascending=False) 

3762 3 10.0 

3763 4 5.0 

3764 2 3.0 

3765 1 1.0 

3766 0 NaN 

3767 dtype: float64 

3768 

3769 Sort values putting NAs first 

3770 

3771 >>> s.sort_values(na_position='first') 

3772 0 NaN 

3773 1 1.0 

3774 2 3.0 

3775 4 5.0 

3776 3 10.0 

3777 dtype: float64 

3778 

3779 Sort a series of strings 

3780 

3781 >>> s = pd.Series(['z', 'b', 'd', 'a', 'c']) 

3782 >>> s 

3783 0 z 

3784 1 b 

3785 2 d 

3786 3 a 

3787 4 c 

3788 dtype: object 

3789 

3790 >>> s.sort_values() 

3791 3 a 

3792 1 b 

3793 4 c 

3794 2 d 

3795 0 z 

3796 dtype: object 

3797 

3798 Sort using a key function. Your `key` function will be 

3799 given the ``Series`` of values and should return an array-like. 

3800 

3801 >>> s = pd.Series(['a', 'B', 'c', 'D', 'e']) 

3802 >>> s.sort_values() 

3803 1 B 

3804 3 D 

3805 0 a 

3806 2 c 

3807 4 e 

3808 dtype: object 

3809 >>> s.sort_values(key=lambda x: x.str.lower()) 

3810 0 a 

3811 1 B 

3812 2 c 

3813 3 D 

3814 4 e 

3815 dtype: object 

3816 

3817 NumPy ufuncs work well here. For example, we can 

3818 sort by the ``sin`` of the value 

3819 

3820 >>> s = pd.Series([-4, -2, 0, 2, 4]) 

3821 >>> s.sort_values(key=np.sin) 

3822 1 -2 

3823 4 4 

3824 2 0 

3825 0 -4 

3826 3 2 

3827 dtype: int64 

3828 

3829 More complicated user-defined functions can be used, 

3830 as long as they expect a Series and return an array-like 

3831 

3832 >>> s.sort_values(key=lambda x: (np.tan(x.cumsum()))) 

3833 0 -4 

3834 3 2 

3835 4 4 

3836 1 -2 

3837 2 0 

3838 dtype: int64 

3839 """ 

3840 inplace = validate_bool_kwarg(inplace, "inplace") 

3841 # Validate the axis parameter 

3842 self._get_axis_number(axis) 

3843 

3844 # GH 5856/5853 

3845 if inplace and self._is_cached: 

3846 raise ValueError( 

3847 "This Series is a view of some other array, to " 

3848 "sort in-place you must create a copy" 

3849 ) 

3850 

3851 if is_list_like(ascending): 

3852 ascending = cast(Sequence[bool], ascending) 

3853 if len(ascending) != 1: 

3854 raise ValueError( 

3855 f"Length of ascending ({len(ascending)}) must be 1 for Series" 

3856 ) 

3857 ascending = ascending[0] 

3858 

3859 ascending = validate_ascending(ascending) 

3860 

3861 if na_position not in ["first", "last"]: 

3862 raise ValueError(f"invalid na_position: {na_position}") 

3863 

3864 # GH 35922. Make sorting stable by leveraging nargsort 

3865 if key: 

3866 values_to_sort = cast(Series, ensure_key_mapped(self, key))._values 

3867 else: 

3868 values_to_sort = self._values 

3869 sorted_index = nargsort(values_to_sort, kind, bool(ascending), na_position) 

3870 

3871 if is_range_indexer(sorted_index, len(sorted_index)): 

3872 if inplace: 

3873 return self._update_inplace(self) 

3874 return self.copy(deep=None) 

3875 

3876 result = self._constructor( 

3877 self._values[sorted_index], index=self.index[sorted_index], copy=False 

3878 ) 

3879 

3880 if ignore_index: 

3881 result.index = default_index(len(sorted_index)) 

3882 

3883 if not inplace: 

3884 return result.__finalize__(self, method="sort_values") 

3885 self._update_inplace(result) 

3886 return None 

3887 

3888 @overload 

3889 def sort_index( 

3890 self, 

3891 *, 

3892 axis: Axis = ..., 

3893 level: IndexLabel = ..., 

3894 ascending: bool | Sequence[bool] = ..., 

3895 inplace: Literal[True], 

3896 kind: SortKind = ..., 

3897 na_position: NaPosition = ..., 

3898 sort_remaining: bool = ..., 

3899 ignore_index: bool = ..., 

3900 key: IndexKeyFunc = ..., 

3901 ) -> None: 

3902 ... 

3903 

3904 @overload 

3905 def sort_index( 

3906 self, 

3907 *, 

3908 axis: Axis = ..., 

3909 level: IndexLabel = ..., 

3910 ascending: bool | Sequence[bool] = ..., 

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

3912 kind: SortKind = ..., 

3913 na_position: NaPosition = ..., 

3914 sort_remaining: bool = ..., 

3915 ignore_index: bool = ..., 

3916 key: IndexKeyFunc = ..., 

3917 ) -> Series: 

3918 ... 

3919 

3920 @overload 

3921 def sort_index( 

3922 self, 

3923 *, 

3924 axis: Axis = ..., 

3925 level: IndexLabel = ..., 

3926 ascending: bool | Sequence[bool] = ..., 

3927 inplace: bool = ..., 

3928 kind: SortKind = ..., 

3929 na_position: NaPosition = ..., 

3930 sort_remaining: bool = ..., 

3931 ignore_index: bool = ..., 

3932 key: IndexKeyFunc = ..., 

3933 ) -> Series | None: 

3934 ... 

3935 

3936 def sort_index( 

3937 self, 

3938 *, 

3939 axis: Axis = 0, 

3940 level: IndexLabel | None = None, 

3941 ascending: bool | Sequence[bool] = True, 

3942 inplace: bool = False, 

3943 kind: SortKind = "quicksort", 

3944 na_position: NaPosition = "last", 

3945 sort_remaining: bool = True, 

3946 ignore_index: bool = False, 

3947 key: IndexKeyFunc | None = None, 

3948 ) -> Series | None: 

3949 """ 

3950 Sort Series by index labels. 

3951 

3952 Returns a new Series sorted by label if `inplace` argument is 

3953 ``False``, otherwise updates the original series and returns None. 

3954 

3955 Parameters 

3956 ---------- 

3957 axis : {0 or 'index'} 

3958 Unused. Parameter needed for compatibility with DataFrame. 

3959 level : int, optional 

3960 If not None, sort on values in specified index level(s). 

3961 ascending : bool or list-like of bools, default True 

3962 Sort ascending vs. descending. When the index is a MultiIndex the 

3963 sort direction can be controlled for each level individually. 

3964 inplace : bool, default False 

3965 If True, perform operation in-place. 

3966 kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, default 'quicksort' 

3967 Choice of sorting algorithm. See also :func:`numpy.sort` for more 

3968 information. 'mergesort' and 'stable' are the only stable algorithms. For 

3969 DataFrames, this option is only applied when sorting on a single 

3970 column or label. 

3971 na_position : {'first', 'last'}, default 'last' 

3972 If 'first' puts NaNs at the beginning, 'last' puts NaNs at the end. 

3973 Not implemented for MultiIndex. 

3974 sort_remaining : bool, default True 

3975 If True and sorting by level and index is multilevel, sort by other 

3976 levels too (in order) after sorting by specified level. 

3977 ignore_index : bool, default False 

3978 If True, the resulting axis will be labeled 0, 1, …, n - 1. 

3979 key : callable, optional 

3980 If not None, apply the key function to the index values 

3981 before sorting. This is similar to the `key` argument in the 

3982 builtin :meth:`sorted` function, with the notable difference that 

3983 this `key` function should be *vectorized*. It should expect an 

3984 ``Index`` and return an ``Index`` of the same shape. 

3985 

3986 Returns 

3987 ------- 

3988 Series or None 

3989 The original Series sorted by the labels or None if ``inplace=True``. 

3990 

3991 See Also 

3992 -------- 

3993 DataFrame.sort_index: Sort DataFrame by the index. 

3994 DataFrame.sort_values: Sort DataFrame by the value. 

3995 Series.sort_values : Sort Series by the value. 

3996 

3997 Examples 

3998 -------- 

3999 >>> s = pd.Series(['a', 'b', 'c', 'd'], index=[3, 2, 1, 4]) 

4000 >>> s.sort_index() 

4001 1 c 

4002 2 b 

4003 3 a 

4004 4 d 

4005 dtype: object 

4006 

4007 Sort Descending 

4008 

4009 >>> s.sort_index(ascending=False) 

4010 4 d 

4011 3 a 

4012 2 b 

4013 1 c 

4014 dtype: object 

4015 

4016 By default NaNs are put at the end, but use `na_position` to place 

4017 them at the beginning 

4018 

4019 >>> s = pd.Series(['a', 'b', 'c', 'd'], index=[3, 2, 1, np.nan]) 

4020 >>> s.sort_index(na_position='first') 

4021 NaN d 

4022 1.0 c 

4023 2.0 b 

4024 3.0 a 

4025 dtype: object 

4026 

4027 Specify index level to sort 

4028 

4029 >>> arrays = [np.array(['qux', 'qux', 'foo', 'foo', 

4030 ... 'baz', 'baz', 'bar', 'bar']), 

4031 ... np.array(['two', 'one', 'two', 'one', 

4032 ... 'two', 'one', 'two', 'one'])] 

4033 >>> s = pd.Series([1, 2, 3, 4, 5, 6, 7, 8], index=arrays) 

4034 >>> s.sort_index(level=1) 

4035 bar one 8 

4036 baz one 6 

4037 foo one 4 

4038 qux one 2 

4039 bar two 7 

4040 baz two 5 

4041 foo two 3 

4042 qux two 1 

4043 dtype: int64 

4044 

4045 Does not sort by remaining levels when sorting by levels 

4046 

4047 >>> s.sort_index(level=1, sort_remaining=False) 

4048 qux one 2 

4049 foo one 4 

4050 baz one 6 

4051 bar one 8 

4052 qux two 1 

4053 foo two 3 

4054 baz two 5 

4055 bar two 7 

4056 dtype: int64 

4057 

4058 Apply a key function before sorting 

4059 

4060 >>> s = pd.Series([1, 2, 3, 4], index=['A', 'b', 'C', 'd']) 

4061 >>> s.sort_index(key=lambda x : x.str.lower()) 

4062 A 1 

4063 b 2 

4064 C 3 

4065 d 4 

4066 dtype: int64 

4067 """ 

4068 

4069 return super().sort_index( 

4070 axis=axis, 

4071 level=level, 

4072 ascending=ascending, 

4073 inplace=inplace, 

4074 kind=kind, 

4075 na_position=na_position, 

4076 sort_remaining=sort_remaining, 

4077 ignore_index=ignore_index, 

4078 key=key, 

4079 ) 

4080 

4081 def argsort( 

4082 self, 

4083 axis: Axis = 0, 

4084 kind: SortKind = "quicksort", 

4085 order: None = None, 

4086 stable: None = None, 

4087 ) -> Series: 

4088 """ 

4089 Return the integer indices that would sort the Series values. 

4090 

4091 Override ndarray.argsort. Argsorts the value, omitting NA/null values, 

4092 and places the result in the same locations as the non-NA values. 

4093 

4094 Parameters 

4095 ---------- 

4096 axis : {0 or 'index'} 

4097 Unused. Parameter needed for compatibility with DataFrame. 

4098 kind : {'mergesort', 'quicksort', 'heapsort', 'stable'}, default 'quicksort' 

4099 Choice of sorting algorithm. See :func:`numpy.sort` for more 

4100 information. 'mergesort' and 'stable' are the only stable algorithms. 

4101 order : None 

4102 Has no effect but is accepted for compatibility with numpy. 

4103 stable : None 

4104 Has no effect but is accepted for compatibility with numpy. 

4105 

4106 Returns 

4107 ------- 

4108 Series[np.intp] 

4109 Positions of values within the sort order with -1 indicating 

4110 nan values. 

4111 

4112 See Also 

4113 -------- 

4114 numpy.ndarray.argsort : Returns the indices that would sort this array. 

4115 

4116 Examples 

4117 -------- 

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

4119 >>> s.argsort() 

4120 0 2 

4121 1 1 

4122 2 0 

4123 dtype: int64 

4124 """ 

4125 if axis != -1: 

4126 # GH#54257 We allow -1 here so that np.argsort(series) works 

4127 self._get_axis_number(axis) 

4128 

4129 values = self._values 

4130 mask = isna(values) 

4131 

4132 if mask.any(): 

4133 # TODO(3.0): once this deprecation is enforced we can call 

4134 # self.array.argsort directly, which will close GH#43840 and 

4135 # GH#12694 

4136 warnings.warn( 

4137 "The behavior of Series.argsort in the presence of NA values is " 

4138 "deprecated. In a future version, NA values will be ordered " 

4139 "last instead of set to -1.", 

4140 FutureWarning, 

4141 stacklevel=find_stack_level(), 

4142 ) 

4143 result = np.full(len(self), -1, dtype=np.intp) 

4144 notmask = ~mask 

4145 result[notmask] = np.argsort(values[notmask], kind=kind) 

4146 else: 

4147 result = np.argsort(values, kind=kind) 

4148 

4149 res = self._constructor( 

4150 result, index=self.index, name=self.name, dtype=np.intp, copy=False 

4151 ) 

4152 return res.__finalize__(self, method="argsort") 

4153 

4154 def nlargest( 

4155 self, n: int = 5, keep: Literal["first", "last", "all"] = "first" 

4156 ) -> Series: 

4157 """ 

4158 Return the largest `n` elements. 

4159 

4160 Parameters 

4161 ---------- 

4162 n : int, default 5 

4163 Return this many descending sorted values. 

4164 keep : {'first', 'last', 'all'}, default 'first' 

4165 When there are duplicate values that cannot all fit in a 

4166 Series of `n` elements: 

4167 

4168 - ``first`` : return the first `n` occurrences in order 

4169 of appearance. 

4170 - ``last`` : return the last `n` occurrences in reverse 

4171 order of appearance. 

4172 - ``all`` : keep all occurrences. This can result in a Series of 

4173 size larger than `n`. 

4174 

4175 Returns 

4176 ------- 

4177 Series 

4178 The `n` largest values in the Series, sorted in decreasing order. 

4179 

4180 See Also 

4181 -------- 

4182 Series.nsmallest: Get the `n` smallest elements. 

4183 Series.sort_values: Sort Series by values. 

4184 Series.head: Return the first `n` rows. 

4185 

4186 Notes 

4187 ----- 

4188 Faster than ``.sort_values(ascending=False).head(n)`` for small `n` 

4189 relative to the size of the ``Series`` object. 

4190 

4191 Examples 

4192 -------- 

4193 >>> countries_population = {"Italy": 59000000, "France": 65000000, 

4194 ... "Malta": 434000, "Maldives": 434000, 

4195 ... "Brunei": 434000, "Iceland": 337000, 

4196 ... "Nauru": 11300, "Tuvalu": 11300, 

4197 ... "Anguilla": 11300, "Montserrat": 5200} 

4198 >>> s = pd.Series(countries_population) 

4199 >>> s 

4200 Italy 59000000 

4201 France 65000000 

4202 Malta 434000 

4203 Maldives 434000 

4204 Brunei 434000 

4205 Iceland 337000 

4206 Nauru 11300 

4207 Tuvalu 11300 

4208 Anguilla 11300 

4209 Montserrat 5200 

4210 dtype: int64 

4211 

4212 The `n` largest elements where ``n=5`` by default. 

4213 

4214 >>> s.nlargest() 

4215 France 65000000 

4216 Italy 59000000 

4217 Malta 434000 

4218 Maldives 434000 

4219 Brunei 434000 

4220 dtype: int64 

4221 

4222 The `n` largest elements where ``n=3``. Default `keep` value is 'first' 

4223 so Malta will be kept. 

4224 

4225 >>> s.nlargest(3) 

4226 France 65000000 

4227 Italy 59000000 

4228 Malta 434000 

4229 dtype: int64 

4230 

4231 The `n` largest elements where ``n=3`` and keeping the last duplicates. 

4232 Brunei will be kept since it is the last with value 434000 based on 

4233 the index order. 

4234 

4235 >>> s.nlargest(3, keep='last') 

4236 France 65000000 

4237 Italy 59000000 

4238 Brunei 434000 

4239 dtype: int64 

4240 

4241 The `n` largest elements where ``n=3`` with all duplicates kept. Note 

4242 that the returned Series has five elements due to the three duplicates. 

4243 

4244 >>> s.nlargest(3, keep='all') 

4245 France 65000000 

4246 Italy 59000000 

4247 Malta 434000 

4248 Maldives 434000 

4249 Brunei 434000 

4250 dtype: int64 

4251 """ 

4252 return selectn.SelectNSeries(self, n=n, keep=keep).nlargest() 

4253 

4254 def nsmallest( 

4255 self, n: int = 5, keep: Literal["first", "last", "all"] = "first" 

4256 ) -> Series: 

4257 """ 

4258 Return the smallest `n` elements. 

4259 

4260 Parameters 

4261 ---------- 

4262 n : int, default 5 

4263 Return this many ascending sorted values. 

4264 keep : {'first', 'last', 'all'}, default 'first' 

4265 When there are duplicate values that cannot all fit in a 

4266 Series of `n` elements: 

4267 

4268 - ``first`` : return the first `n` occurrences in order 

4269 of appearance. 

4270 - ``last`` : return the last `n` occurrences in reverse 

4271 order of appearance. 

4272 - ``all`` : keep all occurrences. This can result in a Series of 

4273 size larger than `n`. 

4274 

4275 Returns 

4276 ------- 

4277 Series 

4278 The `n` smallest values in the Series, sorted in increasing order. 

4279 

4280 See Also 

4281 -------- 

4282 Series.nlargest: Get the `n` largest elements. 

4283 Series.sort_values: Sort Series by values. 

4284 Series.head: Return the first `n` rows. 

4285 

4286 Notes 

4287 ----- 

4288 Faster than ``.sort_values().head(n)`` for small `n` relative to 

4289 the size of the ``Series`` object. 

4290 

4291 Examples 

4292 -------- 

4293 >>> countries_population = {"Italy": 59000000, "France": 65000000, 

4294 ... "Brunei": 434000, "Malta": 434000, 

4295 ... "Maldives": 434000, "Iceland": 337000, 

4296 ... "Nauru": 11300, "Tuvalu": 11300, 

4297 ... "Anguilla": 11300, "Montserrat": 5200} 

4298 >>> s = pd.Series(countries_population) 

4299 >>> s 

4300 Italy 59000000 

4301 France 65000000 

4302 Brunei 434000 

4303 Malta 434000 

4304 Maldives 434000 

4305 Iceland 337000 

4306 Nauru 11300 

4307 Tuvalu 11300 

4308 Anguilla 11300 

4309 Montserrat 5200 

4310 dtype: int64 

4311 

4312 The `n` smallest elements where ``n=5`` by default. 

4313 

4314 >>> s.nsmallest() 

4315 Montserrat 5200 

4316 Nauru 11300 

4317 Tuvalu 11300 

4318 Anguilla 11300 

4319 Iceland 337000 

4320 dtype: int64 

4321 

4322 The `n` smallest elements where ``n=3``. Default `keep` value is 

4323 'first' so Nauru and Tuvalu will be kept. 

4324 

4325 >>> s.nsmallest(3) 

4326 Montserrat 5200 

4327 Nauru 11300 

4328 Tuvalu 11300 

4329 dtype: int64 

4330 

4331 The `n` smallest elements where ``n=3`` and keeping the last 

4332 duplicates. Anguilla and Tuvalu will be kept since they are the last 

4333 with value 11300 based on the index order. 

4334 

4335 >>> s.nsmallest(3, keep='last') 

4336 Montserrat 5200 

4337 Anguilla 11300 

4338 Tuvalu 11300 

4339 dtype: int64 

4340 

4341 The `n` smallest elements where ``n=3`` with all duplicates kept. Note 

4342 that the returned Series has four elements due to the three duplicates. 

4343 

4344 >>> s.nsmallest(3, keep='all') 

4345 Montserrat 5200 

4346 Nauru 11300 

4347 Tuvalu 11300 

4348 Anguilla 11300 

4349 dtype: int64 

4350 """ 

4351 return selectn.SelectNSeries(self, n=n, keep=keep).nsmallest() 

4352 

4353 @doc( 

4354 klass=_shared_doc_kwargs["klass"], 

4355 extra_params=dedent( 

4356 """copy : bool, default True 

4357 Whether to copy underlying data. 

4358 

4359 .. note:: 

4360 The `copy` keyword will change behavior in pandas 3.0. 

4361 `Copy-on-Write 

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

4363 will be enabled by default, which means that all methods with a 

4364 `copy` keyword will use a lazy copy mechanism to defer the copy and 

4365 ignore the `copy` keyword. The `copy` keyword will be removed in a 

4366 future version of pandas. 

4367 

4368 You can already get the future behavior and improvements through 

4369 enabling copy on write ``pd.options.mode.copy_on_write = True``""" 

4370 ), 

4371 examples=dedent( 

4372 """\ 

4373 Examples 

4374 -------- 

4375 >>> s = pd.Series( 

4376 ... ["A", "B", "A", "C"], 

4377 ... index=[ 

4378 ... ["Final exam", "Final exam", "Coursework", "Coursework"], 

4379 ... ["History", "Geography", "History", "Geography"], 

4380 ... ["January", "February", "March", "April"], 

4381 ... ], 

4382 ... ) 

4383 >>> s 

4384 Final exam History January A 

4385 Geography February B 

4386 Coursework History March A 

4387 Geography April C 

4388 dtype: object 

4389 

4390 In the following example, we will swap the levels of the indices. 

4391 Here, we will swap the levels column-wise, but levels can be swapped row-wise 

4392 in a similar manner. Note that column-wise is the default behaviour. 

4393 By not supplying any arguments for i and j, we swap the last and second to 

4394 last indices. 

4395 

4396 >>> s.swaplevel() 

4397 Final exam January History A 

4398 February Geography B 

4399 Coursework March History A 

4400 April Geography C 

4401 dtype: object 

4402 

4403 By supplying one argument, we can choose which index to swap the last 

4404 index with. We can for example swap the first index with the last one as 

4405 follows. 

4406 

4407 >>> s.swaplevel(0) 

4408 January History Final exam A 

4409 February Geography Final exam B 

4410 March History Coursework A 

4411 April Geography Coursework C 

4412 dtype: object 

4413 

4414 We can also define explicitly which indices we want to swap by supplying values 

4415 for both i and j. Here, we for example swap the first and second indices. 

4416 

4417 >>> s.swaplevel(0, 1) 

4418 History Final exam January A 

4419 Geography Final exam February B 

4420 History Coursework March A 

4421 Geography Coursework April C 

4422 dtype: object""" 

4423 ), 

4424 ) 

4425 def swaplevel( 

4426 self, i: Level = -2, j: Level = -1, copy: bool | None = None 

4427 ) -> Series: 

4428 """ 

4429 Swap levels i and j in a :class:`MultiIndex`. 

4430 

4431 Default is to swap the two innermost levels of the index. 

4432 

4433 Parameters 

4434 ---------- 

4435 i, j : int or str 

4436 Levels of the indices to be swapped. Can pass level name as string. 

4437 {extra_params} 

4438 

4439 Returns 

4440 ------- 

4441 {klass} 

4442 {klass} with levels swapped in MultiIndex. 

4443 

4444 {examples} 

4445 """ 

4446 assert isinstance(self.index, MultiIndex) 

4447 result = self.copy(deep=copy and not using_copy_on_write()) 

4448 result.index = self.index.swaplevel(i, j) 

4449 return result 

4450 

4451 def reorder_levels(self, order: Sequence[Level]) -> Series: 

4452 """ 

4453 Rearrange index levels using input order. 

4454 

4455 May not drop or duplicate levels. 

4456 

4457 Parameters 

4458 ---------- 

4459 order : list of int representing new level order 

4460 Reference level by number or key. 

4461 

4462 Returns 

4463 ------- 

4464 type of caller (new object) 

4465 

4466 Examples 

4467 -------- 

4468 >>> arrays = [np.array(["dog", "dog", "cat", "cat", "bird", "bird"]), 

4469 ... np.array(["white", "black", "white", "black", "white", "black"])] 

4470 >>> s = pd.Series([1, 2, 3, 3, 5, 2], index=arrays) 

4471 >>> s 

4472 dog white 1 

4473 black 2 

4474 cat white 3 

4475 black 3 

4476 bird white 5 

4477 black 2 

4478 dtype: int64 

4479 >>> s.reorder_levels([1, 0]) 

4480 white dog 1 

4481 black dog 2 

4482 white cat 3 

4483 black cat 3 

4484 white bird 5 

4485 black bird 2 

4486 dtype: int64 

4487 """ 

4488 if not isinstance(self.index, MultiIndex): # pragma: no cover 

4489 raise Exception("Can only reorder levels on a hierarchical axis.") 

4490 

4491 result = self.copy(deep=None) 

4492 assert isinstance(result.index, MultiIndex) 

4493 result.index = result.index.reorder_levels(order) 

4494 return result 

4495 

4496 def explode(self, ignore_index: bool = False) -> Series: 

4497 """ 

4498 Transform each element of a list-like to a row. 

4499 

4500 Parameters 

4501 ---------- 

4502 ignore_index : bool, default False 

4503 If True, the resulting index will be labeled 0, 1, …, n - 1. 

4504 

4505 Returns 

4506 ------- 

4507 Series 

4508 Exploded lists to rows; index will be duplicated for these rows. 

4509 

4510 See Also 

4511 -------- 

4512 Series.str.split : Split string values on specified separator. 

4513 Series.unstack : Unstack, a.k.a. pivot, Series with MultiIndex 

4514 to produce DataFrame. 

4515 DataFrame.melt : Unpivot a DataFrame from wide format to long format. 

4516 DataFrame.explode : Explode a DataFrame from list-like 

4517 columns to long format. 

4518 

4519 Notes 

4520 ----- 

4521 This routine will explode list-likes including lists, tuples, sets, 

4522 Series, and np.ndarray. The result dtype of the subset rows will 

4523 be object. Scalars will be returned unchanged, and empty list-likes will 

4524 result in a np.nan for that row. In addition, the ordering of elements in 

4525 the output will be non-deterministic when exploding sets. 

4526 

4527 Reference :ref:`the user guide <reshaping.explode>` for more examples. 

4528 

4529 Examples 

4530 -------- 

4531 >>> s = pd.Series([[1, 2, 3], 'foo', [], [3, 4]]) 

4532 >>> s 

4533 0 [1, 2, 3] 

4534 1 foo 

4535 2 [] 

4536 3 [3, 4] 

4537 dtype: object 

4538 

4539 >>> s.explode() 

4540 0 1 

4541 0 2 

4542 0 3 

4543 1 foo 

4544 2 NaN 

4545 3 3 

4546 3 4 

4547 dtype: object 

4548 """ 

4549 if isinstance(self.dtype, ExtensionDtype): 

4550 values, counts = self._values._explode() 

4551 elif len(self) and is_object_dtype(self.dtype): 

4552 values, counts = reshape.explode(np.asarray(self._values)) 

4553 else: 

4554 result = self.copy() 

4555 return result.reset_index(drop=True) if ignore_index else result 

4556 

4557 if ignore_index: 

4558 index: Index = default_index(len(values)) 

4559 else: 

4560 index = self.index.repeat(counts) 

4561 

4562 return self._constructor(values, index=index, name=self.name, copy=False) 

4563 

4564 def unstack( 

4565 self, 

4566 level: IndexLabel = -1, 

4567 fill_value: Hashable | None = None, 

4568 sort: bool = True, 

4569 ) -> DataFrame: 

4570 """ 

4571 Unstack, also known as pivot, Series with MultiIndex to produce DataFrame. 

4572 

4573 Parameters 

4574 ---------- 

4575 level : int, str, or list of these, default last level 

4576 Level(s) to unstack, can pass level name. 

4577 fill_value : scalar value, default None 

4578 Value to use when replacing NaN values. 

4579 sort : bool, default True 

4580 Sort the level(s) in the resulting MultiIndex columns. 

4581 

4582 Returns 

4583 ------- 

4584 DataFrame 

4585 Unstacked Series. 

4586 

4587 Notes 

4588 ----- 

4589 Reference :ref:`the user guide <reshaping.stacking>` for more examples. 

4590 

4591 Examples 

4592 -------- 

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

4594 ... index=pd.MultiIndex.from_product([['one', 'two'], 

4595 ... ['a', 'b']])) 

4596 >>> s 

4597 one a 1 

4598 b 2 

4599 two a 3 

4600 b 4 

4601 dtype: int64 

4602 

4603 >>> s.unstack(level=-1) 

4604 a b 

4605 one 1 2 

4606 two 3 4 

4607 

4608 >>> s.unstack(level=0) 

4609 one two 

4610 a 1 3 

4611 b 2 4 

4612 """ 

4613 from pandas.core.reshape.reshape import unstack 

4614 

4615 return unstack(self, level, fill_value, sort) 

4616 

4617 # ---------------------------------------------------------------------- 

4618 # function application 

4619 

4620 def map( 

4621 self, 

4622 arg: Callable | Mapping | Series, 

4623 na_action: Literal["ignore"] | None = None, 

4624 ) -> Series: 

4625 """ 

4626 Map values of Series according to an input mapping or function. 

4627 

4628 Used for substituting each value in a Series with another value, 

4629 that may be derived from a function, a ``dict`` or 

4630 a :class:`Series`. 

4631 

4632 Parameters 

4633 ---------- 

4634 arg : function, collections.abc.Mapping subclass or Series 

4635 Mapping correspondence. 

4636 na_action : {None, 'ignore'}, default None 

4637 If 'ignore', propagate NaN values, without passing them to the 

4638 mapping correspondence. 

4639 

4640 Returns 

4641 ------- 

4642 Series 

4643 Same index as caller. 

4644 

4645 See Also 

4646 -------- 

4647 Series.apply : For applying more complex functions on a Series. 

4648 Series.replace: Replace values given in `to_replace` with `value`. 

4649 DataFrame.apply : Apply a function row-/column-wise. 

4650 DataFrame.map : Apply a function elementwise on a whole DataFrame. 

4651 

4652 Notes 

4653 ----- 

4654 When ``arg`` is a dictionary, values in Series that are not in the 

4655 dictionary (as keys) are converted to ``NaN``. However, if the 

4656 dictionary is a ``dict`` subclass that defines ``__missing__`` (i.e. 

4657 provides a method for default values), then this default is used 

4658 rather than ``NaN``. 

4659 

4660 Examples 

4661 -------- 

4662 >>> s = pd.Series(['cat', 'dog', np.nan, 'rabbit']) 

4663 >>> s 

4664 0 cat 

4665 1 dog 

4666 2 NaN 

4667 3 rabbit 

4668 dtype: object 

4669 

4670 ``map`` accepts a ``dict`` or a ``Series``. Values that are not found 

4671 in the ``dict`` are converted to ``NaN``, unless the dict has a default 

4672 value (e.g. ``defaultdict``): 

4673 

4674 >>> s.map({'cat': 'kitten', 'dog': 'puppy'}) 

4675 0 kitten 

4676 1 puppy 

4677 2 NaN 

4678 3 NaN 

4679 dtype: object 

4680 

4681 It also accepts a function: 

4682 

4683 >>> s.map('I am a {}'.format) 

4684 0 I am a cat 

4685 1 I am a dog 

4686 2 I am a nan 

4687 3 I am a rabbit 

4688 dtype: object 

4689 

4690 To avoid applying the function to missing values (and keep them as 

4691 ``NaN``) ``na_action='ignore'`` can be used: 

4692 

4693 >>> s.map('I am a {}'.format, na_action='ignore') 

4694 0 I am a cat 

4695 1 I am a dog 

4696 2 NaN 

4697 3 I am a rabbit 

4698 dtype: object 

4699 """ 

4700 new_values = self._map_values(arg, na_action=na_action) 

4701 return self._constructor(new_values, index=self.index, copy=False).__finalize__( 

4702 self, method="map" 

4703 ) 

4704 

4705 def _gotitem(self, key, ndim, subset=None) -> Self: 

4706 """ 

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

4708 

4709 Parameters 

4710 ---------- 

4711 key : string / list of selections 

4712 ndim : {1, 2} 

4713 Requested ndim of result. 

4714 subset : object, default None 

4715 Subset to act on. 

4716 """ 

4717 return self 

4718 

4719 _agg_see_also_doc = dedent( 

4720 """ 

4721 See Also 

4722 -------- 

4723 Series.apply : Invoke function on a Series. 

4724 Series.transform : Transform function producing a Series with like indexes. 

4725 """ 

4726 ) 

4727 

4728 _agg_examples_doc = dedent( 

4729 """ 

4730 Examples 

4731 -------- 

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

4733 >>> s 

4734 0 1 

4735 1 2 

4736 2 3 

4737 3 4 

4738 dtype: int64 

4739 

4740 >>> s.agg('min') 

4741 1 

4742 

4743 >>> s.agg(['min', 'max']) 

4744 min 1 

4745 max 4 

4746 dtype: int64 

4747 """ 

4748 ) 

4749 

4750 @doc( 

4751 _shared_docs["aggregate"], 

4752 klass=_shared_doc_kwargs["klass"], 

4753 axis=_shared_doc_kwargs["axis"], 

4754 see_also=_agg_see_also_doc, 

4755 examples=_agg_examples_doc, 

4756 ) 

4757 def aggregate(self, func=None, axis: Axis = 0, *args, **kwargs): 

4758 # Validate the axis parameter 

4759 self._get_axis_number(axis) 

4760 

4761 # if func is None, will switch to user-provided "named aggregation" kwargs 

4762 if func is None: 

4763 func = dict(kwargs.items()) 

4764 

4765 op = SeriesApply(self, func, args=args, kwargs=kwargs) 

4766 result = op.agg() 

4767 return result 

4768 

4769 agg = aggregate 

4770 

4771 @doc( 

4772 _shared_docs["transform"], 

4773 klass=_shared_doc_kwargs["klass"], 

4774 axis=_shared_doc_kwargs["axis"], 

4775 ) 

4776 def transform( 

4777 self, func: AggFuncType, axis: Axis = 0, *args, **kwargs 

4778 ) -> DataFrame | Series: 

4779 # Validate axis argument 

4780 self._get_axis_number(axis) 

4781 ser = ( 

4782 self.copy(deep=False) 

4783 if using_copy_on_write() or warn_copy_on_write() 

4784 else self 

4785 ) 

4786 result = SeriesApply(ser, func=func, args=args, kwargs=kwargs).transform() 

4787 return result 

4788 

4789 def apply( 

4790 self, 

4791 func: AggFuncType, 

4792 convert_dtype: bool | lib.NoDefault = lib.no_default, 

4793 args: tuple[Any, ...] = (), 

4794 *, 

4795 by_row: Literal[False, "compat"] = "compat", 

4796 **kwargs, 

4797 ) -> DataFrame | Series: 

4798 """ 

4799 Invoke function on values of Series. 

4800 

4801 Can be ufunc (a NumPy function that applies to the entire Series) 

4802 or a Python function that only works on single values. 

4803 

4804 Parameters 

4805 ---------- 

4806 func : function 

4807 Python function or NumPy ufunc to apply. 

4808 convert_dtype : bool, default True 

4809 Try to find better dtype for elementwise function results. If 

4810 False, leave as dtype=object. Note that the dtype is always 

4811 preserved for some extension array dtypes, such as Categorical. 

4812 

4813 .. deprecated:: 2.1.0 

4814 ``convert_dtype`` has been deprecated. Do ``ser.astype(object).apply()`` 

4815 instead if you want ``convert_dtype=False``. 

4816 args : tuple 

4817 Positional arguments passed to func after the series value. 

4818 by_row : False or "compat", default "compat" 

4819 If ``"compat"`` and func is a callable, func will be passed each element of 

4820 the Series, like ``Series.map``. If func is a list or dict of 

4821 callables, will first try to translate each func into pandas methods. If 

4822 that doesn't work, will try call to apply again with ``by_row="compat"`` 

4823 and if that fails, will call apply again with ``by_row=False`` 

4824 (backward compatible). 

4825 If False, the func will be passed the whole Series at once. 

4826 

4827 ``by_row`` has no effect when ``func`` is a string. 

4828 

4829 .. versionadded:: 2.1.0 

4830 **kwargs 

4831 Additional keyword arguments passed to func. 

4832 

4833 Returns 

4834 ------- 

4835 Series or DataFrame 

4836 If func returns a Series object the result will be a DataFrame. 

4837 

4838 See Also 

4839 -------- 

4840 Series.map: For element-wise operations. 

4841 Series.agg: Only perform aggregating type operations. 

4842 Series.transform: Only perform transforming type operations. 

4843 

4844 Notes 

4845 ----- 

4846 Functions that mutate the passed object can produce unexpected 

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

4848 for more details. 

4849 

4850 Examples 

4851 -------- 

4852 Create a series with typical summer temperatures for each city. 

4853 

4854 >>> s = pd.Series([20, 21, 12], 

4855 ... index=['London', 'New York', 'Helsinki']) 

4856 >>> s 

4857 London 20 

4858 New York 21 

4859 Helsinki 12 

4860 dtype: int64 

4861 

4862 Square the values by defining a function and passing it as an 

4863 argument to ``apply()``. 

4864 

4865 >>> def square(x): 

4866 ... return x ** 2 

4867 >>> s.apply(square) 

4868 London 400 

4869 New York 441 

4870 Helsinki 144 

4871 dtype: int64 

4872 

4873 Square the values by passing an anonymous function as an 

4874 argument to ``apply()``. 

4875 

4876 >>> s.apply(lambda x: x ** 2) 

4877 London 400 

4878 New York 441 

4879 Helsinki 144 

4880 dtype: int64 

4881 

4882 Define a custom function that needs additional positional 

4883 arguments and pass these additional arguments using the 

4884 ``args`` keyword. 

4885 

4886 >>> def subtract_custom_value(x, custom_value): 

4887 ... return x - custom_value 

4888 

4889 >>> s.apply(subtract_custom_value, args=(5,)) 

4890 London 15 

4891 New York 16 

4892 Helsinki 7 

4893 dtype: int64 

4894 

4895 Define a custom function that takes keyword arguments 

4896 and pass these arguments to ``apply``. 

4897 

4898 >>> def add_custom_values(x, **kwargs): 

4899 ... for month in kwargs: 

4900 ... x += kwargs[month] 

4901 ... return x 

4902 

4903 >>> s.apply(add_custom_values, june=30, july=20, august=25) 

4904 London 95 

4905 New York 96 

4906 Helsinki 87 

4907 dtype: int64 

4908 

4909 Use a function from the Numpy library. 

4910 

4911 >>> s.apply(np.log) 

4912 London 2.995732 

4913 New York 3.044522 

4914 Helsinki 2.484907 

4915 dtype: float64 

4916 """ 

4917 return SeriesApply( 

4918 self, 

4919 func, 

4920 convert_dtype=convert_dtype, 

4921 by_row=by_row, 

4922 args=args, 

4923 kwargs=kwargs, 

4924 ).apply() 

4925 

4926 def _reindex_indexer( 

4927 self, 

4928 new_index: Index | None, 

4929 indexer: npt.NDArray[np.intp] | None, 

4930 copy: bool | None, 

4931 ) -> Series: 

4932 # Note: new_index is None iff indexer is None 

4933 # if not None, indexer is np.intp 

4934 if indexer is None and ( 

4935 new_index is None or new_index.names == self.index.names 

4936 ): 

4937 if using_copy_on_write(): 

4938 return self.copy(deep=copy) 

4939 if copy or copy is None: 

4940 return self.copy(deep=copy) 

4941 return self 

4942 

4943 new_values = algorithms.take_nd( 

4944 self._values, indexer, allow_fill=True, fill_value=None 

4945 ) 

4946 return self._constructor(new_values, index=new_index, copy=False) 

4947 

4948 def _needs_reindex_multi(self, axes, method, level) -> bool: 

4949 """ 

4950 Check if we do need a multi reindex; this is for compat with 

4951 higher dims. 

4952 """ 

4953 return False 

4954 

4955 @overload 

4956 def rename( 

4957 self, 

4958 index: Renamer | Hashable | None = ..., 

4959 *, 

4960 axis: Axis | None = ..., 

4961 copy: bool = ..., 

4962 inplace: Literal[True], 

4963 level: Level | None = ..., 

4964 errors: IgnoreRaise = ..., 

4965 ) -> None: 

4966 ... 

4967 

4968 @overload 

4969 def rename( 

4970 self, 

4971 index: Renamer | Hashable | None = ..., 

4972 *, 

4973 axis: Axis | None = ..., 

4974 copy: bool = ..., 

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

4976 level: Level | None = ..., 

4977 errors: IgnoreRaise = ..., 

4978 ) -> Series: 

4979 ... 

4980 

4981 @overload 

4982 def rename( 

4983 self, 

4984 index: Renamer | Hashable | None = ..., 

4985 *, 

4986 axis: Axis | None = ..., 

4987 copy: bool = ..., 

4988 inplace: bool = ..., 

4989 level: Level | None = ..., 

4990 errors: IgnoreRaise = ..., 

4991 ) -> Series | None: 

4992 ... 

4993 

4994 def rename( 

4995 self, 

4996 index: Renamer | Hashable | None = None, 

4997 *, 

4998 axis: Axis | None = None, 

4999 copy: bool | None = None, 

5000 inplace: bool = False, 

5001 level: Level | None = None, 

5002 errors: IgnoreRaise = "ignore", 

5003 ) -> Series | None: 

5004 """ 

5005 Alter Series index labels or name. 

5006 

5007 Function / dict values must be unique (1-to-1). Labels not contained in 

5008 a dict / Series will be left as-is. Extra labels listed don't throw an 

5009 error. 

5010 

5011 Alternatively, change ``Series.name`` with a scalar value. 

5012 

5013 See the :ref:`user guide <basics.rename>` for more. 

5014 

5015 Parameters 

5016 ---------- 

5017 index : scalar, hashable sequence, dict-like or function optional 

5018 Functions or dict-like are transformations to apply to 

5019 the index. 

5020 Scalar or hashable sequence-like will alter the ``Series.name`` 

5021 attribute. 

5022 axis : {0 or 'index'} 

5023 Unused. Parameter needed for compatibility with DataFrame. 

5024 copy : bool, default True 

5025 Also copy underlying data. 

5026 

5027 .. note:: 

5028 The `copy` keyword will change behavior in pandas 3.0. 

5029 `Copy-on-Write 

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

5031 will be enabled by default, which means that all methods with a 

5032 `copy` keyword will use a lazy copy mechanism to defer the copy and 

5033 ignore the `copy` keyword. The `copy` keyword will be removed in a 

5034 future version of pandas. 

5035 

5036 You can already get the future behavior and improvements through 

5037 enabling copy on write ``pd.options.mode.copy_on_write = True`` 

5038 inplace : bool, default False 

5039 Whether to return a new Series. If True the value of copy is ignored. 

5040 level : int or level name, default None 

5041 In case of MultiIndex, only rename labels in the specified level. 

5042 errors : {'ignore', 'raise'}, default 'ignore' 

5043 If 'raise', raise `KeyError` when a `dict-like mapper` or 

5044 `index` contains labels that are not present in the index being transformed. 

5045 If 'ignore', existing keys will be renamed and extra keys will be ignored. 

5046 

5047 Returns 

5048 ------- 

5049 Series or None 

5050 Series with index labels or name altered or None if ``inplace=True``. 

5051 

5052 See Also 

5053 -------- 

5054 DataFrame.rename : Corresponding DataFrame method. 

5055 Series.rename_axis : Set the name of the axis. 

5056 

5057 Examples 

5058 -------- 

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

5060 >>> s 

5061 0 1 

5062 1 2 

5063 2 3 

5064 dtype: int64 

5065 >>> s.rename("my_name") # scalar, changes Series.name 

5066 0 1 

5067 1 2 

5068 2 3 

5069 Name: my_name, dtype: int64 

5070 >>> s.rename(lambda x: x ** 2) # function, changes labels 

5071 0 1 

5072 1 2 

5073 4 3 

5074 dtype: int64 

5075 >>> s.rename({1: 3, 2: 5}) # mapping, changes labels 

5076 0 1 

5077 3 2 

5078 5 3 

5079 dtype: int64 

5080 """ 

5081 if axis is not None: 

5082 # Make sure we raise if an invalid 'axis' is passed. 

5083 axis = self._get_axis_number(axis) 

5084 

5085 if callable(index) or is_dict_like(index): 

5086 # error: Argument 1 to "_rename" of "NDFrame" has incompatible 

5087 # type "Union[Union[Mapping[Any, Hashable], Callable[[Any], 

5088 # Hashable]], Hashable, None]"; expected "Union[Mapping[Any, 

5089 # Hashable], Callable[[Any], Hashable], None]" 

5090 return super()._rename( 

5091 index, # type: ignore[arg-type] 

5092 copy=copy, 

5093 inplace=inplace, 

5094 level=level, 

5095 errors=errors, 

5096 ) 

5097 else: 

5098 return self._set_name(index, inplace=inplace, deep=copy) 

5099 

5100 @Appender( 

5101 """ 

5102 Examples 

5103 -------- 

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

5105 >>> s 

5106 0 1 

5107 1 2 

5108 2 3 

5109 dtype: int64 

5110 

5111 >>> s.set_axis(['a', 'b', 'c'], axis=0) 

5112 a 1 

5113 b 2 

5114 c 3 

5115 dtype: int64 

5116 """ 

5117 ) 

5118 @Substitution( 

5119 klass=_shared_doc_kwargs["klass"], 

5120 axes_single_arg=_shared_doc_kwargs["axes_single_arg"], 

5121 extended_summary_sub="", 

5122 axis_description_sub="", 

5123 see_also_sub="", 

5124 ) 

5125 @Appender(NDFrame.set_axis.__doc__) 

5126 def set_axis( 

5127 self, 

5128 labels, 

5129 *, 

5130 axis: Axis = 0, 

5131 copy: bool | None = None, 

5132 ) -> Series: 

5133 return super().set_axis(labels, axis=axis, copy=copy) 

5134 

5135 # error: Cannot determine type of 'reindex' 

5136 @doc( 

5137 NDFrame.reindex, # type: ignore[has-type] 

5138 klass=_shared_doc_kwargs["klass"], 

5139 optional_reindex=_shared_doc_kwargs["optional_reindex"], 

5140 ) 

5141 def reindex( # type: ignore[override] 

5142 self, 

5143 index=None, 

5144 *, 

5145 axis: Axis | None = None, 

5146 method: ReindexMethod | None = None, 

5147 copy: bool | None = None, 

5148 level: Level | None = None, 

5149 fill_value: Scalar | None = None, 

5150 limit: int | None = None, 

5151 tolerance=None, 

5152 ) -> Series: 

5153 return super().reindex( 

5154 index=index, 

5155 method=method, 

5156 copy=copy, 

5157 level=level, 

5158 fill_value=fill_value, 

5159 limit=limit, 

5160 tolerance=tolerance, 

5161 ) 

5162 

5163 @overload # type: ignore[override] 

5164 def rename_axis( 

5165 self, 

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

5167 *, 

5168 index=..., 

5169 axis: Axis = ..., 

5170 copy: bool = ..., 

5171 inplace: Literal[True], 

5172 ) -> None: 

5173 ... 

5174 

5175 @overload 

5176 def rename_axis( 

5177 self, 

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

5179 *, 

5180 index=..., 

5181 axis: Axis = ..., 

5182 copy: bool = ..., 

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

5184 ) -> Self: 

5185 ... 

5186 

5187 @overload 

5188 def rename_axis( 

5189 self, 

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

5191 *, 

5192 index=..., 

5193 axis: Axis = ..., 

5194 copy: bool = ..., 

5195 inplace: bool = ..., 

5196 ) -> Self | None: 

5197 ... 

5198 

5199 @doc(NDFrame.rename_axis) 

5200 def rename_axis( 

5201 self, 

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

5203 *, 

5204 index=lib.no_default, 

5205 axis: Axis = 0, 

5206 copy: bool = True, 

5207 inplace: bool = False, 

5208 ) -> Self | None: 

5209 return super().rename_axis( 

5210 mapper=mapper, 

5211 index=index, 

5212 axis=axis, 

5213 copy=copy, 

5214 inplace=inplace, 

5215 ) 

5216 

5217 @overload 

5218 def drop( 

5219 self, 

5220 labels: IndexLabel = ..., 

5221 *, 

5222 axis: Axis = ..., 

5223 index: IndexLabel = ..., 

5224 columns: IndexLabel = ..., 

5225 level: Level | None = ..., 

5226 inplace: Literal[True], 

5227 errors: IgnoreRaise = ..., 

5228 ) -> None: 

5229 ... 

5230 

5231 @overload 

5232 def drop( 

5233 self, 

5234 labels: IndexLabel = ..., 

5235 *, 

5236 axis: Axis = ..., 

5237 index: IndexLabel = ..., 

5238 columns: IndexLabel = ..., 

5239 level: Level | None = ..., 

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

5241 errors: IgnoreRaise = ..., 

5242 ) -> Series: 

5243 ... 

5244 

5245 @overload 

5246 def drop( 

5247 self, 

5248 labels: IndexLabel = ..., 

5249 *, 

5250 axis: Axis = ..., 

5251 index: IndexLabel = ..., 

5252 columns: IndexLabel = ..., 

5253 level: Level | None = ..., 

5254 inplace: bool = ..., 

5255 errors: IgnoreRaise = ..., 

5256 ) -> Series | None: 

5257 ... 

5258 

5259 def drop( 

5260 self, 

5261 labels: IndexLabel | None = None, 

5262 *, 

5263 axis: Axis = 0, 

5264 index: IndexLabel | None = None, 

5265 columns: IndexLabel | None = None, 

5266 level: Level | None = None, 

5267 inplace: bool = False, 

5268 errors: IgnoreRaise = "raise", 

5269 ) -> Series | None: 

5270 """ 

5271 Return Series with specified index labels removed. 

5272 

5273 Remove elements of a Series based on specifying the index labels. 

5274 When using a multi-index, labels on different levels can be removed 

5275 by specifying the level. 

5276 

5277 Parameters 

5278 ---------- 

5279 labels : single label or list-like 

5280 Index labels to drop. 

5281 axis : {0 or 'index'} 

5282 Unused. Parameter needed for compatibility with DataFrame. 

5283 index : single label or list-like 

5284 Redundant for application on Series, but 'index' can be used instead 

5285 of 'labels'. 

5286 columns : single label or list-like 

5287 No change is made to the Series; use 'index' or 'labels' instead. 

5288 level : int or level name, optional 

5289 For MultiIndex, level for which the labels will be removed. 

5290 inplace : bool, default False 

5291 If True, do operation inplace and return None. 

5292 errors : {'ignore', 'raise'}, default 'raise' 

5293 If 'ignore', suppress error and only existing labels are dropped. 

5294 

5295 Returns 

5296 ------- 

5297 Series or None 

5298 Series with specified index labels removed or None if ``inplace=True``. 

5299 

5300 Raises 

5301 ------ 

5302 KeyError 

5303 If none of the labels are found in the index. 

5304 

5305 See Also 

5306 -------- 

5307 Series.reindex : Return only specified index labels of Series. 

5308 Series.dropna : Return series without null values. 

5309 Series.drop_duplicates : Return Series with duplicate values removed. 

5310 DataFrame.drop : Drop specified labels from rows or columns. 

5311 

5312 Examples 

5313 -------- 

5314 >>> s = pd.Series(data=np.arange(3), index=['A', 'B', 'C']) 

5315 >>> s 

5316 A 0 

5317 B 1 

5318 C 2 

5319 dtype: int64 

5320 

5321 Drop labels B en C 

5322 

5323 >>> s.drop(labels=['B', 'C']) 

5324 A 0 

5325 dtype: int64 

5326 

5327 Drop 2nd level label in MultiIndex Series 

5328 

5329 >>> midx = pd.MultiIndex(levels=[['llama', 'cow', 'falcon'], 

5330 ... ['speed', 'weight', 'length']], 

5331 ... codes=[[0, 0, 0, 1, 1, 1, 2, 2, 2], 

5332 ... [0, 1, 2, 0, 1, 2, 0, 1, 2]]) 

5333 >>> s = pd.Series([45, 200, 1.2, 30, 250, 1.5, 320, 1, 0.3], 

5334 ... index=midx) 

5335 >>> s 

5336 llama speed 45.0 

5337 weight 200.0 

5338 length 1.2 

5339 cow speed 30.0 

5340 weight 250.0 

5341 length 1.5 

5342 falcon speed 320.0 

5343 weight 1.0 

5344 length 0.3 

5345 dtype: float64 

5346 

5347 >>> s.drop(labels='weight', level=1) 

5348 llama speed 45.0 

5349 length 1.2 

5350 cow speed 30.0 

5351 length 1.5 

5352 falcon speed 320.0 

5353 length 0.3 

5354 dtype: float64 

5355 """ 

5356 return super().drop( 

5357 labels=labels, 

5358 axis=axis, 

5359 index=index, 

5360 columns=columns, 

5361 level=level, 

5362 inplace=inplace, 

5363 errors=errors, 

5364 ) 

5365 

5366 def pop(self, item: Hashable) -> Any: 

5367 """ 

5368 Return item and drops from series. Raise KeyError if not found. 

5369 

5370 Parameters 

5371 ---------- 

5372 item : label 

5373 Index of the element that needs to be removed. 

5374 

5375 Returns 

5376 ------- 

5377 Value that is popped from series. 

5378 

5379 Examples 

5380 -------- 

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

5382 

5383 >>> ser.pop(0) 

5384 1 

5385 

5386 >>> ser 

5387 1 2 

5388 2 3 

5389 dtype: int64 

5390 """ 

5391 return super().pop(item=item) 

5392 

5393 @doc(INFO_DOCSTRING, **series_sub_kwargs) 

5394 def info( 

5395 self, 

5396 verbose: bool | None = None, 

5397 buf: IO[str] | None = None, 

5398 max_cols: int | None = None, 

5399 memory_usage: bool | str | None = None, 

5400 show_counts: bool = True, 

5401 ) -> None: 

5402 return SeriesInfo(self, memory_usage).render( 

5403 buf=buf, 

5404 max_cols=max_cols, 

5405 verbose=verbose, 

5406 show_counts=show_counts, 

5407 ) 

5408 

5409 # TODO(3.0): this can be removed once GH#33302 deprecation is enforced 

5410 def _replace_single(self, to_replace, method: str, inplace: bool, limit): 

5411 """ 

5412 Replaces values in a Series using the fill method specified when no 

5413 replacement value is given in the replace method 

5414 """ 

5415 

5416 result = self if inplace else self.copy() 

5417 

5418 values = result._values 

5419 mask = missing.mask_missing(values, to_replace) 

5420 

5421 if isinstance(values, ExtensionArray): 

5422 # dispatch to the EA's _pad_mask_inplace method 

5423 values._fill_mask_inplace(method, limit, mask) 

5424 else: 

5425 fill_f = missing.get_fill_func(method) 

5426 fill_f(values, limit=limit, mask=mask) 

5427 

5428 if inplace: 

5429 return 

5430 return result 

5431 

5432 def memory_usage(self, index: bool = True, deep: bool = False) -> int: 

5433 """ 

5434 Return the memory usage of the Series. 

5435 

5436 The memory usage can optionally include the contribution of 

5437 the index and of elements of `object` dtype. 

5438 

5439 Parameters 

5440 ---------- 

5441 index : bool, default True 

5442 Specifies whether to include the memory usage of the Series index. 

5443 deep : bool, default False 

5444 If True, introspect the data deeply by interrogating 

5445 `object` dtypes for system-level memory consumption, and include 

5446 it in the returned value. 

5447 

5448 Returns 

5449 ------- 

5450 int 

5451 Bytes of memory consumed. 

5452 

5453 See Also 

5454 -------- 

5455 numpy.ndarray.nbytes : Total bytes consumed by the elements of the 

5456 array. 

5457 DataFrame.memory_usage : Bytes consumed by a DataFrame. 

5458 

5459 Examples 

5460 -------- 

5461 >>> s = pd.Series(range(3)) 

5462 >>> s.memory_usage() 

5463 152 

5464 

5465 Not including the index gives the size of the rest of the data, which 

5466 is necessarily smaller: 

5467 

5468 >>> s.memory_usage(index=False) 

5469 24 

5470 

5471 The memory footprint of `object` values is ignored by default: 

5472 

5473 >>> s = pd.Series(["a", "b"]) 

5474 >>> s.values 

5475 array(['a', 'b'], dtype=object) 

5476 >>> s.memory_usage() 

5477 144 

5478 >>> s.memory_usage(deep=True) 

5479 244 

5480 """ 

5481 v = self._memory_usage(deep=deep) 

5482 if index: 

5483 v += self.index.memory_usage(deep=deep) 

5484 return v 

5485 

5486 def isin(self, values) -> Series: 

5487 """ 

5488 Whether elements in Series are contained in `values`. 

5489 

5490 Return a boolean Series showing whether each element in the Series 

5491 matches an element in the passed sequence of `values` exactly. 

5492 

5493 Parameters 

5494 ---------- 

5495 values : set or list-like 

5496 The sequence of values to test. Passing in a single string will 

5497 raise a ``TypeError``. Instead, turn a single string into a 

5498 list of one element. 

5499 

5500 Returns 

5501 ------- 

5502 Series 

5503 Series of booleans indicating if each element is in values. 

5504 

5505 Raises 

5506 ------ 

5507 TypeError 

5508 * If `values` is a string 

5509 

5510 See Also 

5511 -------- 

5512 DataFrame.isin : Equivalent method on DataFrame. 

5513 

5514 Examples 

5515 -------- 

5516 >>> s = pd.Series(['llama', 'cow', 'llama', 'beetle', 'llama', 

5517 ... 'hippo'], name='animal') 

5518 >>> s.isin(['cow', 'llama']) 

5519 0 True 

5520 1 True 

5521 2 True 

5522 3 False 

5523 4 True 

5524 5 False 

5525 Name: animal, dtype: bool 

5526 

5527 To invert the boolean values, use the ``~`` operator: 

5528 

5529 >>> ~s.isin(['cow', 'llama']) 

5530 0 False 

5531 1 False 

5532 2 False 

5533 3 True 

5534 4 False 

5535 5 True 

5536 Name: animal, dtype: bool 

5537 

5538 Passing a single string as ``s.isin('llama')`` will raise an error. Use 

5539 a list of one element instead: 

5540 

5541 >>> s.isin(['llama']) 

5542 0 True 

5543 1 False 

5544 2 True 

5545 3 False 

5546 4 True 

5547 5 False 

5548 Name: animal, dtype: bool 

5549 

5550 Strings and integers are distinct and are therefore not comparable: 

5551 

5552 >>> pd.Series([1]).isin(['1']) 

5553 0 False 

5554 dtype: bool 

5555 >>> pd.Series([1.1]).isin(['1.1']) 

5556 0 False 

5557 dtype: bool 

5558 """ 

5559 result = algorithms.isin(self._values, values) 

5560 return self._constructor(result, index=self.index, copy=False).__finalize__( 

5561 self, method="isin" 

5562 ) 

5563 

5564 def between( 

5565 self, 

5566 left, 

5567 right, 

5568 inclusive: Literal["both", "neither", "left", "right"] = "both", 

5569 ) -> Series: 

5570 """ 

5571 Return boolean Series equivalent to left <= series <= right. 

5572 

5573 This function returns a boolean vector containing `True` wherever the 

5574 corresponding Series element is between the boundary values `left` and 

5575 `right`. NA values are treated as `False`. 

5576 

5577 Parameters 

5578 ---------- 

5579 left : scalar or list-like 

5580 Left boundary. 

5581 right : scalar or list-like 

5582 Right boundary. 

5583 inclusive : {"both", "neither", "left", "right"} 

5584 Include boundaries. Whether to set each bound as closed or open. 

5585 

5586 .. versionchanged:: 1.3.0 

5587 

5588 Returns 

5589 ------- 

5590 Series 

5591 Series representing whether each element is between left and 

5592 right (inclusive). 

5593 

5594 See Also 

5595 -------- 

5596 Series.gt : Greater than of series and other. 

5597 Series.lt : Less than of series and other. 

5598 

5599 Notes 

5600 ----- 

5601 This function is equivalent to ``(left <= ser) & (ser <= right)`` 

5602 

5603 Examples 

5604 -------- 

5605 >>> s = pd.Series([2, 0, 4, 8, np.nan]) 

5606 

5607 Boundary values are included by default: 

5608 

5609 >>> s.between(1, 4) 

5610 0 True 

5611 1 False 

5612 2 True 

5613 3 False 

5614 4 False 

5615 dtype: bool 

5616 

5617 With `inclusive` set to ``"neither"`` boundary values are excluded: 

5618 

5619 >>> s.between(1, 4, inclusive="neither") 

5620 0 True 

5621 1 False 

5622 2 False 

5623 3 False 

5624 4 False 

5625 dtype: bool 

5626 

5627 `left` and `right` can be any scalar value: 

5628 

5629 >>> s = pd.Series(['Alice', 'Bob', 'Carol', 'Eve']) 

5630 >>> s.between('Anna', 'Daniel') 

5631 0 False 

5632 1 True 

5633 2 True 

5634 3 False 

5635 dtype: bool 

5636 """ 

5637 if inclusive == "both": 

5638 lmask = self >= left 

5639 rmask = self <= right 

5640 elif inclusive == "left": 

5641 lmask = self >= left 

5642 rmask = self < right 

5643 elif inclusive == "right": 

5644 lmask = self > left 

5645 rmask = self <= right 

5646 elif inclusive == "neither": 

5647 lmask = self > left 

5648 rmask = self < right 

5649 else: 

5650 raise ValueError( 

5651 "Inclusive has to be either string of 'both'," 

5652 "'left', 'right', or 'neither'." 

5653 ) 

5654 

5655 return lmask & rmask 

5656 

5657 def case_when( 

5658 self, 

5659 caselist: list[ 

5660 tuple[ 

5661 ArrayLike | Callable[[Series], Series | np.ndarray | Sequence[bool]], 

5662 ArrayLike | Scalar | Callable[[Series], Series | np.ndarray], 

5663 ], 

5664 ], 

5665 ) -> Series: 

5666 """ 

5667 Replace values where the conditions are True. 

5668 

5669 Parameters 

5670 ---------- 

5671 caselist : A list of tuples of conditions and expected replacements 

5672 Takes the form: ``(condition0, replacement0)``, 

5673 ``(condition1, replacement1)``, ... . 

5674 ``condition`` should be a 1-D boolean array-like object 

5675 or a callable. If ``condition`` is a callable, 

5676 it is computed on the Series 

5677 and should return a boolean Series or array. 

5678 The callable must not change the input Series 

5679 (though pandas doesn`t check it). ``replacement`` should be a 

5680 1-D array-like object, a scalar or a callable. 

5681 If ``replacement`` is a callable, it is computed on the Series 

5682 and should return a scalar or Series. The callable 

5683 must not change the input Series 

5684 (though pandas doesn`t check it). 

5685 

5686 .. versionadded:: 2.2.0 

5687 

5688 Returns 

5689 ------- 

5690 Series 

5691 

5692 See Also 

5693 -------- 

5694 Series.mask : Replace values where the condition is True. 

5695 

5696 Examples 

5697 -------- 

5698 >>> c = pd.Series([6, 7, 8, 9], name='c') 

5699 >>> a = pd.Series([0, 0, 1, 2]) 

5700 >>> b = pd.Series([0, 3, 4, 5]) 

5701 

5702 >>> c.case_when(caselist=[(a.gt(0), a), # condition, replacement 

5703 ... (b.gt(0), b)]) 

5704 0 6 

5705 1 3 

5706 2 1 

5707 3 2 

5708 Name: c, dtype: int64 

5709 """ 

5710 if not isinstance(caselist, list): 

5711 raise TypeError( 

5712 f"The caselist argument should be a list; instead got {type(caselist)}" 

5713 ) 

5714 

5715 if not caselist: 

5716 raise ValueError( 

5717 "provide at least one boolean condition, " 

5718 "with a corresponding replacement." 

5719 ) 

5720 

5721 for num, entry in enumerate(caselist): 

5722 if not isinstance(entry, tuple): 

5723 raise TypeError( 

5724 f"Argument {num} must be a tuple; instead got {type(entry)}." 

5725 ) 

5726 if len(entry) != 2: 

5727 raise ValueError( 

5728 f"Argument {num} must have length 2; " 

5729 "a condition and replacement; " 

5730 f"instead got length {len(entry)}." 

5731 ) 

5732 caselist = [ 

5733 ( 

5734 com.apply_if_callable(condition, self), 

5735 com.apply_if_callable(replacement, self), 

5736 ) 

5737 for condition, replacement in caselist 

5738 ] 

5739 default = self.copy() 

5740 conditions, replacements = zip(*caselist) 

5741 common_dtypes = [infer_dtype_from(arg)[0] for arg in [*replacements, default]] 

5742 if len(set(common_dtypes)) > 1: 

5743 common_dtype = find_common_type(common_dtypes) 

5744 updated_replacements = [] 

5745 for condition, replacement in zip(conditions, replacements): 

5746 if is_scalar(replacement): 

5747 replacement = construct_1d_arraylike_from_scalar( 

5748 value=replacement, length=len(condition), dtype=common_dtype 

5749 ) 

5750 elif isinstance(replacement, ABCSeries): 

5751 replacement = replacement.astype(common_dtype) 

5752 else: 

5753 replacement = pd_array(replacement, dtype=common_dtype) 

5754 updated_replacements.append(replacement) 

5755 replacements = updated_replacements 

5756 default = default.astype(common_dtype) 

5757 

5758 counter = reversed(range(len(conditions))) 

5759 for position, condition, replacement in zip( 

5760 counter, conditions[::-1], replacements[::-1] 

5761 ): 

5762 try: 

5763 default = default.mask( 

5764 condition, other=replacement, axis=0, inplace=False, level=None 

5765 ) 

5766 except Exception as error: 

5767 raise ValueError( 

5768 f"Failed to apply condition{position} and replacement{position}." 

5769 ) from error 

5770 return default 

5771 

5772 # error: Cannot determine type of 'isna' 

5773 @doc(NDFrame.isna, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] 

5774 def isna(self) -> Series: 

5775 return NDFrame.isna(self) 

5776 

5777 # error: Cannot determine type of 'isna' 

5778 @doc(NDFrame.isna, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] 

5779 def isnull(self) -> Series: 

5780 """ 

5781 Series.isnull is an alias for Series.isna. 

5782 """ 

5783 return super().isnull() 

5784 

5785 # error: Cannot determine type of 'notna' 

5786 @doc(NDFrame.notna, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] 

5787 def notna(self) -> Series: 

5788 return super().notna() 

5789 

5790 # error: Cannot determine type of 'notna' 

5791 @doc(NDFrame.notna, klass=_shared_doc_kwargs["klass"]) # type: ignore[has-type] 

5792 def notnull(self) -> Series: 

5793 """ 

5794 Series.notnull is an alias for Series.notna. 

5795 """ 

5796 return super().notnull() 

5797 

5798 @overload 

5799 def dropna( 

5800 self, 

5801 *, 

5802 axis: Axis = ..., 

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

5804 how: AnyAll | None = ..., 

5805 ignore_index: bool = ..., 

5806 ) -> Series: 

5807 ... 

5808 

5809 @overload 

5810 def dropna( 

5811 self, 

5812 *, 

5813 axis: Axis = ..., 

5814 inplace: Literal[True], 

5815 how: AnyAll | None = ..., 

5816 ignore_index: bool = ..., 

5817 ) -> None: 

5818 ... 

5819 

5820 def dropna( 

5821 self, 

5822 *, 

5823 axis: Axis = 0, 

5824 inplace: bool = False, 

5825 how: AnyAll | None = None, 

5826 ignore_index: bool = False, 

5827 ) -> Series | None: 

5828 """ 

5829 Return a new Series with missing values removed. 

5830 

5831 See the :ref:`User Guide <missing_data>` for more on which values are 

5832 considered missing, and how to work with missing data. 

5833 

5834 Parameters 

5835 ---------- 

5836 axis : {0 or 'index'} 

5837 Unused. Parameter needed for compatibility with DataFrame. 

5838 inplace : bool, default False 

5839 If True, do operation inplace and return None. 

5840 how : str, optional 

5841 Not in use. Kept for compatibility. 

5842 ignore_index : bool, default ``False`` 

5843 If ``True``, the resulting axis will be labeled 0, 1, …, n - 1. 

5844 

5845 .. versionadded:: 2.0.0 

5846 

5847 Returns 

5848 ------- 

5849 Series or None 

5850 Series with NA entries dropped from it or None if ``inplace=True``. 

5851 

5852 See Also 

5853 -------- 

5854 Series.isna: Indicate missing values. 

5855 Series.notna : Indicate existing (non-missing) values. 

5856 Series.fillna : Replace missing values. 

5857 DataFrame.dropna : Drop rows or columns which contain NA values. 

5858 Index.dropna : Drop missing indices. 

5859 

5860 Examples 

5861 -------- 

5862 >>> ser = pd.Series([1., 2., np.nan]) 

5863 >>> ser 

5864 0 1.0 

5865 1 2.0 

5866 2 NaN 

5867 dtype: float64 

5868 

5869 Drop NA values from a Series. 

5870 

5871 >>> ser.dropna() 

5872 0 1.0 

5873 1 2.0 

5874 dtype: float64 

5875 

5876 Empty strings are not considered NA values. ``None`` is considered an 

5877 NA value. 

5878 

5879 >>> ser = pd.Series([np.nan, 2, pd.NaT, '', None, 'I stay']) 

5880 >>> ser 

5881 0 NaN 

5882 1 2 

5883 2 NaT 

5884 3 

5885 4 None 

5886 5 I stay 

5887 dtype: object 

5888 >>> ser.dropna() 

5889 1 2 

5890 3 

5891 5 I stay 

5892 dtype: object 

5893 """ 

5894 inplace = validate_bool_kwarg(inplace, "inplace") 

5895 ignore_index = validate_bool_kwarg(ignore_index, "ignore_index") 

5896 # Validate the axis parameter 

5897 self._get_axis_number(axis or 0) 

5898 

5899 if self._can_hold_na: 

5900 result = remove_na_arraylike(self) 

5901 else: 

5902 if not inplace: 

5903 result = self.copy(deep=None) 

5904 else: 

5905 result = self 

5906 

5907 if ignore_index: 

5908 result.index = default_index(len(result)) 

5909 

5910 if inplace: 

5911 return self._update_inplace(result) 

5912 else: 

5913 return result 

5914 

5915 # ---------------------------------------------------------------------- 

5916 # Time series-oriented methods 

5917 

5918 def to_timestamp( 

5919 self, 

5920 freq: Frequency | None = None, 

5921 how: Literal["s", "e", "start", "end"] = "start", 

5922 copy: bool | None = None, 

5923 ) -> Series: 

5924 """ 

5925 Cast to DatetimeIndex of Timestamps, at *beginning* of period. 

5926 

5927 Parameters 

5928 ---------- 

5929 freq : str, default frequency of PeriodIndex 

5930 Desired frequency. 

5931 how : {'s', 'e', 'start', 'end'} 

5932 Convention for converting period to timestamp; start of period 

5933 vs. end. 

5934 copy : bool, default True 

5935 Whether or not to return a copy. 

5936 

5937 .. note:: 

5938 The `copy` keyword will change behavior in pandas 3.0. 

5939 `Copy-on-Write 

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

5941 will be enabled by default, which means that all methods with a 

5942 `copy` keyword will use a lazy copy mechanism to defer the copy and 

5943 ignore the `copy` keyword. The `copy` keyword will be removed in a 

5944 future version of pandas. 

5945 

5946 You can already get the future behavior and improvements through 

5947 enabling copy on write ``pd.options.mode.copy_on_write = True`` 

5948 

5949 Returns 

5950 ------- 

5951 Series with DatetimeIndex 

5952 

5953 Examples 

5954 -------- 

5955 >>> idx = pd.PeriodIndex(['2023', '2024', '2025'], freq='Y') 

5956 >>> s1 = pd.Series([1, 2, 3], index=idx) 

5957 >>> s1 

5958 2023 1 

5959 2024 2 

5960 2025 3 

5961 Freq: Y-DEC, dtype: int64 

5962 

5963 The resulting frequency of the Timestamps is `YearBegin` 

5964 

5965 >>> s1 = s1.to_timestamp() 

5966 >>> s1 

5967 2023-01-01 1 

5968 2024-01-01 2 

5969 2025-01-01 3 

5970 Freq: YS-JAN, dtype: int64 

5971 

5972 Using `freq` which is the offset that the Timestamps will have 

5973 

5974 >>> s2 = pd.Series([1, 2, 3], index=idx) 

5975 >>> s2 = s2.to_timestamp(freq='M') 

5976 >>> s2 

5977 2023-01-31 1 

5978 2024-01-31 2 

5979 2025-01-31 3 

5980 Freq: YE-JAN, dtype: int64 

5981 """ 

5982 if not isinstance(self.index, PeriodIndex): 

5983 raise TypeError(f"unsupported Type {type(self.index).__name__}") 

5984 

5985 new_obj = self.copy(deep=copy and not using_copy_on_write()) 

5986 new_index = self.index.to_timestamp(freq=freq, how=how) 

5987 setattr(new_obj, "index", new_index) 

5988 return new_obj 

5989 

5990 def to_period(self, freq: str | None = None, copy: bool | None = None) -> Series: 

5991 """ 

5992 Convert Series from DatetimeIndex to PeriodIndex. 

5993 

5994 Parameters 

5995 ---------- 

5996 freq : str, default None 

5997 Frequency associated with the PeriodIndex. 

5998 copy : bool, default True 

5999 Whether or not to return a copy. 

6000 

6001 .. note:: 

6002 The `copy` keyword will change behavior in pandas 3.0. 

6003 `Copy-on-Write 

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

6005 will be enabled by default, which means that all methods with a 

6006 `copy` keyword will use a lazy copy mechanism to defer the copy and 

6007 ignore the `copy` keyword. The `copy` keyword will be removed in a 

6008 future version of pandas. 

6009 

6010 You can already get the future behavior and improvements through 

6011 enabling copy on write ``pd.options.mode.copy_on_write = True`` 

6012 

6013 Returns 

6014 ------- 

6015 Series 

6016 Series with index converted to PeriodIndex. 

6017 

6018 Examples 

6019 -------- 

6020 >>> idx = pd.DatetimeIndex(['2023', '2024', '2025']) 

6021 >>> s = pd.Series([1, 2, 3], index=idx) 

6022 >>> s = s.to_period() 

6023 >>> s 

6024 2023 1 

6025 2024 2 

6026 2025 3 

6027 Freq: Y-DEC, dtype: int64 

6028 

6029 Viewing the index 

6030 

6031 >>> s.index 

6032 PeriodIndex(['2023', '2024', '2025'], dtype='period[Y-DEC]') 

6033 """ 

6034 if not isinstance(self.index, DatetimeIndex): 

6035 raise TypeError(f"unsupported Type {type(self.index).__name__}") 

6036 

6037 new_obj = self.copy(deep=copy and not using_copy_on_write()) 

6038 new_index = self.index.to_period(freq=freq) 

6039 setattr(new_obj, "index", new_index) 

6040 return new_obj 

6041 

6042 # ---------------------------------------------------------------------- 

6043 # Add index 

6044 _AXIS_ORDERS: list[Literal["index", "columns"]] = ["index"] 

6045 _AXIS_LEN = len(_AXIS_ORDERS) 

6046 _info_axis_number: Literal[0] = 0 

6047 _info_axis_name: Literal["index"] = "index" 

6048 

6049 index = properties.AxisProperty( 

6050 axis=0, 

6051 doc=""" 

6052 The index (axis labels) of the Series. 

6053 

6054 The index of a Series is used to label and identify each element of the 

6055 underlying data. The index can be thought of as an immutable ordered set 

6056 (technically a multi-set, as it may contain duplicate labels), and is 

6057 used to index and align data in pandas. 

6058 

6059 Returns 

6060 ------- 

6061 Index 

6062 The index labels of the Series. 

6063 

6064 See Also 

6065 -------- 

6066 Series.reindex : Conform Series to new index. 

6067 Index : The base pandas index type. 

6068 

6069 Notes 

6070 ----- 

6071 For more information on pandas indexing, see the `indexing user guide 

6072 <https://pandas.pydata.org/docs/user_guide/indexing.html>`__. 

6073 

6074 Examples 

6075 -------- 

6076 To create a Series with a custom index and view the index labels: 

6077 

6078 >>> cities = ['Kolkata', 'Chicago', 'Toronto', 'Lisbon'] 

6079 >>> populations = [14.85, 2.71, 2.93, 0.51] 

6080 >>> city_series = pd.Series(populations, index=cities) 

6081 >>> city_series.index 

6082 Index(['Kolkata', 'Chicago', 'Toronto', 'Lisbon'], dtype='object') 

6083 

6084 To change the index labels of an existing Series: 

6085 

6086 >>> city_series.index = ['KOL', 'CHI', 'TOR', 'LIS'] 

6087 >>> city_series.index 

6088 Index(['KOL', 'CHI', 'TOR', 'LIS'], dtype='object') 

6089 """, 

6090 ) 

6091 

6092 # ---------------------------------------------------------------------- 

6093 # Accessor Methods 

6094 # ---------------------------------------------------------------------- 

6095 str = CachedAccessor("str", StringMethods) 

6096 dt = CachedAccessor("dt", CombinedDatetimelikeProperties) 

6097 cat = CachedAccessor("cat", CategoricalAccessor) 

6098 plot = CachedAccessor("plot", pandas.plotting.PlotAccessor) 

6099 sparse = CachedAccessor("sparse", SparseAccessor) 

6100 struct = CachedAccessor("struct", StructAccessor) 

6101 list = CachedAccessor("list", ListAccessor) 

6102 

6103 # ---------------------------------------------------------------------- 

6104 # Add plotting methods to Series 

6105 hist = pandas.plotting.hist_series 

6106 

6107 # ---------------------------------------------------------------------- 

6108 # Template-Based Arithmetic/Comparison Methods 

6109 

6110 def _cmp_method(self, other, op): 

6111 res_name = ops.get_op_result_name(self, other) 

6112 

6113 if isinstance(other, Series) and not self._indexed_same(other): 

6114 raise ValueError("Can only compare identically-labeled Series objects") 

6115 

6116 lvalues = self._values 

6117 rvalues = extract_array(other, extract_numpy=True, extract_range=True) 

6118 

6119 res_values = ops.comparison_op(lvalues, rvalues, op) 

6120 

6121 return self._construct_result(res_values, name=res_name) 

6122 

6123 def _logical_method(self, other, op): 

6124 res_name = ops.get_op_result_name(self, other) 

6125 self, other = self._align_for_op(other, align_asobject=True) 

6126 

6127 lvalues = self._values 

6128 rvalues = extract_array(other, extract_numpy=True, extract_range=True) 

6129 

6130 res_values = ops.logical_op(lvalues, rvalues, op) 

6131 return self._construct_result(res_values, name=res_name) 

6132 

6133 def _arith_method(self, other, op): 

6134 self, other = self._align_for_op(other) 

6135 return base.IndexOpsMixin._arith_method(self, other, op) 

6136 

6137 def _align_for_op(self, right, align_asobject: bool = False): 

6138 """align lhs and rhs Series""" 

6139 # TODO: Different from DataFrame._align_for_op, list, tuple and ndarray 

6140 # are not coerced here 

6141 # because Series has inconsistencies described in GH#13637 

6142 left = self 

6143 

6144 if isinstance(right, Series): 

6145 # avoid repeated alignment 

6146 if not left.index.equals(right.index): 

6147 if align_asobject: 

6148 if left.dtype not in (object, np.bool_) or right.dtype not in ( 

6149 object, 

6150 np.bool_, 

6151 ): 

6152 warnings.warn( 

6153 "Operation between non boolean Series with different " 

6154 "indexes will no longer return a boolean result in " 

6155 "a future version. Cast both Series to object type " 

6156 "to maintain the prior behavior.", 

6157 FutureWarning, 

6158 stacklevel=find_stack_level(), 

6159 ) 

6160 # to keep original value's dtype for bool ops 

6161 left = left.astype(object) 

6162 right = right.astype(object) 

6163 

6164 left, right = left.align(right, copy=False) 

6165 

6166 return left, right 

6167 

6168 def _binop(self, other: Series, func, level=None, fill_value=None) -> Series: 

6169 """ 

6170 Perform generic binary operation with optional fill value. 

6171 

6172 Parameters 

6173 ---------- 

6174 other : Series 

6175 func : binary operator 

6176 fill_value : float or object 

6177 Value to substitute for NA/null values. If both Series are NA in a 

6178 location, the result will be NA regardless of the passed fill value. 

6179 level : int or level name, default None 

6180 Broadcast across a level, matching Index values on the 

6181 passed MultiIndex level. 

6182 

6183 Returns 

6184 ------- 

6185 Series 

6186 """ 

6187 this = self 

6188 

6189 if not self.index.equals(other.index): 

6190 this, other = self.align(other, level=level, join="outer", copy=False) 

6191 

6192 this_vals, other_vals = ops.fill_binop(this._values, other._values, fill_value) 

6193 

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

6195 result = func(this_vals, other_vals) 

6196 

6197 name = ops.get_op_result_name(self, other) 

6198 out = this._construct_result(result, name) 

6199 return cast(Series, out) 

6200 

6201 def _construct_result( 

6202 self, result: ArrayLike | tuple[ArrayLike, ArrayLike], name: Hashable 

6203 ) -> Series | tuple[Series, Series]: 

6204 """ 

6205 Construct an appropriately-labelled Series from the result of an op. 

6206 

6207 Parameters 

6208 ---------- 

6209 result : ndarray or ExtensionArray 

6210 name : Label 

6211 

6212 Returns 

6213 ------- 

6214 Series 

6215 In the case of __divmod__ or __rdivmod__, a 2-tuple of Series. 

6216 """ 

6217 if isinstance(result, tuple): 

6218 # produced by divmod or rdivmod 

6219 

6220 res1 = self._construct_result(result[0], name=name) 

6221 res2 = self._construct_result(result[1], name=name) 

6222 

6223 # GH#33427 assertions to keep mypy happy 

6224 assert isinstance(res1, Series) 

6225 assert isinstance(res2, Series) 

6226 return (res1, res2) 

6227 

6228 # TODO: result should always be ArrayLike, but this fails for some 

6229 # JSONArray tests 

6230 dtype = getattr(result, "dtype", None) 

6231 out = self._constructor(result, index=self.index, dtype=dtype, copy=False) 

6232 out = out.__finalize__(self) 

6233 

6234 # Set the result's name after __finalize__ is called because __finalize__ 

6235 # would set it back to self.name 

6236 out.name = name 

6237 return out 

6238 

6239 def _flex_method(self, other, op, *, level=None, fill_value=None, axis: Axis = 0): 

6240 if axis is not None: 

6241 self._get_axis_number(axis) 

6242 

6243 res_name = ops.get_op_result_name(self, other) 

6244 

6245 if isinstance(other, Series): 

6246 return self._binop(other, op, level=level, fill_value=fill_value) 

6247 elif isinstance(other, (np.ndarray, list, tuple)): 

6248 if len(other) != len(self): 

6249 raise ValueError("Lengths must be equal") 

6250 other = self._constructor(other, self.index, copy=False) 

6251 result = self._binop(other, op, level=level, fill_value=fill_value) 

6252 result._name = res_name 

6253 return result 

6254 else: 

6255 if fill_value is not None: 

6256 if isna(other): 

6257 return op(self, fill_value) 

6258 self = self.fillna(fill_value) 

6259 

6260 return op(self, other) 

6261 

6262 @Appender(ops.make_flex_doc("eq", "series")) 

6263 def eq( 

6264 self, 

6265 other, 

6266 level: Level | None = None, 

6267 fill_value: float | None = None, 

6268 axis: Axis = 0, 

6269 ) -> Series: 

6270 return self._flex_method( 

6271 other, operator.eq, level=level, fill_value=fill_value, axis=axis 

6272 ) 

6273 

6274 @Appender(ops.make_flex_doc("ne", "series")) 

6275 def ne(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6276 return self._flex_method( 

6277 other, operator.ne, level=level, fill_value=fill_value, axis=axis 

6278 ) 

6279 

6280 @Appender(ops.make_flex_doc("le", "series")) 

6281 def le(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6282 return self._flex_method( 

6283 other, operator.le, level=level, fill_value=fill_value, axis=axis 

6284 ) 

6285 

6286 @Appender(ops.make_flex_doc("lt", "series")) 

6287 def lt(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6288 return self._flex_method( 

6289 other, operator.lt, level=level, fill_value=fill_value, axis=axis 

6290 ) 

6291 

6292 @Appender(ops.make_flex_doc("ge", "series")) 

6293 def ge(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6294 return self._flex_method( 

6295 other, operator.ge, level=level, fill_value=fill_value, axis=axis 

6296 ) 

6297 

6298 @Appender(ops.make_flex_doc("gt", "series")) 

6299 def gt(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6300 return self._flex_method( 

6301 other, operator.gt, level=level, fill_value=fill_value, axis=axis 

6302 ) 

6303 

6304 @Appender(ops.make_flex_doc("add", "series")) 

6305 def add(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6306 return self._flex_method( 

6307 other, operator.add, level=level, fill_value=fill_value, axis=axis 

6308 ) 

6309 

6310 @Appender(ops.make_flex_doc("radd", "series")) 

6311 def radd(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6312 return self._flex_method( 

6313 other, roperator.radd, level=level, fill_value=fill_value, axis=axis 

6314 ) 

6315 

6316 @Appender(ops.make_flex_doc("sub", "series")) 

6317 def sub(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6318 return self._flex_method( 

6319 other, operator.sub, level=level, fill_value=fill_value, axis=axis 

6320 ) 

6321 

6322 subtract = sub 

6323 

6324 @Appender(ops.make_flex_doc("rsub", "series")) 

6325 def rsub(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6326 return self._flex_method( 

6327 other, roperator.rsub, level=level, fill_value=fill_value, axis=axis 

6328 ) 

6329 

6330 @Appender(ops.make_flex_doc("mul", "series")) 

6331 def mul( 

6332 self, 

6333 other, 

6334 level: Level | None = None, 

6335 fill_value: float | None = None, 

6336 axis: Axis = 0, 

6337 ) -> Series: 

6338 return self._flex_method( 

6339 other, operator.mul, level=level, fill_value=fill_value, axis=axis 

6340 ) 

6341 

6342 multiply = mul 

6343 

6344 @Appender(ops.make_flex_doc("rmul", "series")) 

6345 def rmul(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6346 return self._flex_method( 

6347 other, roperator.rmul, level=level, fill_value=fill_value, axis=axis 

6348 ) 

6349 

6350 @Appender(ops.make_flex_doc("truediv", "series")) 

6351 def truediv(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6352 return self._flex_method( 

6353 other, operator.truediv, level=level, fill_value=fill_value, axis=axis 

6354 ) 

6355 

6356 div = truediv 

6357 divide = truediv 

6358 

6359 @Appender(ops.make_flex_doc("rtruediv", "series")) 

6360 def rtruediv(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6361 return self._flex_method( 

6362 other, roperator.rtruediv, level=level, fill_value=fill_value, axis=axis 

6363 ) 

6364 

6365 rdiv = rtruediv 

6366 

6367 @Appender(ops.make_flex_doc("floordiv", "series")) 

6368 def floordiv(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6369 return self._flex_method( 

6370 other, operator.floordiv, level=level, fill_value=fill_value, axis=axis 

6371 ) 

6372 

6373 @Appender(ops.make_flex_doc("rfloordiv", "series")) 

6374 def rfloordiv(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6375 return self._flex_method( 

6376 other, roperator.rfloordiv, level=level, fill_value=fill_value, axis=axis 

6377 ) 

6378 

6379 @Appender(ops.make_flex_doc("mod", "series")) 

6380 def mod(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6381 return self._flex_method( 

6382 other, operator.mod, level=level, fill_value=fill_value, axis=axis 

6383 ) 

6384 

6385 @Appender(ops.make_flex_doc("rmod", "series")) 

6386 def rmod(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6387 return self._flex_method( 

6388 other, roperator.rmod, level=level, fill_value=fill_value, axis=axis 

6389 ) 

6390 

6391 @Appender(ops.make_flex_doc("pow", "series")) 

6392 def pow(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6393 return self._flex_method( 

6394 other, operator.pow, level=level, fill_value=fill_value, axis=axis 

6395 ) 

6396 

6397 @Appender(ops.make_flex_doc("rpow", "series")) 

6398 def rpow(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6399 return self._flex_method( 

6400 other, roperator.rpow, level=level, fill_value=fill_value, axis=axis 

6401 ) 

6402 

6403 @Appender(ops.make_flex_doc("divmod", "series")) 

6404 def divmod(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6405 return self._flex_method( 

6406 other, divmod, level=level, fill_value=fill_value, axis=axis 

6407 ) 

6408 

6409 @Appender(ops.make_flex_doc("rdivmod", "series")) 

6410 def rdivmod(self, other, level=None, fill_value=None, axis: Axis = 0) -> Series: 

6411 return self._flex_method( 

6412 other, roperator.rdivmod, level=level, fill_value=fill_value, axis=axis 

6413 ) 

6414 

6415 # ---------------------------------------------------------------------- 

6416 # Reductions 

6417 

6418 def _reduce( 

6419 self, 

6420 op, 

6421 # error: Variable "pandas.core.series.Series.str" is not valid as a type 

6422 name: str, # type: ignore[valid-type] 

6423 *, 

6424 axis: Axis = 0, 

6425 skipna: bool = True, 

6426 numeric_only: bool = False, 

6427 filter_type=None, 

6428 **kwds, 

6429 ): 

6430 """ 

6431 Perform a reduction operation. 

6432 

6433 If we have an ndarray as a value, then simply perform the operation, 

6434 otherwise delegate to the object. 

6435 """ 

6436 delegate = self._values 

6437 

6438 if axis is not None: 

6439 self._get_axis_number(axis) 

6440 

6441 if isinstance(delegate, ExtensionArray): 

6442 # dispatch to ExtensionArray interface 

6443 return delegate._reduce(name, skipna=skipna, **kwds) 

6444 

6445 else: 

6446 # dispatch to numpy arrays 

6447 if numeric_only and self.dtype.kind not in "iufcb": 

6448 # i.e. not is_numeric_dtype(self.dtype) 

6449 kwd_name = "numeric_only" 

6450 if name in ["any", "all"]: 

6451 kwd_name = "bool_only" 

6452 # GH#47500 - change to TypeError to match other methods 

6453 raise TypeError( 

6454 f"Series.{name} does not allow {kwd_name}={numeric_only} " 

6455 "with non-numeric dtypes." 

6456 ) 

6457 return op(delegate, skipna=skipna, **kwds) 

6458 

6459 @Appender(make_doc("any", ndim=1)) 

6460 # error: Signature of "any" incompatible with supertype "NDFrame" 

6461 def any( # type: ignore[override] 

6462 self, 

6463 *, 

6464 axis: Axis = 0, 

6465 bool_only: bool = False, 

6466 skipna: bool = True, 

6467 **kwargs, 

6468 ) -> bool: 

6469 nv.validate_logical_func((), kwargs, fname="any") 

6470 validate_bool_kwarg(skipna, "skipna", none_allowed=False) 

6471 return self._reduce( 

6472 nanops.nanany, 

6473 name="any", 

6474 axis=axis, 

6475 numeric_only=bool_only, 

6476 skipna=skipna, 

6477 filter_type="bool", 

6478 ) 

6479 

6480 @Appender(make_doc("all", ndim=1)) 

6481 def all( 

6482 self, 

6483 axis: Axis = 0, 

6484 bool_only: bool = False, 

6485 skipna: bool = True, 

6486 **kwargs, 

6487 ) -> bool: 

6488 nv.validate_logical_func((), kwargs, fname="all") 

6489 validate_bool_kwarg(skipna, "skipna", none_allowed=False) 

6490 return self._reduce( 

6491 nanops.nanall, 

6492 name="all", 

6493 axis=axis, 

6494 numeric_only=bool_only, 

6495 skipna=skipna, 

6496 filter_type="bool", 

6497 ) 

6498 

6499 @doc(make_doc("min", ndim=1)) 

6500 def min( 

6501 self, 

6502 axis: Axis | None = 0, 

6503 skipna: bool = True, 

6504 numeric_only: bool = False, 

6505 **kwargs, 

6506 ): 

6507 return NDFrame.min(self, axis, skipna, numeric_only, **kwargs) 

6508 

6509 @doc(make_doc("max", ndim=1)) 

6510 def max( 

6511 self, 

6512 axis: Axis | None = 0, 

6513 skipna: bool = True, 

6514 numeric_only: bool = False, 

6515 **kwargs, 

6516 ): 

6517 return NDFrame.max(self, axis, skipna, numeric_only, **kwargs) 

6518 

6519 @doc(make_doc("sum", ndim=1)) 

6520 def sum( 

6521 self, 

6522 axis: Axis | None = None, 

6523 skipna: bool = True, 

6524 numeric_only: bool = False, 

6525 min_count: int = 0, 

6526 **kwargs, 

6527 ): 

6528 return NDFrame.sum(self, axis, skipna, numeric_only, min_count, **kwargs) 

6529 

6530 @doc(make_doc("prod", ndim=1)) 

6531 def prod( 

6532 self, 

6533 axis: Axis | None = None, 

6534 skipna: bool = True, 

6535 numeric_only: bool = False, 

6536 min_count: int = 0, 

6537 **kwargs, 

6538 ): 

6539 return NDFrame.prod(self, axis, skipna, numeric_only, min_count, **kwargs) 

6540 

6541 @doc(make_doc("mean", ndim=1)) 

6542 def mean( 

6543 self, 

6544 axis: Axis | None = 0, 

6545 skipna: bool = True, 

6546 numeric_only: bool = False, 

6547 **kwargs, 

6548 ): 

6549 return NDFrame.mean(self, axis, skipna, numeric_only, **kwargs) 

6550 

6551 @doc(make_doc("median", ndim=1)) 

6552 def median( 

6553 self, 

6554 axis: Axis | None = 0, 

6555 skipna: bool = True, 

6556 numeric_only: bool = False, 

6557 **kwargs, 

6558 ): 

6559 return NDFrame.median(self, axis, skipna, numeric_only, **kwargs) 

6560 

6561 @doc(make_doc("sem", ndim=1)) 

6562 def sem( 

6563 self, 

6564 axis: Axis | None = None, 

6565 skipna: bool = True, 

6566 ddof: int = 1, 

6567 numeric_only: bool = False, 

6568 **kwargs, 

6569 ): 

6570 return NDFrame.sem(self, axis, skipna, ddof, numeric_only, **kwargs) 

6571 

6572 @doc(make_doc("var", ndim=1)) 

6573 def var( 

6574 self, 

6575 axis: Axis | None = None, 

6576 skipna: bool = True, 

6577 ddof: int = 1, 

6578 numeric_only: bool = False, 

6579 **kwargs, 

6580 ): 

6581 return NDFrame.var(self, axis, skipna, ddof, numeric_only, **kwargs) 

6582 

6583 @doc(make_doc("std", ndim=1)) 

6584 def std( 

6585 self, 

6586 axis: Axis | None = None, 

6587 skipna: bool = True, 

6588 ddof: int = 1, 

6589 numeric_only: bool = False, 

6590 **kwargs, 

6591 ): 

6592 return NDFrame.std(self, axis, skipna, ddof, numeric_only, **kwargs) 

6593 

6594 @doc(make_doc("skew", ndim=1)) 

6595 def skew( 

6596 self, 

6597 axis: Axis | None = 0, 

6598 skipna: bool = True, 

6599 numeric_only: bool = False, 

6600 **kwargs, 

6601 ): 

6602 return NDFrame.skew(self, axis, skipna, numeric_only, **kwargs) 

6603 

6604 @doc(make_doc("kurt", ndim=1)) 

6605 def kurt( 

6606 self, 

6607 axis: Axis | None = 0, 

6608 skipna: bool = True, 

6609 numeric_only: bool = False, 

6610 **kwargs, 

6611 ): 

6612 return NDFrame.kurt(self, axis, skipna, numeric_only, **kwargs) 

6613 

6614 kurtosis = kurt 

6615 product = prod 

6616 

6617 @doc(make_doc("cummin", ndim=1)) 

6618 def cummin(self, axis: Axis | None = None, skipna: bool = True, *args, **kwargs): 

6619 return NDFrame.cummin(self, axis, skipna, *args, **kwargs) 

6620 

6621 @doc(make_doc("cummax", ndim=1)) 

6622 def cummax(self, axis: Axis | None = None, skipna: bool = True, *args, **kwargs): 

6623 return NDFrame.cummax(self, axis, skipna, *args, **kwargs) 

6624 

6625 @doc(make_doc("cumsum", ndim=1)) 

6626 def cumsum(self, axis: Axis | None = None, skipna: bool = True, *args, **kwargs): 

6627 return NDFrame.cumsum(self, axis, skipna, *args, **kwargs) 

6628 

6629 @doc(make_doc("cumprod", 1)) 

6630 def cumprod(self, axis: Axis | None = None, skipna: bool = True, *args, **kwargs): 

6631 return NDFrame.cumprod(self, axis, skipna, *args, **kwargs)