Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2Templating for ops docstrings 

3""" 

4from typing import Dict, Optional 

5 

6 

7def _make_flex_doc(op_name, typ): 

8 """ 

9 Make the appropriate substitutions for the given operation and class-typ 

10 into either _flex_doc_SERIES or _flex_doc_FRAME to return the docstring 

11 to attach to a generated method. 

12 

13 Parameters 

14 ---------- 

15 op_name : str {'__add__', '__sub__', ... '__eq__', '__ne__', ...} 

16 typ : str {series, 'dataframe']} 

17 

18 Returns 

19 ------- 

20 doc : str 

21 """ 

22 op_name = op_name.replace("__", "") 

23 op_desc = _op_descriptions[op_name] 

24 

25 if op_name.startswith("r"): 

26 equiv = "other " + op_desc["op"] + " " + typ 

27 else: 

28 equiv = typ + " " + op_desc["op"] + " other" 

29 

30 if typ == "series": 

31 base_doc = _flex_doc_SERIES 

32 doc_no_examples = base_doc.format( 

33 desc=op_desc["desc"], 

34 op_name=op_name, 

35 equiv=equiv, 

36 reverse=op_desc["reverse"], 

37 ) 

38 if op_desc["series_examples"]: 

39 doc = doc_no_examples + op_desc["series_examples"] 

40 else: 

41 doc = doc_no_examples 

42 elif typ == "dataframe": 

43 base_doc = _flex_doc_FRAME 

44 doc = base_doc.format( 

45 desc=op_desc["desc"], 

46 op_name=op_name, 

47 equiv=equiv, 

48 reverse=op_desc["reverse"], 

49 ) 

50 else: 

51 raise AssertionError("Invalid typ argument.") 

52 return doc 

53 

54 

55_add_example_SERIES = """ 

56Examples 

57-------- 

58>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

59>>> a 

60a 1.0 

61b 1.0 

62c 1.0 

63d NaN 

64dtype: float64 

65>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

66>>> b 

67a 1.0 

68b NaN 

69d 1.0 

70e NaN 

71dtype: float64 

72>>> a.add(b, fill_value=0) 

73a 2.0 

74b 1.0 

75c 1.0 

76d 1.0 

77e NaN 

78dtype: float64 

79""" 

80 

81_sub_example_SERIES = """ 

82Examples 

83-------- 

84>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

85>>> a 

86a 1.0 

87b 1.0 

88c 1.0 

89d NaN 

90dtype: float64 

91>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

92>>> b 

93a 1.0 

94b NaN 

95d 1.0 

96e NaN 

97dtype: float64 

98>>> a.subtract(b, fill_value=0) 

99a 0.0 

100b 1.0 

101c 1.0 

102d -1.0 

103e NaN 

104dtype: float64 

105""" 

106 

107_mul_example_SERIES = """ 

108Examples 

109-------- 

110>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

111>>> a 

112a 1.0 

113b 1.0 

114c 1.0 

115d NaN 

116dtype: float64 

117>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

118>>> b 

119a 1.0 

120b NaN 

121d 1.0 

122e NaN 

123dtype: float64 

124>>> a.multiply(b, fill_value=0) 

125a 1.0 

126b 0.0 

127c 0.0 

128d 0.0 

129e NaN 

130dtype: float64 

131""" 

132 

133_div_example_SERIES = """ 

134Examples 

135-------- 

136>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

137>>> a 

138a 1.0 

139b 1.0 

140c 1.0 

141d NaN 

142dtype: float64 

143>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

144>>> b 

145a 1.0 

146b NaN 

147d 1.0 

148e NaN 

149dtype: float64 

150>>> a.divide(b, fill_value=0) 

151a 1.0 

152b inf 

153c inf 

154d 0.0 

155e NaN 

156dtype: float64 

157""" 

158 

159_floordiv_example_SERIES = """ 

160Examples 

161-------- 

162>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

163>>> a 

164a 1.0 

