Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.9/dist-packages/numpy/lib/_function_base_impl.py: 13%

1291 statements  

« prev     ^ index     » next       coverage.py v7.4.4, created at 2024-04-09 06:12 +0000

1import builtins 

2import collections.abc 

3import functools 

4import re 

5import sys 

6import warnings 

7 

8import numpy as np 

9import numpy._core.numeric as _nx 

10from numpy._core import transpose, overrides 

11from numpy._core.numeric import ( 

12 ones, zeros_like, arange, concatenate, array, asarray, asanyarray, empty, 

13 ndarray, take, dot, where, intp, integer, isscalar, absolute 

14 ) 

15from numpy._core.umath import ( 

16 pi, add, arctan2, frompyfunc, cos, less_equal, sqrt, sin, 

17 mod, exp, not_equal, subtract, minimum 

18 ) 

19from numpy._core.fromnumeric import ( 

20 ravel, nonzero, partition, mean, any, sum 

21 ) 

22from numpy._core.numerictypes import typecodes 

23from numpy.lib._twodim_base_impl import diag 

24from numpy._core.multiarray import ( 

25 _place, bincount, normalize_axis_index, _monotonicity, 

26 interp as compiled_interp, interp_complex as compiled_interp_complex 

27 ) 

28from numpy._core._multiarray_umath import _array_converter 

29from numpy._utils import set_module 

30 

31# needed in this module for compatibility 

32from numpy.lib._histograms_impl import histogram, histogramdd # noqa: F401 

33 

34 

35array_function_dispatch = functools.partial( 

36 overrides.array_function_dispatch, module='numpy') 

37 

38 

39__all__ = [ 

40 'select', 'piecewise', 'trim_zeros', 'copy', 'iterable', 'percentile', 

41 'diff', 'gradient', 'angle', 'unwrap', 'sort_complex', 'flip', 

42 'rot90', 'extract', 'place', 'vectorize', 'asarray_chkfinite', 'average', 

43 'bincount', 'digitize', 'cov', 'corrcoef', 

44 'median', 'sinc', 'hamming', 'hanning', 'bartlett', 

45 'blackman', 'kaiser', 'trapezoid', 'trapz', 'i0', 

46 'meshgrid', 'delete', 'insert', 'append', 'interp', 

47 'quantile' 

48 ] 

49 

50# _QuantileMethods is a dictionary listing all the supported methods to 

51# compute quantile/percentile. 

52# 

53# Below virtual_index refers to the index of the element where the percentile 

54# would be found in the sorted sample. 

55# When the sample contains exactly the percentile wanted, the virtual_index is 

56# an integer to the index of this element. 

57# When the percentile wanted is in between two elements, the virtual_index 

58# is made of a integer part (a.k.a 'i' or 'left') and a fractional part 

59# (a.k.a 'g' or 'gamma') 

60# 

61# Each method in _QuantileMethods has two properties 

62# get_virtual_index : Callable 

63# The function used to compute the virtual_index. 

64# fix_gamma : Callable 

65# A function used for discret methods to force the index to a specific value. 

66_QuantileMethods = dict( 

67 # --- HYNDMAN and FAN METHODS 

68 # Discrete methods 

69 inverted_cdf=dict( 

70 get_virtual_index=lambda n, quantiles: _inverted_cdf(n, quantiles), 

71 fix_gamma=None, # should never be called 

72 ), 

73 averaged_inverted_cdf=dict( 

74 get_virtual_index=lambda n, quantiles: (n * quantiles) - 1, 

75 fix_gamma=lambda gamma, _: _get_gamma_mask( 

76 shape=gamma.shape, 

77 default_value=1., 

78 conditioned_value=0.5, 

79 where=gamma == 0), 

80 ), 

81 closest_observation=dict( 

82 get_virtual_index=lambda n, quantiles: _closest_observation(n, 

83 quantiles), 

84 fix_gamma=None, # should never be called 

85 ), 

86 # Continuous methods 

87 interpolated_inverted_cdf=dict( 

88 get_virtual_index=lambda n, quantiles: 

89 _compute_virtual_index(n, quantiles, 0, 1), 

90 fix_gamma=lambda gamma, _: gamma, 

91 ), 

92 hazen=dict( 

93 get_virtual_index=lambda n, quantiles: 

94 _compute_virtual_index(n, quantiles, 0.5, 0.5), 

95 fix_gamma=lambda gamma, _: gamma, 

96 ), 

97 weibull=dict( 

98 get_virtual_index=lambda n, quantiles: 

99 _compute_virtual_index(n, quantiles, 0, 0), 

100 fix_gamma=lambda gamma, _: gamma, 

101 ), 

102 # Default method. 

103 # To avoid some rounding issues, `(n-1) * quantiles` is preferred to 

104 # `_compute_virtual_index(n, quantiles, 1, 1)`. 

105 # They are mathematically equivalent. 

106 linear=dict( 

107 get_virtual_index=lambda n, quantiles: (n - 1) * quantiles, 

108 fix_gamma=lambda gamma, _: gamma, 

109 ), 

110 median_unbiased=dict( 

111 get_virtual_index=lambda n, quantiles: 

112 _compute_virtual_index(n, quantiles, 1 / 3.0, 1 / 3.0), 

113 fix_gamma=lambda gamma, _: gamma, 

114 ), 

115 normal_unbiased=dict( 

116 get_virtual_index=lambda n, quantiles: 

117 _compute_virtual_index(n, quantiles, 3 / 8.0, 3 / 8.0), 

118 fix_gamma=lambda gamma, _: gamma, 

119 ), 

120 # --- OTHER METHODS 

121 lower=dict( 

122 get_virtual_index=lambda n, quantiles: np.floor( 

123 (n - 1) * quantiles).astype(np.intp), 

124 fix_gamma=None, # should never be called, index dtype is int 

125 ), 

126 higher=dict( 

127 get_virtual_index=lambda n, quantiles: np.ceil( 

128 (n - 1) * quantiles).astype(np.intp), 

129 fix_gamma=None, # should never be called, index dtype is int 

130 ), 

131 midpoint=dict( 

132 get_virtual_index=lambda n, quantiles: 0.5 * ( 

133 np.floor((n - 1) * quantiles) 

134 + np.ceil((n - 1) * quantiles)), 

135 fix_gamma=lambda gamma, index: _get_gamma_mask( 

136 shape=gamma.shape, 

137 default_value=0.5, 

138 conditioned_value=0., 

139 where=index % 1 == 0), 

140 ), 

141 nearest=dict( 

142 get_virtual_index=lambda n, quantiles: np.around( 

143 (n - 1) * quantiles).astype(np.intp), 

144 fix_gamma=None, 

145 # should never be called, index dtype is int 

146 )) 

147 

148 

149def _rot90_dispatcher(m, k=None, axes=None): 

150 return (m,) 

151 

152 

153@array_function_dispatch(_rot90_dispatcher) 

154def rot90(m, k=1, axes=(0, 1)): 

155 """ 

156 Rotate an array by 90 degrees in the plane specified by axes. 

157 

158 Rotation direction is from the first towards the second axis. 

159 This means for a 2D array with the default `k` and `axes`, the 

160 rotation will be counterclockwise. 

161 

162 Parameters 

163 ---------- 

164 m : array_like 

165 Array of two or more dimensions. 

166 k : integer 

167 Number of times the array is rotated by 90 degrees. 

168 axes : (2,) array_like 

169 The array is rotated in the plane defined by the axes. 

170 Axes must be different. 

171 

172 .. versionadded:: 1.12.0 

173 

174 Returns 

175 ------- 

176 y : ndarray 

177 A rotated view of `m`. 

178 

179 See Also 

180 -------- 

181 flip : Reverse the order of elements in an array along the given axis. 

182 fliplr : Flip an array horizontally. 

183 flipud : Flip an array vertically. 

184 

185 Notes 

186 ----- 

187 ``rot90(m, k=1, axes=(1,0))`` is the reverse of 

188 ``rot90(m, k=1, axes=(0,1))`` 

189 

190 ``rot90(m, k=1, axes=(1,0))`` is equivalent to 

191 ``rot90(m, k=-1, axes=(0,1))`` 

192 

193 Examples 

194 -------- 

195 >>> m = np.array([[1,2],[3,4]], int) 

196 >>> m 

197 array([[1, 2], 

198 [3, 4]]) 

199 >>> np.rot90(m) 

200 array([[2, 4], 

201 [1, 3]]) 

202 >>> np.rot90(m, 2) 

203 array([[4, 3], 

204 [2, 1]]) 

205 >>> m = np.arange(8).reshape((2,2,2)) 

206 >>> np.rot90(m, 1, (1,2)) 

207 array([[[1, 3], 

208 [0, 2]], 

209 [[5, 7], 

210 [4, 6]]]) 

211 

212 """ 

213 axes = tuple(axes) 

214 if len(axes) != 2: 

215 raise ValueError("len(axes) must be 2.") 

216 

217 m = asanyarray(m) 

218 

219 if axes[0] == axes[1] or absolute(axes[0] - axes[1]) == m.ndim: 

220 raise ValueError("Axes must be different.") 

221 

222 if (axes[0] >= m.ndim or axes[0] < -m.ndim 

223 or axes[1] >= m.ndim or axes[1] < -m.ndim): 

224 raise ValueError("Axes={} out of range for array of ndim={}." 

225 .format(axes, m.ndim)) 

226 

227 k %= 4 

228 

229 if k == 0: 

230 return m[:] 

231 if k == 2: 

232 return flip(flip(m, axes[0]), axes[1]) 

233 

234 axes_list = arange(0, m.ndim) 

235 (axes_list[axes[0]], axes_list[axes[1]]) = (axes_list[axes[1]], 

236 axes_list[axes[0]]) 

237 

238 if k == 1: 

239 return transpose(flip(m, axes[1]), axes_list) 

240 else: 

241 # k == 3 

242 return flip(transpose(m, axes_list), axes[1]) 

243 

244 

245def _flip_dispatcher(m, axis=None): 

246 return (m,) 

247 

248 

249@array_function_dispatch(_flip_dispatcher) 

250def flip(m, axis=None): 

251 """ 

252 Reverse the order of elements in an array along the given axis. 

253 

254 The shape of the array is preserved, but the elements are reordered. 

255 

256 .. versionadded:: 1.12.0 

257 

258 Parameters 

259 ---------- 

260 m : array_like 

261 Input array. 

262 axis : None or int or tuple of ints, optional 

263 Axis or axes along which to flip over. The default, 

264 axis=None, will flip over all of the axes of the input array. 

265 If axis is negative it counts from the last to the first axis. 

266 

267 If axis is a tuple of ints, flipping is performed on all of the axes 

268 specified in the tuple. 

269 

270 .. versionchanged:: 1.15.0 

271 None and tuples of axes are supported 

272 

273 Returns 

274 ------- 

275 out : array_like 

276 A view of `m` with the entries of axis reversed. Since a view is 

277 returned, this operation is done in constant time. 

278 

279 See Also 

280 -------- 

281 flipud : Flip an array vertically (axis=0). 

282 fliplr : Flip an array horizontally (axis=1). 

283 

284 Notes 

285 ----- 

286 flip(m, 0) is equivalent to flipud(m). 

287 

288 flip(m, 1) is equivalent to fliplr(m). 

289 

290 flip(m, n) corresponds to ``m[...,::-1,...]`` with ``::-1`` at position n. 

291 

292 flip(m) corresponds to ``m[::-1,::-1,...,::-1]`` with ``::-1`` at all 

293 positions. 

294 

295 flip(m, (0, 1)) corresponds to ``m[::-1,::-1,...]`` with ``::-1`` at 

296 position 0 and position 1. 

297 

298 Examples 

299 -------- 

300 >>> A = np.arange(8).reshape((2,2,2)) 

301 >>> A 

302 array([[[0, 1], 

303 [2, 3]], 

304 [[4, 5], 

305 [6, 7]]]) 

306 >>> np.flip(A, 0) 

307 array([[[4, 5], 

308 [6, 7]], 

309 [[0, 1], 

310 [2, 3]]]) 

311 >>> np.flip(A, 1) 

312 array([[[2, 3], 

313 [0, 1]], 

314 [[6, 7], 

315 [4, 5]]]) 

316 >>> np.flip(A) 

317 array([[[7, 6], 

318 [5, 4]], 

319 [[3, 2], 

320 [1, 0]]]) 

321 >>> np.flip(A, (0, 2)) 

322 array([[[5, 4], 

323 [7, 6]], 

324 [[1, 0], 

325 [3, 2]]]) 

326 >>> A = np.random.randn(3,4,5) 

327 >>> np.all(np.flip(A,2) == A[:,:,::-1,...]) 

328 True 

329 """ 

330 if not hasattr(m, 'ndim'): 

331 m = asarray(m) 

332 if axis is None: 

333 indexer = (np.s_[::-1],) * m.ndim 

334 else: 

335 axis = _nx.normalize_axis_tuple(axis, m.ndim) 

336 indexer = [np.s_[:]] * m.ndim 

337 for ax in axis: 

338 indexer[ax] = np.s_[::-1] 

339 indexer = tuple(indexer) 

340 return m[indexer] 

341 

342 

343@set_module('numpy') 

344def iterable(y): 

345 """ 

346 Check whether or not an object can be iterated over. 

347 

348 Parameters 

349 ---------- 

350 y : object 

351 Input object. 

352 

353 Returns 

354 ------- 

355 b : bool 

356 Return ``True`` if the object has an iterator method or is a 

357 sequence and ``False`` otherwise. 

358 

359 

360 Examples 

361 -------- 

362 >>> np.iterable([1, 2, 3]) 

363 True 

364 >>> np.iterable(2) 

365 False 

366 

367 Notes 

368 ----- 

369 In most cases, the results of ``np.iterable(obj)`` are consistent with 

370 ``isinstance(obj, collections.abc.Iterable)``. One notable exception is 

371 the treatment of 0-dimensional arrays:: 

372 

373 >>> from collections.abc import Iterable 

374 >>> a = np.array(1.0) # 0-dimensional numpy array 

375 >>> isinstance(a, Iterable) 

376 True 

377 >>> np.iterable(a) 

378 False 

379 

380 """ 

381 try: 

382 iter(y) 

383 except TypeError: 

384 return False 

385 return True 

386 

387 

388def _weights_are_valid(weights, a, axis): 

389 """Validate weights array. 

390  

391 We assume, weights is not None. 

392 """ 

393 wgt = np.asanyarray(weights) 

394 

395 # Sanity checks 

396 if a.shape != wgt.shape: 

397 if axis is None: 

398 raise TypeError( 

399 "Axis must be specified when shapes of a and weights " 

400 "differ.") 

401 if wgt.shape != tuple(a.shape[ax] for ax in axis): 

402 raise ValueError( 

403 "Shape of weights must be consistent with " 

404 "shape of a along specified axis.") 

405 

406 # setup wgt to broadcast along axis 

407 wgt = wgt.transpose(np.argsort(axis)) 

408 wgt = wgt.reshape(tuple((s if ax in axis else 1) 

409 for ax, s in enumerate(a.shape))) 

410 return wgt 

411 

412 

413def _average_dispatcher(a, axis=None, weights=None, returned=None, *, 

414 keepdims=None): 

415 return (a, weights) 

416 

417 

418@array_function_dispatch(_average_dispatcher) 

419def average(a, axis=None, weights=None, returned=False, *, 

420 keepdims=np._NoValue): 

421 """ 

422 Compute the weighted average along the specified axis. 

423 

424 Parameters 

425 ---------- 

426 a : array_like 

427 Array containing data to be averaged. If `a` is not an array, a 

428 conversion is attempted. 

429 axis : None or int or tuple of ints, optional 

430 Axis or axes along which to average `a`. The default, 

431 `axis=None`, will average over all of the elements of the input array. 

432 If axis is negative it counts from the last to the first axis. 

433 

434 .. versionadded:: 1.7.0 

435 

436 If axis is a tuple of ints, averaging is performed on all of the axes 

437 specified in the tuple instead of a single axis or all the axes as 

438 before. 

439 weights : array_like, optional 

440 An array of weights associated with the values in `a`. Each value in 

441 `a` contributes to the average according to its associated weight. 

442 The array of weights must be the same shape as `a` if no axis is 

443 specified, otherwise the weights must have dimensions and shape 

444 consistent with `a` along the specified axis. 

445 If `weights=None`, then all data in `a` are assumed to have a 

446 weight equal to one. 

447 The calculation is:: 

448 

449 avg = sum(a * weights) / sum(weights) 

450  

451 where the sum is over all included elements. 

452 The only constraint on the values of `weights` is that `sum(weights)` 

453 must not be 0. 

454 returned : bool, optional 

455 Default is `False`. If `True`, the tuple (`average`, `sum_of_weights`) 

456 is returned, otherwise only the average is returned. 

457 If `weights=None`, `sum_of_weights` is equivalent to the number of 

458 elements over which the average is taken. 

459 keepdims : bool, optional 

460 If this is set to True, the axes which are reduced are left 

461 in the result as dimensions with size one. With this option, 

462 the result will broadcast correctly against the original `a`. 

463 *Note:* `keepdims` will not work with instances of `numpy.matrix` 

464 or other classes whose methods do not support `keepdims`. 

465 

466 .. versionadded:: 1.23.0 

467 

468 Returns 

469 ------- 

470 retval, [sum_of_weights] : array_type or double 

471 Return the average along the specified axis. When `returned` is `True`, 

472 return a tuple with the average as the first element and the sum 

473 of the weights as the second element. `sum_of_weights` is of the 

474 same type as `retval`. The result dtype follows a general pattern. 

475 If `weights` is None, the result dtype will be that of `a` , or ``float64`` 

476 if `a` is integral. Otherwise, if `weights` is not None and `a` is non- 

477 integral, the result type will be the type of lowest precision capable of 

478 representing values of both `a` and `weights`. If `a` happens to be 

479 integral, the previous rules still applies but the result dtype will 

480 at least be ``float64``. 

481 

482 Raises 

483 ------ 

484 ZeroDivisionError 

485 When all weights along axis are zero. See `numpy.ma.average` for a 

486 version robust to this type of error. 

487 TypeError 

488 When `weights` does not have the same shape as `a`, and `axis=None`. 

489 ValueError 

490 When `weights` does not have dimensions and shape consistent with `a` 

491 along specified `axis`. 

492 

493 See Also 

494 -------- 

495 mean 

496 

497 ma.average : average for masked arrays -- useful if your data contains 

498 "missing" values 

499 numpy.result_type : Returns the type that results from applying the 

500 numpy type promotion rules to the arguments. 

501 

502 Examples 

503 -------- 

504 >>> data = np.arange(1, 5) 

505 >>> data 

506 array([1, 2, 3, 4]) 

507 >>> np.average(data) 

508 2.5 

509 >>> np.average(np.arange(1, 11), weights=np.arange(10, 0, -1)) 

510 4.0 

511 

512 >>> data = np.arange(6).reshape((3, 2)) 

513 >>> data 

514 array([[0, 1], 

515 [2, 3], 

516 [4, 5]]) 

517 >>> np.average(data, axis=1, weights=[1./4, 3./4]) 

518 array([0.75, 2.75, 4.75]) 

519 >>> np.average(data, weights=[1./4, 3./4]) 

520 Traceback (most recent call last): 

521 ... 

522 TypeError: Axis must be specified when shapes of a and weights differ. 

523 

524 With ``keepdims=True``, the following result has shape (3, 1). 

525 

526 >>> np.average(data, axis=1, keepdims=True) 

527 array([[0.5], 

528 [2.5], 

529 [4.5]]) 

530 

531 >>> data = np.arange(8).reshape((2, 2, 2)) 

532 >>> data 

533 array([[[0, 1], 

534 [2, 3]], 

535 [[4, 5], 

536 [6, 7]]]) 

537 >>> np.average(data, axis=(0, 1), weights=[[1./4, 3./4], [1., 1./2]]) 

538 array([3.4, 4.4]) 

539 >>> np.average(data, axis=0, weights=[[1./4, 3./4], [1., 1./2]]) 

540 Traceback (most recent call last): 

541 ... 

542 ValueError: Shape of weights must be consistent 

543 with shape of a along specified axis. 

544 """ 

545 a = np.asanyarray(a) 

546 

547 if axis is not None: 

548 axis = _nx.normalize_axis_tuple(axis, a.ndim, argname="axis") 

549 

550 if keepdims is np._NoValue: 

551 # Don't pass on the keepdims argument if one wasn't given. 

552 keepdims_kw = {} 

553 else: 

554 keepdims_kw = {'keepdims': keepdims} 

555 

556 if weights is None: 

557 avg = a.mean(axis, **keepdims_kw) 

558 avg_as_array = np.asanyarray(avg) 

559 scl = avg_as_array.dtype.type(a.size/avg_as_array.size) 

560 else: 

561 wgt = _weights_are_valid(weights=weights, a=a, axis=axis) 

562 

563 if issubclass(a.dtype.type, (np.integer, np.bool)): 

564 result_dtype = np.result_type(a.dtype, wgt.dtype, 'f8') 

565 else: 

566 result_dtype = np.result_type(a.dtype, wgt.dtype) 

567 

568 scl = wgt.sum(axis=axis, dtype=result_dtype, **keepdims_kw) 

569 if np.any(scl == 0.0): 

570 raise ZeroDivisionError( 

571 "Weights sum to zero, can't be normalized") 

572 

573 avg = avg_as_array = np.multiply(a, wgt, 

574 dtype=result_dtype).sum(axis, **keepdims_kw) / scl 

575 

576 if returned: 

577 if scl.shape != avg_as_array.shape: 

578 scl = np.broadcast_to(scl, avg_as_array.shape).copy() 

579 return avg, scl 

580 else: 

581 return avg 

582 

583 

584@set_module('numpy') 

585def asarray_chkfinite(a, dtype=None, order=None): 

586 """Convert the input to an array, checking for NaNs or Infs. 

587 

588 Parameters 

589 ---------- 

590 a : array_like 

591 Input data, in any form that can be converted to an array. This 

592 includes lists, lists of tuples, tuples, tuples of tuples, tuples 

593 of lists and ndarrays. Success requires no NaNs or Infs. 

594 dtype : data-type, optional 

595 By default, the data-type is inferred from the input data. 

596 order : {'C', 'F', 'A', 'K'}, optional 

597 Memory layout. 'A' and 'K' depend on the order of input array a. 

598 'C' row-major (C-style), 

599 'F' column-major (Fortran-style) memory representation. 

600 'A' (any) means 'F' if `a` is Fortran contiguous, 'C' otherwise 

601 'K' (keep) preserve input order 

602 Defaults to 'C'. 

603 

604 Returns 

605 ------- 

606 out : ndarray 

607 Array interpretation of `a`. No copy is performed if the input 

608 is already an ndarray. If `a` is a subclass of ndarray, a base 

609 class ndarray is returned. 

610 

611 Raises 

612 ------ 

613 ValueError 

614 Raises ValueError if `a` contains NaN (Not a Number) or Inf (Infinity). 

615 

616 See Also 

617 -------- 

618 asarray : Create and array. 

619 asanyarray : Similar function which passes through subclasses. 

620 ascontiguousarray : Convert input to a contiguous array. 

621 asfortranarray : Convert input to an ndarray with column-major 

622 memory order. 

623 fromiter : Create an array from an iterator. 

624 fromfunction : Construct an array by executing a function on grid 

625 positions. 

626 

627 Examples 

628 -------- 

629 Convert a list into an array. If all elements are finite 

630 ``asarray_chkfinite`` is identical to ``asarray``. 

631 

632 >>> a = [1, 2] 

633 >>> np.asarray_chkfinite(a, dtype=float) 

634 array([1., 2.]) 

635 

636 Raises ValueError if array_like contains Nans or Infs. 

637 

638 >>> a = [1, 2, np.inf] 

639 >>> try: 

640 ... np.asarray_chkfinite(a) 

641 ... except ValueError: 

642 ... print('ValueError') 

643 ... 

644 ValueError 

645 

646 """ 

647 a = asarray(a, dtype=dtype, order=order) 

648 if a.dtype.char in typecodes['AllFloat'] and not np.isfinite(a).all(): 

649 raise ValueError( 

650 "array must not contain infs or NaNs") 

651 return a 

652 

653 

654def _piecewise_dispatcher(x, condlist, funclist, *args, **kw): 

655 yield x 

656 # support the undocumented behavior of allowing scalars 

657 if np.iterable(condlist): 

658 yield from condlist 

659 

660 

661@array_function_dispatch(_piecewise_dispatcher) 

662def piecewise(x, condlist, funclist, *args, **kw): 

663 """ 

664 Evaluate a piecewise-defined function. 

665 

666 Given a set of conditions and corresponding functions, evaluate each 

667 function on the input data wherever its condition is true. 

668 

669 Parameters 

670 ---------- 

671 x : ndarray or scalar 

672 The input domain. 

673 condlist : list of bool arrays or bool scalars 

674 Each boolean array corresponds to a function in `funclist`. Wherever 

675 `condlist[i]` is True, `funclist[i](x)` is used as the output value. 

676 

677 Each boolean array in `condlist` selects a piece of `x`, 

678 and should therefore be of the same shape as `x`. 

679 

680 The length of `condlist` must correspond to that of `funclist`. 

681 If one extra function is given, i.e. if 

682 ``len(funclist) == len(condlist) + 1``, then that extra function 

683 is the default value, used wherever all conditions are false. 

684 funclist : list of callables, f(x,*args,**kw), or scalars 

685 Each function is evaluated over `x` wherever its corresponding 

686 condition is True. It should take a 1d array as input and give an 1d 

687 array or a scalar value as output. If, instead of a callable, 

688 a scalar is provided then a constant function (``lambda x: scalar``) is 

689 assumed. 

690 args : tuple, optional 

691 Any further arguments given to `piecewise` are passed to the functions 

692 upon execution, i.e., if called ``piecewise(..., ..., 1, 'a')``, then 

693 each function is called as ``f(x, 1, 'a')``. 

694 kw : dict, optional 

695 Keyword arguments used in calling `piecewise` are passed to the 

696 functions upon execution, i.e., if called 

697 ``piecewise(..., ..., alpha=1)``, then each function is called as 

698 ``f(x, alpha=1)``. 

699 

700 Returns 

701 ------- 

702 out : ndarray 

703 The output is the same shape and type as x and is found by 

704 calling the functions in `funclist` on the appropriate portions of `x`, 

705 as defined by the boolean arrays in `condlist`. Portions not covered 

706 by any condition have a default value of 0. 

707 

708 

709 See Also 

710 -------- 

711 choose, select, where 

712 

713 Notes 

714 ----- 

715 This is similar to choose or select, except that functions are 

716 evaluated on elements of `x` that satisfy the corresponding condition from 

717 `condlist`. 

718 

719 The result is:: 

720 

721 |-- 

722 |funclist[0](x[condlist[0]]) 

723 out = |funclist[1](x[condlist[1]]) 

724 |... 

725 |funclist[n2](x[condlist[n2]]) 

726 |-- 

727 

728 Examples 

729 -------- 

730 Define the signum function, which is -1 for ``x < 0`` and +1 for ``x >= 0``. 

731 

732 >>> x = np.linspace(-2.5, 2.5, 6) 

733 >>> np.piecewise(x, [x < 0, x >= 0], [-1, 1]) 

734 array([-1., -1., -1., 1., 1., 1.]) 

735 

736 Define the absolute value, which is ``-x`` for ``x <0`` and ``x`` for 

737 ``x >= 0``. 

738 

739 >>> np.piecewise(x, [x < 0, x >= 0], [lambda x: -x, lambda x: x]) 

740 array([2.5, 1.5, 0.5, 0.5, 1.5, 2.5]) 

741 

742 Apply the same function to a scalar value. 

743 

744 >>> y = -2 

745 >>> np.piecewise(y, [y < 0, y >= 0], [lambda x: -x, lambda x: x]) 

746 array(2) 

747 

748 """ 

749 x = asanyarray(x) 

750 n2 = len(funclist) 

751 

752 # undocumented: single condition is promoted to a list of one condition 

753 if isscalar(condlist) or ( 

754 not isinstance(condlist[0], (list, ndarray)) and x.ndim != 0): 

755 condlist = [condlist] 

756 

757 condlist = asarray(condlist, dtype=bool) 

758 n = len(condlist) 

759 

760 if n == n2 - 1: # compute the "otherwise" condition. 

761 condelse = ~np.any(condlist, axis=0, keepdims=True) 

762 condlist = np.concatenate([condlist, condelse], axis=0) 

763 n += 1 

764 elif n != n2: 

765 raise ValueError( 

766 "with {} condition(s), either {} or {} functions are expected" 

767 .format(n, n, n+1) 

768 ) 

769 

770 y = zeros_like(x) 

771 for cond, func in zip(condlist, funclist): 

772 if not isinstance(func, collections.abc.Callable): 

773 y[cond] = func 

774 else: 

775 vals = x[cond] 

776 if vals.size > 0: 

777 y[cond] = func(vals, *args, **kw) 

778 

779 return y 

780 

781 

782def _select_dispatcher(condlist, choicelist, default=None): 

783 yield from condlist 

784 yield from choicelist 

785 

786 

787@array_function_dispatch(_select_dispatcher) 

788def select(condlist, choicelist, default=0): 

