docstrings.py 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. """
  2. Templating for ops docstrings
  3. """
  4. from __future__ import annotations
  5. def make_flex_doc(op_name: str, typ: str) -> str:
  6. """
  7. Make the appropriate substitutions for the given operation and class-typ
  8. into either _flex_doc_SERIES or _flex_doc_FRAME to return the docstring
  9. to attach to a generated method.
  10. Parameters
  11. ----------
  12. op_name : str {'__add__', '__sub__', ... '__eq__', '__ne__', ...}
  13. typ : str {series, 'dataframe']}
  14. Returns
  15. -------
  16. doc : str
  17. """
  18. op_name = op_name.replace("__", "")
  19. op_desc = _op_descriptions[op_name]
  20. op_desc_op = op_desc["op"]
  21. assert op_desc_op is not None # for mypy
  22. if op_name.startswith("r"):
  23. equiv = f"other {op_desc_op} {typ}"
  24. elif op_name == "divmod":
  25. equiv = f"{op_name}({typ}, other)"
  26. else:
  27. equiv = f"{typ} {op_desc_op} other"
  28. if typ == "series":
  29. base_doc = _flex_doc_SERIES
  30. if op_desc["reverse"]:
  31. base_doc += _see_also_reverse_SERIES.format(
  32. reverse=op_desc["reverse"], see_also_desc=op_desc["see_also_desc"]
  33. )
  34. doc_no_examples = base_doc.format(
  35. desc=op_desc["desc"],
  36. op_name=op_name,
  37. equiv=equiv,
  38. series_returns=op_desc["series_returns"],
  39. )
  40. ser_example = op_desc["series_examples"]
  41. if ser_example:
  42. doc = doc_no_examples + ser_example
  43. else:
  44. doc = doc_no_examples
  45. elif typ == "dataframe":
  46. base_doc = _flex_doc_FRAME
  47. doc = base_doc.format(
  48. desc=op_desc["desc"],
  49. op_name=op_name,
  50. equiv=equiv,
  51. reverse=op_desc["reverse"],
  52. )
  53. else:
  54. raise AssertionError("Invalid typ argument.")
  55. return doc
  56. _common_examples_algebra_SERIES = """
  57. Examples
  58. --------
  59. >>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd'])
  60. >>> a
  61. a 1.0
  62. b 1.0
  63. c 1.0
  64. d NaN
  65. dtype: float64
  66. >>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e'])
  67. >>> b
  68. a 1.0
  69. b NaN
  70. d 1.0
  71. e NaN
  72. dtype: float64"""
  73. _common_examples_comparison_SERIES = """
  74. Examples
  75. --------
  76. >>> a = pd.Series([1, 1, 1, np.nan, 1], index=['a', 'b', 'c', 'd', 'e'])
  77. >>> a
  78. a 1.0
  79. b 1.0
  80. c 1.0
  81. d NaN
  82. e 1.0
  83. dtype: float64
  84. >>> b = pd.Series([0, 1, 2, np.nan, 1], index=['a', 'b', 'c', 'd', 'f'])
  85. >>> b
  86. a 0.0
  87. b 1.0
  88. c 2.0
  89. d NaN
  90. f 1.0
  91. dtype: float64"""
  92. _add_example_SERIES = (
  93. _common_examples_algebra_SERIES
  94. + """
  95. >>> a.add(b, fill_value=0)
  96. a 2.0
  97. b 1.0
  98. c 1.0
  99. d 1.0
  100. e NaN
  101. dtype: float64
  102. """
  103. )
  104. _sub_example_SERIES = (
  105. _common_examples_algebra_SERIES
  106. + """
  107. >>> a.subtract(b, fill_value=0)
  108. a 0.0
  109. b 1.0
  110. c 1.0
  111. d -1.0
  112. e NaN
  113. dtype: float64
  114. """
  115. )
  116. _mul_example_SERIES = (
  117. _common_examples_algebra_SERIES
  118. + """
  119. >>> a.multiply(b, fill_value=0)
  120. a 1.0
  121. b 0.0
  122. c 0.0
  123. d 0.0
  124. e NaN
  125. dtype: float64
  126. """
  127. )
  128. _div_example_SERIES = (
  129. _common_examples_algebra_SERIES
  130. + """
  131. >>> a.divide(b, fill_value=0)
  132. a 1.0
  133. b inf
  134. c inf
  135. d 0.0
  136. e NaN
  137. dtype: float64
  138. """
  139. )
  140. _floordiv_example_SERIES = (
  141. _common_examples_algebra_SERIES
  142. + """
  143. >>> a.floordiv(b, fill_value=0)
  144. a 1.0
  145. b inf
  146. c inf
  147. d 0.0
  148. e NaN
  149. dtype: float64
  150. """
  151. )
  152. _divmod_example_SERIES = (
  153. _common_examples_algebra_SERIES
  154. + """
  155. >>> a.divmod(b, fill_value=0)
  156. (a 1.0
  157. b NaN
  158. c NaN
  159. d 0.0
  160. e NaN
  161. dtype: float64,
  162. a 0.0
  163. b NaN
  164. c NaN
  165. d 0.0
  166. e NaN
  167. dtype: float64)
  168. """
  169. )
  170. _mod_example_SERIES = (
  171. _common_examples_algebra_SERIES
  172. + """
  173. >>> a.mod(b, fill_value=0)
  174. a 0.0
  175. b NaN
  176. c NaN
  177. d 0.0
  178. e NaN
  179. dtype: float64
  180. """
  181. )
  182. _pow_example_SERIES = (
  183. _common_examples_algebra_SERIES
  184. + """
  185. >>> a.pow(b, fill_value=0)
  186. a 1.0
  187. b 1.0
  188. c 1.0
  189. d 0.0
  190. e NaN
  191. dtype: float64
  192. """
  193. )
  194. _ne_example_SERIES = (
  195. _common_examples_algebra_SERIES
  196. + """
  197. >>> a.ne(b, fill_value=0)
  198. a False
  199. b True
  200. c True
  201. d True
  202. e True
  203. dtype: bool
  204. """
  205. )
  206. _eq_example_SERIES = (
  207. _common_examples_algebra_SERIES
  208. + """
  209. >>> a.eq(b, fill_value=0)
  210. a True
  211. b False
  212. c False
  213. d False
  214. e False
  215. dtype: bool
  216. """
  217. )
  218. _lt_example_SERIES = (
  219. _common_examples_comparison_SERIES
  220. + """
  221. >>> a.lt(b, fill_value=0)
  222. a False
  223. b False
  224. c True
  225. d False
  226. e False
  227. f True
  228. dtype: bool
  229. """
  230. )
  231. _le_example_SERIES = (
  232. _common_examples_comparison_SERIES
  233. + """
  234. >>> a.le(b, fill_value=0)
  235. a False
  236. b True
  237. c True
  238. d False
  239. e False
  240. f True
  241. dtype: bool
  242. """
  243. )
  244. _gt_example_SERIES = (
  245. _common_examples_comparison_SERIES
  246. + """
  247. >>> a.gt(b, fill_value=0)
  248. a True
  249. b False
  250. c False
  251. d False
  252. e True
  253. f False
  254. dtype: bool
  255. """
  256. )
  257. _ge_example_SERIES = (
  258. _common_examples_comparison_SERIES
  259. + """
  260. >>> a.ge(b, fill_value=0)
  261. a True
  262. b True
  263. c False
  264. d False
  265. e True
  266. f False
  267. dtype: bool
  268. """
  269. )
  270. _returns_series = """Series\n The result of the operation."""
  271. _returns_tuple = """2-Tuple of Series\n The result of the operation."""
  272. _op_descriptions: dict[str, dict[str, str | None]] = {
  273. # Arithmetic Operators
  274. "add": {
  275. "op": "+",
  276. "desc": "Addition",
  277. "reverse": "radd",
  278. "series_examples": _add_example_SERIES,
  279. "series_returns": _returns_series,
  280. },
  281. "sub": {
  282. "op": "-",
  283. "desc": "Subtraction",
  284. "reverse": "rsub",
  285. "series_examples": _sub_example_SERIES,
  286. "series_returns": _returns_series,
  287. },
  288. "mul": {
  289. "op": "*",
  290. "desc": "Multiplication",
  291. "reverse": "rmul",
  292. "series_examples": _mul_example_SERIES,
  293. "series_returns": _returns_series,
  294. "df_examples": None,
  295. },
  296. "mod": {
  297. "op": "%",
  298. "desc": "Modulo",
  299. "reverse": "rmod",
  300. "series_examples": _mod_example_SERIES,
  301. "series_returns": _returns_series,
  302. },
  303. "pow": {
  304. "op": "**",
  305. "desc": "Exponential power",
  306. "reverse": "rpow",
  307. "series_examples": _pow_example_SERIES,
  308. "series_returns": _returns_series,
  309. "df_examples": None,
  310. },
  311. "truediv": {
  312. "op": "/",
  313. "desc": "Floating division",
  314. "reverse": "rtruediv",
  315. "series_examples": _div_example_SERIES,
  316. "series_returns": _returns_series,
  317. "df_examples": None,
  318. },
  319. "floordiv": {
  320. "op": "//",
  321. "desc": "Integer division",
  322. "reverse": "rfloordiv",
  323. "series_examples": _floordiv_example_SERIES,
  324. "series_returns": _returns_series,
  325. "df_examples": None,
  326. },
  327. "divmod": {
  328. "op": "divmod",
  329. "desc": "Integer division and modulo",
  330. "reverse": "rdivmod",
  331. "series_examples": _divmod_example_SERIES,
  332. "series_returns": _returns_tuple,
  333. "df_examples": None,
  334. },
  335. # Comparison Operators
  336. "eq": {
  337. "op": "==",
  338. "desc": "Equal to",
  339. "reverse": None,
  340. "series_examples": _eq_example_SERIES,
  341. "series_returns": _returns_series,
  342. },
  343. "ne": {
  344. "op": "!=",
  345. "desc": "Not equal to",
  346. "reverse": None,
  347. "series_examples": _ne_example_SERIES,
  348. "series_returns": _returns_series,
  349. },
  350. "lt": {
  351. "op": "<",
  352. "desc": "Less than",
  353. "reverse": None,
  354. "series_examples": _lt_example_SERIES,
  355. "series_returns": _returns_series,
  356. },
  357. "le": {
  358. "op": "<=",
  359. "desc": "Less than or equal to",
  360. "reverse": None,
  361. "series_examples": _le_example_SERIES,
  362. "series_returns": _returns_series,
  363. },
  364. "gt": {
  365. "op": ">",
  366. "desc": "Greater than",
  367. "reverse": None,
  368. "series_examples": _gt_example_SERIES,
  369. "series_returns": _returns_series,
  370. },
  371. "ge": {
  372. "op": ">=",
  373. "desc": "Greater than or equal to",
  374. "reverse": None,
  375. "series_examples": _ge_example_SERIES,
  376. "series_returns": _returns_series,
  377. },
  378. }
  379. _py_num_ref = """see
  380. `Python documentation
  381. <https://docs.python.org/3/reference/datamodel.html#emulating-numeric-types>`_
  382. for more details"""
  383. _op_names = list(_op_descriptions.keys())
  384. for key in _op_names:
  385. reverse_op = _op_descriptions[key]["reverse"]
  386. if reverse_op is not None:
  387. _op_descriptions[reverse_op] = _op_descriptions[key].copy()
  388. _op_descriptions[reverse_op]["reverse"] = key
  389. _op_descriptions[key][
  390. "see_also_desc"
  391. ] = f"Reverse of the {_op_descriptions[key]['desc']} operator, {_py_num_ref}"
  392. _op_descriptions[reverse_op][
  393. "see_also_desc"
  394. ] = f"Element-wise {_op_descriptions[key]['desc']}, {_py_num_ref}"
  395. _flex_doc_SERIES = """
  396. Return {desc} of series and other, element-wise (binary operator `{op_name}`).
  397. Equivalent to ``{equiv}``, but with support to substitute a fill_value for
  398. missing data in either one of the inputs.
  399. Parameters
  400. ----------
  401. other : Series or scalar value
  402. level : int or name
  403. Broadcast across a level, matching Index values on the
  404. passed MultiIndex level.
  405. fill_value : None or float value, default None (NaN)
  406. Fill existing missing (NaN) values, and any new element needed for
  407. successful Series alignment, with this value before computation.
  408. If data in both corresponding Series locations is missing
  409. the result of filling (at that location) will be missing.
  410. axis : {{0 or 'index'}}
  411. Unused. Parameter needed for compatibility with DataFrame.
  412. Returns
  413. -------
  414. {series_returns}
  415. """
  416. _see_also_reverse_SERIES = """
  417. See Also
  418. --------
  419. Series.{reverse} : {see_also_desc}.
  420. """
  421. _flex_doc_FRAME = """
  422. Get {desc} of dataframe and other, element-wise (binary operator `{op_name}`).
  423. Equivalent to ``{equiv}``, but with support to substitute a fill_value
  424. for missing data in one of the inputs. With reverse version, `{reverse}`.
  425. Among flexible wrappers (`add`, `sub`, `mul`, `div`, `mod`, `pow`) to
  426. arithmetic operators: `+`, `-`, `*`, `/`, `//`, `%`, `**`.
  427. Parameters
  428. ----------
  429. other : scalar, sequence, Series, dict or DataFrame
  430. Any single or multiple element data structure, or list-like object.
  431. axis : {{0 or 'index', 1 or 'columns'}}
  432. Whether to compare by the index (0 or 'index') or columns.
  433. (1 or 'columns'). For Series input, axis to match Series index on.
  434. level : int or label
  435. Broadcast across a level, matching Index values on the
  436. passed MultiIndex level.
  437. fill_value : float or None, default None
  438. Fill existing missing (NaN) values, and any new element needed for
  439. successful DataFrame alignment, with this value before computation.
  440. If data in both corresponding DataFrame locations is missing
  441. the result will be missing.
  442. Returns
  443. -------
  444. DataFrame
  445. Result of the arithmetic operation.
  446. See Also
  447. --------
  448. DataFrame.add : Add DataFrames.
  449. DataFrame.sub : Subtract DataFrames.
  450. DataFrame.mul : Multiply DataFrames.
  451. DataFrame.div : Divide DataFrames (float division).
  452. DataFrame.truediv : Divide DataFrames (float division).
  453. DataFrame.floordiv : Divide DataFrames (integer division).
  454. DataFrame.mod : Calculate modulo (remainder after division).
  455. DataFrame.pow : Calculate exponential power.
  456. Notes
  457. -----
  458. Mismatched indices will be unioned together.
  459. Examples
  460. --------
  461. >>> df = pd.DataFrame({{'angles': [0, 3, 4],
  462. ... 'degrees': [360, 180, 360]}},
  463. ... index=['circle', 'triangle', 'rectangle'])
  464. >>> df
  465. angles degrees
  466. circle 0 360
  467. triangle 3 180
  468. rectangle 4 360
  469. Add a scalar with operator version which return the same
  470. results.
  471. >>> df + 1
  472. angles degrees
  473. circle 1 361
  474. triangle 4 181
  475. rectangle 5 361
  476. >>> df.add(1)
  477. angles degrees
  478. circle 1 361
  479. triangle 4 181
  480. rectangle 5 361
  481. Divide by constant with reverse version.
  482. >>> df.div(10)
  483. angles degrees
  484. circle 0.0 36.0
  485. triangle 0.3 18.0
  486. rectangle 0.4 36.0
  487. >>> df.rdiv(10)
  488. angles degrees
  489. circle inf 0.027778
  490. triangle 3.333333 0.055556
  491. rectangle 2.500000 0.027778
  492. Subtract a list and Series by axis with operator version.
  493. >>> df - [1, 2]
  494. angles degrees
  495. circle -1 358
  496. triangle 2 178
  497. rectangle 3 358
  498. >>> df.sub([1, 2], axis='columns')
  499. angles degrees
  500. circle -1 358
  501. triangle 2 178
  502. rectangle 3 358
  503. >>> df.sub(pd.Series([1, 1, 1], index=['circle', 'triangle', 'rectangle']),
  504. ... axis='index')
  505. angles degrees
  506. circle -1 359
  507. triangle 2 179
  508. rectangle 3 359
  509. Multiply a dictionary by axis.
  510. >>> df.mul({{'angles': 0, 'degrees': 2}})
  511. angles degrees
  512. circle 0 720
  513. triangle 0 360
  514. rectangle 0 720
  515. >>> df.mul({{'circle': 0, 'triangle': 2, 'rectangle': 3}}, axis='index')
  516. angles degrees
  517. circle 0 0
  518. triangle 6 360
  519. rectangle 12 1080
  520. Multiply a DataFrame of different shape with operator version.
  521. >>> other = pd.DataFrame({{'angles': [0, 3, 4]}},
  522. ... index=['circle', 'triangle', 'rectangle'])
  523. >>> other
  524. angles
  525. circle 0
  526. triangle 3
  527. rectangle 4
  528. >>> df * other
  529. angles degrees
  530. circle 0 NaN
  531. triangle 9 NaN
  532. rectangle 16 NaN
  533. >>> df.mul(other, fill_value=0)
  534. angles degrees
  535. circle 0 0.0
  536. triangle 9 0.0
  537. rectangle 16 0.0
  538. Divide by a MultiIndex by level.
  539. >>> df_multindex = pd.DataFrame({{'angles': [0, 3, 4, 4, 5, 6],
  540. ... 'degrees': [360, 180, 360, 360, 540, 720]}},
  541. ... index=[['A', 'A', 'A', 'B', 'B', 'B'],
  542. ... ['circle', 'triangle', 'rectangle',
  543. ... 'square', 'pentagon', 'hexagon']])
  544. >>> df_multindex
  545. angles degrees
  546. A circle 0 360
  547. triangle 3 180
  548. rectangle 4 360
  549. B square 4 360
  550. pentagon 5 540
  551. hexagon 6 720
  552. >>> df.div(df_multindex, level=1, fill_value=0)
  553. angles degrees
  554. A circle NaN 1.0
  555. triangle 1.0 1.0
  556. rectangle 1.0 1.0
  557. B square 0.0 0.0
  558. pentagon 0.0 0.0
  559. hexagon 0.0 0.0
  560. """
  561. _flex_comp_doc_FRAME = """
  562. Get {desc} of dataframe and other, element-wise (binary operator `{op_name}`).
  563. Among flexible wrappers (`eq`, `ne`, `le`, `lt`, `ge`, `gt`) to comparison
  564. operators.
  565. Equivalent to `==`, `!=`, `<=`, `<`, `>=`, `>` with support to choose axis
  566. (rows or columns) and level for comparison.
  567. Parameters
  568. ----------
  569. other : scalar, sequence, Series, or DataFrame
  570. Any single or multiple element data structure, or list-like object.
  571. axis : {{0 or 'index', 1 or 'columns'}}, default 'columns'
  572. Whether to compare by the index (0 or 'index') or columns
  573. (1 or 'columns').
  574. level : int or label
  575. Broadcast across a level, matching Index values on the passed
  576. MultiIndex level.
  577. Returns
  578. -------
  579. DataFrame of bool
  580. Result of the comparison.
  581. See Also
  582. --------
  583. DataFrame.eq : Compare DataFrames for equality elementwise.
  584. DataFrame.ne : Compare DataFrames for inequality elementwise.
  585. DataFrame.le : Compare DataFrames for less than inequality
  586. or equality elementwise.
  587. DataFrame.lt : Compare DataFrames for strictly less than
  588. inequality elementwise.
  589. DataFrame.ge : Compare DataFrames for greater than inequality
  590. or equality elementwise.
  591. DataFrame.gt : Compare DataFrames for strictly greater than
  592. inequality elementwise.
  593. Notes
  594. -----
  595. Mismatched indices will be unioned together.
  596. `NaN` values are considered different (i.e. `NaN` != `NaN`).
  597. Examples
  598. --------
  599. >>> df = pd.DataFrame({{'cost': [250, 150, 100],
  600. ... 'revenue': [100, 250, 300]}},
  601. ... index=['A', 'B', 'C'])
  602. >>> df
  603. cost revenue
  604. A 250 100
  605. B 150 250
  606. C 100 300
  607. Comparison with a scalar, using either the operator or method:
  608. >>> df == 100
  609. cost revenue
  610. A False True
  611. B False False
  612. C True False
  613. >>> df.eq(100)
  614. cost revenue
  615. A False True
  616. B False False
  617. C True False
  618. When `other` is a :class:`Series`, the columns of a DataFrame are aligned
  619. with the index of `other` and broadcast:
  620. >>> df != pd.Series([100, 250], index=["cost", "revenue"])
  621. cost revenue
  622. A True True
  623. B True False
  624. C False True
  625. Use the method to control the broadcast axis:
  626. >>> df.ne(pd.Series([100, 300], index=["A", "D"]), axis='index')
  627. cost revenue
  628. A True False
  629. B True True
  630. C True True
  631. D True True
  632. When comparing to an arbitrary sequence, the number of columns must
  633. match the number elements in `other`:
  634. >>> df == [250, 100]
  635. cost revenue
  636. A True True
  637. B False False
  638. C False False
  639. Use the method to control the axis:
  640. >>> df.eq([250, 250, 100], axis='index')
  641. cost revenue
  642. A True False
  643. B False True
  644. C True False
  645. Compare to a DataFrame of different shape.
  646. >>> other = pd.DataFrame({{'revenue': [300, 250, 100, 150]}},
  647. ... index=['A', 'B', 'C', 'D'])
  648. >>> other
  649. revenue
  650. A 300
  651. B 250
  652. C 100
  653. D 150
  654. >>> df.gt(other)
  655. cost revenue
  656. A False False
  657. B False False
  658. C False True
  659. D False False
  660. Compare to a MultiIndex by level.
  661. >>> df_multindex = pd.DataFrame({{'cost': [250, 150, 100, 150, 300, 220],
  662. ... 'revenue': [100, 250, 300, 200, 175, 225]}},
  663. ... index=[['Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2'],
  664. ... ['A', 'B', 'C', 'A', 'B', 'C']])
  665. >>> df_multindex
  666. cost revenue
  667. Q1 A 250 100
  668. B 150 250
  669. C 100 300
  670. Q2 A 150 200
  671. B 300 175
  672. C 220 225
  673. >>> df.le(df_multindex, level=1)
  674. cost revenue
  675. Q1 A True True
  676. B True True
  677. C True True
  678. Q2 A False True
  679. B True False
  680. C True False
  681. """