165b 1.0 

166c 1.0 

167d NaN 

168dtype: float64 

169>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

170>>> b 

171a 1.0 

172b NaN 

173d 1.0 

174e NaN 

175dtype: float64 

176>>> a.floordiv(b, fill_value=0) 

177a 1.0 

178b NaN 

179c NaN 

180d 0.0 

181e NaN 

182dtype: float64 

183""" 

184 

185_mod_example_SERIES = """ 

186Examples 

187-------- 

188>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

189>>> a 

190a 1.0 

191b 1.0 

192c 1.0 

193d NaN 

194dtype: float64 

195>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

196>>> b 

197a 1.0 

198b NaN 

199d 1.0 

200e NaN 

201dtype: float64 

202>>> a.mod(b, fill_value=0) 

203a 0.0 

204b NaN 

205c NaN 

206d 0.0 

207e NaN 

208dtype: float64 

209""" 

210_pow_example_SERIES = """ 

211Examples 

212-------- 

213>>> a = pd.Series([1, 1, 1, np.nan], index=['a', 'b', 'c', 'd']) 

214>>> a 

215a 1.0 

216b 1.0 

217c 1.0 

218d NaN 

219dtype: float64 

220>>> b = pd.Series([1, np.nan, 1, np.nan], index=['a', 'b', 'd', 'e']) 

221>>> b 

222a 1.0 

223b NaN 

224d 1.0 

225e NaN 

226dtype: float64 

227>>> a.pow(b, fill_value=0) 

228a 1.0 

229b 1.0 

230c 1.0 

231d 0.0 

232e NaN 

233dtype: float64 

234""" 

235 

236_op_descriptions: Dict[str, Dict[str, Optional[str]]] = { 

237 # Arithmetic Operators 

238 "add": { 

239 "op": "+", 

240 "desc": "Addition", 

241 "reverse": "radd", 

242 "series_examples": _add_example_SERIES, 

243 }, 

244 "sub": { 

245 "op": "-", 

246 "desc": "Subtraction", 

247 "reverse": "rsub", 

248 "series_examples": _sub_example_SERIES, 

249 }, 

250 "mul": { 

251 "op": "*", 

252 "desc": "Multiplication", 

253 "reverse": "rmul", 

254 "series_examples": _mul_example_SERIES, 

255 "df_examples": None, 

256 }, 

257 "mod": { 

258 "op": "%", 

259 "desc": "Modulo", 

260 "reverse": "rmod", 

261 "series_examples": _mod_example_SERIES, 

262 }, 

263 "pow": { 

264 "op": "**", 

265 "desc": "Exponential power", 

266 "reverse": "rpow", 

267 "series_examples": _pow_example_SERIES, 

268 "df_examples": None, 

269 }, 

270 "truediv": { 

271 "op": "/", 

272 "desc": "Floating division", 

273 "reverse": "rtruediv", 

274 "series_examples": _div_example_SERIES, 

275 "df_examples": None, 

276 }, 

277 "floordiv": { 

278 "op": "//", 

279 "desc": "Integer division", 

280 "reverse": "rfloordiv", 

281 "series_examples": _floordiv_example_SERIES, 

282 "df_examples": None, 

283 }, 

284 "divmod": { 

285 "op": "divmod", 

286 "desc": "Integer division and modulo", 

287 "reverse": "rdivmod", 

288 "series_examples": None, 

289 "df_examples": None, 

290 }, 

291 # Comparison Operators 

292 "eq": {"op": "==", "desc": "Equal to", "reverse": None, "series_examples": None}, 

293 "ne": { 

294 "op": "!=", 

295 "desc": "Not equal to", 

296 "reverse": None, 

297 "series_examples": None, 

298 }, 

299 "lt": {"op": "<", "desc": "Less than", "reverse": None, "series_examples": None}, 

300 "le": { 

301 "op": "<=", 

302 "desc": "Less than or equal to", 

303 "reverse": None, 

304 "series_examples": None, 

305 }, 

306 "gt": {"op": ">", "desc": "Greater than", "reverse": None, "series_examples": None}, 

307 "ge": { 

308 "op": ">=", 

309 "desc": "Greater than or equal to", 

310 "reverse": None, 

311 "series_examples": None, 

312 }, 

313} 

314 

315_op_names = list(_op_descriptions.keys()) 

316for key in _op_names: 

317 reverse_op = _op_descriptions[key]["reverse"] 

318 if reverse_op is not None: 

319 _op_descriptions[reverse_op] = _op_descriptions[key].copy() 

320 _op_descriptions[reverse_op]["reverse"] = key 

321 

322_flex_doc_SERIES = """ 