789 """ 

790 Return an array drawn from elements in choicelist, depending on conditions. 

791 

792 Parameters 

793 ---------- 

794 condlist : list of bool ndarrays 

795 The list of conditions which determine from which array in `choicelist` 

796 the output elements are taken. When multiple conditions are satisfied, 

797 the first one encountered in `condlist` is used. 

798 choicelist : list of ndarrays 

799 The list of arrays from which the output elements are taken. It has 

800 to be of the same length as `condlist`. 

801 default : scalar, optional 

802 The element inserted in `output` when all conditions evaluate to False. 

803 

804 Returns 

805 ------- 

806 output : ndarray 

807 The output at position m is the m-th element of the array in 

808 `choicelist` where the m-th element of the corresponding array in 

809 `condlist` is True. 

810 

811 See Also 

812 -------- 

813 where : Return elements from one of two arrays depending on condition. 

814 take, choose, compress, diag, diagonal 

815 

816 Examples 

817 -------- 

818 Beginning with an array of integers from 0 to 5 (inclusive), 

819 elements less than ``3`` are negated, elements greater than ``3`` 

820 are squared, and elements not meeting either of these conditions 

821 (exactly ``3``) are replaced with a `default` value of ``42``. 

822 

823 >>> x = np.arange(6) 

824 >>> condlist = [x<3, x>3] 

825 >>> choicelist = [x, x**2] 

826 >>> np.select(condlist, choicelist, 42) 

827 array([ 0, 1, 2, 42, 16, 25]) 

828 

829 When multiple conditions are satisfied, the first one encountered in 

830 `condlist` is used. 

831 

832 >>> condlist = [x<=4, x>3] 

833 >>> choicelist = [x, x**2] 

834 >>> np.select(condlist, choicelist, 55) 

835 array([ 0, 1, 2, 3, 4, 25]) 

836 

837 """ 

838 # Check the size of condlist and choicelist are the same, or abort. 

839 if len(condlist) != len(choicelist): 

840 raise ValueError( 

841 'list of cases must be same length as list of conditions') 

842 

843 # Now that the dtype is known, handle the deprecated select([], []) case 

844 if len(condlist) == 0: 

845 raise ValueError("select with an empty condition list is not possible") 

846 

847 # TODO: This preserves the Python int, float, complex manually to get the 

848 # right `result_type` with NEP 50. Most likely we will grow a better 

849 # way to spell this (and this can be replaced). 

850 choicelist = [ 

851 choice if type(choice) in (int, float, complex) else np.asarray(choice) 

852 for choice in choicelist] 

853 choicelist.append(default if type(default) in (int, float, complex) 

854 else np.asarray(default)) 

855 

856 try: 

857 dtype = np.result_type(*choicelist) 

858 except TypeError as e: 

859 msg = f'Choicelist and default value do not have a common dtype: {e}' 

860 raise TypeError(msg) from None 

861 

862 # Convert conditions to arrays and broadcast conditions and choices 

863 # as the shape is needed for the result. Doing it separately optimizes 

864 # for example when all choices are scalars. 

865 condlist = np.broadcast_arrays(*condlist) 

866 choicelist = np.broadcast_arrays(*choicelist) 

867 

868 # If cond array is not an ndarray in boolean format or scalar bool, abort. 

869 for i, cond in enumerate(condlist): 

870 if cond.dtype.type is not np.bool: 

871 raise TypeError( 

872 'invalid entry {} in condlist: should be boolean ndarray'.format(i)) 

873 

874 if choicelist[0].ndim == 0: 

875 # This may be common, so avoid the call. 

876 result_shape = condlist[0].shape 

877 else: 

878 result_shape = np.broadcast_arrays(condlist[0], choicelist[0])[0].shape 

879 

880 result = np.full(result_shape, choicelist[-1], dtype) 

881 

882 # Use np.copyto to burn each choicelist array onto result, using the 

883 # corresponding condlist as a boolean mask. This is done in reverse 

884 # order since the first choice should take precedence. 

885 choicelist = choicelist[-2::-1] 

886 condlist = condlist[::-1] 

887 for choice, cond in zip(choicelist, condlist): 

888 np.copyto(result, choice, where=cond) 

889 

890 return result 

891 

892 

893def _copy_dispatcher(a, order=None, subok=None): 

894 return (a,) 

895 

896 

897@array_function_dispatch(_copy_dispatcher) 

898def copy(a, order='K', subok=False): 

899 """ 

900 Return an array copy of the given object. 

901 

902 Parameters 

903 ---------- 

904 a : array_like 

905 Input data. 

906 order : {'C', 'F', 'A', 'K'}, optional 

907 Controls the memory layout of the copy. 'C' means C-order, 

908 'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous, 

909 'C' otherwise. 'K' means match the layout of `a` as closely 

910 as possible. (Note that this function and :meth:`ndarray.copy` are very 

911 similar, but have different default values for their order= 

912 arguments.) 

913 subok : bool, optional 

914 If True, then sub-classes will be passed-through, otherwise the 

915 returned array will be forced to be a base-class array (defaults to False). 

916 

917 .. versionadded:: 1.19.0 

918 

919 Returns 

920 ------- 

921 arr : ndarray 

922 Array interpretation of `a`. 

923 

924 See Also 

925 -------- 

926 ndarray.copy : Preferred method for creating an array copy 

927 

928 Notes 

929 ----- 

930 This is equivalent to: 

931 

932 >>> np.array(a, copy=True) #doctest: +SKIP 

933 

934 The copy made of the data is shallow, i.e., for arrays with object dtype, 

935 the new array will point to the same objects. 

936 See Examples from `ndarray.copy`. 

937 

938 Examples 

939 -------- 

940 Create an array x, with a reference y and a copy z: 

941 

942 >>> x = np.array([1, 2, 3]) 

943 >>> y = x 

944 >>> z = np.copy(x) 

945 

946 Note that, when we modify x, y changes, but not z: 

947 

948 >>> x[0] = 10 

949 >>> x[0] == y[0] 

950 True 

951 >>> x[0] == z[0] 

952 False 

953 

954 Note that, np.copy clears previously set WRITEABLE=False flag. 

955 

956 >>> a = np.array([1, 2, 3]) 

957 >>> a.flags["WRITEABLE"] = False 

958 >>> b = np.copy(a) 

959 >>> b.flags["WRITEABLE"] 

960 True 

961 >>> b[0] = 3 

962 >>> b 

963 array([3, 2, 3]) 

964 """ 

965 return array(a, order=order, subok=subok, copy=True) 

966 

967# Basic operations 

968 

969 

970def _gradient_dispatcher(f, *varargs, axis=None, edge_order=None): 

971 yield f 

972 yield from varargs 

973 

974 

975@array_function_dispatch(_gradient_dispatcher) 

976def gradient(f, *varargs, axis=None, edge_order=1): 

977 """ 

978 Return the gradient of an N-dimensional array. 

979 

980 The gradient is computed using second order accurate central differences 

981 in the interior points and either first or second order accurate one-sides 

982 (forward or backwards) differences at the boundaries. 

983 The returned gradient hence has the same shape as the input array. 

984 

985 Parameters 

986 ---------- 

987 f : array_like 

988 An N-dimensional array containing samples of a scalar function. 

989 varargs : list of scalar or array, optional 

990 Spacing between f values. Default unitary spacing for all dimensions. 

991 Spacing can be specified using: 

992 

993 1. single scalar to specify a sample distance for all dimensions. 

994 2. N scalars to specify a constant sample distance for each dimension. 

995 i.e. `dx`, `dy`, `dz`, ... 

996 3. N arrays to specify the coordinates of the values along each 

997 dimension of F. The length of the array must match the size of 

998 the corresponding dimension 

999 4. Any combination of N scalars/arrays with the meaning of 2. and 3. 

1000 

1001 If `axis` is given, the number of varargs must equal the number of axes. 

1002 Default: 1. 

1003 

1004 edge_order : {1, 2}, optional 

1005 Gradient is calculated using N-th order accurate differences 

1006 at the boundaries. Default: 1. 

1007 

1008 .. versionadded:: 1.9.1 

1009 

1010 axis : None or int or tuple of ints, optional 

1011 Gradient is calculated only along the given axis or axes 

1012 The default (axis = None) is to calculate the gradient for all the axes 

1013 of the input array. axis may be negative, in which case it counts from 

1014 the last to the first axis. 

1015 

1016 .. versionadded:: 1.11.0 

1017 

1018 Returns 

1019 ------- 

1020 gradient : ndarray or list of ndarray 

1021 A list of ndarrays (or a single ndarray if there is only one dimension) 

1022 corresponding to the derivatives of f with respect to each dimension. 

1023 Each derivative has the same shape as f. 

1024 

1025 Examples 

1026 -------- 

1027 >>> f = np.array([1, 2, 4, 7, 11, 16], dtype=float) 

1028 >>> np.gradient(f) 

1029 array([1. , 1.5, 2.5, 3.5, 4.5, 5. ]) 

1030 >>> np.gradient(f, 2) 

1031 array([0.5 , 0.75, 1.25, 1.75, 2.25, 2.5 ]) 

1032 

1033 Spacing can be also specified with an array that represents the coordinates 

1034 of the values F along the dimensions. 

1035 For instance a uniform spacing: 

1036 

1037 >>> x = np.arange(f.size) 

1038 >>> np.gradient(f, x) 

1039 array([1. , 1.5, 2.5, 3.5, 4.5, 5. ]) 

1040 

1041 Or a non uniform one: 

1042 

1043 >>> x = np.array([0., 1., 1.5, 3.5, 4., 6.], dtype=float) 

1044 >>> np.gradient(f, x) 

1045 array([1. , 3. , 3.5, 6.7, 6.9, 2.5]) 

1046 

1047 For two dimensional arrays, the return will be two arrays ordered by 

1048 axis. In this example the first array stands for the gradient in 

1049 rows and the second one in columns direction: 

1050 

1051 >>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=float)) 

1052 [array([[ 2., 2., -1.], 

1053 [ 2., 2., -1.]]), array([[1. , 2.5, 4. ], 

1054 [1. , 1. , 1. ]])] 

1055 

1056 In this example the spacing is also specified: 

1057 uniform for axis=0 and non uniform for axis=1 

1058 

1059 >>> dx = 2. 

1060 >>> y = [1., 1.5, 3.5] 

1061 >>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=float), dx, y) 

1062 [array([[ 1. , 1. , -0.5], 

1063 [ 1. , 1. , -0.5]]), array([[2. , 2. , 2. ], 

1064 [2. , 1.7, 0.5]])] 

1065 

1066 It is possible to specify how boundaries are treated using `edge_order` 

1067 

1068 >>> x = np.array([0, 1, 2, 3, 4]) 

1069 >>> f = x**2 

1070 >>> np.gradient(f, edge_order=1) 

1071 array([1., 2., 4., 6., 7.]) 

1072 >>> np.gradient(f, edge_order=2) 

1073 array([0., 2., 4., 6., 8.]) 

1074 

1075 The `axis` keyword can be used to specify a subset of axes of which the 

1076 gradient is calculated 

1077 

1078 >>> np.gradient(np.array([[1, 2, 6], [3, 4, 5]], dtype=float), axis=0) 

1079 array([[ 2., 2., -1.], 

1080 [ 2., 2., -1.]]) 

1081 

1082 Notes 

1083 ----- 

1084 Assuming that :math:`f\\in C^{3}` (i.e., :math:`f` has at least 3 continuous 

1085 derivatives) and let :math:`h_{*}` be a non-homogeneous stepsize, we 

1086 minimize the "consistency error" :math:`\\eta_{i}` between the true gradient 

1087 and its estimate from a linear combination of the neighboring grid-points: 

1088 

1089 .. math:: 

1090 

1091 \\eta_{i} = f_{i}^{\\left(1\\right)} - 

1092 \\left[ \\alpha f\\left(x_{i}\\right) + 

1093 \\beta f\\left(x_{i} + h_{d}\\right) + 

1094 \\gamma f\\left(x_{i}-h_{s}\\right) 

1095 \\right] 

1096 

1097 By substituting :math:`f(x_{i} + h_{d})` and :math:`f(x_{i} - h_{s})` 

1098 with their Taylor series expansion, this translates into solving 

1099 the following the linear system: 

1100 

1101 .. math:: 

1102 

1103 \\left\\{ 

1104 \\begin{array}{r} 

1105 \\alpha+\\beta+\\gamma=0 \\\\ 

1106 \\beta h_{d}-\\gamma h_{s}=1 \\\\ 

1107 \\beta h_{d}^{2}+\\gamma h_{s}^{2}=0 

1108 \\end{array} 

1109 \\right. 

1110 

1111 The resulting approximation of :math:`f_{i}^{(1)}` is the following: 

1112 

1113 .. math:: 

1114 

1115 \\hat f_{i}^{(1)} = 

1116 \\frac{ 

1117 h_{s}^{2}f\\left(x_{i} + h_{d}\\right) 

1118 + \\left(h_{d}^{2} - h_{s}^{2}\\right)f\\left(x_{i}\\right) 

1119 - h_{d}^{2}f\\left(x_{i}-h_{s}\\right)} 

1120 { h_{s}h_{d}\\left(h_{d} + h_{s}\\right)} 

1121 + \\mathcal{O}\\left(\\frac{h_{d}h_{s}^{2} 

1122 + h_{s}h_{d}^{2}}{h_{d} 

1123 + h_{s}}\\right) 

1124 

1125 It is worth noting that if :math:`h_{s}=h_{d}` 

1126 (i.e., data are evenly spaced) 

1127 we find the standard second order approximation: 

1128 

1129 .. math:: 

1130 

1131 \\hat f_{i}^{(1)}= 

1132 \\frac{f\\left(x_{i+1}\\right) - f\\left(x_{i-1}\\right)}{2h} 

1133 + \\mathcal{O}\\left(h^{2}\\right) 

1134 

1135 With a similar procedure the forward/backward approximations used for 

1136 boundaries can be derived. 

1137 

1138 References 

1139 ---------- 

1140 .. [1] Quarteroni A., Sacco R., Saleri F. (2007) Numerical Mathematics 

1141 (Texts in Applied Mathematics). New York: Springer. 

1142 .. [2] Durran D. R. (1999) Numerical Methods for Wave Equations 

1143 in Geophysical Fluid Dynamics. New York: Springer. 

1144 .. [3] Fornberg B. (1988) Generation of Finite Difference Formulas on 

1145 Arbitrarily Spaced Grids, 

1146 Mathematics of Computation 51, no. 184 : 699-706. 

1147 `PDF <https://www.ams.org/journals/mcom/1988-51-184/ 

1148 S0025-5718-1988-0935077-0/S0025-5718-1988-0935077-0.pdf>`_. 

1149 """ 

1150 f = np.asanyarray(f) 

1151 N = f.ndim # number of dimensions 

1152 

1153 if axis is None: 

1154 axes = tuple(range(N)) 

1155 else: 

1156 axes = _nx.normalize_axis_tuple(axis, N) 

1157 

1158 len_axes = len(axes) 

1159 n = len(varargs) 

1160 if n == 0: 

1161 # no spacing argument - use 1 in all axes 

1162 dx = [1.0] * len_axes 

1163 elif n == 1 and np.ndim(varargs[0]) == 0: 

1164 # single scalar for all axes 

1165 dx = varargs * len_axes 

1166 elif n == len_axes: 

1167 # scalar or 1d array for each axis 

1168 dx = list(varargs) 

1169 for i, distances in enumerate(dx): 

1170 distances = np.asanyarray(distances) 

1171 if distances.ndim == 0: 

1172 continue 

1173 elif distances.ndim != 1: 

1174 raise ValueError("distances must be either scalars or 1d") 

1175 if len(distances) != f.shape[axes[i]]: 

1176 raise ValueError("when 1d, distances must match " 

1177 "the length of the corresponding dimension") 

1178 if np.issubdtype(distances.dtype, np.integer): 

1179 # Convert numpy integer types to float64 to avoid modular 

1180 # arithmetic in np.diff(distances). 

1181 distances = distances.astype(np.float64) 

1182 diffx = np.diff(distances) 

1183 # if distances are constant reduce to the scalar case 

1184 # since it brings a consistent speedup 

1185 if (diffx == diffx[0]).all(): 

1186 diffx = diffx[0] 

1187 dx[i] = diffx 

1188 else: 

1189 raise TypeError("invalid number of arguments") 

1190 

1191 if edge_order > 2: 

1192 raise ValueError("'edge_order' greater than 2 not supported") 

1193 

1194 # use central differences on interior and one-sided differences on the 

1195 # endpoints. This preserves second order-accuracy over the full domain. 

1196 

1197 outvals = [] 

1198 

1199 # create slice objects --- initially all are [:, :, ..., :] 

1200 slice1 = [slice(None)]*N 

1201 slice2 = [slice(None)]*N 

1202 slice3 = [slice(None)]*N 

1203 slice4 = [slice(None)]*N 

1204 

1205 otype = f.dtype 

1206 if otype.type is np.datetime64: 

1207 # the timedelta dtype with the same unit information 

1208 otype = np.dtype(otype.name.replace('datetime', 'timedelta')) 

1209 # view as timedelta to allow addition 

1210 f = f.view(otype) 

1211 elif otype.type is np.timedelta64: 

1212 pass 

1213 elif np.issubdtype(otype, np.inexact): 

1214 pass 

1215 else: 

1216 # All other types convert to floating point. 

1217 # First check if f is a numpy integer type; if so, convert f to float64 

1218 # to avoid modular arithmetic when computing the changes in f. 

1219 if np.issubdtype(otype, np.integer): 

1220 f = f.astype(np.float64) 

1221 otype = np.float64 

1222 

1223 for axis, ax_dx in zip(axes, dx): 

1224 if f.shape[axis] < edge_order + 1: 

1225 raise ValueError( 

1226 "Shape of array too small to calculate a numerical gradient, " 

1227 "at least (edge_order + 1) elements are required.") 

1228 # result allocation 

1229 out = np.empty_like(f, dtype=otype) 

1230 

1231 # spacing for the current axis 

1232 uniform_spacing = np.ndim(ax_dx) == 0 

1233 

1234 # Numerical differentiation: 2nd order interior 

1235 slice1[axis] = slice(1, -1) 

1236 slice2[axis] = slice(None, -2) 

1237 slice3[axis] = slice(1, -1) 

1238 slice4[axis] = slice(2, None) 

1239 

1240 if uniform_spacing: 

1241 out[tuple(slice1)] = (f[tuple(slice4)] - f[tuple(slice2)]) / (2. * ax_dx) 

1242 else: 

1243 dx1 = ax_dx[0:-1] 

1244 dx2 = ax_dx[1:] 

1245 a = -(dx2)/(dx1 * (dx1 + dx2)) 

1246 b = (dx2 - dx1) / (dx1 * dx2) 

1247 c = dx1 / (dx2 * (dx1 + dx2)) 

1248 # fix the shape for broadcasting 

1249 shape = np.ones(N, dtype=int) 

1250 shape[axis] = -1 

1251 a.shape = b.shape = c.shape = shape 

1252 # 1D equivalent -- out[1:-1] = a * f[:-2] + b * f[1:-1] + c * f[2:] 

1253 out[tuple(slice1)] = a * f[tuple(slice2)] + b * f[tuple(slice3)] + c * f[tuple(slice4)] 

1254 

1255 # Numerical differentiation: 1st order edges 

1256 if edge_order == 1: 

1257 slice1[axis] = 0 

1258 slice2[axis] = 1 

1259 slice3[axis] = 0 

1260 dx_0 = ax_dx if uniform_spacing else ax_dx[0] 

1261 # 1D equivalent -- out[0] = (f[1] - f[0]) / (x[1] - x[0]) 

1262 out[tuple(slice1)] = (f[tuple(slice2)] - f[tuple(slice3)]) / dx_0 

1263 

1264 slice1[axis] = -1 

1265 slice2[axis] = -1 

1266 slice3[axis] = -2 

1267 dx_n = ax_dx if uniform_spacing else ax_dx[-1] 

1268 # 1D equivalent -- out[-1] = (f[-1] - f[-2]) / (x[-1] - x[-2]) 

1269 out[tuple(slice1)] = (f[tuple(slice2)] - f[tuple(slice3)]) / dx_n 

1270 

1271 # Numerical differentiation: 2nd order edges 

1272 else: 

1273 slice1[axis] = 0 

1274 slice2[axis] = 0 

1275 slice3[axis] = 1 

1276 slice4[axis] = 2 

1277 if uniform_spacing: 

1278 a = -1.5 / ax_dx 

1279 b = 2. / ax_dx 

1280 c = -0.5 / ax_dx 

1281 else: 

1282 dx1 = ax_dx[0] 

1283 dx2 = ax_dx[1] 

1284 a = -(2. * dx1 + dx2)/(dx1 * (dx1 + dx2)) 

1285 b = (dx1 + dx2) / (dx1 * dx2) 

1286 c = - dx1 / (dx2 * (dx1 + dx2)) 

1287 # 1D equivalent -- out[0] = a * f[0] + b * f[1] + c * f[2] 

1288 out[tuple(slice1)] = a * f[tuple(slice2)] + b * f[tuple(slice3)] + c * f[tuple(slice4)] 

1289 

1290 slice1[axis] = -1 

1291 slice2[axis] = -3 

1292 slice3[axis] = -2 

1293 slice4[axis] = -1 

1294 if uniform_spacing: 

1295 a = 0.5 / ax_dx 

1296 b = -2. / ax_dx 

1297 c = 1.5 / ax_dx 

1298 else: 

1299 dx1 = ax_dx[-2] 

1300 dx2 = ax_dx[-1] 

1301 a = (dx2) / (dx1 * (dx1 + dx2)) 

1302 b = - (dx2 + dx1) / (dx1 * dx2) 

1303 c = (2. * dx2 + dx1) / (dx2 * (dx1 + dx2)) 

1304 # 1D equivalent -- out[-1] = a * f[-3] + b * f[-2] + c * f[-1] 

1305 out[tuple(slice1)] = a * f[tuple(slice2)] + b * f[tuple(slice3)] + c * f[tuple(slice4)] 

1306 

1307 outvals.append(out) 

1308 

1309 # reset the slice object in this dimension to ":" 

1310 slice1[axis] = slice(None) 

1311 slice2[axis] = slice(None) 

1312 slice3[axis] = slice(None) 

1313 slice4[axis] = slice(None) 

1314 

1315 if len_axes == 1: 

1316 return outvals[0] 

1317 return tuple(outvals) 

1318 

1319 

1320def _diff_dispatcher(a, n=None, axis=None, prepend=None, append=None): 

1321 return (a, prepend, append) 

1322 

1323 

1324@array_function_dispatch(_diff_dispatcher) 

1325def diff(a, n=1, axis=-1, prepend=np._NoValue, append=np._NoValue): 

1326 """ 

1327 Calculate the n-th discrete difference along the given axis. 

1328 

1329 The first difference is given by ``out[i] = a[i+1] - a[i]`` along 

1330 the given axis, higher differences are calculated by using `diff` 

1331 recursively. 

1332 

1333 Parameters 

1334 ---------- 

1335 a : array_like 

1336 Input array 

1337 n : int, optional 

1338 The number of times values are differenced. If zero, the input 

1339 is returned as-is. 

1340 axis : int, optional 

1341 The axis along which the difference is taken, default is the 

1342 last axis. 

1343 prepend, append : array_like, optional 

1344 Values to prepend or append to `a` along axis prior to 

1345 performing the difference. Scalar values are expanded to 

1346 arrays with length 1 in the direction of axis and the shape 

1347 of the input array in along all other axes. Otherwise the 

1348 dimension and shape must match `a` except along axis. 

1349 

1350 .. versionadded:: 1.16.0 

1351 

1352 Returns 

1353 ------- 

1354 diff : ndarray 

1355 The n-th differences. The shape of the output is the same as `a` 

1356 except along `axis` where the dimension is smaller by `n`. The 

1357 type of the output is the same as the type of the difference 

1358 between any two elements of `a`. This is the same as the type of 

1359 `a` in most cases. A notable exception is `datetime64`, which 

1360 results in a `timedelta64` output array. 

1361 

1362 See Also 

1363 -------- 

1364 gradient, ediff1d, cumsum 

1365 

1366 Notes 

1367 ----- 

1368 Type is preserved for boolean arrays, so the result will contain 

1369 `False` when consecutive elements are the same and `True` when they 

1370 differ. 

1371 

1372 For unsigned integer arrays, the results will also be unsigned. This 

1373 should not be surprising, as the result is consistent with 

1374 calculating the difference directly: 

1375 

1376 >>> u8_arr = np.array([1, 0], dtype=np.uint8) 

1377 >>> np.diff(u8_arr) 

1378 array([255], dtype=uint8) 

1379 >>> u8_arr[1,...] - u8_arr[0,...] 

1380 255 

1381 

1382 If this is not desirable, then the array should be cast to a larger 

1383 integer type first: 

1384 

1385 >>> i16_arr = u8_arr.astype(np.int16) 

1386 >>> np.diff(i16_arr) 

1387 array([-1], dtype=int16) 

1388 

1389 Examples 

1390 -------- 

1391 >>> x = np.array([1, 2, 4, 7, 0]) 

1392 >>> np.diff(x) 

1393 array([ 1, 2, 3, -7]) 

1394 >>> np.diff(x, n=2) 

1395 array([ 1, 1, -10]) 

1396 

1397 >>> x = np.array([[1, 3, 6, 10], [0, 5, 6, 8]]) 

1398 >>> np.diff(x) 

1399 array([[2, 3, 4], 

1400 [5, 1, 2]]) 

1401 >>> np.diff(x, axis=0) 

1402 array([[-1, 2, 0, -2]]) 

1403 

1404 >>> x = np.arange('1066-10-13', '1066-10-16', dtype=np.datetime64) 

1405 >>> np.diff(x) 

1406 array([1, 1], dtype='timedelta64[D]') 

1407 

1408 """ 

1409 if n == 0: 

1410 return a 

1411 if n < 0: 

1412 raise ValueError( 

1413 "order must be non-negative but got " + repr(n)) 

1414 

1415 a = asanyarray(a) 

1416 nd = a.ndim 

1417 if nd == 0: 

1418 raise ValueError("diff requires input that is at least one dimensional") 

1419 axis = normalize_axis_index(axis, nd) 

1420 

1421 combined = [] 

1422 if prepend is not np._NoValue: 

1423 prepend = np.asanyarray(prepend) 

1424 if prepend.ndim == 0: 

1425 shape = list(a.shape) 

1426 shape[axis] = 1 

1427 prepend = np.broadcast_to(prepend, tuple(shape)) 

1428 combined.append(prepend) 

1429 

1430 combined.append(a) 

1431 

1432 if append is not np._NoValue: 

1433 append = np.asanyarray(append) 

1434 if append.ndim == 0: 

1435 shape = list(a.shape) 

1436 shape[axis] = 1 

1437 append = np.broadcast_to(append, tuple(shape)) 

1438 combined.append(append) 

1439 

1440 if len(combined) > 1: 

1441 a = np.concatenate(combined, axis) 

1442 

1443 slice1 = [slice(None)] * nd 

1444 slice2 = [slice(None)] * nd 

1445 slice1[axis] = slice(1, None) 

1446 slice2[axis] = slice(None, -1) 

1447 slice1 = tuple(slice1) 

1448 slice2 = tuple(slice2) 

1449 

1450 op = not_equal if a.dtype == np.bool else subtract 

1451 for _ in range(n): 

1452 a = op(a[slice1], a[slice2]) 

1453 

1454 return a 

1455 

1456 

1457def _interp_dispatcher(x, xp, fp, left=None, right=None, period=None): 

1458 return (x, xp, fp) 

1459 

1460 

1461@array_function_dispatch(_interp_dispatcher) 

1462def interp(x, xp, fp, left=None, right=None, period=None): 

