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)