323Return {desc} of series and other, element-wise (binary operator `{op_name}`). 

324 

325Equivalent to ``{equiv}``, but with support to substitute a fill_value for 

326missing data in one of the inputs. 

327 

328Parameters 

329---------- 

330other : Series or scalar value 

331fill_value : None or float value, default None (NaN) 

332 Fill existing missing (NaN) values, and any new element needed for 

333 successful Series alignment, with this value before computation. 

334 If data in both corresponding Series locations is missing 

335 the result will be missing. 

336level : int or name 

337 Broadcast across a level, matching Index values on the 

338 passed MultiIndex level. 

339 

340Returns 

341------- 

342Series 

343 The result of the operation. 

344 

345See Also 

346-------- 

347Series.{reverse} 

348""" 

349 

350_arith_doc_FRAME = """ 

351Binary operator %s with support to substitute a fill_value for missing data in 

352one of the inputs 

353 

354Parameters 

355---------- 

356other : Series, DataFrame, or constant 

357axis : {0, 1, 'index', 'columns'} 

358 For Series input, axis to match Series index on 

359fill_value : None or float value, default None 

360 Fill existing missing (NaN) values, and any new element needed for 

361 successful DataFrame alignment, with this value before computation. 

362 If data in both corresponding DataFrame locations is missing 

363 the result will be missing 

364level : int or name 

365 Broadcast across a level, matching Index values on the 

366 passed MultiIndex level 

367 

368Returns 

369------- 

370result : DataFrame 

371 

372Notes 

373----- 

374Mismatched indices will be unioned together 

375""" 

376 

377_flex_doc_FRAME = """ 

378Get {desc} of dataframe and other, element-wise (binary operator `{op_name}`). 

379 

380Equivalent to ``{equiv}``, but with support to substitute a fill_value 

381for missing data in one of the inputs. With reverse version, `{reverse}`. 

382 

383Among flexible wrappers (`add`, `sub`, `mul`, `div`, `mod`, `pow`) to 

384arithmetic operators: `+`, `-`, `*`, `/`, `//`, `%`, `**`. 

385 

386Parameters 

387---------- 

388other : scalar, sequence, Series, or DataFrame 

389 Any single or multiple element data structure, or list-like object. 

390axis : {{0 or 'index', 1 or 'columns'}} 

391 Whether to compare by the index (0 or 'index') or columns 

392 (1 or 'columns'). For Series input, axis to match Series index on. 

393level : int or label 

394 Broadcast across a level, matching Index values on the 

395 passed MultiIndex level. 

396fill_value : float or None, default None 

397 Fill existing missing (NaN) values, and any new element needed for 

398 successful DataFrame alignment, with this value before computation. 

399 If data in both corresponding DataFrame locations is missing 

400 the result will be missing. 

401 

402Returns 

403------- 

404DataFrame 

405 Result of the arithmetic operation. 

406 

407See Also 

408-------- 

409DataFrame.add : Add DataFrames. 

410DataFrame.sub : Subtract DataFrames. 

411DataFrame.mul : Multiply DataFrames. 

412DataFrame.div : Divide DataFrames (float division). 

413DataFrame.truediv : Divide DataFrames (float division). 