1463 """ 

1464 One-dimensional linear interpolation for monotonically increasing sample points. 

1465 

1466 Returns the one-dimensional piecewise linear interpolant to a function 

1467 with given discrete data points (`xp`, `fp`), evaluated at `x`. 

1468 

1469 Parameters 

1470 ---------- 

1471 x : array_like 

1472 The x-coordinates at which to evaluate the interpolated values. 

1473 

1474 xp : 1-D sequence of floats 

1475 The x-coordinates of the data points, must be increasing if argument 

1476 `period` is not specified. Otherwise, `xp` is internally sorted after 

1477 normalizing the periodic boundaries with ``xp = xp % period``. 

1478 

1479 fp : 1-D sequence of float or complex 

1480 The y-coordinates of the data points, same length as `xp`. 

1481 

1482 left : optional float or complex corresponding to fp 

1483 Value to return for `x < xp[0]`, default is `fp[0]`. 

1484 

1485 right : optional float or complex corresponding to fp 

1486 Value to return for `x > xp[-1]`, default is `fp[-1]`. 

1487 

1488 period : None or float, optional 

1489 A period for the x-coordinates. This parameter allows the proper 

1490 interpolation of angular x-coordinates. Parameters `left` and `right` 

1491 are ignored if `period` is specified. 

1492 

1493 .. versionadded:: 1.10.0 

1494 

1495 Returns 

1496 ------- 

1497 y : float or complex (corresponding to fp) or ndarray 

1498 The interpolated values, same shape as `x`. 

1499 

1500 Raises 

1501 ------ 

1502 ValueError 

1503 If `xp` and `fp` have different length 

1504 If `xp` or `fp` are not 1-D sequences 

1505 If `period == 0` 

1506 

1507 See Also 

1508 -------- 

1509 scipy.interpolate 

1510 

1511 Warnings 

1512 -------- 

1513 The x-coordinate sequence is expected to be increasing, but this is not 

1514 explicitly enforced. However, if the sequence `xp` is non-increasing, 

1515 interpolation results are meaningless. 

1516 

1517 Note that, since NaN is unsortable, `xp` also cannot contain NaNs. 

1518 

1519 A simple check for `xp` being strictly increasing is:: 

1520 

1521 np.all(np.diff(xp) > 0) 

1522 

1523 Examples 

1524 -------- 

1525 >>> xp = [1, 2, 3] 

1526 >>> fp = [3, 2, 0] 

1527 >>> np.interp(2.5, xp, fp) 

1528 1.0 

1529 >>> np.interp([0, 1, 1.5, 2.72, 3.14], xp, fp) 

1530 array([3. , 3. , 2.5 , 0.56, 0. ]) 

1531 >>> UNDEF = -99.0 

1532 >>> np.interp(3.14, xp, fp, right=UNDEF) 

1533 -99.0 

1534 

1535 Plot an interpolant to the sine function: 

1536 

1537 >>> x = np.linspace(0, 2*np.pi, 10) 

1538 >>> y = np.sin(x) 

1539 >>> xvals = np.linspace(0, 2*np.pi, 50) 

1540 >>> yinterp = np.interp(xvals, x, y) 

1541 >>> import matplotlib.pyplot as plt 

1542 >>> plt.plot(x, y, 'o') 

1543 [<matplotlib.lines.Line2D object at 0x...>] 

1544 >>> plt.plot(xvals, yinterp, '-x') 

1545 [<matplotlib.lines.Line2D object at 0x...>] 

1546 >>> plt.show() 

1547 

1548 Interpolation with periodic x-coordinates: 

1549 

1550 >>> x = [-180, -170, -185, 185, -10, -5, 0, 365] 

1551 >>> xp = [190, -190, 350, -350] 

1552 >>> fp = [5, 10, 3, 4] 

1553 >>> np.interp(x, xp, fp, period=360) 

1554 array([7.5 , 5. , 8.75, 6.25, 3. , 3.25, 3.5 , 3.75]) 

1555 

1556 Complex interpolation: 

1557 

1558 >>> x = [1.5, 4.0] 

1559 >>> xp = [2,3,5] 

1560 >>> fp = [1.0j, 0, 2+3j] 

1561 >>> np.interp(x, xp, fp) 

1562 array([0.+1.j , 1.+1.5j]) 

1563 

1564 """ 

1565 

1566 fp = np.asarray(fp) 

1567 

1568 if np.iscomplexobj(fp): 

1569 interp_func = compiled_interp_complex 

1570 input_dtype = np.complex128 

1571 else: 

1572 interp_func = compiled_interp 

1573 input_dtype = np.float64 

1574 

1575 if period is not None: 

1576 if period == 0: 

1577 raise ValueError("period must be a non-zero value") 

1578 period = abs(period) 

1579 left = None 

1580 right = None 

1581 

1582 x = np.asarray(x, dtype=np.float64) 

1583 xp = np.asarray(xp, dtype=np.float64) 

1584 fp = np.asarray(fp, dtype=input_dtype) 

1585 

1586 if xp.ndim != 1 or fp.ndim != 1: 

1587 raise ValueError("Data points must be 1-D sequences") 

1588 if xp.shape[0] != fp.shape[0]: 

1589 raise ValueError("fp and xp are not of the same length") 

1590 # normalizing periodic boundaries 

1591 x = x % period 

1592 xp = xp % period 

1593 asort_xp = np.argsort(xp) 

1594 xp = xp[asort_xp] 

1595 fp = fp[asort_xp] 

1596 xp = np.concatenate((xp[-1:]-period, xp, xp[0:1]+period)) 

1597 fp = np.concatenate((fp[-1:], fp, fp[0:1])) 

1598 

1599 return interp_func(x, xp, fp, left, right) 

1600 

1601 

1602def _angle_dispatcher(z, deg=None): 

1603 return (z,) 

1604 

1605 

1606@array_function_dispatch(_angle_dispatcher) 

1607def angle(z, deg=False): 

1608 """ 

1609 Return the angle of the complex argument. 

1610 

1611 Parameters 

1612 ---------- 

1613 z : array_like 

1614 A complex number or sequence of complex numbers. 

1615 deg : bool, optional 

1616 Return angle in degrees if True, radians if False (default). 

1617 

1618 Returns 

1619 ------- 

1620 angle : ndarray or scalar 

1621 The counterclockwise angle from the positive real axis on the complex 

1622 plane in the range ``(-pi, pi]``, with dtype as numpy.float64. 

1623 

1624 .. versionchanged:: 1.16.0 

1625 This function works on subclasses of ndarray like `ma.array`. 

1626 

1627 See Also 

1628 -------- 

1629 arctan2 

1630 absolute 

1631 

1632 Notes 

1633 ----- 

1634 This function passes the imaginary and real parts of the argument to 

1635 `arctan2` to compute the result; consequently, it follows the convention 

1636 of `arctan2` when the magnitude of the argument is zero. See example. 

1637 

1638 Examples 

1639 -------- 

1640 >>> np.angle([1.0, 1.0j, 1+1j]) # in radians 

1641 array([ 0. , 1.57079633, 0.78539816]) # may vary 

1642 >>> np.angle(1+1j, deg=True) # in degrees 

1643 45.0 

1644 >>> np.angle([0., -0., complex(0., -0.), complex(-0., -0.)]) # convention 

1645 array([ 0. , 3.14159265, -0. , -3.14159265]) 

1646 

1647 """ 

1648 z = asanyarray(z) 

1649 if issubclass(z.dtype.type, _nx.complexfloating): 

1650 zimag = z.imag 

1651 zreal = z.real 

1652 else: 

1653 zimag = 0 

1654 zreal = z 

1655 

1656 a = arctan2(zimag, zreal) 

1657 if deg: 

1658 a *= 180/pi 

1659 return a 

1660 

1661 

1662def _unwrap_dispatcher(p, discont=None, axis=None, *, period=None): 

1663 return (p,) 

1664 

1665 

1666@array_function_dispatch(_unwrap_dispatcher) 

1667def unwrap(p, discont=None, axis=-1, *, period=2*pi): 

1668 r""" 

1669 Unwrap by taking the complement of large deltas with respect to the period. 

1670 

1671 This unwraps a signal `p` by changing elements which have an absolute 

1672 difference from their predecessor of more than ``max(discont, period/2)`` 

1673 to their `period`-complementary values. 

1674 

1675 For the default case where `period` is :math:`2\pi` and `discont` is 

1676 :math:`\pi`, this unwraps a radian phase `p` such that adjacent differences 

1677 are never greater than :math:`\pi` by adding :math:`2k\pi` for some 

1678 integer :math:`k`. 

1679 

1680 Parameters 

1681 ---------- 

1682 p : array_like 

1683 Input array. 

1684 discont : float, optional 

1685 Maximum discontinuity between values, default is ``period/2``. 

1686 Values below ``period/2`` are treated as if they were ``period/2``. 

1687 To have an effect different from the default, `discont` should be 

1688 larger than ``period/2``. 

1689 axis : int, optional 

1690 Axis along which unwrap will operate, default is the last axis. 

1691 period : float, optional 

1692 Size of the range over which the input wraps. By default, it is 

1693 ``2 pi``. 

1694 

1695 .. versionadded:: 1.21.0 

1696 

1697 Returns 

1698 ------- 

1699 out : ndarray 

1700 Output array. 

1701 

1702 See Also 

1703 -------- 

1704 rad2deg, deg2rad 

1705 

1706 Notes 

1707 ----- 

1708 If the discontinuity in `p` is smaller than ``period/2``, 

1709 but larger than `discont`, no unwrapping is done because taking 

1710 the complement would only make the discontinuity larger. 

1711 

1712 Examples 

1713 -------- 

1714 >>> phase = np.linspace(0, np.pi, num=5) 

1715 >>> phase[3:] += np.pi 

1716 >>> phase 

1717 array([ 0. , 0.78539816, 1.57079633, 5.49778714, 6.28318531]) # may vary 

1718 >>> np.unwrap(phase) 

1719 array([ 0. , 0.78539816, 1.57079633, -0.78539816, 0. ]) # may vary 

1720 >>> np.unwrap([0, 1, 2, -1, 0], period=4) 

1721 array([0, 1, 2, 3, 4]) 

1722 >>> np.unwrap([ 1, 2, 3, 4, 5, 6, 1, 2, 3], period=6) 

1723 array([1, 2, 3, 4, 5, 6, 7, 8, 9]) 

1724 >>> np.unwrap([2, 3, 4, 5, 2, 3, 4, 5], period=4) 

1725 array([2, 3, 4, 5, 6, 7, 8, 9]) 

1726 >>> phase_deg = np.mod(np.linspace(0 ,720, 19), 360) - 180 

1727 >>> np.unwrap(phase_deg, period=360) 

1728 array([-180., -140., -100., -60., -20., 20., 60., 100., 140., 

1729 180., 220., 260., 300., 340., 380., 420., 460., 500., 

1730 540.]) 

1731 """ 

1732 p = asarray(p) 

1733 nd = p.ndim 

1734 dd = diff(p, axis=axis) 

1735 if discont is None: 

1736 discont = period/2 

1737 slice1 = [slice(None, None)]*nd # full slices 

1738 slice1[axis] = slice(1, None) 

1739 slice1 = tuple(slice1) 

1740 dtype = np.result_type(dd, period) 

1741 if _nx.issubdtype(dtype, _nx.integer): 

1742 interval_high, rem = divmod(period, 2) 

1743 boundary_ambiguous = rem == 0 

1744 else: 

1745 interval_high = period / 2 

1746 boundary_ambiguous = True 

1747 interval_low = -interval_high 

1748 ddmod = mod(dd - interval_low, period) + interval_low 

1749 if boundary_ambiguous: 

1750 # for `mask = (abs(dd) == period/2)`, the above line made 

1751 # `ddmod[mask] == -period/2`. correct these such that 

1752 # `ddmod[mask] == sign(dd[mask])*period/2`. 

1753 _nx.copyto(ddmod, interval_high, 

1754 where=(ddmod == interval_low) & (dd > 0)) 

1755 ph_correct = ddmod - dd 

1756 _nx.copyto(ph_correct, 0, where=abs(dd) < discont) 

1757 up = array(p, copy=True, dtype=dtype) 

1758 up[slice1] = p[slice1] + ph_correct.cumsum(axis) 

1759 return up 

1760 

1761 

1762def _sort_complex(a): 

1763 return (a,) 

1764 

1765 

1766@array_function_dispatch(_sort_complex) 

1767def sort_complex(a): 

1768 """ 

1769 Sort a complex array using the real part first, then the imaginary part. 

1770 

1771 Parameters 

1772 ---------- 

1773 a : array_like 

1774 Input array 

1775 

1776 Returns 

1777 ------- 

1778 out : complex ndarray 

1779 Always returns a sorted complex array. 

1780 

1781 Examples 

1782 -------- 

1783 >>> np.sort_complex([5, 3, 6, 2, 1]) 

1784 array([1.+0.j, 2.+0.j, 3.+0.j, 5.+0.j, 6.+0.j]) 

1785 

1786 >>> np.sort_complex([1 + 2j, 2 - 1j, 3 - 2j, 3 - 3j, 3 + 5j]) 

1787 array([1.+2.j, 2.-1.j, 3.-3.j, 3.-2.j, 3.+5.j]) 

1788 

1789 """ 

1790 b = array(a, copy=True) 

1791 b.sort() 

1792 if not issubclass(b.dtype.type, _nx.complexfloating): 

1793 if b.dtype.char in 'bhBH': 

1794 return b.astype('F') 

1795 elif b.dtype.char == 'g': 

1796 return b.astype('G') 

1797 else: 

1798 return b.astype('D') 

1799 else: 

1800 return b 

1801 

1802 

1803def _trim_zeros(filt, trim=None): 

1804 return (filt,) 

1805 

1806 

1807@array_function_dispatch(_trim_zeros) 

1808def trim_zeros(filt, trim='fb'): 

1809 """ 

1810 Trim the leading and/or trailing zeros from a 1-D array or sequence. 

1811 

1812 Parameters 

1813 ---------- 

1814 filt : 1-D array or sequence 

1815 Input array. 

1816 trim : str, optional 

1817 A string with 'f' representing trim from front and 'b' to trim from 

1818 back. Default is 'fb', trim zeros from both front and back of the 

1819 array. 

1820 

1821 Returns 

1822 ------- 

1823 trimmed : 1-D array or sequence 

1824 The result of trimming the input. The input data type is preserved. 

1825 

1826 Examples 

1827 -------- 

1828 >>> a = np.array((0, 0, 0, 1, 2, 3, 0, 2, 1, 0)) 

1829 >>> np.trim_zeros(a) 

1830 array([1, 2, 3, 0, 2, 1]) 

1831 

1832 >>> np.trim_zeros(a, 'b') 

1833 array([0, 0, 0, ..., 0, 2, 1]) 

1834 

1835 The input data type is preserved, list/tuple in means list/tuple out. 

1836 

1837 >>> np.trim_zeros([0, 1, 2, 0]) 

1838 [1, 2] 

1839 

1840 """ 

1841 

1842 first = 0 

1843 trim = trim.upper() 

1844 if 'F' in trim: 

1845 for i in filt: 

1846 if i != 0.: 

1847 break 

1848 else: 

1849 first = first + 1 

1850 last = len(filt) 

1851 if 'B' in trim: 

1852 for i in filt[::-1]: 

1853 if i != 0.: 

1854 break 

1855 else: 

1856 last = last - 1 

1857 return filt[first:last] 

1858 

1859 

1860def _extract_dispatcher(condition, arr): 

1861 return (condition, arr) 

1862 

1863 

1864@array_function_dispatch(_extract_dispatcher) 

1865def extract(condition, arr): 

1866 """ 

1867 Return the elements of an array that satisfy some condition. 

1868 

1869 This is equivalent to ``np.compress(ravel(condition), ravel(arr))``. If 

1870 `condition` is boolean ``np.extract`` is equivalent to ``arr[condition]``. 

1871 

1872 Note that `place` does the exact opposite of `extract`. 

1873 

1874 Parameters 

1875 ---------- 

1876 condition : array_like 

1877 An array whose nonzero or True entries indicate the elements of `arr` 

1878 to extract. 

1879 arr : array_like 

1880 Input array of the same size as `condition`. 

1881 

1882 Returns 

1883 ------- 

1884 extract : ndarray 

1885 Rank 1 array of values from `arr` where `condition` is True. 

1886 

1887 See Also 

1888 -------- 

1889 take, put, copyto, compress, place 

1890 

1891 Examples 

1892 -------- 

1893 >>> arr = np.arange(12).reshape((3, 4)) 

1894 >>> arr 

1895 array([[ 0, 1, 2, 3], 

1896 [ 4, 5, 6, 7], 

1897 [ 8, 9, 10, 11]]) 

1898 >>> condition = np.mod(arr, 3)==0 

1899 >>> condition 

1900 array([[ True, False, False, True], 

1901 [False, False, True, False], 

1902 [False, True, False, False]]) 

1903 >>> np.extract(condition, arr) 

1904 array([0, 3, 6, 9]) 

1905 

1906 

1907 If `condition` is boolean: 

1908 

1909 >>> arr[condition] 

1910 array([0, 3, 6, 9]) 

1911 

1912 """ 

1913 return _nx.take(ravel(arr), nonzero(ravel(condition))[0]) 

1914 

1915 

1916def _place_dispatcher(arr, mask, vals): 

1917 return (arr, mask, vals) 

1918 

1919 

1920@array_function_dispatch(_place_dispatcher) 

1921def place(arr, mask, vals): 

1922 """ 

1923 Change elements of an array based on conditional and input values. 

1924 

1925 Similar to ``np.copyto(arr, vals, where=mask)``, the difference is that 

1926 `place` uses the first N elements of `vals`, where N is the number of 

1927 True values in `mask`, while `copyto` uses the elements where `mask` 

1928 is True. 

1929 

1930 Note that `extract` does the exact opposite of `place`. 

1931 

1932 Parameters 

1933 ---------- 

1934 arr : ndarray 

1935 Array to put data into. 

1936 mask : array_like 

1937 Boolean mask array. Must have the same size as `a`. 

1938 vals : 1-D sequence 

1939 Values to put into `a`. Only the first N elements are used, where 

1940 N is the number of True values in `mask`. If `vals` is smaller 

1941 than N, it will be repeated, and if elements of `a` are to be masked, 

1942 this sequence must be non-empty. 

1943 

1944 See Also 

1945 -------- 

1946 copyto, put, take, extract 

1947 

1948 Examples 

1949 -------- 

1950 >>> arr = np.arange(6).reshape(2, 3) 

1951 >>> np.place(arr, arr>2, [44, 55]) 

1952 >>> arr 

1953 array([[ 0, 1, 2], 

1954 [44, 55, 44]]) 

1955 

1956 """ 

1957 return _place(arr, mask, vals) 

1958 

1959 

1960def disp(mesg, device=None, linefeed=True): 

1961 """ 

1962 Display a message on a device. 

1963 

1964 .. deprecated:: 2.0 

1965 Use your own printing function instead. 

1966 

1967 Parameters 

1968 ---------- 

1969 mesg : str 

1970 Message to display. 

1971 device : object 

1972 Device to write message. If None, defaults to ``sys.stdout`` which is 

1973 very similar to ``print``. `device` needs to have ``write()`` and 

1974 ``flush()`` methods. 

1975 linefeed : bool, optional 

1976 Option whether to print a line feed or not. Defaults to True. 

1977 

1978 Raises 

1979 ------ 

1980 AttributeError 

1981 If `device` does not have a ``write()`` or ``flush()`` method. 

1982 

1983 Examples 

1984 -------- 

1985 Besides ``sys.stdout``, a file-like object can also be used as it has 

1986 both required methods: 

1987 

1988 >>> from io import StringIO 

1989 >>> buf = StringIO() 

1990 >>> np.disp('"Display" in a file', device=buf) 

1991 >>> buf.getvalue() 

1992 '"Display" in a file\\n' 

1993 

1994 """ 

1995 

1996 # Deprecated in NumPy 2.0, 2023-07-11 

1997 warnings.warn( 

1998 "`disp` is deprecated, " 

1999 "use your own printing function instead. " 

2000 "(deprecated in NumPy 2.0)", 

2001 DeprecationWarning, 

2002 stacklevel=2 

2003 ) 

2004 

2005 if device is None: 

2006 device = sys.stdout 

2007 if linefeed: 

2008 device.write('%s\n' % mesg) 

2009 else: 

2010 device.write('%s' % mesg) 

2011 device.flush() 

2012 return 

2013 

2014 

2015# See https://docs.scipy.org/doc/numpy/reference/c-api.generalized-ufuncs.html 

2016_DIMENSION_NAME = r'\w+' 

2017_CORE_DIMENSION_LIST = '(?:{0:}(?:,{0:})*)?'.format(_DIMENSION_NAME) 

2018_ARGUMENT = r'\({}\)'.format(_CORE_DIMENSION_LIST) 

2019_ARGUMENT_LIST = '{0:}(?:,{0:})*'.format(_ARGUMENT) 

2020_SIGNATURE = '^{0:}->{0:}$'.format(_ARGUMENT_LIST) 

2021 

2022 

2023def _parse_gufunc_signature(signature): 

2024 """ 

2025 Parse string signatures for a generalized universal function. 

2026 

2027 Arguments 

2028 --------- 

2029 signature : string 

2030 Generalized universal function signature, e.g., ``(m,n),(n,p)->(m,p)`` 

2031 for ``np.matmul``. 

2032 

2033 Returns 

2034 ------- 

2035 Tuple of input and output core dimensions parsed from the signature, each 

2036 of the form List[Tuple[str, ...]]. 

2037 """ 

2038 signature = re.sub(r'\s+', '', signature) 

2039 

2040 if not re.match(_SIGNATURE, signature): 

2041 raise ValueError( 

2042 'not a valid gufunc signature: {}'.format(signature)) 

2043 return tuple([tuple(re.findall(_DIMENSION_NAME, arg)) 

2044 for arg in re.findall(_ARGUMENT, arg_list)] 

2045 for arg_list in signature.split('->')) 

2046 

2047 

2048def _update_dim_sizes(dim_sizes, arg, core_dims): 

2049 """ 

2050 Incrementally check and update core dimension sizes for a single argument. 

2051 

2052 Arguments 

2053 --------- 

2054 dim_sizes : Dict[str, int] 

2055 Sizes of existing core dimensions. Will be updated in-place. 

2056 arg : ndarray 

2057 Argument to examine. 

2058 core_dims : Tuple[str, ...] 

2059 Core dimensions for this argument. 

2060 """ 

2061 if not core_dims: 

2062 return 

2063 

2064 num_core_dims = len(core_dims) 

2065 if arg.ndim < num_core_dims: 

2066 raise ValueError( 

2067 '%d-dimensional argument does not have enough ' 

2068 'dimensions for all core dimensions %r' 

2069 % (arg.ndim, core_dims)) 

2070 

2071 core_shape = arg.shape[-num_core_dims:] 

2072 for dim, size in zip(core_dims, core_shape): 

2073 if dim in dim_sizes: 

2074 if size != dim_sizes[dim]: 

2075 raise ValueError( 

2076 'inconsistent size for core dimension %r: %r vs %r' 

2077 % (dim, size, dim_sizes[dim])) 

2078 else: 

2079 dim_sizes[dim] = size 

2080 

2081 

2082def _parse_input_dimensions(args, input_core_dims): 

2083 """ 

2084 Parse broadcast and core dimensions for vectorize with a signature. 

2085 

2086 Arguments 

2087 --------- 

2088 args : Tuple[ndarray, ...] 

2089 Tuple of input arguments to examine. 

2090 input_core_dims : List[Tuple[str, ...]] 

2091 List of core dimensions corresponding to each input. 

2092 

2093 Returns 

2094 ------- 

2095 broadcast_shape : Tuple[int, ...] 

2096 Common shape to broadcast all non-core dimensions to. 

2097 dim_sizes : Dict[str, int] 

2098 Common sizes for named core dimensions. 

2099 """ 

2100 broadcast_args = [] 

2101 dim_sizes = {} 

2102 for arg, core_dims in zip(args, input_core_dims): 

2103 _update_dim_sizes(dim_sizes, arg, core_dims) 

2104 ndim = arg.ndim - len(core_dims) 

2105 dummy_array = np.lib.stride_tricks.as_strided(0, arg.shape[:ndim]) 

2106 broadcast_args.append(dummy_array) 

2107 broadcast_shape = np.lib._stride_tricks_impl._broadcast_shape( 

2108 *broadcast_args 

2109 ) 

2110 return broadcast_shape, dim_sizes 

2111 

2112 

2113def _calculate_shapes(broadcast_shape, dim_sizes, list_of_core_dims): 

2114 """Helper for calculating broadcast shapes with core dimensions.""" 

2115 return [broadcast_shape + tuple(dim_sizes[dim] for dim in core_dims) 

2116 for core_dims in list_of_core_dims] 

2117 

2118 

2119def _create_arrays(broadcast_shape, dim_sizes, list_of_core_dims, dtypes, 

2120 results=None): 

2121 """Helper for creating output arrays in vectorize.""" 

2122 shapes = _calculate_shapes(broadcast_shape, dim_sizes, list_of_core_dims) 

2123 if dtypes is None: 

2124 dtypes = [None] * len(shapes) 

2125 if results is None: 

2126 arrays = tuple(np.empty(shape=shape, dtype=dtype) 

2127 for shape, dtype in zip(shapes, dtypes)) 

2128 else: 

2129 arrays = tuple(np.empty_like(result, shape=shape, dtype=dtype) 

2130 for result, shape, dtype 

2131 in zip(results, shapes, dtypes)) 

2132 return arrays 

2133 

2134 

2135@set_module('numpy') 

2136class vectorize: 

2137 """ 

2138 vectorize(pyfunc=np._NoValue, otypes=None, doc=None, excluded=None, 

2139 cache=False, signature=None) 

2140 

2141 Returns an object that acts like pyfunc, but takes arrays as input. 

2142 

2143 Define a vectorized function which takes a nested sequence of objects or 

2144 numpy arrays as inputs and returns a single numpy array or a tuple of numpy 

2145 arrays. The vectorized function evaluates `pyfunc` over successive tuples 

2146 of the input arrays like the python map function, except it uses the 

2147 broadcasting rules of numpy. 

2148 

2149 The data type of the output of `vectorized` is determined by calling 

2150 the function with the first element of the input. This can be avoided 

2151 by specifying the `otypes` argument. 

2152 

2153 Parameters 

2154 ---------- 

2155 pyfunc : callable, optional 

2156 A python function or method. 

2157 Can be omitted to produce a decorator with keyword arguments. 

2158 otypes : str or list of dtypes, optional 

2159 The output data type. It must be specified as either a string of 

2160 typecode characters or a list of data type specifiers. There should 

2161 be one data type specifier for each output. 

2162 doc : str, optional 

2163 The docstring for the function. If None, the docstring will be the 

2164 ``pyfunc.__doc__``. 

2165 excluded : set, optional 

2166 Set of strings or integers representing the positional or keyword 

2167 arguments for which the function will not be vectorized. These will be 

2168 passed directly to `pyfunc` unmodified. 

2169 

2170 .. versionadded:: 1.7.0 

2171 

2172 cache : bool, optional 

2173 If `True`, then cache the first function call that determines the number 

2174 of outputs if `otypes` is not provided. 

2175 

2176 .. versionadded:: 1.7.0 

2177 

2178 signature : string, optional 

2179 Generalized universal function signature, e.g., ``(m,n),(n)->(m)`` for 

2180 vectorized matrix-vector multiplication. If provided, ``pyfunc`` will 

2181 be called with (and expected to return) arrays with shapes given by the 

2182 size of corresponding core dimensions. By default, ``pyfunc`` is 

2183 assumed to take scalars as input and output. 

2184 

2185 .. versionadded:: 1.12.0 

2186 

2187 Returns 

2188 ------- 

2189 out : callable 

2190 A vectorized function if ``pyfunc`` was provided, 

2191 a decorator otherwise. 

2192 

2193 See Also 

2194 -------- 

2195 frompyfunc : Takes an arbitrary Python function and returns a ufunc 

2196 

2197 Notes 

2198 ----- 

2199 The `vectorize` function is provided primarily for convenience, not for 

2200 performance. The implementation is essentially a for loop. 

2201 

2202 If `otypes` is not specified, then a call to the function with the 

2203 first argument will be used to determine the number of outputs. The 

2204 results of this call will be cached if `cache` is `True` to prevent 

2205 calling the function twice. However, to implement the cache, the 

2206 original function must be wrapped which will slow down subsequent 

2207 calls, so only do this if your function is expensive. 

2208 

2209 The new keyword argument interface and `excluded` argument support 

2210 further degrades performance. 

2211 

2212 References 

2213 ---------- 

2214 .. [1] :doc:`/reference/c-api/generalized-ufuncs` 

2215 

2216 Examples 

2217 -------- 

2218 >>> def myfunc(a, b): 

2219 ... "Return a-b if a>b, otherwise return a+b" 

2220 ... if a > b: 

2221 ... return a - b 

2222 ... else: 

2223 ... return a + b 

2224 

2225 >>> vfunc = np.vectorize(myfunc) 

2226 >>> vfunc([1, 2, 3, 4], 2) 

2227 array([3, 4, 1, 2]) 

2228 

2229 The docstring is taken from the input function to `vectorize` unless it 

2230 is specified: 

2231 

2232 >>> vfunc.__doc__ 

2233 'Return a-b if a>b, otherwise return a+b' 

2234 >>> vfunc = np.vectorize(myfunc, doc='Vectorized `myfunc`') 

2235 >>> vfunc.__doc__ 

2236 'Vectorized `myfunc`' 

2237 

2238 The output type is determined by evaluating the first element of the input, 

2239 unless it is specified: 

2240 

2241 >>> out = vfunc([1, 2, 3, 4], 2) 

2242 >>> type(out[0]) 

2243 <class 'numpy.int64'> 

2244 >>> vfunc = np.vectorize(myfunc, otypes=[float]) 

2245 >>> out = vfunc([1, 2, 3, 4], 2) 

2246 >>> type(out[0]) 

2247 <class 'numpy.float64'> 

2248 

2249 The `excluded` argument can be used to prevent vectorizing over certain 

2250 arguments. This can be useful for array-like arguments of a fixed length 

2251 such as the coefficients for a polynomial as in `polyval`: 

2252 

2253 >>> def mypolyval(p, x): 

2254 ... _p = list(p) 

2255 ... res = _p.pop(0) 

2256 ... while _p: 

2257 ... res = res*x + _p.pop(0) 

2258 ... return res 

2259 >>> vpolyval = np.vectorize(mypolyval, excluded=['p']) 

2260 >>> vpolyval(p=[1, 2, 3], x=[0, 1]) 

2261 array([3, 6]) 

2262 

2263 Positional arguments may also be excluded by specifying their position: 

2264 

2265 >>> vpolyval.excluded.add(0) 

2266 >>> vpolyval([1, 2, 3], x=[0, 1]) 

2267 array([3, 6]) 

2268 

2269 The `signature` argument allows for vectorizing functions that act on 

2270 non-scalar arrays of fixed length. For example, you can use it for a 

2271 vectorized calculation of Pearson correlation coefficient and its p-value: 

2272 

2273 >>> import scipy.stats 

2274 >>> pearsonr = np.vectorize(scipy.stats.pearsonr, 

2275 ... signature='(n),(n)->(),()') 

2276 >>> pearsonr([[0, 1, 2, 3]], [[1, 2, 3, 4], [4, 3, 2, 1]]) 

2277 (array([ 1., -1.]), array([ 0., 0.])) 

2278 

2279 Or for a vectorized convolution: 

2280 

2281 >>> convolve = np.vectorize(np.convolve, signature='(n),(m)->(k)') 

2282 >>> convolve(np.eye(4), [1, 2, 1]) 

2283 array([[1., 2., 1., 0., 0., 0.], 

2284 [0., 1., 2., 1., 0., 0.], 

2285 [0., 0., 1., 2., 1., 0.], 

2286 [0., 0., 0., 1., 2., 1.]]) 

2287 

2288 Decorator syntax is supported. The decorator can be called as 

2289 a function to provide keyword arguments: 

2290 

2291 >>> @np.vectorize 

2292 ... def identity(x): 

2293 ... return x 

2294 ... 

2295 >>> identity([0, 1, 2]) 

2296 array([0, 1, 2]) 

2297 >>> @np.vectorize(otypes=[float]) 

2298 ... def as_float(x): 

2299 ... return x 

2300 ... 

2301 >>> as_float([0, 1, 2]) 

2302 array([0., 1., 2.]) 

2303 """ 

2304 def __init__(self, pyfunc=np._NoValue, otypes=None, doc=None, 

2305 excluded=None, cache=False, signature=None): 

2306 

2307 if (pyfunc != np._NoValue) and (not callable(pyfunc)): 

2308 #Splitting the error message to keep 

2309 #the length below 79 characters. 

2310 part1 = "When used as a decorator, " 

2311 part2 = "only accepts keyword arguments." 

2312 raise TypeError(part1 + part2) 

2313 

2314 self.pyfunc = pyfunc 

2315 self.cache = cache 

2316 self.signature = signature 

2317 if pyfunc != np._NoValue and hasattr(pyfunc, '__name__'): 

2318 self.__name__ = pyfunc.__name__ 

2319 

2320 self._ufunc = {} # Caching to improve default performance 

2321 self._doc = None 

2322 self.__doc__ = doc 

2323 if doc is None and hasattr(pyfunc, '__doc__'): 

2324 self.__doc__ = pyfunc.__doc__ 

2325 else: 

2326 self._doc = doc 

2327 

2328 if isinstance(otypes, str): 

2329 for char in otypes: 

2330 if char not in typecodes['All']: 

2331 raise ValueError("Invalid otype specified: %s" % (char,)) 

2332 elif iterable(otypes): 

2333 otypes = [_nx.dtype(x) for x in otypes] 

2334 elif otypes is not None: 

2335 raise ValueError("Invalid otype specification") 

2336 self.otypes = otypes 

2337 

2338 # Excluded variable support 

2339 if excluded is None: 

2340 excluded = set() 

2341 self.excluded = set(excluded) 

2342 

2343 if signature is not None: 

2344 self._in_and_out_core_dims = _parse_gufunc_signature(signature) 

2345 else: 

2346 self._in_and_out_core_dims = None 

2347 

2348 def _init_stage_2(self, pyfunc, *args, **kwargs): 

2349 self.__name__ = pyfunc.__name__ 

2350 self.pyfunc = pyfunc 

2351 if self._doc is None: 

2352 self.__doc__ = pyfunc.__doc__ 

2353 else: 

2354 self.__doc__ = self._doc 

2355 

2356 def _call_as_normal(self, *args, **kwargs): 

2357 """ 

2358 Return arrays with the results of `pyfunc` broadcast (vectorized) over 

2359 `args` and `kwargs` not in `excluded`. 

2360 """ 

2361 excluded = self.excluded 

2362 if not kwargs and not excluded: 

2363 func = self.pyfunc 

2364 vargs = args 

2365 else: 

2366 # The wrapper accepts only positional arguments: we use `names` and 

2367 # `inds` to mutate `the_args` and `kwargs` to pass to the original 

2368 # function. 

2369 nargs = len(args) 

2370 

2371 names = [_n for _n in kwargs if _n not in excluded] 

2372 inds = [_i for _i in range(nargs) if _i not in excluded] 

2373 the_args = list(args) 

2374 

2375 def func(*vargs): 

2376 for _n, _i in enumerate(inds): 

2377 the_args[_i] = vargs[_n] 

2378 kwargs.update(zip(names, vargs[len(inds):])) 

2379 return self.pyfunc(*the_args, **kwargs) 

2380 

2381 vargs = [args[_i] for _i in inds] 

2382 vargs.extend([kwargs[_n] for _n in names]) 

2383 

2384 return self._vectorize_call(func=func, args=vargs) 

2385 

2386 def __call__(self, *args, **kwargs): 

2387 if self.pyfunc is np._NoValue: 

2388 self._init_stage_2(*args, **kwargs) 

2389 return self 

2390 

2391 return self._call_as_normal(*args, **kwargs) 

2392 

2393 def _get_ufunc_and_otypes(self, func, args): 

2394 """Return (ufunc, otypes).""" 

2395 # frompyfunc will fail if args is empty 

2396 if not args: 

2397 raise ValueError('args can not be empty') 

2398 

2399 if self.otypes is not None: 

2400 otypes = self.otypes 

2401 

2402 # self._ufunc is a dictionary whose keys are the number of 

2403 # arguments (i.e. len(args)) and whose values are ufuncs created 

2404 # by frompyfunc. len(args) can be different for different calls if 

2405 # self.pyfunc has parameters with default values. We only use the 

2406 # cache when func is self.pyfunc, which occurs when the call uses 

2407 # only positional arguments and no arguments are excluded. 

2408 

2409 nin = len(args) 

2410 nout = len(self.otypes) 

2411 if func is not self.pyfunc or nin not in self._ufunc: 

2412 ufunc = frompyfunc(func, nin, nout) 

2413 else: 

2414 ufunc = None # We'll get it from self._ufunc 

2415 if func is self.pyfunc: 

2416 ufunc = self._ufunc.setdefault(nin, ufunc) 

2417 else: 

2418 # Get number of outputs and output types by calling the function on 

2419 # the first entries of args. We also cache the result to prevent 

2420 # the subsequent call when the ufunc is evaluated. 

2421 # Assumes that ufunc first evaluates the 0th elements in the input 

2422 # arrays (the input values are not checked to ensure this) 

2423 args = [asarray(arg) for arg in args] 

2424 if builtins.any(arg.size == 0 for arg in args): 

2425 raise ValueError('cannot call `vectorize` on size 0 inputs ' 

2426 'unless `otypes` is set') 

2427 

2428 inputs = [arg.flat[0] for arg in args] 

2429 outputs = func(*inputs) 

2430 

2431 # Performance note: profiling indicates that -- for simple 

2432 # functions at least -- this wrapping can almost double the 

2433 # execution time. 

2434 # Hence we make it optional. 

2435 if self.cache: 

2436 _cache = [outputs] 

2437 

2438 def _func(*vargs): 

2439 if _cache: 

2440 return _cache.pop() 

2441 else: 

2442 return func(*vargs) 

2443 else: 

2444 _func = func 

2445 

2446 if isinstance(outputs, tuple): 

2447 nout = len(outputs) 

2448 else: 

2449 nout = 1 

2450 outputs = (outputs,) 

2451 

2452 otypes = ''.join([asarray(outputs[_k]).dtype.char 

2453 for _k in range(nout)]) 

2454 

2455 # Performance note: profiling indicates that creating the ufunc is 

2456 # not a significant cost compared with wrapping so it seems not 

2457 # worth trying to cache this. 

2458 ufunc = frompyfunc(_func, len(args), nout) 

2459 

2460 return ufunc, otypes 

2461 

2462 def _vectorize_call(self, func, args): 

2463 """Vectorized call to `func` over positional `args`.""" 

2464 if self.signature is not None: 

2465 res = self._vectorize_call_with_signature(func, args) 

2466 elif not args: 

2467 res = func() 

2468 else: 

2469 ufunc, otypes = self._get_ufunc_and_otypes(func=func, args=args) 

2470 

2471 # Convert args to object arrays first 

2472 inputs = [asanyarray(a, dtype=object) for a in args] 

2473 

2474 outputs = ufunc(*inputs) 

2475 

2476 if ufunc.nout == 1: 

2477 res = asanyarray(outputs, dtype=otypes[0]) 

2478 else: 

2479 res = tuple([asanyarray(x, dtype=t) 

2480 for x, t in zip(outputs, otypes)]) 

2481 return res 

2482 

2483 def _vectorize_call_with_signature(self, func, args): 

2484 """Vectorized call over positional arguments with a signature.""" 

2485 input_core_dims, output_core_dims = self._in_and_out_core_dims 

2486 

2487 if len(args) != len(input_core_dims): 

2488 raise TypeError('wrong number of positional arguments: ' 

2489 'expected %r, got %r' 

2490 % (len(input_core_dims), len(args))) 

2491 args = tuple(asanyarray(arg) for arg in args) 

2492 

2493 broadcast_shape, dim_sizes = _parse_input_dimensions( 

2494 args, input_core_dims) 

2495 input_shapes = _calculate_shapes(broadcast_shape, dim_sizes, 

2496 input_core_dims) 

2497 args = [np.broadcast_to(arg, shape, subok=True) 

2498 for arg, shape in zip(args, input_shapes)] 

2499 

2500 outputs = None 

2501 otypes = self.otypes 

2502 nout = len(output_core_dims) 

2503 

2504 for index in np.ndindex(*broadcast_shape): 

2505 results = func(*(arg[index] for arg in args)) 

2506 

2507 n_results = len(results) if isinstance(results, tuple) else 1 

2508 

2509 if nout != n_results: 

2510 raise ValueError( 

2511 'wrong number of outputs from pyfunc: expected %r, got %r' 

2512 % (nout, n_results)) 

2513 

2514 if nout == 1: 

2515 results = (results,) 

2516 

2517 if outputs is None: 

2518 for result, core_dims in zip(results, output_core_dims): 

2519 _update_dim_sizes(dim_sizes, result, core_dims) 

2520 

2521 outputs = _create_arrays(broadcast_shape, dim_sizes, 

2522 output_core_dims, otypes, results) 

2523 

2524 for output, result in zip(outputs, results): 

2525 output[index] = result 

2526 

2527 if outputs is None: 

2528 # did not call the function even once 

2529 if otypes is None: 

2530 raise ValueError('cannot call `vectorize` on size 0 inputs ' 

2531 'unless `otypes` is set') 

2532 if builtins.any(dim not in dim_sizes 

2533 for dims in output_core_dims 

2534 for dim in dims): 

2535 raise ValueError('cannot call `vectorize` with a signature ' 

2536 'including new output dimensions on size 0 ' 

2537 'inputs') 

2538 outputs = _create_arrays(broadcast_shape, dim_sizes, 

2539 output_core_dims, otypes) 

2540 

2541 return outputs[0] if nout == 1 else outputs 

2542 

2543 

2544def _cov_dispatcher(m, y=None, rowvar=None, bias=None, ddof=None, 

2545 fweights=None, aweights=None, *, dtype=None): 

2546 return (m, y, fweights, aweights) 

2547 

2548 

2549@array_function_dispatch(_cov_dispatcher) 

2550def cov(m, y=None, rowvar=True, bias=False, ddof=None, fweights=None, 

2551 aweights=None, *, dtype=None): 

2552 """ 

2553 Estimate a covariance matrix, given data and weights. 

2554 

2555 Covariance indicates the level to which two variables vary together. 

2556 If we examine N-dimensional samples, :math:`X = [x_1, x_2, ... x_N]^T`, 

2557 then the covariance matrix element :math:`C_{ij}` is the covariance of 

2558 :math:`x_i` and :math:`x_j`. The element :math:`C_{ii}` is the variance 

2559 of :math:`x_i`. 

2560 

2561 See the notes for an outline of the algorithm. 

2562 

2563 Parameters 

2564 ---------- 

2565 m : array_like 

2566 A 1-D or 2-D array containing multiple variables and observations. 

2567 Each row of `m` represents a variable, and each column a single 

2568 observation of all those variables. Also see `rowvar` below. 

2569 y : array_like, optional 

2570 An additional set of variables and observations. `y` has the same form 

2571 as that of `m`. 

2572 rowvar : bool, optional 

2573 If `rowvar` is True (default), then each row represents a 

2574 variable, with observations in the columns. Otherwise, the relationship 

2575 is transposed: each column represents a variable, while the rows 

2576 contain observations. 

2577 bias : bool, optional 

2578 Default normalization (False) is by ``(N - 1)``, where ``N`` is the 

2579 number of observations given (unbiased estimate). If `bias` is True, 

2580 then normalization is by ``N``. These values can be overridden by using 

2581 the keyword ``ddof`` in numpy versions >= 1.5. 

2582 ddof : int, optional 

2583 If not ``None`` the default value implied by `bias` is overridden. 

2584 Note that ``ddof=1`` will return the unbiased estimate, even if both 

2585 `fweights` and `aweights` are specified, and ``ddof=0`` will return 

2586 the simple average. See the notes for the details. The default value 

2587 is ``None``. 

2588 

2589 .. versionadded:: 1.5 

2590 fweights : array_like, int, optional 

2591 1-D array of integer frequency weights; the number of times each 

2592 observation vector should be repeated. 

2593 

2594 .. versionadded:: 1.10 

2595 aweights : array_like, optional 

2596 1-D array of observation vector weights. These relative weights are 

2597 typically large for observations considered "important" and smaller for 

2598 observations considered less "important". If ``ddof=0`` the array of 

2599 weights can be used to assign probabilities to observation vectors. 

2600 

2601 .. versionadded:: 1.10 

2602 dtype : data-type, optional 

2603 Data-type of the result. By default, the return data-type will have 

2604 at least `numpy.float64` precision. 

2605 

2606 .. versionadded:: 1.20 

2607 

2608 Returns 

2609 ------- 

2610 out : ndarray 

2611 The covariance matrix of the variables. 

2612 

2613 See Also 

2614 -------- 

2615 corrcoef : Normalized covariance matrix 

2616 

2617 Notes 

2618 ----- 

2619 Assume that the observations are in the columns of the observation 

2620 array `m` and let ``f = fweights`` and ``a = aweights`` for brevity. The 

2621 steps to compute the weighted covariance are as follows:: 

2622 

2623 >>> m = np.arange(10, dtype=np.float64) 

2624 >>> f = np.arange(10) * 2 

2625 >>> a = np.arange(10) ** 2. 

2626 >>> ddof = 1 

2627 >>> w = f * a 

2628 >>> v1 = np.sum(w) 

2629 >>> v2 = np.sum(w * a) 

2630 >>> m -= np.sum(m * w, axis=None, keepdims=True) / v1 

2631 >>> cov = np.dot(m * w, m.T) * v1 / (v1**2 - ddof * v2) 

2632 

2633 Note that when ``a == 1``, the normalization factor 

2634 ``v1 / (v1**2 - ddof * v2)`` goes over to ``1 / (np.sum(f) - ddof)`` 

2635 as it should. 

2636 

2637 Examples 

2638 -------- 

2639 Consider two variables, :math:`x_0` and :math:`x_1`, which 

2640 correlate perfectly, but in opposite directions: 

2641 

2642 >>> x = np.array([[0, 2], [1, 1], [2, 0]]).T 

2643 >>> x 

2644 array([[0, 1, 2], 

2645 [2, 1, 0]]) 

2646 

2647 Note how :math:`x_0` increases while :math:`x_1` decreases. The covariance 

2648 matrix shows this clearly: 

2649 

2650 >>> np.cov(x) 

2651 array([[ 1., -1.], 

2652 [-1., 1.]]) 

2653 

2654 Note that element :math:`C_{0,1}`, which shows the correlation between 

2655 :math:`x_0` and :math:`x_1`, is negative. 

2656 

2657 Further, note how `x` and `y` are combined: 

2658 

2659 >>> x = [-2.1, -1, 4.3] 

2660 >>> y = [3, 1.1, 0.12] 

2661 >>> X = np.stack((x, y), axis=0) 

2662 >>> np.cov(X) 

2663 array([[11.71 , -4.286 ], # may vary 

2664 [-4.286 , 2.144133]]) 

2665 >>> np.cov(x, y) 

2666 array([[11.71 , -4.286 ], # may vary 

2667 [-4.286 , 2.144133]]) 

2668 >>> np.cov(x) 

2669 array(11.71) 

2670 

2671 """ 

2672 # Check inputs 

2673 if ddof is not None and ddof != int(ddof): 

2674 raise ValueError( 

2675 "ddof must be integer") 

2676 

2677 # Handles complex arrays too 

2678 m = np.asarray(m) 

2679 if m.ndim > 2: 

2680 raise ValueError("m has more than 2 dimensions") 

2681 

2682 if y is not None: 

2683 y = np.asarray(y) 

2684 if y.ndim > 2: 

2685 raise ValueError("y has more than 2 dimensions") 

2686 

2687 if dtype is None: 

2688 if y is None: 

2689 dtype = np.result_type(m, np.float64) 

2690 else: 

2691 dtype = np.result_type(m, y, np.float64) 

2692 

2693 X = array(m, ndmin=2, dtype=dtype) 

2694 if not rowvar and X.shape[0] != 1: 

2695 X = X.T 

2696 if X.shape[0] == 0: 

2697 return np.array([]).reshape(0, 0) 

2698 if y is not None: 

2699 y = array(y, copy=None, ndmin=2, dtype=dtype) 

2700 if not rowvar and y.shape[0] != 1: 

2701 y = y.T 

2702 X = np.concatenate((X, y), axis=0) 

2703 

2704 if ddof is None: 

2705 if bias == 0: 

2706 ddof = 1 

2707 else: 

2708 ddof = 0 

2709 

2710 # Get the product of frequencies and weights 

2711 w = None 

2712 if fweights is not None: 

2713 fweights = np.asarray(fweights, dtype=float) 

2714 if not np.all(fweights == np.around(fweights)): 

2715 raise TypeError( 

2716 "fweights must be integer") 

2717 if fweights.ndim > 1: 

2718 raise RuntimeError( 

2719 "cannot handle multidimensional fweights") 

2720 if fweights.shape[0] != X.shape[1]: 

2721 raise RuntimeError( 

2722 "incompatible numbers of samples and fweights") 

2723 if any(fweights < 0): 

2724 raise ValueError( 

2725 "fweights cannot be negative") 

2726 w = fweights 

2727 if aweights is not None: 

2728 aweights = np.asarray(aweights, dtype=float) 

2729 if aweights.ndim > 1: 

2730 raise RuntimeError( 

2731 "cannot handle multidimensional aweights") 

2732 if aweights.shape[0] != X.shape[1]: 

2733 raise RuntimeError( 

2734 "incompatible numbers of samples and aweights") 

2735 if any(aweights < 0): 

2736 raise ValueError( 

2737 "aweights cannot be negative") 

2738 if w is None: 

2739 w = aweights 

2740 else: 

2741 w *= aweights 

2742 

2743 avg, w_sum = average(X, axis=1, weights=w, returned=True) 

2744 w_sum = w_sum[0] 

2745 

2746 # Determine the normalization 

2747 if w is None: 

2748 fact = X.shape[1] - ddof 

2749 elif ddof == 0: 

2750 fact = w_sum 

2751 elif aweights is None: 

2752 fact = w_sum - ddof 

2753 else: 

2754 fact = w_sum - ddof*sum(w*aweights)/w_sum 

2755 

2756 if fact <= 0: 

2757 warnings.warn("Degrees of freedom <= 0 for slice", 

2758 RuntimeWarning, stacklevel=2) 

2759 fact = 0.0 

2760 

2761 X -= avg[:, None] 

2762 if w is None: 

2763 X_T = X.T 

2764 else: 

2765 X_T = (X*w).T 

2766 c = dot(X, X_T.conj()) 

2767 c *= np.true_divide(1, fact) 

2768 return c.squeeze() 

2769 

2770 

2771def _corrcoef_dispatcher(x, y=None, rowvar=None, bias=None, ddof=None, *, 

2772 dtype=None): 

2773 return (x, y) 

2774 

2775 

2776@array_function_dispatch(_corrcoef_dispatcher) 

2777def corrcoef(x, y=None, rowvar=True, bias=np._NoValue, ddof=np._NoValue, *, 

2778 dtype=None): 

2779 """ 

2780 Return Pearson product-moment correlation coefficients. 

2781 

2782 Please refer to the documentation for `cov` for more detail. The 

2783 relationship between the correlation coefficient matrix, `R`, and the 

2784 covariance matrix, `C`, is 

2785 

2786 .. math:: R_{ij} = \\frac{ C_{ij} } { \\sqrt{ C_{ii} C_{jj} } } 

2787 

2788 The values of `R` are between -1 and 1, inclusive. 

2789 

2790 Parameters 

2791 ---------- 

2792 x : array_like 

2793 A 1-D or 2-D array containing multiple variables and observations. 

2794 Each row of `x` represents a variable, and each column a single 

2795 observation of all those variables. Also see `rowvar` below. 

2796 y : array_like, optional 

2797 An additional set of variables and observations. `y` has the same 

2798 shape as `x`. 

2799 rowvar : bool, optional 

2800 If `rowvar` is True (default), then each row represents a 

2801 variable, with observations in the columns. Otherwise, the relationship 

2802 is transposed: each column represents a variable, while the rows 

2803 contain observations. 

2804 bias : _NoValue, optional 

2805 Has no effect, do not use. 

2806 

2807 .. deprecated:: 1.10.0 

2808 ddof : _NoValue, optional 

2809 Has no effect, do not use. 

2810 

2811 .. deprecated:: 1.10.0 

2812 dtype : data-type, optional 

2813 Data-type of the result. By default, the return data-type will have 

2814 at least `numpy.float64` precision. 

2815 

2816 .. versionadded:: 1.20 

2817 

2818 Returns 

2819 ------- 

2820 R : ndarray 

2821 The correlation coefficient matrix of the variables. 

2822 

2823 See Also 

2824 -------- 

2825 cov : Covariance matrix 

2826 

2827 Notes 

2828 ----- 

2829 Due to floating point rounding the resulting array may not be Hermitian, 

2830 the diagonal elements may not be 1, and the elements may not satisfy the 

2831 inequality abs(a) <= 1. The real and imaginary parts are clipped to the 

2832 interval [-1, 1] in an attempt to improve on that situation but is not 

2833 much help in the complex case. 

2834 

2835 This function accepts but discards arguments `bias` and `ddof`. This is 

2836 for backwards compatibility with previous versions of this function. These 

2837 arguments had no effect on the return values of the function and can be 

2838 safely ignored in this and previous versions of numpy. 

2839 

2840 Examples 

2841 -------- 

2842 In this example we generate two random arrays, ``xarr`` and ``yarr``, and 

2843 compute the row-wise and column-wise Pearson correlation coefficients, 

2844 ``R``. Since ``rowvar`` is true by default, we first find the row-wise 

2845 Pearson correlation coefficients between the variables of ``xarr``. 

2846 

2847 >>> import numpy as np 

2848 >>> rng = np.random.default_rng(seed=42) 

2849 >>> xarr = rng.random((3, 3)) 

2850 >>> xarr 

2851 array([[0.77395605, 0.43887844, 0.85859792], 

2852 [0.69736803, 0.09417735, 0.97562235], 

2853 [0.7611397 , 0.78606431, 0.12811363]]) 

2854 >>> R1 = np.corrcoef(xarr) 

2855 >>> R1 

2856 array([[ 1. , 0.99256089, -0.68080986], 

2857 [ 0.99256089, 1. , -0.76492172], 

2858 [-0.68080986, -0.76492172, 1. ]]) 

2859 

2860 If we add another set of variables and observations ``yarr``, we can 

2861 compute the row-wise Pearson correlation coefficients between the 

2862 variables in ``xarr`` and ``yarr``. 

2863 

2864 >>> yarr = rng.random((3, 3)) 

2865 >>> yarr 

2866 array([[0.45038594, 0.37079802, 0.92676499], 

2867 [0.64386512, 0.82276161, 0.4434142 ], 

2868 [0.22723872, 0.55458479, 0.06381726]]) 

2869 >>> R2 = np.corrcoef(xarr, yarr) 

2870 >>> R2 

2871 array([[ 1. , 0.99256089, -0.68080986, 0.75008178, -0.934284 , 

2872 -0.99004057], 

2873 [ 0.99256089, 1. , -0.76492172, 0.82502011, -0.97074098, 

2874 -0.99981569], 

2875 [-0.68080986, -0.76492172, 1. , -0.99507202, 0.89721355, 

2876 0.77714685], 

2877 [ 0.75008178, 0.82502011, -0.99507202, 1. , -0.93657855, 

2878 -0.83571711], 

2879 [-0.934284 , -0.97074098, 0.89721355, -0.93657855, 1. , 

2880 0.97517215], 

2881 [-0.99004057, -0.99981569, 0.77714685, -0.83571711, 0.97517215, 

2882 1. ]]) 

2883 

2884 Finally if we use the option ``rowvar=False``, the columns are now 

2885 being treated as the variables and we will find the column-wise Pearson 

2886 correlation coefficients between variables in ``xarr`` and ``yarr``. 

2887 

2888 >>> R3 = np.corrcoef(xarr, yarr, rowvar=False) 

2889 >>> R3 

2890 array([[ 1. , 0.77598074, -0.47458546, -0.75078643, -0.9665554 , 

2891 0.22423734], 

2892 [ 0.77598074, 1. , -0.92346708, -0.99923895, -0.58826587, 

2893 -0.44069024], 

2894 [-0.47458546, -0.92346708, 1. , 0.93773029, 0.23297648, 

2895 0.75137473], 

2896 [-0.75078643, -0.99923895, 0.93773029, 1. , 0.55627469, 

2897 0.47536961], 

2898 [-0.9665554 , -0.58826587, 0.23297648, 0.55627469, 1. , 

2899 -0.46666491], 

2900 [ 0.22423734, -0.44069024, 0.75137473, 0.47536961, -0.46666491, 

2901 1. ]]) 

2902 

2903 """ 

2904 if bias is not np._NoValue or ddof is not np._NoValue: 

2905 # 2015-03-15, 1.10 

2906 warnings.warn('bias and ddof have no effect and are deprecated', 

2907 DeprecationWarning, stacklevel=2) 

2908 c = cov(x, y, rowvar, dtype=dtype) 

2909 try: 

2910 d = diag(c) 

2911 except ValueError: 

2912 # scalar covariance 

2913 # nan if incorrect value (nan, inf, 0), 1 otherwise 

2914 return c / c 

2915 stddev = sqrt(d.real) 

2916 c /= stddev[:, None] 

2917 c /= stddev[None, :] 

2918 

2919 # Clip real and imaginary parts to [-1, 1]. This does not guarantee 

2920 # abs(a[i,j]) <= 1 for complex arrays, but is the best we can do without 

2921 # excessive work. 

2922 np.clip(c.real, -1, 1, out=c.real) 

2923 if np.iscomplexobj(c): 

2924 np.clip(c.imag, -1, 1, out=c.imag) 

2925 

2926 return c 

2927 

2928 

2929@set_module('numpy') 

2930def blackman(M): 