414DataFrame.floordiv : Divide DataFrames (integer division). 

415DataFrame.mod : Calculate modulo (remainder after division). 

416DataFrame.pow : Calculate exponential power. 

417 

418Notes 

419----- 

420Mismatched indices will be unioned together. 

421 

422Examples 

423-------- 

424>>> df = pd.DataFrame({{'angles': [0, 3, 4], 

425... 'degrees': [360, 180, 360]}}, 

426... index=['circle', 'triangle', 'rectangle']) 

427>>> df 

428 angles degrees 

429circle 0 360 

430triangle 3 180 

431rectangle 4 360 

432 

433Add a scalar with operator version which return the same 

434results. 

435 

436>>> df + 1 

437 angles degrees 

438circle 1 361 

439triangle 4 181 

440rectangle 5 361 

441 

442>>> df.add(1) 

443 angles degrees 

444circle 1 361 

445triangle 4 181 

446rectangle 5 361 

447 

448Divide by constant with reverse version. 

449 

450>>> df.div(10) 

451 angles degrees 

452circle 0.0 36.0 

453triangle 0.3 18.0 

454rectangle 0.4 36.0 

455 

456>>> df.rdiv(10) 

457 angles degrees 

458circle inf 0.027778 

459triangle 3.333333 0.055556 

460rectangle 2.500000 0.027778 

461 

462Subtract a list and Series by axis with operator version. 

463 

464>>> df - [1, 2] 

465 angles degrees 

466circle -1 358 

467triangle 2 178 

468rectangle 3 358 

469 

470>>> df.sub([1, 2], axis='columns') 

471 angles degrees 

472circle -1 358 

473triangle 2 178 

474rectangle 3 358 

475 

476>>> df.sub(pd.Series([1, 1, 1], index=['circle', 'triangle', 'rectangle']), 

477... axis='index') 

478 angles degrees 

479circle -1 359 

480triangle 2 179 

481rectangle 3 359 

482 

483Multiply a DataFrame of different shape with operator version. 

484 

485>>> other = pd.DataFrame({{'angles': [0, 3, 4]}}, 

486... index=['circle', 'triangle', 'rectangle']) 

487>>> other 

488 angles 

489circle 0 

490triangle 3 

491rectangle 4 

492 

493>>> df * other 

494 angles degrees 

495circle 0 NaN 

496triangle 9 NaN 

497rectangle 16 NaN 

498 

499>>> df.mul(other, fill_value=0) 

500 angles degrees 

501circle 0 0.0 

502triangle 9 0.0 

503rectangle 16 0.0 

504 

505Divide by a MultiIndex by level. 

506 

507>>> df_multindex = pd.DataFrame({{'angles': [0, 3, 4, 4, 5, 6], 

508... 'degrees': [360, 180, 360, 360, 540, 720]}}, 

509... index=[['A', 'A', 'A', 'B', 'B', 'B'], 

510... ['circle', 'triangle', 'rectangle', 

511... 'square', 'pentagon', 'hexagon']]) 

512>>> df_multindex 

513 angles degrees 

514A circle 0 360 

515 triangle 3 180 

516 rectangle 4 360 

517B square 4 360 

518 pentagon 5 540 

519 hexagon 6 720 

520 

521>>> df.div(df_multindex, level=1, fill_value=0) 

522 angles degrees 

523A circle NaN 1.0 

524 triangle 1.0 1.0 

525 rectangle 1.0 1.0 

526B square 0.0 0.0 

527 pentagon 0.0 0.0 

528 hexagon 0.0 0.0 

529""" 

530 

531_flex_comp_doc_FRAME = """ 

532Get {desc} of dataframe and other, element-wise (binary operator `{op_name}`). 

533 

534Among flexible wrappers (`eq`, `ne`, `le`, `lt`, `ge`, `gt`) to comparison 

535operators. 

536 

537Equivalent to `==`, `=!`, `<=`, `<`, `>=`, `>` with support to choose axis 