2931 """ 

2932 Return the Blackman window. 

2933 

2934 The Blackman window is a taper formed by using the first three 

2935 terms of a summation of cosines. It was designed to have close to the 

2936 minimal leakage possible. It is close to optimal, only slightly worse 

2937 than a Kaiser window. 

2938 

2939 Parameters 

2940 ---------- 

2941 M : int 

2942 Number of points in the output window. If zero or less, an empty 

2943 array is returned. 

2944 

2945 Returns 

2946 ------- 

2947 out : ndarray 

2948 The window, with the maximum value normalized to one (the value one 

2949 appears only if the number of samples is odd). 

2950 

2951 See Also 

2952 -------- 

2953 bartlett, hamming, hanning, kaiser 

2954 

2955 Notes 

2956 ----- 

2957 The Blackman window is defined as 

2958 

2959 .. math:: w(n) = 0.42 - 0.5 \\cos(2\\pi n/M) + 0.08 \\cos(4\\pi n/M) 

2960 

2961 Most references to the Blackman window come from the signal processing 

2962 literature, where it is used as one of many windowing functions for 

2963 smoothing values. It is also known as an apodization (which means 

2964 "removing the foot", i.e. smoothing discontinuities at the beginning 

2965 and end of the sampled signal) or tapering function. It is known as a 

2966 "near optimal" tapering function, almost as good (by some measures) 

2967 as the kaiser window. 

2968 

2969 References 

2970 ---------- 

2971 Blackman, R.B. and Tukey, J.W., (1958) The measurement of power spectra, 

2972 Dover Publications, New York. 

2973 

2974 Oppenheim, A.V., and R.W. Schafer. Discrete-Time Signal Processing. 

2975 Upper Saddle River, NJ: Prentice-Hall, 1999, pp. 468-471. 

2976 

2977 Examples 

2978 -------- 

2979 >>> import matplotlib.pyplot as plt 

2980 >>> np.blackman(12) 

2981 array([-1.38777878e-17, 3.26064346e-02, 1.59903635e-01, # may vary 

2982 4.14397981e-01, 7.36045180e-01, 9.67046769e-01, 

2983 9.67046769e-01, 7.36045180e-01, 4.14397981e-01, 

2984 1.59903635e-01, 3.26064346e-02, -1.38777878e-17]) 

2985 

2986 Plot the window and the frequency response. 

2987 

2988 .. plot:: 

2989 :include-source: 

2990 

2991 import matplotlib.pyplot as plt 

2992 from numpy.fft import fft, fftshift 

2993 window = np.blackman(51) 

2994 plt.plot(window) 

2995 plt.title("Blackman window") 

2996 plt.ylabel("Amplitude") 

2997 plt.xlabel("Sample") 

2998 plt.show() # doctest: +SKIP 

2999 

3000 plt.figure() 

3001 A = fft(window, 2048) / 25.5 

3002 mag = np.abs(fftshift(A)) 

3003 freq = np.linspace(-0.5, 0.5, len(A)) 

3004 with np.errstate(divide='ignore', invalid='ignore'): 

3005 response = 20 * np.log10(mag) 

3006 response = np.clip(response, -100, 100) 

3007 plt.plot(freq, response) 

3008 plt.title("Frequency response of Blackman window") 

3009 plt.ylabel("Magnitude [dB]") 

3010 plt.xlabel("Normalized frequency [cycles per sample]") 

3011 plt.axis('tight') 

3012 plt.show() 

3013 

3014 """ 

3015 # Ensures at least float64 via 0.0. M should be an integer, but conversion 

3016 # to double is safe for a range. 

3017 values = np.array([0.0, M]) 

3018 M = values[1] 

3019 

3020 if M < 1: 

3021 return array([], dtype=values.dtype) 

3022 if M == 1: 

3023 return ones(1, dtype=values.dtype) 

3024 n = arange(1-M, M, 2) 

3025 return 0.42 + 0.5*cos(pi*n/(M-1)) + 0.08*cos(2.0*pi*n/(M-1)) 

3026 

3027 

3028@set_module('numpy') 

3029def bartlett(M): 

3030 """ 

3031 Return the Bartlett window. 

3032 

3033 The Bartlett window is very similar to a triangular window, except 

3034 that the end points are at zero. It is often used in signal 

3035 processing for tapering a signal, without generating too much 

3036 ripple in the frequency domain. 

3037 

3038 Parameters 

3039 ---------- 

3040 M : int 

3041 Number of points in the output window. If zero or less, an 

3042 empty array is returned. 

3043 

3044 Returns 

3045 ------- 

3046 out : array 

3047 The triangular window, with the maximum value normalized to one 

3048 (the value one appears only if the number of samples is odd), with 

3049 the first and last samples equal to zero. 

3050 

3051 See Also 

3052 -------- 

3053 blackman, hamming, hanning, kaiser 

3054 

3055 Notes 

3056 ----- 

3057 The Bartlett window is defined as 

3058 

3059 .. math:: w(n) = \\frac{2}{M-1} \\left( 

3060 \\frac{M-1}{2} - \\left|n - \\frac{M-1}{2}\\right| 

3061 \\right) 

3062 

3063 Most references to the Bartlett window come from the signal processing 

3064 literature, where it is used as one of many windowing functions for 

3065 smoothing values. Note that convolution with this window produces linear 

3066 interpolation. It is also known as an apodization (which means "removing 

3067 the foot", i.e. smoothing discontinuities at the beginning and end of the 

3068 sampled signal) or tapering function. The Fourier transform of the 

3069 Bartlett window is the product of two sinc functions. Note the excellent 

3070 discussion in Kanasewich [2]_. 

3071 

3072 References 

3073 ---------- 

3074 .. [1] M.S. Bartlett, "Periodogram Analysis and Continuous Spectra", 

3075 Biometrika 37, 1-16, 1950. 

3076 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", 

3077 The University of Alberta Press, 1975, pp. 109-110. 

3078 .. [3] A.V. Oppenheim and R.W. Schafer, "Discrete-Time Signal 

3079 Processing", Prentice-Hall, 1999, pp. 468-471. 

3080 .. [4] Wikipedia, "Window function", 

3081 https://en.wikipedia.org/wiki/Window_function 

3082 .. [5] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, 

3083 "Numerical Recipes", Cambridge University Press, 1986, page 429. 

3084 

3085 Examples 

3086 -------- 

3087 >>> import matplotlib.pyplot as plt 

3088 >>> np.bartlett(12) 

3089 array([ 0. , 0.18181818, 0.36363636, 0.54545455, 0.72727273, # may vary 

3090 0.90909091, 0.90909091, 0.72727273, 0.54545455, 0.36363636, 

3091 0.18181818, 0. ]) 

3092 

3093 Plot the window and its frequency response (requires SciPy and matplotlib). 

3094 

3095 .. plot:: 

3096 :include-source: 

3097 

3098 import matplotlib.pyplot as plt 

3099 from numpy.fft import fft, fftshift 

3100 window = np.bartlett(51) 

3101 plt.plot(window) 

3102 plt.title("Bartlett window") 

3103 plt.ylabel("Amplitude") 

3104 plt.xlabel("Sample") 

3105 plt.show() 

3106 plt.figure() 

3107 A = fft(window, 2048) / 25.5 

3108 mag = np.abs(fftshift(A)) 

3109 freq = np.linspace(-0.5, 0.5, len(A)) 

3110 with np.errstate(divide='ignore', invalid='ignore'): 

3111 response = 20 * np.log10(mag) 

3112 response = np.clip(response, -100, 100) 

3113 plt.plot(freq, response) 

3114 plt.title("Frequency response of Bartlett window") 

3115 plt.ylabel("Magnitude [dB]") 

3116 plt.xlabel("Normalized frequency [cycles per sample]") 

3117 plt.axis('tight') 

3118 plt.show() 

3119 

3120 """ 

3121 # Ensures at least float64 via 0.0. M should be an integer, but conversion 

3122 # to double is safe for a range. 

3123 values = np.array([0.0, M]) 

3124 M = values[1] 

3125 

3126 if M < 1: 

3127 return array([], dtype=values.dtype) 

3128 if M == 1: 

3129 return ones(1, dtype=values.dtype) 

3130 n = arange(1-M, M, 2) 

3131 return where(less_equal(n, 0), 1 + n/(M-1), 1 - n/(M-1)) 

3132 

3133 

3134@set_module('numpy') 

3135def hanning(M): 

3136 """ 

3137 Return the Hanning window. 

3138 

3139 The Hanning window is a taper formed by using a weighted cosine. 

3140 

3141 Parameters 

3142 ---------- 

3143 M : int 

3144 Number of points in the output window. If zero or less, an 

3145 empty array is returned. 

3146 

3147 Returns 

3148 ------- 

3149 out : ndarray, shape(M,) 

3150 The window, with the maximum value normalized to one (the value 

3151 one appears only if `M` is odd). 

3152 

3153 See Also 

3154 -------- 

3155 bartlett, blackman, hamming, kaiser 

3156 

3157 Notes 

3158 ----- 

3159 The Hanning window is defined as 

3160 

3161 .. math:: w(n) = 0.5 - 0.5\\cos\\left(\\frac{2\\pi{n}}{M-1}\\right) 

3162 \\qquad 0 \\leq n \\leq M-1 

3163 

3164 The Hanning was named for Julius von Hann, an Austrian meteorologist. 

3165 It is also known as the Cosine Bell. Some authors prefer that it be 

3166 called a Hann window, to help avoid confusion with the very similar 

3167 Hamming window. 

3168 

3169 Most references to the Hanning window come from the signal processing 

3170 literature, where it is used as one of many windowing functions for 

3171 smoothing values. It is also known as an apodization (which means 

3172 "removing the foot", i.e. smoothing discontinuities at the beginning 

3173 and end of the sampled signal) or tapering function. 

3174 

3175 References 

3176 ---------- 

3177 .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power 

3178 spectra, Dover Publications, New York. 

3179 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", 

3180 The University of Alberta Press, 1975, pp. 106-108. 

3181 .. [3] Wikipedia, "Window function", 

3182 https://en.wikipedia.org/wiki/Window_function 

3183 .. [4] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, 

3184 "Numerical Recipes", Cambridge University Press, 1986, page 425. 

3185 

3186 Examples 

3187 -------- 

3188 >>> np.hanning(12) 

3189 array([0. , 0.07937323, 0.29229249, 0.57115742, 0.82743037, 

3190 0.97974649, 0.97974649, 0.82743037, 0.57115742, 0.29229249, 

3191 0.07937323, 0. ]) 

3192 

3193 Plot the window and its frequency response. 

3194 

3195 .. plot:: 

3196 :include-source: 

3197 

3198 import matplotlib.pyplot as plt 

3199 from numpy.fft import fft, fftshift 

3200 window = np.hanning(51) 

3201 plt.plot(window) 

3202 plt.title("Hann window") 

3203 plt.ylabel("Amplitude") 

3204 plt.xlabel("Sample") 

3205 plt.show() 

3206 

3207 plt.figure() 

3208 A = fft(window, 2048) / 25.5 

3209 mag = np.abs(fftshift(A)) 

3210 freq = np.linspace(-0.5, 0.5, len(A)) 

3211 with np.errstate(divide='ignore', invalid='ignore'): 

3212 response = 20 * np.log10(mag) 

3213 response = np.clip(response, -100, 100) 

3214 plt.plot(freq, response) 

3215 plt.title("Frequency response of the Hann window") 

3216 plt.ylabel("Magnitude [dB]") 

3217 plt.xlabel("Normalized frequency [cycles per sample]") 

3218 plt.axis('tight') 

3219 plt.show() 

3220 

3221 """ 

3222 # Ensures at least float64 via 0.0. M should be an integer, but conversion 

3223 # to double is safe for a range. 

3224 values = np.array([0.0, M]) 

3225 M = values[1] 

3226 

3227 if M < 1: 

3228 return array([], dtype=values.dtype) 

3229 if M == 1: 

3230 return ones(1, dtype=values.dtype) 

3231 n = arange(1-M, M, 2) 

3232 return 0.5 + 0.5*cos(pi*n/(M-1)) 

3233 

3234 

3235@set_module('numpy') 

3236def hamming(M): 

3237 """ 

3238 Return the Hamming window. 

3239 

3240 The Hamming window is a taper formed by using a weighted cosine. 

3241 

3242 Parameters 

3243 ---------- 

3244 M : int 

3245 Number of points in the output window. If zero or less, an 

3246 empty array is returned. 

3247 

3248 Returns 

3249 ------- 

3250 out : ndarray 

3251 The window, with the maximum value normalized to one (the value 

3252 one appears only if the number of samples is odd). 

3253 

3254 See Also 

3255 -------- 

3256 bartlett, blackman, hanning, kaiser 

3257 

3258 Notes 

3259 ----- 

3260 The Hamming window is defined as 

3261 

3262 .. math:: w(n) = 0.54 - 0.46\\cos\\left(\\frac{2\\pi{n}}{M-1}\\right) 

3263 \\qquad 0 \\leq n \\leq M-1 

3264 

3265 The Hamming was named for R. W. Hamming, an associate of J. W. Tukey 

3266 and is described in Blackman and Tukey. It was recommended for 

3267 smoothing the truncated autocovariance function in the time domain. 

3268 Most references to the Hamming window come from the signal processing 

3269 literature, where it is used as one of many windowing functions for 

3270 smoothing values. It is also known as an apodization (which means 

3271 "removing the foot", i.e. smoothing discontinuities at the beginning 

3272 and end of the sampled signal) or tapering function. 

3273 

3274 References 

3275 ---------- 

3276 .. [1] Blackman, R.B. and Tukey, J.W., (1958) The measurement of power 

3277 spectra, Dover Publications, New York. 

3278 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", The 

3279 University of Alberta Press, 1975, pp. 109-110. 

3280 .. [3] Wikipedia, "Window function", 

3281 https://en.wikipedia.org/wiki/Window_function 

3282 .. [4] W.H. Press, B.P. Flannery, S.A. Teukolsky, and W.T. Vetterling, 

3283 "Numerical Recipes", Cambridge University Press, 1986, page 425. 

3284 

3285 Examples 

3286 -------- 

3287 >>> np.hamming(12) 

3288 array([ 0.08 , 0.15302337, 0.34890909, 0.60546483, 0.84123594, # may vary 

3289 0.98136677, 0.98136677, 0.84123594, 0.60546483, 0.34890909, 

3290 0.15302337, 0.08 ]) 

3291 

3292 Plot the window and the frequency response. 

3293 

3294 .. plot:: 

3295 :include-source: 

3296 

3297 import matplotlib.pyplot as plt 

3298 from numpy.fft import fft, fftshift 

3299 window = np.hamming(51) 

3300 plt.plot(window) 

3301 plt.title("Hamming window") 

3302 plt.ylabel("Amplitude") 

3303 plt.xlabel("Sample") 

3304 plt.show() 

3305 

3306 plt.figure() 

3307 A = fft(window, 2048) / 25.5 

3308 mag = np.abs(fftshift(A)) 

3309 freq = np.linspace(-0.5, 0.5, len(A)) 

3310 response = 20 * np.log10(mag) 

3311 response = np.clip(response, -100, 100) 

3312 plt.plot(freq, response) 

3313 plt.title("Frequency response of Hamming window") 

3314 plt.ylabel("Magnitude [dB]") 

3315 plt.xlabel("Normalized frequency [cycles per sample]") 

3316 plt.axis('tight') 

3317 plt.show() 

3318 

3319 """ 

3320 # Ensures at least float64 via 0.0. M should be an integer, but conversion 

3321 # to double is safe for a range. 

3322 values = np.array([0.0, M]) 

3323 M = values[1] 

3324 

3325 if M < 1: 

3326 return array([], dtype=values.dtype) 

3327 if M == 1: 

3328 return ones(1, dtype=values.dtype) 

3329 n = arange(1-M, M, 2) 

3330 return 0.54 + 0.46*cos(pi*n/(M-1)) 

3331 

3332 

3333## Code from cephes for i0 

3334 

3335_i0A = [ 

3336 -4.41534164647933937950E-18, 

3337 3.33079451882223809783E-17, 

3338 -2.43127984654795469359E-16, 

3339 1.71539128555513303061E-15, 

3340 -1.16853328779934516808E-14, 

3341 7.67618549860493561688E-14, 

3342 -4.85644678311192946090E-13, 

3343 2.95505266312963983461E-12, 

3344 -1.72682629144155570723E-11, 

3345 9.67580903537323691224E-11, 

3346 -5.18979560163526290666E-10, 

3347 2.65982372468238665035E-9, 

3348 -1.30002500998624804212E-8, 

3349 6.04699502254191894932E-8, 

3350 -2.67079385394061173391E-7, 

3351 1.11738753912010371815E-6, 

3352 -4.41673835845875056359E-6, 

3353 1.64484480707288970893E-5, 

3354 -5.75419501008210370398E-5, 

3355 1.88502885095841655729E-4, 

3356 -5.76375574538582365885E-4, 

3357 1.63947561694133579842E-3, 

3358 -4.32430999505057594430E-3, 

3359 1.05464603945949983183E-2, 

3360 -2.37374148058994688156E-2, 

3361 4.93052842396707084878E-2, 

3362 -9.49010970480476444210E-2, 

3363 1.71620901522208775349E-1, 

3364 -3.04682672343198398683E-1, 

3365 6.76795274409476084995E-1 

3366 ] 

3367 

3368_i0B = [ 

3369 -7.23318048787475395456E-18, 

3370 -4.83050448594418207126E-18, 

3371 4.46562142029675999901E-17, 

3372 3.46122286769746109310E-17, 

3373 -2.82762398051658348494E-16, 

3374 -3.42548561967721913462E-16, 

3375 1.77256013305652638360E-15, 

3376 3.81168066935262242075E-15, 

3377 -9.55484669882830764870E-15, 

3378 -4.15056934728722208663E-14, 

3379 1.54008621752140982691E-14, 

3380 3.85277838274214270114E-13, 

3381 7.18012445138366623367E-13, 

3382 -1.79417853150680611778E-12, 

3383 -1.32158118404477131188E-11, 

3384 -3.14991652796324136454E-11, 

3385 1.18891471078464383424E-11, 

3386 4.94060238822496958910E-10, 

3387 3.39623202570838634515E-9, 

3388 2.26666899049817806459E-8, 

3389 2.04891858946906374183E-7, 

3390 2.89137052083475648297E-6, 

3391 6.88975834691682398426E-5, 

3392 3.36911647825569408990E-3, 

3393 8.04490411014108831608E-1 

3394 ] 

3395 

3396 

3397def _chbevl(x, vals): 

3398 b0 = vals[0] 

3399 b1 = 0.0 

3400 

3401 for i in range(1, len(vals)): 

3402 b2 = b1 

3403 b1 = b0 

3404 b0 = x*b1 - b2 + vals[i] 

3405 

3406 return 0.5*(b0 - b2) 

3407 

3408 

3409def _i0_1(x): 

3410 return exp(x) * _chbevl(x/2.0-2, _i0A) 

3411 

3412 

3413def _i0_2(x): 

3414 return exp(x) * _chbevl(32.0/x - 2.0, _i0B) / sqrt(x) 

3415 

3416 

3417def _i0_dispatcher(x): 

3418 return (x,) 

3419 

3420 

3421@array_function_dispatch(_i0_dispatcher) 

3422def i0(x): 

3423 """ 

3424 Modified Bessel function of the first kind, order 0. 

3425 

3426 Usually denoted :math:`I_0`. 

3427 

3428 Parameters 

3429 ---------- 

3430 x : array_like of float 

3431 Argument of the Bessel function. 

3432 

3433 Returns 

3434 ------- 

3435 out : ndarray, shape = x.shape, dtype = float 

3436 The modified Bessel function evaluated at each of the elements of `x`. 

3437 

3438 See Also 

3439 -------- 

3440 scipy.special.i0, scipy.special.iv, scipy.special.ive 

3441 

3442 Notes 

3443 ----- 

3444 The scipy implementation is recommended over this function: it is a 

3445 proper ufunc written in C, and more than an order of magnitude faster. 

3446 

3447 We use the algorithm published by Clenshaw [1]_ and referenced by 

3448 Abramowitz and Stegun [2]_, for which the function domain is 

3449 partitioned into the two intervals [0,8] and (8,inf), and Chebyshev 

3450 polynomial expansions are employed in each interval. Relative error on 

3451 the domain [0,30] using IEEE arithmetic is documented [3]_ as having a 

3452 peak of 5.8e-16 with an rms of 1.4e-16 (n = 30000). 

3453 

3454 References 

3455 ---------- 

3456 .. [1] C. W. Clenshaw, "Chebyshev series for mathematical functions", in 

3457 *National Physical Laboratory Mathematical Tables*, vol. 5, London: 

3458 Her Majesty's Stationery Office, 1962. 

3459 .. [2] M. Abramowitz and I. A. Stegun, *Handbook of Mathematical 

3460 Functions*, 10th printing, New York: Dover, 1964, pp. 379. 

3461 https://personal.math.ubc.ca/~cbm/aands/page_379.htm 

3462 .. [3] https://metacpan.org/pod/distribution/Math-Cephes/lib/Math/Cephes.pod#i0:-Modified-Bessel-function-of-order-zero 

3463 

3464 Examples 

3465 -------- 

3466 >>> np.i0(0.) 

3467 array(1.0) 

3468 >>> np.i0([0, 1, 2, 3]) 

3469 array([1. , 1.26606588, 2.2795853 , 4.88079259]) 

3470 

3471 """ 

3472 x = np.asanyarray(x) 

3473 if x.dtype.kind == 'c': 

3474 raise TypeError("i0 not supported for complex values") 

3475 if x.dtype.kind != 'f': 

3476 x = x.astype(float) 

3477 x = np.abs(x) 

3478 return piecewise(x, [x <= 8.0], [_i0_1, _i0_2]) 

3479 

3480## End of cephes code for i0 

3481 

3482 

3483@set_module('numpy') 

3484def kaiser(M, beta): 

3485 """ 

3486 Return the Kaiser window. 

3487 

3488 The Kaiser window is a taper formed by using a Bessel function. 

3489 

3490 Parameters 

3491 ---------- 

3492 M : int 

3493 Number of points in the output window. If zero or less, an 

3494 empty array is returned. 

3495 beta : float 

3496 Shape parameter for window. 

3497 

3498 Returns 

3499 ------- 

3500 out : array 

3501 The window, with the maximum value normalized to one (the value 

3502 one appears only if the number of samples is odd). 

3503 

3504 See Also 

3505 -------- 

3506 bartlett, blackman, hamming, hanning 

3507 

3508 Notes 

3509 ----- 

3510 The Kaiser window is defined as 

3511 

3512 .. math:: w(n) = I_0\\left( \\beta \\sqrt{1-\\frac{4n^2}{(M-1)^2}} 

3513 \\right)/I_0(\\beta) 

3514 

3515 with 

3516 

3517 .. math:: \\quad -\\frac{M-1}{2} \\leq n \\leq \\frac{M-1}{2}, 

3518 

3519 where :math:`I_0` is the modified zeroth-order Bessel function. 

3520 

3521 The Kaiser was named for Jim Kaiser, who discovered a simple 

3522 approximation to the DPSS window based on Bessel functions. The Kaiser 

3523 window is a very good approximation to the Digital Prolate Spheroidal 

3524 Sequence, or Slepian window, which is the transform which maximizes the 

3525 energy in the main lobe of the window relative to total energy. 

3526 

3527 The Kaiser can approximate many other windows by varying the beta 

3528 parameter. 

3529 

3530 ==== ======================= 

3531 beta Window shape 

3532 ==== ======================= 

3533 0 Rectangular 

3534 5 Similar to a Hamming 

3535 6 Similar to a Hanning 

3536 8.6 Similar to a Blackman 

3537 ==== ======================= 

3538 

3539 A beta value of 14 is probably a good starting point. Note that as beta 

3540 gets large, the window narrows, and so the number of samples needs to be 

3541 large enough to sample the increasingly narrow spike, otherwise NaNs will 

3542 get returned. 

3543 

3544 Most references to the Kaiser window come from the signal processing 

3545 literature, where it is used as one of many windowing functions for 

3546 smoothing values. It is also known as an apodization (which means 

3547 "removing the foot", i.e. smoothing discontinuities at the beginning 

3548 and end of the sampled signal) or tapering function. 

3549 

3550 References 

3551 ---------- 

3552 .. [1] J. F. Kaiser, "Digital Filters" - Ch 7 in "Systems analysis by 

3553 digital computer", Editors: F.F. Kuo and J.F. Kaiser, p 218-285. 

3554 John Wiley and Sons, New York, (1966). 

3555 .. [2] E.R. Kanasewich, "Time Sequence Analysis in Geophysics", The 

3556 University of Alberta Press, 1975, pp. 177-178. 

3557 .. [3] Wikipedia, "Window function", 

3558 https://en.wikipedia.org/wiki/Window_function 

3559 

3560 Examples 

3561 -------- 

3562 >>> import matplotlib.pyplot as plt 

3563 >>> np.kaiser(12, 14) 

3564 array([7.72686684e-06, 3.46009194e-03, 4.65200189e-02, # may vary 

3565 2.29737120e-01, 5.99885316e-01, 9.45674898e-01, 

3566 9.45674898e-01, 5.99885316e-01, 2.29737120e-01, 

3567 4.65200189e-02, 3.46009194e-03, 7.72686684e-06]) 

3568 

3569 

3570 Plot the window and the frequency response. 

3571 

3572 .. plot:: 

3573 :include-source: 

3574 

3575 import matplotlib.pyplot as plt 

3576 from numpy.fft import fft, fftshift 

3577 window = np.kaiser(51, 14) 

3578 plt.plot(window) 

3579 plt.title("Kaiser window") 

3580 plt.ylabel("Amplitude") 

3581 plt.xlabel("Sample") 

3582 plt.show() 

3583 

3584 plt.figure() 

3585 A = fft(window, 2048) / 25.5 

3586 mag = np.abs(fftshift(A)) 

3587 freq = np.linspace(-0.5, 0.5, len(A)) 

3588 response = 20 * np.log10(mag) 

3589 response = np.clip(response, -100, 100) 

3590 plt.plot(freq, response) 

3591 plt.title("Frequency response of Kaiser window") 

3592 plt.ylabel("Magnitude [dB]") 

3593 plt.xlabel("Normalized frequency [cycles per sample]") 

3594 plt.axis('tight') 

3595 plt.show() 

3596 

3597 """ 

3598 # Ensures at least float64 via 0.0. M should be an integer, but conversion 

3599 # to double is safe for a range. (Simplified result_type with 0.0 

3600 # strongly typed. result-type is not/less order sensitive, but that mainly 

3601 # matters for integers anyway.) 

3602 values = np.array([0.0, M, beta]) 

3603 M = values[1] 

3604 beta = values[2] 

3605 

3606 if M == 1: 

3607 return np.ones(1, dtype=values.dtype) 

3608 n = arange(0, M) 

3609 alpha = (M-1)/2.0 

3610 return i0(beta * sqrt(1-((n-alpha)/alpha)**2.0))/i0(beta) 

3611 

3612 

3613def _sinc_dispatcher(x): 

3614 return (x,) 

3615 

3616 

3617@array_function_dispatch(_sinc_dispatcher) 

3618def sinc(x): 

3619 r""" 

3620 Return the normalized sinc function. 

3621 

3622 The sinc function is equal to :math:`\sin(\pi x)/(\pi x)` for any argument 

3623 :math:`x\ne 0`. ``sinc(0)`` takes the limit value 1, making ``sinc`` not 

3624 only everywhere continuous but also infinitely differentiable. 

3625 

3626 .. note:: 

3627 

3628 Note the normalization factor of ``pi`` used in the definition. 

3629 This is the most commonly used definition in signal processing. 

3630 Use ``sinc(x / np.pi)`` to obtain the unnormalized sinc function 

3631 :math:`\sin(x)/x` that is more common in mathematics. 

3632 

3633 Parameters 

3634 ---------- 

3635 x : ndarray 

3636 Array (possibly multi-dimensional) of values for which to calculate 

3637 ``sinc(x)``. 

3638 

3639 Returns 

3640 ------- 

3641 out : ndarray 

3642 ``sinc(x)``, which has the same shape as the input. 

3643 

3644 Notes 

3645 ----- 

3646 The name sinc is short for "sine cardinal" or "sinus cardinalis". 

3647 

3648 The sinc function is used in various signal processing applications, 

3649 including in anti-aliasing, in the construction of a Lanczos resampling 

3650 filter, and in interpolation. 

3651 

3652 For bandlimited interpolation of discrete-time signals, the ideal 

3653 interpolation kernel is proportional to the sinc function. 

3654 

3655 References 

3656 ---------- 

3657 .. [1] Weisstein, Eric W. "Sinc Function." From MathWorld--A Wolfram Web 

3658 Resource. https://mathworld.wolfram.com/SincFunction.html 

3659 .. [2] Wikipedia, "Sinc function", 

3660 https://en.wikipedia.org/wiki/Sinc_function 

3661 

3662 Examples 

3663 -------- 

3664 >>> import matplotlib.pyplot as plt 

3665 >>> x = np.linspace(-4, 4, 41) 

3666 >>> np.sinc(x) 

3667 array([-3.89804309e-17, -4.92362781e-02, -8.40918587e-02, # may vary 

3668 -8.90384387e-02, -5.84680802e-02, 3.89804309e-17, 

3669 6.68206631e-02, 1.16434881e-01, 1.26137788e-01, 

3670 8.50444803e-02, -3.89804309e-17, -1.03943254e-01, 

3671 -1.89206682e-01, -2.16236208e-01, -1.55914881e-01, 

3672 3.89804309e-17, 2.33872321e-01, 5.04551152e-01, 

3673 7.56826729e-01, 9.35489284e-01, 1.00000000e+00, 

3674 9.35489284e-01, 7.56826729e-01, 5.04551152e-01, 

3675 2.33872321e-01, 3.89804309e-17, -1.55914881e-01, 

3676 -2.16236208e-01, -1.89206682e-01, -1.03943254e-01, 

3677 -3.89804309e-17, 8.50444803e-02, 1.26137788e-01, 

3678 1.16434881e-01, 6.68206631e-02, 3.89804309e-17, 

3679 -5.84680802e-02, -8.90384387e-02, -8.40918587e-02, 

3680 -4.92362781e-02, -3.89804309e-17]) 

3681 

3682 >>> plt.plot(x, np.sinc(x)) 

3683 [<matplotlib.lines.Line2D object at 0x...>] 

3684 >>> plt.title("Sinc Function") 

3685 Text(0.5, 1.0, 'Sinc Function') 

3686 >>> plt.ylabel("Amplitude") 

3687 Text(0, 0.5, 'Amplitude') 

3688 >>> plt.xlabel("X") 

3689 Text(0.5, 0, 'X') 

3690 >>> plt.show() 

3691 

3692 """ 

3693 x = np.asanyarray(x) 

3694 y = pi * where(x == 0, 1.0e-20, x) 

3695 return sin(y)/y 

3696 

3697 

3698def _ureduce(a, func, keepdims=False, **kwargs): 

3699 """ 

3700 Internal Function. 

3701 Call `func` with `a` as first argument swapping the axes to use extended 

3702 axis on functions that don't support it natively. 

3703 

3704 Returns result and a.shape with axis dims set to 1. 

3705 

3706 Parameters 

3707 ---------- 

3708 a : array_like 

3709 Input array or object that can be converted to an array. 

3710 func : callable 

3711 Reduction function capable of receiving a single axis argument. 

3712 It is called with `a` as first argument followed by `kwargs`. 

3713 kwargs : keyword arguments 

3714 additional keyword arguments to pass to `func`. 

3715 

3716 Returns 

3717 ------- 

3718 result : tuple 

3719 Result of func(a, **kwargs) and a.shape with axis dims set to 1 

3720 which can be used to reshape the result to the same shape a ufunc with 

3721 keepdims=True would produce. 

3722 

3723 """ 

3724 a = np.asanyarray(a) 

3725 axis = kwargs.get('axis', None) 

3726 out = kwargs.get('out', None) 

3727 

3728 if keepdims is np._NoValue: 

3729 keepdims = False 

3730 

3731 nd = a.ndim 

3732 if axis is not None: 

3733 axis = _nx.normalize_axis_tuple(axis, nd) 

3734 

3735 if keepdims: 

3736 if out is not None: 

3737 index_out = tuple( 

3738 0 if i in axis else slice(None) for i in range(nd)) 

3739 kwargs['out'] = out[(Ellipsis, ) + index_out] 

3740 

3741 if len(axis) == 1: 

3742 kwargs['axis'] = axis[0] 

3743 else: 

3744 keep = set(range(nd)) - set(axis) 

3745 nkeep = len(keep) 

3746 # swap axis that should not be reduced to front 

3747 for i, s in enumerate(sorted(keep)): 

3748 a = a.swapaxes(i, s) 

3749 # merge reduced axis 

3750 a = a.reshape(a.shape[:nkeep] + (-1,)) 

3751 kwargs['axis'] = -1 

3752 else: 

3753 if keepdims: 

3754 if out is not None: 

3755 index_out = (0, ) * nd 

3756 kwargs['out'] = out[(Ellipsis, ) + index_out] 

3757 

3758 r = func(a, **kwargs) 

3759 

3760 if out is not None: 

3761 return out 

3762 

3763 if keepdims: 

3764 if axis is None: 

3765 index_r = (np.newaxis, ) * nd 

3766 else: 

3767 index_r = tuple( 

3768 np.newaxis if i in axis else slice(None) 

3769 for i in range(nd)) 

3770 r = r[(Ellipsis, ) + index_r] 

3771 

3772 return r 

3773 

3774 

3775def _median_dispatcher( 

3776 a, axis=None, out=None, overwrite_input=None, keepdims=None): 

3777 return (a, out) 

3778 

3779 

3780@array_function_dispatch(_median_dispatcher) 

3781def median(a, axis=None, out=None, overwrite_input=False, keepdims=False): 

3782 """ 

3783 Compute the median along the specified axis. 

3784 

3785 Returns the median of the array elements. 

3786 

3787 Parameters 

3788 ---------- 

3789 a : array_like 

3790 Input array or object that can be converted to an array. 

3791 axis : {int, sequence of int, None}, optional 

3792 Axis or axes along which the medians are computed. The default, 

3793 axis=None, will compute the median along a flattened version of 

3794 the array. 

3795  

3796 .. versionadded:: 1.9.0 

3797 

3798 If a sequence of axes, the array is first flattened along the 

3799 given axes, then the median is computed along the resulting 

3800 flattened axis. 

3801 out : ndarray, optional 

3802 Alternative output array in which to place the result. It must 

3803 have the same shape and buffer length as the expected output, 

3804 but the type (of the output) will be cast if necessary. 

3805 overwrite_input : bool, optional 

3806 If True, then allow use of memory of input array `a` for 

3807 calculations. The input array will be modified by the call to 

3808 `median`. This will save memory when you do not need to preserve 

3809 the contents of the input array. Treat the input as undefined, 

3810 but it will probably be fully or partially sorted. Default is 

3811 False. If `overwrite_input` is ``True`` and `a` is not already an 

3812 `ndarray`, an error will be raised. 

3813 keepdims : bool, optional 

3814 If this is set to True, the axes which are reduced are left 

3815 in the result as dimensions with size one. With this option, 

3816 the result will broadcast correctly against the original `arr`. 

3817 

3818 .. versionadded:: 1.9.0 

3819 

3820 Returns 

3821 ------- 

3822 median : ndarray 

3823 A new array holding the result. If the input contains integers 

3824 or floats smaller than ``float64``, then the output data-type is 

3825 ``np.float64``. Otherwise, the data-type of the output is the 

3826 same as that of the input. If `out` is specified, that array is 

3827 returned instead. 

3828 

3829 See Also 

3830 -------- 

3831 mean, percentile 

3832 

3833 Notes 

3834 ----- 

3835 Given a vector ``V`` of length ``N``, the median of ``V`` is the 

3836 middle value of a sorted copy of ``V``, ``V_sorted`` - i 

3837 e., ``V_sorted[(N-1)/2]``, when ``N`` is odd, and the average of the 

3838 two middle values of ``V_sorted`` when ``N`` is even. 

3839 

3840 Examples 

3841 -------- 

3842 >>> a = np.array([[10, 7, 4], [3, 2, 1]]) 

3843 >>> a 

3844 array([[10, 7, 4], 

3845 [ 3, 2, 1]]) 

3846 >>> np.median(a) 

3847 np.float64(3.5) 

3848 >>> np.median(a, axis=0) 

3849 array([6.5, 4.5, 2.5]) 

3850 >>> np.median(a, axis=1) 

3851 array([7., 2.]) 

3852 >>> np.median(a, axis=(0, 1)) 

3853 np.float64(3.5) 

3854 >>> m = np.median(a, axis=0) 

3855 >>> out = np.zeros_like(m) 

3856 >>> np.median(a, axis=0, out=m) 

3857 array([6.5, 4.5, 2.5]) 

3858 >>> m 

3859 array([6.5, 4.5, 2.5]) 

3860 >>> b = a.copy() 

3861 >>> np.median(b, axis=1, overwrite_input=True) 

3862 array([7., 2.]) 

3863 >>> assert not np.all(a==b) 

3864 >>> b = a.copy() 

3865 >>> np.median(b, axis=None, overwrite_input=True) 

3866 np.float64(3.5) 

3867 >>> assert not np.all(a==b) 

3868 

3869 """ 

3870 return _ureduce(a, func=_median, keepdims=keepdims, axis=axis, out=out, 

3871 overwrite_input=overwrite_input) 

3872 

3873 

3874def _median(a, axis=None, out=None, overwrite_input=False): 

3875 # can't be reasonably be implemented in terms of percentile as we have to 

3876 # call mean to not break astropy 

3877 a = np.asanyarray(a) 

3878 

3879 # Set the partition indexes 

3880 if axis is None: 

3881 sz = a.size 

3882 else: 

3883 sz = a.shape[axis] 

3884 if sz % 2 == 0: 

3885 szh = sz // 2 

3886 kth = [szh - 1, szh] 

3887 else: 