538(rows or columns) and level for comparison. 

539 

540Parameters 

541---------- 

542other : scalar, sequence, Series, or DataFrame 

543 Any single or multiple element data structure, or list-like object. 

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

545 Whether to compare by the index (0 or 'index') or columns 

546 (1 or 'columns'). 

547level : int or label 

548 Broadcast across a level, matching Index values on the passed 

549 MultiIndex level. 

550 

551Returns 

552------- 

553DataFrame of bool 

554 Result of the comparison. 

555 

556See Also 

557-------- 

558DataFrame.eq : Compare DataFrames for equality elementwise. 

559DataFrame.ne : Compare DataFrames for inequality elementwise. 

560DataFrame.le : Compare DataFrames for less than inequality 

561 or equality elementwise. 

562DataFrame.lt : Compare DataFrames for strictly less than 

563 inequality elementwise. 

564DataFrame.ge : Compare DataFrames for greater than inequality 

565 or equality elementwise. 

566DataFrame.gt : Compare DataFrames for strictly greater than 

567 inequality elementwise. 

568 

569Notes 

570----- 

571Mismatched indices will be unioned together. 

572`NaN` values are considered different (i.e. `NaN` != `NaN`). 

573 

574Examples 

575-------- 

576>>> df = pd.DataFrame({{'cost': [250, 150, 100], 

577... 'revenue': [100, 250, 300]}}, 

578... index=['A', 'B', 'C']) 

579>>> df 

580 cost revenue 

581A 250 100 

582B 150 250 

583C 100 300 

584 

585Comparison with a scalar, using either the operator or method: 

586 

587>>> df == 100 

588 cost revenue 

589A False True 

590B False False 

591C True False 

592 

593>>> df.eq(100) 

594 cost revenue 

595A False True 

596B False False 

597C True False 

598 

599When `other` is a :class:`Series`, the columns of a DataFrame are aligned 

600with the index of `other` and broadcast: 

601 

602>>> df != pd.Series([100, 250], index=["cost", "revenue"]) 

603 cost revenue 

604A True True 

605B True False 

606C False True 

607 

608Use the method to control the broadcast axis: 

609 

610>>> df.ne(pd.Series([100, 300], index=["A", "D"]), axis='index') 

611 cost revenue 

612A True False 

613B True True 

614C True True 

615D True True 

616 

617When comparing to an arbitrary sequence, the number of columns must 

618match the number elements in `other`: 

619 

620>>> df == [250, 100] 

621 cost revenue 

622A True True 

623B False False 

624C False False 

625 

626Use the method to control the axis: 

627 

628>>> df.eq([250, 250, 100], axis='index') 

629 cost revenue 

630A True False 

631B False True 

632C True False 

633 

634Compare to a DataFrame of different shape. 

635 

636>>> other = pd.DataFrame({{'revenue': [300, 250, 100, 150]}}, 

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

638>>> other 

639 revenue 

640A 300 

641B 250 

642C 100 

643D 150 

644 

645>>> df.gt(other) 

646 cost revenue 

647A False False 

648B False False 

649C False True 

650D False False 

651 

652Compare to a MultiIndex by level. 

653 

654>>> df_multindex = pd.DataFrame({{'cost': [250, 150, 100, 150, 300, 220], 

655... 'revenue': [100, 250, 300, 200, 175, 225]}}, 

656... index=[['Q1', 'Q1', 'Q1', 'Q2', 'Q2', 'Q2'], 

657... ['A', 'B', 'C', 'A', 'B', 'C']]) 

658>>> df_multindex 

659 cost revenue 

660Q1 A 250 100 

661 B 150 250 

662 C 100 300 

663Q2 A 150 200 

664 B 300 175 

665 C 220 225 

666 

667>>> df.le(df_multindex, level=1) 

668 cost revenue 

669Q1 A True True 

670 B True True 

671 C True True 

672Q2 A False True 

673 B True False 

674 C True False 

675"""