3888 kth = [(sz - 1) // 2] 

3889 

3890 # We have to check for NaNs (as of writing 'M' doesn't actually work). 

3891 supports_nans = np.issubdtype(a.dtype, np.inexact) or a.dtype.kind in 'Mm' 

3892 if supports_nans: 

3893 kth.append(-1) 

3894 

3895 if overwrite_input: 

3896 if axis is None: 

3897 part = a.ravel() 

3898 part.partition(kth) 

3899 else: 

3900 a.partition(kth, axis=axis) 

3901 part = a 

3902 else: 

3903 part = partition(a, kth, axis=axis) 

3904 

3905 if part.shape == (): 

3906 # make 0-D arrays work 

3907 return part.item() 

3908 if axis is None: 

3909 axis = 0 

3910 

3911 indexer = [slice(None)] * part.ndim 

3912 index = part.shape[axis] // 2 

3913 if part.shape[axis] % 2 == 1: 

3914 # index with slice to allow mean (below) to work 

3915 indexer[axis] = slice(index, index+1) 

3916 else: 

3917 indexer[axis] = slice(index-1, index+1) 

3918 indexer = tuple(indexer) 

3919 

3920 # Use mean in both odd and even case to coerce data type, 

3921 # using out array if needed. 

3922 rout = mean(part[indexer], axis=axis, out=out) 

3923 if supports_nans and sz > 0: 

3924 # If nans are possible, warn and replace by nans like mean would. 

3925 rout = np.lib._utils_impl._median_nancheck(part, rout, axis) 

3926 

3927 return rout 

3928 

3929 

3930def _percentile_dispatcher(a, q, axis=None, out=None, overwrite_input=None, 

3931 method=None, keepdims=None, *, weights=None, 

3932 interpolation=None): 

3933 return (a, q, out, weights) 

3934 

3935 

3936@array_function_dispatch(_percentile_dispatcher) 

3937def percentile(a, 

3938 q, 

3939 axis=None, 

3940 out=None, 

3941 overwrite_input=False, 

3942 method="linear", 

3943 keepdims=False, 

3944 *, 

3945 weights=None, 

3946 interpolation=None): 

3947 """ 

3948 Compute the q-th percentile of the data along the specified axis. 

3949 

3950 Returns the q-th percentile(s) of the array elements. 

3951 

3952 Parameters 

3953 ---------- 

3954 a : array_like of real numbers 

3955 Input array or object that can be converted to an array. 

3956 q : array_like of float 

3957 Percentage or sequence of percentages for the percentiles to compute. 

3958 Values must be between 0 and 100 inclusive. 

3959 axis : {int, tuple of int, None}, optional 

3960 Axis or axes along which the percentiles are computed. The 

3961 default is to compute the percentile(s) along a flattened 

3962 version of the array. 

3963 

3964 .. versionchanged:: 1.9.0 

3965 A tuple of axes is supported 

3966 out : ndarray, optional 

3967 Alternative output array in which to place the result. It must 

3968 have the same shape and buffer length as the expected output, 

3969 but the type (of the output) will be cast if necessary. 

3970 overwrite_input : bool, optional 

3971 If True, then allow the input array `a` to be modified by intermediate 

3972 calculations, to save memory. In this case, the contents of the input 

3973 `a` after this function completes is undefined. 

3974 method : str, optional 

3975 This parameter specifies the method to use for estimating the 

3976 percentile. There are many different methods, some unique to NumPy. 

3977 See the notes for explanation. The options sorted by their R type 

3978 as summarized in the H&F paper [1]_ are: 

3979 

3980 1. 'inverted_cdf' 

3981 2. 'averaged_inverted_cdf' 

3982 3. 'closest_observation' 

3983 4. 'interpolated_inverted_cdf' 

3984 5. 'hazen' 

3985 6. 'weibull' 

3986 7. 'linear' (default) 

3987 8. 'median_unbiased' 

3988 9. 'normal_unbiased' 

3989 

3990 The first three methods are discontinuous. NumPy further defines the 

3991 following discontinuous variations of the default 'linear' (7.) option: 

3992 

3993 * 'lower' 

3994 * 'higher', 

3995 * 'midpoint' 

3996 * 'nearest' 

3997 

3998 .. versionchanged:: 1.22.0 

3999 This argument was previously called "interpolation" and only 

4000 offered the "linear" default and last four options. 

4001 

4002 keepdims : bool, optional 

4003 If this is set to True, the axes which are reduced are left in 

4004 the result as dimensions with size one. With this option, the 

4005 result will broadcast correctly against the original array `a`. 

4006 

4007 .. versionadded:: 1.9.0 

4008 

4009 weights : array_like, optional 

4010 An array of weights associated with the values in `a`. Each value in 

4011 `a` contributes to the percentile according to its associated weight. 

4012 The weights array can either be 1-D (in which case its length must be 

4013 the size of `a` along the given axis) or of the same shape as `a`. 

4014 If `weights=None`, then all data in `a` are assumed to have a 

4015 weight equal to one. 

4016 Only `method="inverted_cdf"` supports weights. 

4017 See the notes for more details. 

4018 

4019 .. versionadded:: 2.0.0 

4020 

4021 interpolation : str, optional 

4022 Deprecated name for the method keyword argument. 

4023 

4024 .. deprecated:: 1.22.0 

4025 

4026 Returns 

4027 ------- 

4028 percentile : scalar or ndarray 

4029 If `q` is a single percentile and `axis=None`, then the result 

4030 is a scalar. If multiple percentiles are given, first axis of 

4031 the result corresponds to the percentiles. The other axes are 

4032 the axes that remain after the reduction of `a`. If the input 

4033 contains integers or floats smaller than ``float64``, the output 

4034 data-type is ``float64``. Otherwise, the output data-type is the 

4035 same as that of the input. If `out` is specified, that array is 

4036 returned instead. 

4037 

4038 See Also 

4039 -------- 

4040 mean 

4041 median : equivalent to ``percentile(..., 50)`` 

4042 nanpercentile 

4043 quantile : equivalent to percentile, except q in the range [0, 1]. 

4044 

4045 Notes 

4046 ----- 

4047 In general, the percentile at percentage level :math:`q` of a cumulative 

4048 distribution function :math:`F(y)=P(Y \\leq y)` with probability measure 

4049 :math:`P` is defined as any number :math:`x` that fulfills the 

4050 *coverage conditions* 

4051 

4052 .. math:: P(Y < x) \\leq q/100 \\quad\\text{and} 

4053 \\quad P(Y \\leq x) \\geq q/100 

4054 

4055 with random variable :math:`Y\\sim P`. 

4056 Sample percentiles, the result of ``percentile``, provide nonparametric 

4057 estimation of the underlying population counterparts, represented by the 

4058 unknown :math:`F`, given a data vector ``a`` of length ``n``. 

4059 

4060 One type of estimators arises when one considers :math:`F` as the empirical 

4061 distribution function of the data, i.e. 

4062 :math:`F(y) = \\frac{1}{n} \\sum_i 1_{a_i \\leq y}`. 

4063 Then, different methods correspond to different choices of :math:`x` that 

4064 fulfill the above inequalities. Methods that follow this approach are 

4065 ``inverted_cdf`` and ``averaged_inverted_cdf``. 

4066 

4067 A more general way to define sample percentile estimators is as follows. 

4068 The empirical q-percentile of ``a`` is the ``n * q/100``-th value of the 

4069 way from the minimum to the maximum in a sorted copy of ``a``. The values 

4070 and distances of the two nearest neighbors as well as the `method` 

4071 parameter will determine the percentile if the normalized ranking does not 

4072 match the location of ``n * q/100`` exactly. This function is the same as 

4073 the median if ``q=50``, the same as the minimum if ``q=0`` and the same 

4074 as the maximum if ``q=100``. 

4075 

4076 The optional `method` parameter specifies the method to use when the 

4077 desired percentile lies between two indexes ``i`` and ``j = i + 1``. 

4078 In that case, we first determine ``i + g``, a virtual index that lies 

4079 between ``i`` and ``j``, where ``i`` is the floor and ``g`` is the 

4080 fractional part of the index. The final result is, then, an interpolation 

4081 of ``a[i]`` and ``a[j]`` based on ``g``. During the computation of ``g``, 

4082 ``i`` and ``j`` are modified using correction constants ``alpha`` and 

4083 ``beta`` whose choices depend on the ``method`` used. Finally, note that 

4084 since Python uses 0-based indexing, the code subtracts another 1 from the 

4085 index internally. 

4086 

4087 The following formula determines the virtual index ``i + g``, the location 

4088 of the percentile in the sorted sample: 

4089 

4090 .. math:: 

4091 i + g = (q / 100) * ( n - alpha - beta + 1 ) + alpha 

4092 

4093 The different methods then work as follows 

4094 

4095 inverted_cdf: 

4096 method 1 of H&F [1]_. 

4097 This method gives discontinuous results: 

4098 

4099 * if g > 0 ; then take j 

4100 * if g = 0 ; then take i 

4101 

4102 averaged_inverted_cdf: 

4103 method 2 of H&F [1]_. 

4104 This method gives discontinuous results: 

4105 

4106 * if g > 0 ; then take j 

4107 * if g = 0 ; then average between bounds 

4108 

4109 closest_observation: 

4110 method 3 of H&F [1]_. 

4111 This method gives discontinuous results: 

4112 

4113 * if g > 0 ; then take j 

4114 * if g = 0 and index is odd ; then take j 

4115 * if g = 0 and index is even ; then take i 

4116 

4117 interpolated_inverted_cdf: 

4118 method 4 of H&F [1]_. 

4119 This method gives continuous results using: 

4120 

4121 * alpha = 0 

4122 * beta = 1 

4123 

4124 hazen: 

4125 method 5 of H&F [1]_. 

4126 This method gives continuous results using: 

4127 

4128 * alpha = 1/2 

4129 * beta = 1/2 

4130 

4131 weibull: 

4132 method 6 of H&F [1]_. 

4133 This method gives continuous results using: 

4134 

4135 * alpha = 0 

4136 * beta = 0 

4137 

4138 linear: 

4139 method 7 of H&F [1]_. 

4140 This method gives continuous results using: 

4141 

4142 * alpha = 1 

4143 * beta = 1 

4144 

4145 median_unbiased: 

4146 method 8 of H&F [1]_. 

4147 This method is probably the best method if the sample 

4148 distribution function is unknown (see reference). 

4149 This method gives continuous results using: 

4150 

4151 * alpha = 1/3 

4152 * beta = 1/3 

4153 

4154 normal_unbiased: 

4155 method 9 of H&F [1]_. 

4156 This method is probably the best method if the sample 

4157 distribution function is known to be normal. 

4158 This method gives continuous results using: 

4159 

4160 * alpha = 3/8 

4161 * beta = 3/8 

4162 

4163 lower: 

4164 NumPy method kept for backwards compatibility. 

4165 Takes ``i`` as the interpolation point. 

4166 

4167 higher: 

4168 NumPy method kept for backwards compatibility. 

4169 Takes ``j`` as the interpolation point. 

4170 

4171 nearest: 

4172 NumPy method kept for backwards compatibility. 

4173 Takes ``i`` or ``j``, whichever is nearest. 

4174 

4175 midpoint: 

4176 NumPy method kept for backwards compatibility. 

4177 Uses ``(i + j) / 2``. 

4178 

4179 For weighted percentiles, the above coverage conditions still hold. The 

4180 empirical cumulative distribution is simply replaced by its weighted 

4181 version, i.e. 

4182 :math:`P(Y \\leq t) = \\frac{1}{\\sum_i w_i} \\sum_i w_i 1_{x_i \\leq t}`. 

4183 Only ``method="inverted_cdf"`` supports weights. 

4184 

4185 

4186 Examples 

4187 -------- 

4188 >>> a = np.array([[10, 7, 4], [3, 2, 1]]) 

4189 >>> a 

4190 array([[10, 7, 4], 

4191 [ 3, 2, 1]]) 

4192 >>> np.percentile(a, 50) 

4193 3.5 

4194 >>> np.percentile(a, 50, axis=0) 

4195 array([6.5, 4.5, 2.5]) 

4196 >>> np.percentile(a, 50, axis=1) 

4197 array([7., 2.]) 

4198 >>> np.percentile(a, 50, axis=1, keepdims=True) 

4199 array([[7.], 

4200 [2.]]) 

4201 

4202 >>> m = np.percentile(a, 50, axis=0) 

4203 >>> out = np.zeros_like(m) 

4204 >>> np.percentile(a, 50, axis=0, out=out) 

4205 array([6.5, 4.5, 2.5]) 

4206 >>> m 

4207 array([6.5, 4.5, 2.5]) 

4208 

4209 >>> b = a.copy() 

4210 >>> np.percentile(b, 50, axis=1, overwrite_input=True) 

4211 array([7., 2.]) 

4212 >>> assert not np.all(a == b) 

4213 

4214 The different methods can be visualized graphically: 

4215 

4216 .. plot:: 

4217 

4218 import matplotlib.pyplot as plt 

4219 

4220 a = np.arange(4) 

4221 p = np.linspace(0, 100, 6001) 

4222 ax = plt.gca() 

4223 lines = [ 

4224 ('linear', '-', 'C0'), 

4225 ('inverted_cdf', ':', 'C1'), 

4226 # Almost the same as `inverted_cdf`: 

4227 ('averaged_inverted_cdf', '-.', 'C1'), 

4228 ('closest_observation', ':', 'C2'), 

4229 ('interpolated_inverted_cdf', '--', 'C1'), 

4230 ('hazen', '--', 'C3'), 

4231 ('weibull', '-.', 'C4'), 

4232 ('median_unbiased', '--', 'C5'), 

4233 ('normal_unbiased', '-.', 'C6'), 

4234 ] 

4235 for method, style, color in lines: 

4236 ax.plot( 

4237 p, np.percentile(a, p, method=method), 

4238 label=method, linestyle=style, color=color) 

4239 ax.set( 

4240 title='Percentiles for different methods and data: ' + str(a), 

4241 xlabel='Percentile', 

4242 ylabel='Estimated percentile value', 

4243 yticks=a) 

4244 ax.legend(bbox_to_anchor=(1.03, 1)) 

4245 plt.tight_layout() 

4246 plt.show() 

4247 

4248 References 

4249 ---------- 

4250 .. [1] R. J. Hyndman and Y. Fan, 

4251 "Sample quantiles in statistical packages," 

4252 The American Statistician, 50(4), pp. 361-365, 1996 

4253 

4254 """ 

4255 if interpolation is not None: 

4256 method = _check_interpolation_as_method( 

4257 method, interpolation, "percentile") 

4258 

4259 a = np.asanyarray(a) 

4260 if a.dtype.kind == "c": 

4261 raise TypeError("a must be an array of real numbers") 

4262 

4263 # Use dtype of array if possible (e.g., if q is a python int or float) 

4264 # by making the divisor have the dtype of the data array. 

4265 q = np.true_divide(q, a.dtype.type(100) if a.dtype.kind == "f" else 100) 

4266 q = asanyarray(q) # undo any decay that the ufunc performed (see gh-13105) 

4267 if not _quantile_is_valid(q): 

4268 raise ValueError("Percentiles must be in the range [0, 100]") 

4269 

4270 if weights is not None: 

4271 if method != "inverted_cdf": 

4272 msg = ("Only method 'inverted_cdf' supports weights. " 

4273 f"Got: {method}.") 

4274 raise ValueError(msg) 

4275 if axis is not None: 

4276 axis = _nx.normalize_axis_tuple(axis, a.ndim, argname="axis") 

4277 weights = _weights_are_valid(weights=weights, a=a, axis=axis) 

4278 if np.any(weights < 0): 

4279 raise ValueError("Weights must be non-negative.") 

4280 

4281 return _quantile_unchecked( 

4282 a, q, axis, out, overwrite_input, method, keepdims, weights) 

4283 

4284 

4285def _quantile_dispatcher(a, q, axis=None, out=None, overwrite_input=None, 

4286 method=None, keepdims=None, *, weights=None, 

4287 interpolation=None): 

4288 return (a, q, out, weights) 

4289 

4290 

4291@array_function_dispatch(_quantile_dispatcher) 

4292def quantile(a, 

4293 q, 

4294 axis=None, 

4295 out=None, 

4296 overwrite_input=False, 

4297 method="linear", 

4298 keepdims=False, 

4299 *, 

4300 weights=None, 

4301 interpolation=None): 

4302 """ 

4303 Compute the q-th quantile of the data along the specified axis. 

4304 

4305 .. versionadded:: 1.15.0 

4306 

4307 Parameters 

4308 ---------- 

4309 a : array_like of real numbers 

4310 Input array or object that can be converted to an array. 

4311 q : array_like of float 

4312 Probability or sequence of probabilities for the quantiles to compute. 

4313 Values must be between 0 and 1 inclusive. 

4314 axis : {int, tuple of int, None}, optional 

4315 Axis or axes along which the quantiles are computed. The default is 

4316 to compute the quantile(s) along a flattened version of the array. 

4317 out : ndarray, optional 

4318 Alternative output array in which to place the result. It must have 

4319 the same shape and buffer length as the expected output, but the 

4320 type (of the output) will be cast if necessary. 

4321 overwrite_input : bool, optional 

4322 If True, then allow the input array `a` to be modified by 

4323 intermediate calculations, to save memory. In this case, the 

4324 contents of the input `a` after this function completes is 

4325 undefined. 

4326 method : str, optional 

4327 This parameter specifies the method to use for estimating the 

4328 quantile. There are many different methods, some unique to NumPy. 

4329 See the notes for explanation. The options sorted by their R type 

4330 as summarized in the H&F paper [1]_ are: 

4331 

4332 1. 'inverted_cdf' 

4333 2. 'averaged_inverted_cdf' 

4334 3. 'closest_observation' 

4335 4. 'interpolated_inverted_cdf' 

4336 5. 'hazen' 

4337 6. 'weibull' 

4338 7. 'linear' (default) 

4339 8. 'median_unbiased' 

4340 9. 'normal_unbiased' 

4341 

4342 The first three methods are discontinuous. NumPy further defines the 

4343 following discontinuous variations of the default 'linear' (7.) option: 

4344 

4345 * 'lower' 

4346 * 'higher', 

4347 * 'midpoint' 

4348 * 'nearest' 

4349 

4350 .. versionchanged:: 1.22.0 

4351 This argument was previously called "interpolation" and only 

4352 offered the "linear" default and last four options. 

4353 

4354 keepdims : bool, optional 

4355 If this is set to True, the axes which are reduced are left in 

4356 the result as dimensions with size one. With this option, the 

4357 result will broadcast correctly against the original array `a`. 

4358 

4359 weights : array_like, optional 

4360 An array of weights associated with the values in `a`. Each value in 

4361 `a` contributes to the quantile according to its associated weight. 

4362 The weights array can either be 1-D (in which case its length must be 

4363 the size of `a` along the given axis) or of the same shape as `a`. 

4364 If `weights=None`, then all data in `a` are assumed to have a 

4365 weight equal to one. 

4366 Only `method="inverted_cdf"` supports weights. 

4367 See the notes for more details. 

4368 

4369 .. versionadded:: 2.0.0 

4370 

4371 interpolation : str, optional 

4372 Deprecated name for the method keyword argument. 

4373 

4374 .. deprecated:: 1.22.0 

4375 

4376 Returns 

4377 ------- 

4378 quantile : scalar or ndarray 

4379 If `q` is a single probability and `axis=None`, then the result 

4380 is a scalar. If multiple probability levels are given, first axis 

4381 of the result corresponds to the quantiles. The other axes are 

4382 the axes that remain after the reduction of `a`. If the input 

4383 contains integers or floats smaller than ``float64``, the output 

4384 data-type is ``float64``. Otherwise, the output data-type is the 

4385 same as that of the input. If `out` is specified, that array is 

4386 returned instead. 

4387 

4388 See Also 

4389 -------- 

4390 mean 

4391 percentile : equivalent to quantile, but with q in the range [0, 100]. 

4392 median : equivalent to ``quantile(..., 0.5)`` 

4393 nanquantile 

4394 

4395 Notes 

4396 ----- 

4397 In general, the quantile at probability level :math:`q` of a cumulative 

4398 distribution function :math:`F(y)=P(Y \\leq y)` with probability measure 

4399 :math:`P` is defined as any number :math:`x` that fulfills the 

4400 *coverage conditions* 

4401 

4402 .. math:: P(Y < x) \\leq q \\quad\\text{and}\\quad P(Y \\leq x) \\geq q 

4403 

4404 with random variable :math:`Y\\sim P`. 

4405 Sample quantiles, the result of ``quantile``, provide nonparametric 

4406 estimation of the underlying population counterparts, represented by the 

4407 unknown :math:`F`, given a data vector ``a`` of length ``n``. 

4408 

4409 One type of estimators arises when one considers :math:`F` as the empirical 

4410 distribution function of the data, i.e. 

4411 :math:`F(y) = \\frac{1}{n} \\sum_i 1_{a_i \\leq y}`. 

4412 Then, different methods correspond to different choices of :math:`x` that 

4413 fulfill the above inequalities. Methods that follow this approach are 

4414 ``inverted_cdf`` and ``averaged_inverted_cdf``. 

4415 

4416 A more general way to define sample quantile estimators is as follows. 

4417 The empirical q-quantile of ``a`` is the ``n * q``-th value of the 

4418 way from the minimum to the maximum in a sorted copy of ``a``. The values 

4419 and distances of the two nearest neighbors as well as the `method` 

4420 parameter will determine the quantile if the normalized ranking does not 

4421 match the location of ``n * q`` exactly. This function is the same as 

4422 the median if ``q=0.5``, the same as the minimum if ``q=0.0`` and the same 

4423 as the maximum if ``q=1.0``. 

4424 

4425 The optional `method` parameter specifies the method to use when the 

4426 desired quantile lies between two indexes ``i`` and ``j = i + 1``. 

4427 In that case, we first determine ``i + g``, a virtual index that lies 

4428 between ``i`` and ``j``, where ``i`` is the floor and ``g`` is the 

4429 fractional part of the index. The final result is, then, an interpolation 

4430 of ``a[i]`` and ``a[j]`` based on ``g``. During the computation of ``g``, 

4431 ``i`` and ``j`` are modified using correction constants ``alpha`` and 

4432 ``beta`` whose choices depend on the ``method`` used. Finally, note that 

4433 since Python uses 0-based indexing, the code subtracts another 1 from the 

4434 index internally. 

4435 

4436 The following formula determines the virtual index ``i + g``, the location 

4437 of the quantile in the sorted sample: 

4438 

4439 .. math:: 

4440 i + g = q * ( n - alpha - beta + 1 ) + alpha 

4441 

4442 The different methods then work as follows 

4443 

4444 inverted_cdf: 

4445 method 1 of H&F [1]_. 

4446 This method gives discontinuous results: 

4447 

4448 * if g > 0 ; then take j 

4449 * if g = 0 ; then take i 

4450 

4451 averaged_inverted_cdf: 

4452 method 2 of H&F [1]_. 

4453 This method gives discontinuous results: 

4454 

4455 * if g > 0 ; then take j 

4456 * if g = 0 ; then average between bounds 

4457 

4458 closest_observation: 

4459 method 3 of H&F [1]_. 

4460 This method gives discontinuous results: 

4461 

4462 * if g > 0 ; then take j 

4463 * if g = 0 and index is odd ; then take j 

4464 * if g = 0 and index is even ; then take i 

4465 

4466 interpolated_inverted_cdf: 

4467 method 4 of H&F [1]_. 

4468 This method gives continuous results using: 

4469 

4470 * alpha = 0 

4471 * beta = 1 

4472 

4473 hazen: 

4474 method 5 of H&F [1]_. 

4475 This method gives continuous results using: 

4476 

4477 * alpha = 1/2 

4478 * beta = 1/2 

4479 

4480 weibull: 

4481 method 6 of H&F [1]_. 

4482 This method gives continuous results using: 

4483 

4484 * alpha = 0 

4485 * beta = 0 

4486 

4487 linear: 

4488 method 7 of H&F [1]_. 

4489 This method gives continuous results using: 

4490 

4491 * alpha = 1 

4492 * beta = 1 

4493 

4494 median_unbiased: 

4495 method 8 of H&F [1]_. 

4496 This method is probably the best method if the sample 

4497 distribution function is unknown (see reference). 

4498 This method gives continuous results using: 

4499 

4500 * alpha = 1/3 

4501 * beta = 1/3 

4502 

4503 normal_unbiased: 

4504 method 9 of H&F [1]_. 

4505 This method is probably the best method if the sample 

4506 distribution function is known to be normal. 

4507 This method gives continuous results using: 

4508 

4509 * alpha = 3/8 

4510 * beta = 3/8 

4511 

4512 lower: 

4513 NumPy method kept for backwards compatibility. 

4514 Takes ``i`` as the interpolation point. 

4515 

4516 higher: 

4517 NumPy method kept for backwards compatibility. 

4518 Takes ``j`` as the interpolation point. 

4519 

4520 nearest: 

4521 NumPy method kept for backwards compatibility. 

4522 Takes ``i`` or ``j``, whichever is nearest. 

4523 

4524 midpoint: 

4525 NumPy method kept for backwards compatibility. 

4526 Uses ``(i + j) / 2``. 

4527 

4528 **Weighted quantiles:** 

4529 For weighted quantiles, the above coverage conditions still hold. The 

4530 empirical cumulative distribution is simply replaced by its weighted 

4531 version, i.e.  

4532 :math:`P(Y \\leq t) = \\frac{1}{\\sum_i w_i} \\sum_i w_i 1_{x_i \\leq t}`. 

4533 Only ``method="inverted_cdf"`` supports weights. 

4534 

4535 Examples 

4536 -------- 

4537 >>> a = np.array([[10, 7, 4], [3, 2, 1]]) 

4538 >>> a 

4539 array([[10, 7, 4], 

4540 [ 3, 2, 1]]) 

4541 >>> np.quantile(a, 0.5) 

4542 3.5 

4543 >>> np.quantile(a, 0.5, axis=0) 

4544 array([6.5, 4.5, 2.5]) 

4545 >>> np.quantile(a, 0.5, axis=1) 

4546 array([7., 2.]) 

4547 >>> np.quantile(a, 0.5, axis=1, keepdims=True) 

4548 array([[7.], 

4549 [2.]]) 

4550 >>> m = np.quantile(a, 0.5, axis=0) 

4551 >>> out = np.zeros_like(m) 

4552 >>> np.quantile(a, 0.5, axis=0, out=out) 

4553 array([6.5, 4.5, 2.5]) 

4554 >>> m 

4555 array([6.5, 4.5, 2.5]) 

4556 >>> b = a.copy() 

4557 >>> np.quantile(b, 0.5, axis=1, overwrite_input=True) 

4558 array([7., 2.]) 

4559 >>> assert not np.all(a == b) 

4560 

4561 See also `numpy.percentile` for a visualization of most methods. 

4562 

4563 References 

4564 ---------- 

4565 .. [1] R. J. Hyndman and Y. Fan, 

4566 "Sample quantiles in statistical packages," 

4567 The American Statistician, 50(4), pp. 361-365, 1996 

4568 

4569 """ 

4570 if interpolation is not None: 

4571 method = _check_interpolation_as_method( 

4572 method, interpolation, "quantile") 

4573 

4574 a = np.asanyarray(a) 

4575 if a.dtype.kind == "c": 

4576 raise TypeError("a must be an array of real numbers") 

4577 

4578 # Use dtype of array if possible (e.g., if q is a python int or float). 

4579 if isinstance(q, (int, float)) and a.dtype.kind == "f": 

4580 q = np.asanyarray(q, dtype=a.dtype) 

4581 else: 

4582 q = np.asanyarray(q) 

4583 

4584 if not _quantile_is_valid(q): 

4585 raise ValueError("Quantiles must be in the range [0, 1]") 

4586 

4587 if weights is not None: 

4588 if method != "inverted_cdf": 

4589 msg = ("Only method 'inverted_cdf' supports weights. " 

4590 f"Got: {method}.") 

4591 raise ValueError(msg) 

4592 if axis is not None: 

4593 axis = _nx.normalize_axis_tuple(axis, a.ndim, argname="axis") 

4594 weights = _weights_are_valid(weights=weights, a=a, axis=axis) 

4595 if np.any(weights < 0): 

4596 raise ValueError("Weights must be non-negative.") 

4597 

4598 return _quantile_unchecked( 

4599 a, q, axis, out, overwrite_input, method, keepdims, weights) 

4600 

4601 

4602def _quantile_unchecked(a, 

4603 q, 

4604 axis=None, 

4605 out=None, 

4606 overwrite_input=False, 

4607 method="linear", 

4608 keepdims=False, 

4609 weights=None): 

4610 """Assumes that q is in [0, 1], and is an ndarray""" 

4611 return _ureduce(a, 

4612 func=_quantile_ureduce_func, 

4613 q=q, 

4614 weights=weights, 

4615 keepdims=keepdims, 

4616 axis=axis, 

4617 out=out, 

4618 overwrite_input=overwrite_input, 

4619 method=method) 

4620 

4621 

4622def _quantile_is_valid(q): 

4623 # avoid expensive reductions, relevant for arrays with < O(1000) elements 

4624 if q.ndim == 1 and q.size < 10: 

4625 for i in range(q.size): 

4626 if not (0.0 <= q[i] <= 1.0): 

4627 return False 

4628 else: 

4629 if not (q.min() >= 0 and q.max() <= 1): 

4630 return False 

4631 return True 

4632 

4633 

4634def _check_interpolation_as_method(method, interpolation, fname): 

4635 # Deprecated NumPy 1.22, 2021-11-08 

4636 warnings.warn( 

4637 f"the `interpolation=` argument to {fname} was renamed to " 

4638 "`method=`, which has additional options.\n" 

4639 "Users of the modes 'nearest', 'lower', 'higher', or " 

4640 "'midpoint' are encouraged to review the method they used. " 

4641 "(Deprecated NumPy 1.22)", 

4642 DeprecationWarning, stacklevel=4) 

4643 if method != "linear": 

4644 # sanity check, we assume this basically never happens 

4645 raise TypeError( 

4646 "You shall not pass both `method` and `interpolation`!\n" 

4647 "(`interpolation` is Deprecated in favor of `method`)") 

4648 return interpolation 

4649 

4650 

4651def _compute_virtual_index(n, quantiles, alpha: float, beta: float): 

4652 """ 

4653 Compute the floating point indexes of an array for the linear 

4654 interpolation of quantiles. 

4655 n : array_like 

4656 The sample sizes. 

4657 quantiles : array_like 

4658 The quantiles values. 

4659 alpha : float 

4660 A constant used to correct the index computed. 

4661 beta : float 

4662 A constant used to correct the index computed. 

4663 

4664 alpha and beta values depend on the chosen method 

4665 (see quantile documentation) 

4666 

4667 Reference: 

4668 Hyndman&Fan paper "Sample Quantiles in Statistical Packages", 

4669 DOI: 10.1080/00031305.1996.10473566 

4670 """ 

4671 return n * quantiles + ( 

4672 alpha + quantiles * (1 - alpha - beta) 

4673 ) - 1 

4674 

4675 

4676def _get_gamma(virtual_indexes, previous_indexes, method): 

4677 """ 

4678 Compute gamma (a.k.a 'm' or 'weight') for the linear interpolation 

4679 of quantiles. 

4680 

4681 virtual_indexes : array_like 

4682 The indexes where the percentile is supposed to be found in the sorted 

4683 sample. 

4684 previous_indexes : array_like 

4685 The floor values of virtual_indexes. 

4686 interpolation : dict 

4687 The interpolation method chosen, which may have a specific rule 

4688 modifying gamma. 

4689 

4690 gamma is usually the fractional part of virtual_indexes but can be modified 

4691 by the interpolation method. 

4692 """ 

4693 gamma = np.asanyarray(virtual_indexes - previous_indexes) 

4694 gamma = method["fix_gamma"](gamma, virtual_indexes) 

4695 # Ensure both that we have an array, and that we keep the dtype 

4696 # (which may have been matched to the input array). 

4697 return np.asanyarray(gamma, dtype=virtual_indexes.dtype) 

4698 

4699 

4700def _lerp(a, b, t, out=None): 

4701 """ 

4702 Compute the linear interpolation weighted by gamma on each point of 

4703 two same shape array. 

4704 

4705 a : array_like 

4706 Left bound. 

4707 b : array_like 

4708 Right bound. 

4709 t : array_like 

4710 The interpolation weight. 

4711 out : array_like 

4712 Output array. 

4713 """ 

4714 diff_b_a = subtract(b, a) 

4715 # asanyarray is a stop-gap until gh-13105 

4716 lerp_interpolation = asanyarray(add(a, diff_b_a * t, out=out)) 

4717 subtract(b, diff_b_a * (1 - t), out=lerp_interpolation, where=t >= 0.5, 

4718 casting='unsafe', dtype=type(lerp_interpolation.dtype)) 

4719 if lerp_interpolation.ndim == 0 and out is None: 

4720 lerp_interpolation = lerp_interpolation[()] # unpack 0d arrays 

4721 return lerp_interpolation 

4722 

4723 

4724def _get_gamma_mask(shape, default_value, conditioned_value, where): 

4725 out = np.full(shape, default_value) 

4726 np.copyto(out, conditioned_value, where=where, casting="unsafe") 

4727 return out 

4728 

4729 

4730def _discret_interpolation_to_boundaries(index, gamma_condition_fun): 

4731 previous = np.floor(index) 

4732 next = previous + 1 

4733 gamma = index - previous 

4734 res = _get_gamma_mask(shape=index.shape, 

4735 default_value=next, 

4736 conditioned_value=previous, 

4737 where=gamma_condition_fun(gamma, index) 

4738 ).astype(np.intp) 

4739 # Some methods can lead to out-of-bound integers, clip them: 

4740 res[res < 0] = 0 

4741 return res 

4742 

4743 

4744def _closest_observation(n, quantiles): 

4745 gamma_fun = lambda gamma, index: (gamma == 0) & (np.floor(index) % 2 == 0) 

4746 return _discret_interpolation_to_boundaries((n * quantiles) - 1 - 0.5, 

4747 gamma_fun) 

4748 

4749 

4750def _inverted_cdf(n, quantiles): 

4751 gamma_fun = lambda gamma, _: (gamma == 0) 

4752 return _discret_interpolation_to_boundaries((n * quantiles) - 1, 

4753 gamma_fun) 

4754 

4755 

4756def _quantile_ureduce_func( 

4757 a: np.array, 

4758 q: np.array, 

4759 weights: np.array, 

4760 axis: int = None, 

4761 out=None, 

4762 overwrite_input: bool = False, 

4763 method="linear", 

4764) -> np.array: 

4765 if q.ndim > 2: 

4766 # The code below works fine for nd, but it might not have useful 

4767 # semantics. For now, keep the supported dimensions the same as it was 

4768 # before. 

4769 raise ValueError("q must be a scalar or 1d") 

4770 if overwrite_input: 

4771 if axis is None: 

4772 axis = 0 

4773 arr = a.ravel() 

4774 wgt = None if weights is None else weights.ravel() 

4775 else: 

4776 arr = a 

4777 wgt = weights 

4778 else: 

4779 if axis is None: 

4780 axis = 0 

4781 arr = a.flatten() 

4782 wgt = None if weights is None else weights.flatten() 

4783 else: 

4784 arr = a.copy() 

4785 wgt = weights 

4786 result = _quantile(arr, 

4787 quantiles=q, 

4788 axis=axis, 

4789 method=method, 

4790 out=out, 

4791 weights=wgt) 

4792 return result 

4793 

4794 

4795def _get_indexes(arr, virtual_indexes, valid_values_count): 

4796 """ 

4797 Get the valid indexes of arr neighbouring virtual_indexes. 

4798 Note 

4799 This is a companion function to linear interpolation of 

4800 Quantiles 

4801 

4802 Returns 

4803 ------- 

4804 (previous_indexes, next_indexes): Tuple 

4805 A Tuple of virtual_indexes neighbouring indexes 

4806 """ 

4807 previous_indexes = np.asanyarray(np.floor(virtual_indexes)) 

4808 next_indexes = np.asanyarray(previous_indexes + 1) 

4809 indexes_above_bounds = virtual_indexes >= valid_values_count - 1 

4810 # When indexes is above max index, take the max value of the array 

4811 if indexes_above_bounds.any(): 

4812 previous_indexes[indexes_above_bounds] = -1 

4813 next_indexes[indexes_above_bounds] = -1 

4814 # When indexes is below min index, take the min value of the array 

4815 indexes_below_bounds = virtual_indexes < 0 

4816 if indexes_below_bounds.any(): 

4817 previous_indexes[indexes_below_bounds] = 0 

4818 next_indexes[indexes_below_bounds] = 0 

4819 if np.issubdtype(arr.dtype, np.inexact): 

4820 # After the sort, slices having NaNs will have for last element a NaN 

4821 virtual_indexes_nans = np.isnan(virtual_indexes) 

4822 if virtual_indexes_nans.any(): 

4823 previous_indexes[virtual_indexes_nans] = -1 

4824 next_indexes[virtual_indexes_nans] = -1 

4825 previous_indexes = previous_indexes.astype(np.intp) 

4826 next_indexes = next_indexes.astype(np.intp) 

4827 return previous_indexes, next_indexes 

4828 

4829 

4830def _quantile( 

4831 arr: np.array, 

4832 quantiles: np.array, 

4833 axis: int = -1, 

4834 method="linear", 

4835 out=None, 

4836 weights=None, 

4837): 

4838 """ 

4839 Private function that doesn't support extended axis or keepdims. 

4840 These methods are extended to this function using _ureduce 

4841 See nanpercentile for parameter usage 

4842 It computes the quantiles of the array for the given axis. 

4843 A linear interpolation is performed based on the `interpolation`. 

4844 

4845 By default, the method is "linear" where alpha == beta == 1 which 

4846 performs the 7th method of Hyndman&Fan. 

4847 With "median_unbiased" we get alpha == beta == 1/3 

4848 thus the 8th method of Hyndman&Fan. 

4849 """ 

4850 # --- Setup 

4851 arr = np.asanyarray(arr) 

4852 values_count = arr.shape[axis] 

4853 # The dimensions of `q` are prepended to the output shape, so we need the 

4854 # axis being sampled from `arr` to be last. 

4855 if axis != 0: # But moveaxis is slow, so only call it if necessary. 

4856 arr = np.moveaxis(arr, axis, destination=0) 

4857 supports_nans = ( 

4858 np.issubdtype(arr.dtype, np.inexact) or arr.dtype.kind in 'Mm' 

4859 ) 

4860 

4861 if weights is None: 

4862 # --- Computation of indexes 

4863 # Index where to find the value in the sorted array. 

4864 # Virtual because it is a floating point value, not an valid index. 

4865 # The nearest neighbours are used for interpolation 

4866 try: 

4867 method_props = _QuantileMethods[method] 

4868 except KeyError: 

4869 raise ValueError( 

4870 f"{method!r} is not a valid method. Use one of: " 

4871 f"{_QuantileMethods.keys()}") from None 

4872 virtual_indexes = method_props["get_virtual_index"](values_count, 

4873 quantiles) 

4874 virtual_indexes = np.asanyarray(virtual_indexes) 

4875 

4876 if method_props["fix_gamma"] is None: 

4877 supports_integers = True 

4878 else: 

4879 int_virtual_indices = np.issubdtype(virtual_indexes.dtype, 

4880 np.integer) 

4881 supports_integers = method == 'linear' and int_virtual_indices 

4882 

4883 if supports_integers: 

4884 # No interpolation needed, take the points along axis 

4885 if supports_nans: 

4886 # may contain nan, which would sort to the end 

4887 arr.partition( 

4888 concatenate((virtual_indexes.ravel(), [-1])), axis=0, 

4889 ) 

4890 slices_having_nans = np.isnan(arr[-1, ...]) 

4891 else: 

4892 # cannot contain nan 

4893 arr.partition(virtual_indexes.ravel(), axis=0) 

4894 slices_having_nans = np.array(False, dtype=bool) 

4895 result = take(arr, virtual_indexes, axis=0, out=out) 

4896 else: 

4897 previous_indexes, next_indexes = _get_indexes(arr, 

4898 virtual_indexes, 

4899 values_count) 

4900 # --- Sorting 

4901 arr.partition( 

4902 np.unique(np.concatenate(([0, -1], 

4903 previous_indexes.ravel(), 

4904 next_indexes.ravel(), 

4905 ))), 

4906 axis=0) 

4907 if supports_nans: 

4908 slices_having_nans = np.isnan(arr[-1, ...]) 

4909 else: 

4910 slices_having_nans = None 

4911 # --- Get values from indexes 

4912 previous = arr[previous_indexes] 

4913 next = arr[next_indexes] 

4914 # --- Linear interpolation 

4915 gamma = _get_gamma(virtual_indexes, previous_indexes, method_props) 

4916 result_shape = virtual_indexes.shape + (1,) * (arr.ndim - 1) 

4917 gamma = gamma.reshape(result_shape) 

4918 result = _lerp(previous, 

4919 next, 

4920 gamma, 

4921 out=out) 

4922 else: 

4923 # Weighted case 

4924 # This implements method="inverted_cdf", the only supported weighted 

4925 # method, which needs to sort anyway. 

4926 weights = np.asanyarray(weights) 

4927 if axis != 0: 

4928 weights = np.moveaxis(weights, axis, destination=0) 

4929 index_array = np.argsort(arr, axis=0, kind="stable") 

4930 

4931 # arr = arr[index_array, ...] # but this adds trailing dimensions of 

4932 # 1. 

4933 arr = np.take_along_axis(arr, index_array, axis=0) 

4934 if weights.shape == arr.shape: 

4935 weights = np.take_along_axis(weights, index_array, axis=0) 

4936 else: 

4937 # weights is 1d 

4938 weights = weights.reshape(-1)[index_array, ...] 

4939 

4940 if supports_nans: 

4941 # may contain nan, which would sort to the end 

4942 slices_having_nans = np.isnan(arr[-1, ...]) 

4943 else: 

4944 # cannot contain nan 

4945 slices_having_nans = np.array(False, dtype=bool) 

4946 

4947 # We use the weights to calculate the empirical cumulative 

4948 # distribution function cdf 

4949 cdf = weights.cumsum(axis=0, dtype=np.float64) 

4950 cdf /= cdf[-1, ...] # normalization to 1 

4951 # Search index i such that 

4952 # sum(weights[j], j=0..i-1) < quantile <= sum(weights[j], j=0..i) 

4953 # is then equivalent to 

4954 # cdf[i-1] < quantile <= cdf[i] 

4955 # Unfortunately, searchsorted only accepts 1-d arrays as first 

4956 # argument, so we will need to iterate over dimensions. 

4957 

4958 # Without the following cast, searchsorted can return surprising 

4959 # results, e.g. 

4960 # np.searchsorted(np.array([0.2, 0.4, 0.6, 0.8, 1.]), 

4961 # np.array(0.4, dtype=np.float32), side="left") 

4962 # returns 2 instead of 1 because 0.4 is not binary representable. 

4963 if quantiles.dtype.kind == "f": 

4964 cdf = cdf.astype(quantiles.dtype) 

4965 

4966 def find_cdf_1d(arr, cdf): 

4967 indices = np.searchsorted(cdf, quantiles, side="left") 

4968 # We might have reached the maximum with i = len(arr), e.g. for 

4969 # quantiles = 1, and need to cut it to len(arr) - 1. 

4970 indices = minimum(indices, values_count - 1) 

4971 result = take(arr, indices, axis=0) 

4972 return result 

4973 

4974 r_shape = arr.shape[1:] 

4975 if quantiles.ndim > 0: 

4976 r_shape = quantiles.shape + r_shape 

4977 if out is None: 

4978 result = np.empty_like(arr, shape=r_shape) 

4979 else: 

4980 if out.shape != r_shape: 

4981 msg = (f"Wrong shape of argument 'out', shape={r_shape} is " 

4982 f"required; got shape={out.shape}.") 

4983 raise ValueError(msg) 

4984 result = out 

4985 

4986 # See apply_along_axis, which we do for axis=0. Note that Ni = (,) 

4987 # always, so we remove it here. 

4988 Nk = arr.shape[1:] 

4989 for kk in np.ndindex(Nk): 

4990 result[(...,) + kk] = find_cdf_1d( 

4991 arr[np.s_[:, ] + kk], cdf[np.s_[:, ] + kk] 

4992 ) 

4993 

4994 # Make result the same as in unweighted inverted_cdf. 

4995 if result.shape == () and result.dtype == np.dtype("O"): 

4996 result = result.item() 

4997 

4998 if np.any(slices_having_nans): 

4999 if result.ndim == 0 and out is None: 

5000 # can't write to a scalar, but indexing will be correct 

5001 result = arr[-1] 

5002 else: 

5003 np.copyto(result, arr[-1, ...], where=slices_having_nans) 

5004 return result 

5005 

5006 

5007def _trapezoid_dispatcher(y, x=None, dx=None, axis=None): 

5008 return (y, x) 

5009 

5010 

5011@array_function_dispatch(_trapezoid_dispatcher) 

5012def trapezoid(y, x=None, dx=1.0, axis=-1): 

5013 r""" 

5014 Integrate along the given axis using the composite trapezoidal rule. 

5015 

5016 If `x` is provided, the integration happens in sequence along its 

5017 elements - they are not sorted. 

5018 

5019 Integrate `y` (`x`) along each 1d slice on the given axis, compute 

5020 :math:`\int y(x) dx`. 

5021 When `x` is specified, this integrates along the parametric curve, 

5022 computing :math:`\int_t y(t) dt = 

5023 \int_t y(t) \left.\frac{dx}{dt}\right|_{x=x(t)} dt`. 

5024 

5025 .. versionadded:: 2.0.0 

5026 

5027 Parameters 

5028 ---------- 

5029 y : array_like 

5030 Input array to integrate. 

5031 x : array_like, optional 

5032 The sample points corresponding to the `y` values. If `x` is None, 

5033 the sample points are assumed to be evenly spaced `dx` apart. The 

5034 default is None. 

5035 dx : scalar, optional 

5036 The spacing between sample points when `x` is None. The default is 1. 

5037 axis : int, optional 

5038 The axis along which to integrate. 

5039 

5040 Returns 

5041 ------- 

5042 trapezoid : float or ndarray 

5043 Definite integral of `y` = n-dimensional array as approximated along 

5044 a single axis by the trapezoidal rule. If `y` is a 1-dimensional array, 

5045 then the result is a float. If `n` is greater than 1, then the result 

5046 is an `n`-1 dimensional array. 

5047 

5048 See Also 

5049 -------- 

5050 sum, cumsum 

5051 

5052 Notes 

5053 ----- 

5054 Image [2]_ illustrates trapezoidal rule -- y-axis locations of points 

5055 will be taken from `y` array, by default x-axis distances between 

5056 points will be 1.0, alternatively they can be provided with `x` array 

5057 or with `dx` scalar. Return value will be equal to combined area under 

5058 the red lines. 

5059 

5060 

5061 References 

5062 ---------- 

5063 .. [1] Wikipedia page: https://en.wikipedia.org/wiki/Trapezoidal_rule 

5064 

5065 .. [2] Illustration image: 

5066 https://en.wikipedia.org/wiki/File:Composite_trapezoidal_rule_illustration.png 

5067 

5068 Examples 

5069 -------- 

5070 Use the trapezoidal rule on evenly spaced points: 

5071 

5072 >>> np.trapezoid([1, 2, 3]) 

5073 4.0 

5074 

5075 The spacing between sample points can be selected by either the 

5076 ``x`` or ``dx`` arguments: 

5077 

5078 >>> np.trapezoid([1, 2, 3], x=[4, 6, 8]) 

5079 8.0 

5080 >>> np.trapezoid([1, 2, 3], dx=2) 

5081 8.0 

5082 

5083 Using a decreasing ``x`` corresponds to integrating in reverse: 

5084 

5085 >>> np.trapezoid([1, 2, 3], x=[8, 6, 4]) 

5086 -8.0 

5087 

5088 More generally ``x`` is used to integrate along a parametric curve. We can 

5089 estimate the integral :math:`\int_0^1 x^2 = 1/3` using: 

5090 

5091 >>> x = np.linspace(0, 1, num=50) 

5092 >>> y = x**2 

5093 >>> np.trapezoid(y, x) 

5094 0.33340274885464394 

5095 

5096 Or estimate the area of a circle, noting we repeat the sample which closes 

5097 the curve: 

5098 

5099 >>> theta = np.linspace(0, 2 * np.pi, num=1000, endpoint=True) 

5100 >>> np.trapezoid(np.cos(theta), x=np.sin(theta)) 

5101 3.141571941375841 

5102 

5103 ``np.trapezoid`` can be applied along a specified axis to do multiple 

5104 computations in one call: 

5105 

5106 >>> a = np.arange(6).reshape(2, 3) 

5107 >>> a 

5108 array([[0, 1, 2], 

5109 [3, 4, 5]]) 

5110 >>> np.trapezoid(a, axis=0) 

5111 array([1.5, 2.5, 3.5]) 

5112 >>> np.trapezoid(a, axis=1) 

5113 array([2., 8.]) 

5114 """ 

5115 

5116 y = asanyarray(y) 

5117 if x is None: 

5118 d = dx 

5119 else: 

5120 x = asanyarray(x) 

5121 if x.ndim == 1: 

5122 d = diff(x) 

5123 # reshape to correct shape 

5124 shape = [1]*y.ndim 

5125 shape[axis] = d.shape[0] 

5126 d = d.reshape(shape) 

5127 else: 

5128 d = diff(x, axis=axis) 

5129 nd = y.ndim 

5130 slice1 = [slice(None)]*nd 

5131 slice2 = [slice(None)]*nd 

5132 slice1[axis] = slice(1, None) 

5133 slice2[axis] = slice(None, -1) 

5134 try: 

5135 ret = (d * (y[tuple(slice1)] + y[tuple(slice2)]) / 2.0).sum(axis) 

5136 except ValueError: 

5137 # Operations didn't work, cast to ndarray 

5138 d = np.asarray(d) 

5139 y = np.asarray(y) 

5140 ret = add.reduce(d * (y[tuple(slice1)]+y[tuple(slice2)])/2.0, axis) 

5141 return ret 

5142 

5143 

5144@set_module('numpy') 

5145def trapz(y, x=None, dx=1.0, axis=-1): 

5146 """ 

5147 `trapz` is deprecated in NumPy 2.0. 

5148 

5149 Please use `trapezoid` instead, or one of the numerical integration 

5150 functions in `scipy.integrate`. 

5151 """ 

5152 # Deprecated in NumPy 2.0, 2023-08-18 

5153 warnings.warn( 

5154 "`trapz` is deprecated. Use `trapezoid` instead, or one of the " 

5155 "numerical integration functions in `scipy.integrate`.", 

5156 DeprecationWarning, 

5157 stacklevel=2 

5158 ) 

5159 return trapezoid(y, x=x, dx=dx, axis=axis) 

5160 

5161 

5162def _meshgrid_dispatcher(*xi, copy=None, sparse=None, indexing=None): 

5163 return xi 

5164 

5165 

5166# Based on scitools meshgrid 

5167@array_function_dispatch(_meshgrid_dispatcher) 

5168def meshgrid(*xi, copy=True, sparse=False, indexing='xy'): 

5169 """ 

5170 Return a tuple of coordinate matrices from coordinate vectors. 

5171 

5172 Make N-D coordinate arrays for vectorized evaluations of 

5173 N-D scalar/vector fields over N-D grids, given 

5174 one-dimensional coordinate arrays x1, x2,..., xn. 

5175 

5176 .. versionchanged:: 1.9 

5177 1-D and 0-D cases are allowed. 

5178 

5179 Parameters 

5180 ---------- 

5181 x1, x2,..., xn : array_like 

5182 1-D arrays representing the coordinates of a grid. 

5183 indexing : {'xy', 'ij'}, optional 

5184 Cartesian ('xy', default) or matrix ('ij') indexing of output. 

5185 See Notes for more details. 

5186 

5187 .. versionadded:: 1.7.0 

5188 sparse : bool, optional 

5189 If True the shape of the returned coordinate array for dimension *i* 

5190 is reduced from ``(N1, ..., Ni, ... Nn)`` to 

5191 ``(1, ..., 1, Ni, 1, ..., 1)``. These sparse coordinate grids are 

5192 intended to be use with :ref:`basics.broadcasting`. When all 

5193 coordinates are used in an expression, broadcasting still leads to a 

5194 fully-dimensonal result array. 

5195 

5196 Default is False. 

5197 

5198 .. versionadded:: 1.7.0 

5199 copy : bool, optional 

5200 If False, a view into the original arrays are returned in order to 

5201 conserve memory. Default is True. Please note that 

5202 ``sparse=False, copy=False`` will likely return non-contiguous 

5203 arrays. Furthermore, more than one element of a broadcast array 

5204 may refer to a single memory location. If you need to write to the 

5205 arrays, make copies first. 

5206 

5207 .. versionadded:: 1.7.0 

5208 

5209 Returns 

5210 ------- 

5211 X1, X2,..., XN : tuple of ndarrays 

5212 For vectors `x1`, `x2`,..., `xn` with lengths ``Ni=len(xi)``, 

5213 returns ``(N1, N2, N3,..., Nn)`` shaped arrays if indexing='ij' 

5214 or ``(N2, N1, N3,..., Nn)`` shaped arrays if indexing='xy' 

5215 with the elements of `xi` repeated to fill the matrix along 

5216 the first dimension for `x1`, the second for `x2` and so on. 

5217 

5218 Notes 

5219 ----- 

5220 This function supports both indexing conventions through the indexing 

5221 keyword argument. Giving the string 'ij' returns a meshgrid with 

5222 matrix indexing, while 'xy' returns a meshgrid with Cartesian indexing. 

5223 In the 2-D case with inputs of length M and N, the outputs are of shape 

5224 (N, M) for 'xy' indexing and (M, N) for 'ij' indexing. In the 3-D case 

5225 with inputs of length M, N and P, outputs are of shape (N, M, P) for 

5226 'xy' indexing and (M, N, P) for 'ij' indexing. The difference is 

5227 illustrated by the following code snippet:: 

5228 

5229 xv, yv = np.meshgrid(x, y, indexing='ij') 

5230 for i in range(nx): 

5231 for j in range(ny): 

5232 # treat xv[i,j], yv[i,j] 

5233 

5234 xv, yv = np.meshgrid(x, y, indexing='xy') 

5235 for i in range(nx): 

5236 for j in range(ny): 

5237 # treat xv[j,i], yv[j,i] 

5238 

5239 In the 1-D and 0-D case, the indexing and sparse keywords have no effect. 

5240 

5241 See Also 

5242 -------- 

5243 mgrid : Construct a multi-dimensional "meshgrid" using indexing notation. 

5244 ogrid : Construct an open multi-dimensional "meshgrid" using indexing 

5245 notation. 

5246 :ref:`how-to-index` 

5247 

5248 Examples 

5249 -------- 

5250 >>> nx, ny = (3, 2) 

5251 >>> x = np.linspace(0, 1, nx) 

5252 >>> y = np.linspace(0, 1, ny) 

5253 >>> xv, yv = np.meshgrid(x, y) 

5254 >>> xv 

5255 array([[0. , 0.5, 1. ], 

5256 [0. , 0.5, 1. ]]) 

5257 >>> yv 

5258 array([[0., 0., 0.], 

5259 [1., 1., 1.]]) 

5260 

5261 The result of `meshgrid` is a coordinate grid: 

5262 

5263 >>> import matplotlib.pyplot as plt 

5264 >>> plt.plot(xv, yv, marker='o', color='k', linestyle='none') 

5265 >>> plt.show() 

5266 

5267 You can create sparse output arrays to save memory and computation time. 

5268 

5269 >>> xv, yv = np.meshgrid(x, y, sparse=True) 

5270 >>> xv 

5271 array([[0. , 0.5, 1. ]]) 

5272 >>> yv 

5273 array([[0.], 

5274 [1.]]) 

5275 

5276 `meshgrid` is very useful to evaluate functions on a grid. If the 

5277 function depends on all coordinates, both dense and sparse outputs can be 

5278 used. 

5279 

5280 >>> x = np.linspace(-5, 5, 101) 

5281 >>> y = np.linspace(-5, 5, 101) 

5282 >>> # full coordinate arrays 

5283 >>> xx, yy = np.meshgrid(x, y) 

5284 >>> zz = np.sqrt(xx**2 + yy**2) 

5285 >>> xx.shape, yy.shape, zz.shape 

5286 ((101, 101), (101, 101), (101, 101)) 

5287 >>> # sparse coordinate arrays 

5288 >>> xs, ys = np.meshgrid(x, y, sparse=True) 

5289 >>> zs = np.sqrt(xs**2 + ys**2) 

5290 >>> xs.shape, ys.shape, zs.shape 

5291 ((1, 101), (101, 1), (101, 101)) 

5292 >>> np.array_equal(zz, zs) 

5293 True 

5294 

5295 >>> h = plt.contourf(x, y, zs) 

5296 >>> plt.axis('scaled') 

5297 >>> plt.colorbar() 

5298 >>> plt.show() 

5299 """ 

5300 ndim = len(xi) 

5301 

5302 if indexing not in ['xy', 'ij']: 

5303 raise ValueError( 

5304 "Valid values for `indexing` are 'xy' and 'ij'.") 

5305 

5306 s0 = (1,) * ndim 

5307 output = [np.asanyarray(x).reshape(s0[:i] + (-1,) + s0[i + 1:]) 

5308 for i, x in enumerate(xi)] 

5309 

5310 if indexing == 'xy' and ndim > 1: 

5311 # switch first and second axis 

5312 output[0].shape = (1, -1) + s0[2:] 

5313 output[1].shape = (-1, 1) + s0[2:] 

5314 

5315 if not sparse: 

5316 # Return the full N-D matrix (not only the 1-D vector) 

5317 output = np.broadcast_arrays(*output, subok=True) 

5318 

5319 if copy: 

5320 output = tuple(x.copy() for x in output) 

5321 

5322 return output 

5323 

5324 

5325def _delete_dispatcher(arr, obj, axis=None): 

5326 return (arr, obj) 

5327 

5328 

5329@array_function_dispatch(_delete_dispatcher) 

5330def delete(arr, obj, axis=None): 

5331 """ 

5332 Return a new array with sub-arrays along an axis deleted. For a one 

5333 dimensional array, this returns those entries not returned by 

5334 `arr[obj]`. 

5335 

5336 Parameters 

5337 ---------- 

5338 arr : array_like 

5339 Input array. 

5340 obj : slice, int or array of ints 

5341 Indicate indices of sub-arrays to remove along the specified axis. 

5342 

5343 .. versionchanged:: 1.19.0 

5344 Boolean indices are now treated as a mask of elements to remove, 

5345 rather than being cast to the integers 0 and 1. 

5346 

5347 axis : int, optional 

5348 The axis along which to delete the subarray defined by `obj`. 

5349 If `axis` is None, `obj` is applied to the flattened array. 

5350 

5351 Returns 

5352 ------- 

5353 out : ndarray 

5354 A copy of `arr` with the elements specified by `obj` removed. Note 

5355 that `delete` does not occur in-place. If `axis` is None, `out` is 

5356 a flattened array. 

5357 

5358 See Also 

5359 -------- 

5360 insert : Insert elements into an array. 

5361 append : Append elements at the end of an array. 

5362 

5363 Notes 

5364 ----- 

5365 Often it is preferable to use a boolean mask. For example: 

5366 

5367 >>> arr = np.arange(12) + 1 

5368 >>> mask = np.ones(len(arr), dtype=bool) 

5369 >>> mask[[0,2,4]] = False 

5370 >>> result = arr[mask,...] 

5371 

5372 Is equivalent to ``np.delete(arr, [0,2,4], axis=0)``, but allows further 

5373 use of `mask`. 

5374 

5375 Examples 

5376 -------- 

5377 >>> arr = np.array([[1,2,3,4], [5,6,7,8], [9,10,11,12]]) 

5378 >>> arr 

5379 array([[ 1, 2, 3, 4], 

5380 [ 5, 6, 7, 8], 

5381 [ 9, 10, 11, 12]]) 

5382 >>> np.delete(arr, 1, 0) 

5383 array([[ 1, 2, 3, 4], 

5384 [ 9, 10, 11, 12]]) 

5385 

5386 >>> np.delete(arr, np.s_[::2], 1) 

5387 array([[ 2, 4], 

5388 [ 6, 8], 

5389 [10, 12]]) 

5390 >>> np.delete(arr, [1,3,5], None) 

5391 array([ 1, 3, 5, 7, 8, 9, 10, 11, 12]) 

5392 

5393 """ 

5394 conv = _array_converter(arr) 

5395 arr, = conv.as_arrays(subok=False) 

5396 

5397 ndim = arr.ndim 

5398 arrorder = 'F' if arr.flags.fnc else 'C' 

5399 if axis is None: 

5400 if ndim != 1: 

5401 arr = arr.ravel() 

5402 # needed for np.matrix, which is still not 1d after being ravelled 

5403 ndim = arr.ndim 

5404 axis = ndim - 1 

5405 else: 

5406 axis = normalize_axis_index(axis, ndim) 

5407 

5408 slobj = [slice(None)]*ndim 

5409 N = arr.shape[axis] 

5410 newshape = list(arr.shape) 

5411 

5412 if isinstance(obj, slice): 

5413 start, stop, step = obj.indices(N) 

5414 xr = range(start, stop, step) 

5415 numtodel = len(xr) 

5416 

5417 if numtodel <= 0: 

5418 return conv.wrap(arr.copy(order=arrorder), to_scalar=False) 

5419 

5420 # Invert if step is negative: 

5421 if step < 0: 

5422 step = -step 

5423 start = xr[-1] 

5424 stop = xr[0] + 1 

5425 

5426 newshape[axis] -= numtodel 

5427 new = empty(newshape, arr.dtype, arrorder) 

5428 # copy initial chunk 

5429 if start == 0: 

5430 pass 

5431 else: 

5432 slobj[axis] = slice(None, start) 

5433 new[tuple(slobj)] = arr[tuple(slobj)] 

5434 # copy end chunk 

5435 if stop == N: 

5436 pass 

5437 else: 

5438 slobj[axis] = slice(stop-numtodel, None) 

5439 slobj2 = [slice(None)]*ndim 

5440 slobj2[axis] = slice(stop, None) 

5441 new[tuple(slobj)] = arr[tuple(slobj2)] 

5442 # copy middle pieces 

5443 if step == 1: 

5444 pass 

5445 else: # use array indexing. 

5446 keep = ones(stop-start, dtype=bool) 

5447 keep[:stop-start:step] = False 

5448 slobj[axis] = slice(start, stop-numtodel) 

5449 slobj2 = [slice(None)]*ndim 

5450 slobj2[axis] = slice(start, stop) 

5451 arr = arr[tuple(slobj2)] 

5452 slobj2[axis] = keep 

5453 new[tuple(slobj)] = arr[tuple(slobj2)] 

5454 

5455 return conv.wrap(new, to_scalar=False) 

5456 

5457 if isinstance(obj, (int, integer)) and not isinstance(obj, bool): 

5458 single_value = True 

5459 else: 

5460 single_value = False 

5461 _obj = obj 

5462 obj = np.asarray(obj) 

5463 # `size == 0` to allow empty lists similar to indexing, but (as there) 

5464 # is really too generic: 

5465 if obj.size == 0 and not isinstance(_obj, np.ndarray): 

5466 obj = obj.astype(intp) 

5467 elif obj.size == 1 and obj.dtype.kind in "ui": 

5468 # For a size 1 integer array we can use the single-value path 

5469 # (most dtypes, except boolean, should just fail later). 

5470 obj = obj.item() 

5471 single_value = True 

5472 

5473 if single_value: 

5474 # optimization for a single value 

5475 if (obj < -N or obj >= N): 

5476 raise IndexError( 

5477 "index %i is out of bounds for axis %i with " 

5478 "size %i" % (obj, axis, N)) 

5479 if (obj < 0): 

5480 obj += N 

5481 newshape[axis] -= 1 

5482 new = empty(newshape, arr.dtype, arrorder) 

5483 slobj[axis] = slice(None, obj) 

5484 new[tuple(slobj)] = arr[tuple(slobj)] 

5485 slobj[axis] = slice(obj, None) 

5486 slobj2 = [slice(None)]*ndim 

5487 slobj2[axis] = slice(obj+1, None) 

5488 new[tuple(slobj)] = arr[tuple(slobj2)] 

5489 else: 

5490 if obj.dtype == bool: 

5491 if obj.shape != (N,): 

5492 raise ValueError('boolean array argument obj to delete ' 

5493 'must be one dimensional and match the axis ' 

5494 'length of {}'.format(N)) 

5495 

5496 # optimization, the other branch is slower 

5497 keep = ~obj 

5498 else: 

5499 keep = ones(N, dtype=bool) 

5500 keep[obj,] = False 

5501 

5502 slobj[axis] = keep 

5503 new = arr[tuple(slobj)] 

5504 

5505 return conv.wrap(new, to_scalar=False) 

5506 

5507 

5508def _insert_dispatcher(arr, obj, values, axis=None): 

5509 return (arr, obj, values) 

5510 

5511 

5512@array_function_dispatch(_insert_dispatcher) 

5513def insert(arr, obj, values, axis=None): 

5514 """ 

5515 Insert values along the given axis before the given indices. 

5516 

5517 Parameters 

5518 ---------- 

5519 arr : array_like 

5520 Input array. 

5521 obj : int, slice or sequence of ints 

5522 Object that defines the index or indices before which `values` is 

5523 inserted. 

5524 

5525 .. versionadded:: 1.8.0 

5526 

5527 Support for multiple insertions when `obj` is a single scalar or a 

5528 sequence with one element (similar to calling insert multiple 

5529 times). 

5530 values : array_like 

5531 Values to insert into `arr`. If the type of `values` is different 

5532 from that of `arr`, `values` is converted to the type of `arr`. 

5533 `values` should be shaped so that ``arr[...,obj,...] = values`` 

5534 is legal. 

5535 axis : int, optional 

5536 Axis along which to insert `values`. If `axis` is None then `arr` 

5537 is flattened first. 

5538 

5539 Returns 

5540 ------- 

5541 out : ndarray 

5542 A copy of `arr` with `values` inserted. Note that `insert` 

5543 does not occur in-place: a new array is returned. If 

5544 `axis` is None, `out` is a flattened array. 

5545 

5546 See Also 

5547 -------- 

5548 append : Append elements at the end of an array. 

5549 concatenate : Join a sequence of arrays along an existing axis. 

5550 delete : Delete elements from an array. 

5551 

5552 Notes 

5553 ----- 

5554 Note that for higher dimensional inserts ``obj=0`` behaves very different 

5555 from ``obj=[0]`` just like ``arr[:,0,:] = values`` is different from 

5556 ``arr[:,[0],:] = values``. 

5557 

5558 Examples 

5559 -------- 

5560 >>> a = np.array([[1, 1], [2, 2], [3, 3]]) 

5561 >>> a 

5562 array([[1, 1], 

5563 [2, 2], 

5564 [3, 3]]) 

5565 >>> np.insert(a, 1, 5) 

5566 array([1, 5, 1, ..., 2, 3, 3]) 

5567 >>> np.insert(a, 1, 5, axis=1) 

5568 array([[1, 5, 1], 

5569 [2, 5, 2], 

5570 [3, 5, 3]]) 

5571 

5572 Difference between sequence and scalars: 

5573 

5574 >>> np.insert(a, [1], [[1],[2],[3]], axis=1) 

5575 array([[1, 1, 1], 

5576 [2, 2, 2], 

5577 [3, 3, 3]]) 

5578 >>> np.array_equal(np.insert(a, 1, [1, 2, 3], axis=1), 

5579 ... np.insert(a, [1], [[1],[2],[3]], axis=1)) 

5580 True 

5581 

5582 >>> b = a.flatten() 

5583 >>> b 

5584 array([1, 1, 2, 2, 3, 3]) 

5585 >>> np.insert(b, [2, 2], [5, 6]) 

5586 array([1, 1, 5, ..., 2, 3, 3]) 

5587 

5588 >>> np.insert(b, slice(2, 4), [5, 6]) 

5589 array([1, 1, 5, ..., 2, 3, 3]) 

5590 

5591 >>> np.insert(b, [2, 2], [7.13, False]) # type casting 

5592 array([1, 1, 7, ..., 2, 3, 3]) 

5593 

5594 >>> x = np.arange(8).reshape(2, 4) 

5595 >>> idx = (1, 3) 

5596 >>> np.insert(x, idx, 999, axis=1) 

5597 array([[ 0, 999, 1, 2, 999, 3], 

5598 [ 4, 999, 5, 6, 999, 7]]) 

5599 

5600 """ 

5601 conv = _array_converter(arr) 

5602 arr, = conv.as_arrays(subok=False) 

5603 

5604 ndim = arr.ndim 

5605 arrorder = 'F' if arr.flags.fnc else 'C' 

5606 if axis is None: 

5607 if ndim != 1: 

5608 arr = arr.ravel() 

5609 # needed for np.matrix, which is still not 1d after being ravelled 

5610 ndim = arr.ndim 

5611 axis = ndim - 1 

5612 else: 

5613 axis = normalize_axis_index(axis, ndim) 

5614 slobj = [slice(None)]*ndim 

5615 N = arr.shape[axis] 

5616 newshape = list(arr.shape) 

5617 

5618 if isinstance(obj, slice): 

5619 # turn it into a range object 

5620 indices = arange(*obj.indices(N), dtype=intp) 

5621 else: 

5622 # need to copy obj, because indices will be changed in-place 

5623 indices = np.array(obj) 

5624 if indices.dtype == bool: 

5625 # See also delete 

5626 # 2012-10-11, NumPy 1.8 

5627 warnings.warn( 

5628 "in the future insert will treat boolean arrays and " 

5629 "array-likes as a boolean index instead of casting it to " 

5630 "integer", FutureWarning, stacklevel=2) 

5631 indices = indices.astype(intp) 

5632 # Code after warning period: 

5633 #if obj.ndim != 1: 

5634 # raise ValueError('boolean array argument obj to insert ' 

5635 # 'must be one dimensional') 

5636 #indices = np.flatnonzero(obj) 

5637 elif indices.ndim > 1: 

5638 raise ValueError( 

5639 "index array argument obj to insert must be one dimensional " 

5640 "or scalar") 

5641 if indices.size == 1: 

5642 index = indices.item() 

5643 if index < -N or index > N: 

5644 raise IndexError(f"index {obj} is out of bounds for axis {axis} " 

5645 f"with size {N}") 

5646 if (index < 0): 

5647 index += N 

5648 

5649 # There are some object array corner cases here, but we cannot avoid 

5650 # that: 

5651 values = array(values, copy=None, ndmin=arr.ndim, dtype=arr.dtype) 

5652 if indices.ndim == 0: 

5653 # broadcasting is very different here, since a[:,0,:] = ... behaves 

5654 # very different from a[:,[0],:] = ...! This changes values so that 

5655 # it works likes the second case. (here a[:,0:1,:]) 

5656 values = np.moveaxis(values, 0, axis) 

5657 numnew = values.shape[axis] 

5658 newshape[axis] += numnew 

5659 new = empty(newshape, arr.dtype, arrorder) 

5660 slobj[axis] = slice(None, index) 

5661 new[tuple(slobj)] = arr[tuple(slobj)] 

5662 slobj[axis] = slice(index, index+numnew) 

5663 new[tuple(slobj)] = values 

5664 slobj[axis] = slice(index+numnew, None) 

5665 slobj2 = [slice(None)] * ndim 

5666 slobj2[axis] = slice(index, None) 

5667 new[tuple(slobj)] = arr[tuple(slobj2)] 

5668 

5669 return conv.wrap(new, to_scalar=False) 

5670 

5671 elif indices.size == 0 and not isinstance(obj, np.ndarray): 

5672 # Can safely cast the empty list to intp 

5673 indices = indices.astype(intp) 

5674 

5675 indices[indices < 0] += N 

5676 

5677 numnew = len(indices) 

5678 order = indices.argsort(kind='mergesort') # stable sort 

5679 indices[order] += np.arange(numnew) 

5680 

5681 newshape[axis] += numnew 

5682 old_mask = ones(newshape[axis], dtype=bool) 

5683 old_mask[indices] = False 

5684 

5685 new = empty(newshape, arr.dtype, arrorder) 

5686 slobj2 = [slice(None)]*ndim 

5687 slobj[axis] = indices 

5688 slobj2[axis] = old_mask 

5689 new[tuple(slobj)] = values 

5690 new[tuple(slobj2)] = arr 

5691 

5692 return conv.wrap(new, to_scalar=False) 

5693 

5694 

5695def _append_dispatcher(arr, values, axis=None): 

5696 return (arr, values) 

5697 

5698 

5699@array_function_dispatch(_append_dispatcher) 

5700def append(arr, values, axis=None): 

5701 """ 

5702 Append values to the end of an array. 

5703 

5704 Parameters 

5705 ---------- 

5706 arr : array_like 

5707 Values are appended to a copy of this array. 

5708 values : array_like 

5709 These values are appended to a copy of `arr`. It must be of the 

5710 correct shape (the same shape as `arr`, excluding `axis`). If 

5711 `axis` is not specified, `values` can be any shape and will be 

5712 flattened before use. 

5713 axis : int, optional 

5714 The axis along which `values` are appended. If `axis` is not 

5715 given, both `arr` and `values` are flattened before use. 

5716 

5717 Returns 

5718 ------- 

5719 append : ndarray 

5720 A copy of `arr` with `values` appended to `axis`. Note that 

5721 `append` does not occur in-place: a new array is allocated and 

5722 filled. If `axis` is None, `out` is a flattened array. 

5723 

5724 See Also 

5725 -------- 

5726 insert : Insert elements into an array. 

5727 delete : Delete elements from an array. 

5728 

5729 Examples 

5730 -------- 

5731 >>> np.append([1, 2, 3], [[4, 5, 6], [7, 8, 9]]) 

5732 array([1, 2, 3, ..., 7, 8, 9]) 

5733 

5734 When `axis` is specified, `values` must have the correct shape. 

5735 

5736 >>> np.append([[1, 2, 3], [4, 5, 6]], [[7, 8, 9]], axis=0) 

5737 array([[1, 2, 3], 

5738 [4, 5, 6], 

5739 [7, 8, 9]]) 

5740 >>> np.append([[1, 2, 3], [4, 5, 6]], [7, 8, 9], axis=0) 

5741 Traceback (most recent call last): 

5742 ... 

5743 ValueError: all the input arrays must have same number of dimensions, but 

5744 the array at index 0 has 2 dimension(s) and the array at index 1 has 1 

5745 dimension(s) 

5746 

5747 """ 

5748 arr = asanyarray(arr) 

5749 if axis is None: 

5750 if arr.ndim != 1: 

5751 arr = arr.ravel() 

5752 values = ravel(values) 

5753 axis = arr.ndim-1 

5754 return concatenate((arr, values), axis=axis) 

5755 

5756 

5757def _digitize_dispatcher(x, bins, right=None): 

5758 return (x, bins) 

5759 

5760 

5761@array_function_dispatch(_digitize_dispatcher) 

5762def digitize(x, bins, right=False): 

5763 """ 

5764 Return the indices of the bins to which each value in input array belongs. 

5765 

5766 ========= ============= ============================ 

5767 `right` order of bins returned index `i` satisfies 

5768 ========= ============= ============================ 

5769 ``False`` increasing ``bins[i-1] <= x < bins[i]`` 

5770 ``True`` increasing ``bins[i-1] < x <= bins[i]`` 

5771 ``False`` decreasing ``bins[i-1] > x >= bins[i]`` 

5772 ``True`` decreasing ``bins[i-1] >= x > bins[i]`` 

5773 ========= ============= ============================ 

5774 

5775 If values in `x` are beyond the bounds of `bins`, 0 or ``len(bins)`` is 

5776 returned as appropriate. 

5777 

5778 Parameters 

5779 ---------- 

5780 x : array_like 

5781 Input array to be binned. Prior to NumPy 1.10.0, this array had to 

5782 be 1-dimensional, but can now have any shape. 

5783 bins : array_like 

5784 Array of bins. It has to be 1-dimensional and monotonic. 

5785 right : bool, optional 

5786 Indicating whether the intervals include the right or the left bin 

5787 edge. Default behavior is (right==False) indicating that the interval 

5788 does not include the right edge. The left bin end is open in this 

5789 case, i.e., bins[i-1] <= x < bins[i] is the default behavior for 

5790 monotonically increasing bins. 

5791 

5792 Returns 

5793 ------- 

5794 indices : ndarray of ints 

5795 Output array of indices, of same shape as `x`. 

5796 

5797 Raises 

5798 ------ 

5799 ValueError 

5800 If `bins` is not monotonic. 

5801 TypeError 

5802 If the type of the input is complex. 

5803 

5804 See Also 

5805 -------- 

5806 bincount, histogram, unique, searchsorted 

5807 

5808 Notes 

5809 ----- 

5810 If values in `x` are such that they fall outside the bin range, 

5811 attempting to index `bins` with the indices that `digitize` returns 

5812 will result in an IndexError. 

5813 

5814 .. versionadded:: 1.10.0 

5815 

5816 `numpy.digitize` is implemented in terms of `numpy.searchsorted`. 

5817 This means that a binary search is used to bin the values, which scales 

5818 much better for larger number of bins than the previous linear search. 

5819 It also removes the requirement for the input array to be 1-dimensional. 

5820 

5821 For monotonically *increasing* `bins`, the following are equivalent:: 

5822 

5823 np.digitize(x, bins, right=True) 

5824 np.searchsorted(bins, x, side='left') 

5825 

5826 Note that as the order of the arguments are reversed, the side must be too. 

5827 The `searchsorted` call is marginally faster, as it does not do any 

5828 monotonicity checks. Perhaps more importantly, it supports all dtypes. 

5829 

5830 Examples 

5831 -------- 

5832 >>> x = np.array([0.2, 6.4, 3.0, 1.6]) 

5833 >>> bins = np.array([0.0, 1.0, 2.5, 4.0, 10.0]) 

5834 >>> inds = np.digitize(x, bins) 

5835 >>> inds 

5836 array([1, 4, 3, 2]) 

5837 >>> for n in range(x.size): 

5838 ... print(bins[inds[n]-1], "<=", x[n], "<", bins[inds[n]]) 

5839 ... 

5840 0.0 <= 0.2 < 1.0 

5841 4.0 <= 6.4 < 10.0 

5842 2.5 <= 3.0 < 4.0 

5843 1.0 <= 1.6 < 2.5 

5844 

5845 >>> x = np.array([1.2, 10.0, 12.4, 15.5, 20.]) 

5846 >>> bins = np.array([0, 5, 10, 15, 20]) 

5847 >>> np.digitize(x,bins,right=True) 

5848 array([1, 2, 3, 4, 4]) 

5849 >>> np.digitize(x,bins,right=False) 

5850 array([1, 3, 3, 4, 5]) 

5851 """ 

5852 x = _nx.asarray(x) 

5853 bins = _nx.asarray(bins) 

5854 

5855 # here for compatibility, searchsorted below is happy to take this 

5856 if np.issubdtype(x.dtype, _nx.complexfloating): 

5857 raise TypeError("x may not be complex") 

5858 

5859 mono = _monotonicity(bins) 

5860 if mono == 0: 

5861 raise ValueError("bins must be monotonically increasing or decreasing") 

5862 

5863 # this is backwards because the arguments below are swapped 

5864 side = 'left' if right else 'right' 

5865 if mono == -1: 

5866 # reverse the bins, and invert the results 

5867 return len(bins) - _nx.searchsorted(bins[::-1], x, side=side) 

5868 else: 

5869 return _nx.searchsorted(bins, x, side=side)