NumPy 源码解析(五十一)
.\numpy\numpy\_core\numeric.py
import functools
import itertools
import operator
import sys
import warnings
import numbers
import builtins
import math
import numpy as np
from . import multiarray
from . import numerictypes as nt
from .multiarray import (
ALLOW_THREADS, BUFSIZE, CLIP, MAXDIMS, MAY_SHARE_BOUNDS, MAY_SHARE_EXACT,
RAISE, WRAP, arange, array, asarray, asanyarray, ascontiguousarray,
asfortranarray, broadcast, can_cast, concatenate, copyto, dot, dtype,
empty, empty_like, flatiter, frombuffer, from_dlpack, fromfile, fromiter,
fromstring, inner, lexsort, matmul, may_share_memory, min_scalar_type,
ndarray, nditer, nested_iters, promote_types, putmask, result_type,
shares_memory, vdot, where, zeros, normalize_axis_index,
_get_promotion_state, _set_promotion_state, vecdot
)
from . import overrides
from . import umath
from . import shape_base
from .overrides import set_array_function_like_doc, set_module
from .umath import (multiply, invert, sin, PINF, NAN)
from . import numerictypes
from ..exceptions import AxisError
from ._ufunc_config import errstate, _no_nep50_warning
bitwise_not = invert
ufunc = type(sin)
newaxis = None
array_function_dispatch = functools.partial(
overrides.array_function_dispatch, module='numpy')
__all__ = [
'newaxis', 'ndarray', 'flatiter', 'nditer', 'nested_iters', 'ufunc',
'arange', 'array', 'asarray', 'asanyarray', 'ascontiguousarray',
'asfortranarray', 'zeros', 'count_nonzero', 'empty', 'broadcast', 'dtype',
'fromstring', 'fromfile', 'frombuffer', 'from_dlpack', 'where',
'argwhere', 'copyto', 'concatenate', 'lexsort', 'astype',
'can_cast', 'promote_types', 'min_scalar_type',
'result_type', 'isfortran', 'empty_like', 'zeros_like', 'ones_like',
'correlate', 'convolve', 'inner', 'dot', 'outer', 'vdot', 'roll',
'rollaxis', 'moveaxis', 'cross', 'tensordot', 'little_endian',
'fromiter', 'array_equal', 'array_equiv', 'indices', 'fromfunction',
'isclose', 'isscalar', 'binary_repr', 'base_repr', 'ones',
'identity', 'allclose', 'putmask',
'flatnonzero', 'inf', 'nan', 'False_', 'True_', 'bitwise_not',
'full', 'full_like', 'matmul', 'vecdot', 'shares_memory',
'may_share_memory', '_get_promotion_state', '_set_promotion_state']
def _zeros_like_dispatcher(
a, dtype=None, order=None, subok=None, shape=None, *, device=None
):
return (a,)
@array_function_dispatch(_zeros_like_dispatcher)
def zeros_like(
a, dtype=None, order='K', subok=True, shape=None, *, device=None
):
"""
Return an array of zeros with the same shape and type as a given array.
Parameters
----------
a : array_like
The shape and data-type of `a` define these same attributes of
the returned array.
dtype : data-type, optional
Overrides the data type of the result.
.. versionadded:: 1.6.0
"""
res = empty_like(
a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
)
z = zeros(1, dtype=res.dtype)
multiarray.copyto(res, z, casting='unsafe')
return res
@set_array_function_like_doc
@set_module('numpy')
def ones(shape, dtype=None, order='C', *, device=None, like=None):
"""
Return a new array of given shape and type, filled with ones.
Parameters
----------
shape : int or sequence of ints
Shape of the new array, e.g., ``(2, 3)`` or ``2``.
dtype : data-type, optional
The desired data-type for the array, e.g., `numpy.int8`. Default is
`numpy.float64`.
order : {'C', 'F'}, optional, default: C
Whether to store multi-dimensional data in row-major
(C-style) or column-major (Fortran-style) order in
memory.
device : str, optional
The device on which to place the created array. Default: None.
For Array-API interoperability only, so must be ``"cpu"`` if passed.
.. versionadded:: 2.0.0
${ARRAY_FUNCTION_LIKE}
.. versionadded:: 1.20.0
Returns
-------
out : ndarray
Array of ones with the given shape, dtype, and order.
See Also
--------
ones_like : Return an array of ones with shape and type of input.
empty : Return a new uninitialized array.
zeros : Return a new array setting values to zero.
full : Return a new array of given shape filled with value.
Examples
--------
>>> np.ones(5)
array([1., 1., 1., 1., 1.])
>>> np.ones((5,), dtype=int)
array([1, 1, 1, 1, 1])
>>> np.ones((2, 1))
array([[1.],
[1.]])
>>> s = (2,2)
>>> np.ones(s)
array([[1., 1.],
[1., 1.]])
"""
if like is not None:
return _ones_with_like(
like, shape, dtype=dtype, order=order, device=device
)
a = empty(shape, dtype, order, device=device)
multiarray.copyto(a, 1, casting='unsafe')
return a
_ones_with_like = array_function_dispatch()(ones)
def _ones_like_dispatcher(
a, dtype=None, order=None, subok=None, shape=None, *, device=None
):
return (a,)
@array_function_dispatch(_ones_like_dispatcher)
def ones_like(
a, dtype=None, order='K', subok=True, shape=None, *, device=None
):
"""
Return an array of ones with the same shape and type as a given array.
Parameters
----------
a : array_like
The shape and data-type of `a` define these same attributes of
the returned array.
dtype : data-type, optional
Overrides the data type of the result.
.. versionadded:: 1.6.0
order : {'C', 'F', 'A', or 'K'}, optional
Overrides the memory layout of the result. 'C' means C-order,
'F' means F-order, 'A' means 'F' if `a` is Fortran contiguous,
'C' otherwise. 'K' means match the layout of `a` as closely
as possible.
.. versionadded:: 1.6.0
subok : bool, optional.
If True, then the newly created array will use the sub-class
type of `a`, otherwise it will be a base-class array. Defaults
to True.
"""
pass
"""
res = empty_like(
a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
)
# 将值1复制到res数组中,使用'unsafe'转换方式
multiarray.copyto(res, 1, casting='unsafe')
# 返回生成的数组res
return res
# 定义一个函数 `_full_dispatcher`,用于创建包含指定元素的数组,返回值是一个元组
def _full_dispatcher(
shape, fill_value, dtype=None, order=None, *, device=None, like=None
):
return(like,)
# 修饰器,设置函数的行为类似于某个函数文档
@set_array_function_like_doc
# 设置函数所属的模块为 'numpy'
@set_module('numpy')
# 定义函数 `full`,返回一个指定形状和类型的新数组,用指定值填充
def full(shape, fill_value, dtype=None, order='C', *, device=None, like=None):
"""
Return a new array of given shape and type, filled with `fill_value`.
Parameters
----------
shape : int or sequence of ints
Shape of the new array, e.g., ``(2, 3)`` or ``2``.
fill_value : scalar or array_like
Fill value.
dtype : data-type, optional
The desired data-type for the array The default, None, means
``np.array(fill_value).dtype``.
order : {'C', 'F'}, optional
Whether to store multidimensional data in C- or Fortran-contiguous
(row- or column-wise) order in memory.
device : str, optional
The device on which to place the created array. Default: None.
For Array-API interoperability only, so must be ``"cpu"`` if passed.
.. versionadded:: 2.0.0
${ARRAY_FUNCTION_LIKE}
.. versionadded:: 1.20.0
Returns
-------
out : ndarray
Array of `fill_value` with the given shape, dtype, and order.
See Also
--------
full_like : Return a new array with shape of input filled with value.
empty : Return a new uninitialized array.
ones : Return a new array setting values to one.
zeros : Return a new array setting values to zero.
Examples
--------
>>> np.full((2, 2), np.inf)
array([[inf, inf],
[inf, inf]])
>>> np.full((2, 2), 10)
array([[10, 10],
[10, 10]])
>>> np.full((2, 2), [1, 2])
array([[1, 2],
[1, 2]])
"""
# 如果指定了 `like` 参数,则返回根据 `like` 的形状和类型创建的新数组
if like is not None:
return _full_with_like(
like, shape, fill_value, dtype=dtype, order=order, device=device
)
# 如果未指定 `dtype`,将 `fill_value` 转换成数组并获取其数据类型
if dtype is None:
fill_value = asarray(fill_value)
dtype = fill_value.dtype
# 创建一个未初始化的数组 `a`,指定形状、数据类型、存储顺序和设备
a = empty(shape, dtype, order, device=device)
# 将 `fill_value` 的值复制到数组 `a` 中
multiarray.copyto(a, fill_value, casting='unsafe')
return a
# 使用函数分发装饰器注册 `full` 函数
_full_with_like = array_function_dispatch()(full)
# 定义一个函数 `_full_like_dispatcher`,用于返回一个元组,指定其参数 `a`
def _full_like_dispatcher(
a, fill_value, dtype=None, order=None, subok=None, shape=None,
*, device=None
):
return (a,)
# 使用函数分发装饰器注册 `full_like` 函数,并指定 `_full_like_dispatcher` 作为分发函数
@array_function_dispatch(_full_like_dispatcher)
# 定义函数 `full_like`,返回一个与给定数组 `a` 相同形状和类型的新数组,用指定值填充
def full_like(
a, fill_value, dtype=None, order='K', subok=True, shape=None,
*, device=None
):
"""
Return a full array with the same shape and type as a given array.
Parameters
----------
a : array_like
The shape and data-type of `a` define these same attributes of
the returned array.
fill_value : array_like
Fill value.
dtype : data-type, optional
Overrides the data type of the result.
"""
# 创建一个与输入数组 `a` 相同形状和类型的新数组,使用指定的填充值 `fill_value`
res = empty_like(
a, dtype=dtype, order=order, subok=subok, shape=shape, device=device
)
# 将 `fill_value` 的值复制到新创建的数组 `res` 中,使用不安全的类型转换
multiarray.copyto(res, fill_value, casting='unsafe')
# 返回填充后的新数组 `res`
return res
# 定义一个分发器函数,用于向 `count_nonzero` 函数分发参数 `a`
def _count_nonzero_dispatcher(a, axis=None, *, keepdims=None):
# 返回一个元组,包含参数 `a`,其他参数为默认值
return (a,)
# 使用装饰器 `array_function_dispatch` 装饰的 `count_nonzero` 函数
@array_function_dispatch(_count_nonzero_dispatcher)
def count_nonzero(a, axis=None, *, keepdims=False):
"""
Counts the number of non-zero values in the array `a`.
The word "non-zero" is in reference to the Python 2.x
built-in method `__nonzero__()` (renamed `__bool__()`
in Python 3.x) of Python objects that tests an object's
"truthfulness". For example, any number is considered
truthful if it is nonzero, whereas any string is considered
truthful if it is not the empty string. Thus, this function
(recursively) counts how many elements in `a` (and in
sub-arrays thereof) have their `__nonzero__()` or `__bool__()`
method evaluated to `True`.
Parameters
----------
a : array_like
The array for which to count non-zeros.
axis : int or tuple, optional
Axis or tuple of axes along which to count non-zeros.
Default is None, meaning that non-zeros will be counted
along a flattened version of `a`.
.. versionadded:: 1.12.0
keepdims : bool, optional
If this is set to True, the axes that are counted are left
in the result as dimensions with size one. With this option,
the result will broadcast correctly against the input array.
.. versionadded:: 1.19.0
Returns
-------
count : int or array of int
Number of non-zero values in the array along a given axis.
Otherwise, the total number of non-zero values in the array
is returned.
See Also
--------
nonzero : Return the coordinates of all the non-zero values.
Examples
--------
>>> np.count_nonzero(np.eye(4))
4
>>> a = np.array([[0, 1, 7, 0],
... [3, 0, 2, 19]])
>>> np.count_nonzero(a)
5
>>> np.count_nonzero(a, axis=0)
array([1, 1, 2, 1])
>>> np.count_nonzero(a, axis=1)
array([2, 3])
>>> np.count_nonzero(a, axis=1, keepdims=True)
array([[2],
[3]])
"""
# 如果 `axis` 为 None 并且 `keepdims` 为 False,则调用 `multiarray.count_nonzero` 函数
if axis is None and not keepdims:
return multiarray.count_nonzero(a)
# 将 `a` 转换为 `ndarray` 类型
a = asanyarray(a)
# TODO: this works around .astype(bool) not working properly (gh-9847)
# 如果 `a` 的数据类型为字符类型,则创建一个布尔类型的数组 `a_bool`
if np.issubdtype(a.dtype, np.character):
a_bool = a != a.dtype.type()
else:
# 否则,将 `a` 转换为布尔类型的数组 `a_bool`
a_bool = a.astype(np.bool, copy=False)
# 返回沿指定轴(如果有)求和后的布尔类型数组 `a_bool`,结果的数据类型为 `np.intp`
return a_bool.sum(axis=axis, dtype=np.intp, keepdims=keepdims)
# 使用装饰器 `set_module` 装饰的 `isfortran` 函数
@set_module('numpy')
def isfortran(a):
"""
Check if the array is Fortran contiguous but *not* C contiguous.
This function is obsolete. If you only want to check if an array is Fortran
contiguous use `a.flags.f_contiguous` instead.
Parameters
----------
a : ndarray
Input array.
Returns
-------
isfortran : bool
Returns True if the array is Fortran contiguous but *not* C contiguous.
Examples
--------
np.array allows to specify whether the array is written in C-contiguous
order (last index varies the fastest), or FORTRAN-contiguous order in
memory (first index varies the fastest).
>>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C')
>>> a
array([[1, 2, 3],
[4, 5, 6]])
>>> np.isfortran(a)
False
>>> b = np.array([[1, 2, 3], [4, 5, 6]], order='F')
>>> b
array([[1, 2, 3],
[4, 5, 6]])
>>> np.isfortran(b)
True
The transpose of a C-ordered array is a FORTRAN-ordered array.
>>> a = np.array([[1, 2, 3], [4, 5, 6]], order='C')
>>> a
array([[1, 2, 3],
[4, 5, 6]])
>>> np.isfortran(a)
False
>>> b = a.T
>>> b
array([[1, 4],
[2, 5],
[3, 6]])
>>> np.isfortran(b)
True
C-ordered arrays evaluate as False even if they are also FORTRAN-ordered.
>>> np.isfortran(np.array([1, 2], order='F'))
False
"""
# 返回数组 a 的 flags 属性中的 fnc 属性值
return a.flags.fnc
# 定义一个函数分派器,用于返回输入参数元组
def _argwhere_dispatcher(a):
return (a,)
# 使用装饰器将_dispatcher函数与argwhere函数关联,用于根据输入类型调度函数
@array_function_dispatch(_argwhere_dispatcher)
def argwhere(a):
"""
Find the indices of array elements that are non-zero, grouped by element.
Parameters
----------
a : array_like
Input data.
Returns
-------
index_array : (N, a.ndim) ndarray
Indices of elements that are non-zero. Indices are grouped by element.
This array will have shape ``(N, a.ndim)`` where ``N`` is the number of
non-zero items.
See Also
--------
where, nonzero
Notes
-----
``np.argwhere(a)`` is almost the same as ``np.transpose(np.nonzero(a))``,
but produces a result of the correct shape for a 0D array.
The output of ``argwhere`` is not suitable for indexing arrays.
For this purpose use ``nonzero(a)`` instead.
Examples
--------
>>> x = np.arange(6).reshape(2,3)
>>> x
array([[0, 1, 2],
[3, 4, 5]])
>>> np.argwhere(x>1)
array([[0, 2],
[1, 0],
[1, 1],
[1, 2]])
"""
# 如果输入数组a的维度为0,则提升为至少1维数组
if np.ndim(a) == 0:
a = shape_base.atleast_1d(a)
# 然后去除添加的维度
return argwhere(a)[:, :0]
# 返回数组a中非零元素的索引数组,索引按元素分组
return transpose(nonzero(a))
# 定义一个函数分派器,用于返回输入参数元组
def _flatnonzero_dispatcher(a):
return (a,)
# 使用装饰器将_dispatcher函数与flatnonzero函数关联,用于根据输入类型调度函数
@array_function_dispatch(_flatnonzero_dispatcher)
def flatnonzero(a):
"""
Return indices that are non-zero in the flattened version of a.
This is equivalent to ``np.nonzero(np.ravel(a))[0]``.
Parameters
----------
a : array_like
Input data.
Returns
-------
res : ndarray
Output array, containing the indices of the elements of ``a.ravel()``
that are non-zero.
See Also
--------
nonzero : Return the indices of the non-zero elements of the input array.
ravel : Return a 1-D array containing the elements of the input array.
Examples
--------
>>> x = np.arange(-2, 3)
>>> x
array([-2, -1, 0, 1, 2])
>>> np.flatnonzero(x)
array([0, 1, 3, 4])
Use the indices of the non-zero elements as an index array to extract
these elements:
>>> x.ravel()[np.flatnonzero(x)]
array([-2, -1, 1, 2])
"""
# 返回数组a的扁平化版本中非零元素的索引数组
return np.nonzero(np.ravel(a))[0]
# 定义一个函数分派器,用于返回输入参数元组
def _correlate_dispatcher(a, v, mode=None):
return (a, v)
# 使用装饰器将_dispatcher函数与correlate函数关联,用于根据输入类型调度函数
@array_function_dispatch(_correlate_dispatcher)
def correlate(a, v, mode='valid'):
r"""
Cross-correlation of two 1-dimensional sequences.
This function computes the correlation as generally defined in signal
processing texts [1]_:
.. math:: c_k = \sum_n a_{n+k} \cdot \overline{v}_n
with a and v sequences being zero-padded where necessary and
:math:`\overline v` denoting complex conjugation.
Parameters
----------
a, v : array_like
Input sequences.
mode : {'valid', 'same', 'full'}, optional
# 模式参数,指定交叉相关计算的模式,可以是'valid'、'same'、'full'
Refer to the `convolve` docstring. Note that the default
# 参考`convolve`函数的文档字符串,注意默认值为'valid',而不是`convolve`函数的'full'
is 'valid', unlike `convolve`, which uses 'full'.
Returns
-------
out : ndarray
# 返回值为 ndarray 类型,表示输入数组 a 和 v 的离散交叉相关结果
Discrete cross-correlation of `a` and `v`.
See Also
--------
convolve : Discrete, linear convolution of two one-dimensional sequences.
scipy.signal.correlate : uses FFT which has superior performance
on large arrays.
# 参见函数 convolve:计算两个一维序列的离散线性卷积。
# scipy.signal.correlate 使用 FFT 在大数组上有更优越的性能表现。
Notes
-----
The definition of correlation above is not unique and sometimes
correlation may be defined differently. Another common definition is [1]_:
.. math:: c'_k = \sum_n a_{n} \cdot \overline{v_{n+k}}
which is related to :math:`c_k` by :math:`c'_k = c_{-k}`.
# 上述的相关定义不是唯一的,有时可能会有不同的定义。另一个常见的定义如 [1] 所示:
# 这与 c_k 的关系由 c'_k = c_{-k} 给出。
`numpy.correlate` may perform slowly in large arrays (i.e. n = 1e5)
because it does not use the FFT to compute the convolution; in that case,
`scipy.signal.correlate` might be preferable.
References
----------
.. [1] Wikipedia, "Cross-correlation",
https://en.wikipedia.org/wiki/Cross-correlation
Examples
--------
>>> np.correlate([1, 2, 3], [0, 1, 0.5])
array([3.5])
>>> np.correlate([1, 2, 3], [0, 1, 0.5], "same")
array([2. , 3.5, 3. ])
>>> np.correlate([1, 2, 3], [0, 1, 0.5], "full")
array([0.5, 2. , 3.5, 3. , 0. ])
Using complex sequences:
>>> np.correlate([1+1j, 2, 3-1j], [0, 1, 0.5j], 'full')
array([ 0.5-0.5j, 1.0+0.j , 1.5-1.5j, 3.0-1.j , 0.0+0.j ])
Note that you get the time reversed, complex conjugated result
(:math:`\overline{c_{-k}}`) when the two input sequences a and v change
places:
>>> np.correlate([0, 1, 0.5j], [1+1j, 2, 3-1j], 'full')
array([ 0.0+0.j , 3.0+1.j , 1.5+1.5j, 1.0+0.j , 0.5+0.5j])
"""
return multiarray.correlate2(a, v, mode)
# 调用 multiarray 模块的 correlate2 函数,计算输入数组 a 和 v 的离散交叉相关结果
# 定义一个调度函数,用于派发输入给卷积函数
def _convolve_dispatcher(a, v, mode=None):
# 返回输入参数 a 和 v 的元组
return (a, v)
# 使用装饰器 array_function_dispatch 将 _convolve_dispatcher 函数与 convolve 函数关联起来
@array_function_dispatch(_convolve_dispatcher)
def convolve(a, v, mode='full'):
"""
Returns the discrete, linear convolution of two one-dimensional sequences.
The convolution operator is often seen in signal processing, where it
models the effect of a linear time-invariant system on a signal [1]_. In
probability theory, the sum of two independent random variables is
distributed according to the convolution of their individual
distributions.
If `v` is longer than `a`, the arrays are swapped before computation.
Parameters
----------
a : (N,) array_like
First one-dimensional input array.
v : (M,) array_like
Second one-dimensional input array.
mode : {'full', 'valid', 'same'}, optional
'full':
By default, mode is 'full'. This returns the convolution
at each point of overlap, with an output shape of (N+M-1,). At
the end-points of the convolution, the signals do not overlap
completely, and boundary effects may be seen.
'same':
Mode 'same' returns output of length ``max(M, N)``. Boundary
effects are still visible.
'valid':
Mode 'valid' returns output of length
``max(M, N) - min(M, N) + 1``. The convolution product is only given
for points where the signals overlap completely. Values outside
the signal boundary have no effect.
Returns
-------
out : ndarray
Discrete, linear convolution of `a` and `v`.
See Also
--------
scipy.signal.fftconvolve : Convolve two arrays using the Fast Fourier
Transform.
scipy.linalg.toeplitz : Used to construct the convolution operator.
polymul : Polynomial multiplication. Same output as convolve, but also
accepts poly1d objects as input.
Notes
-----
The discrete convolution operation is defined as
.. math:: (a * v)_n = \\sum_{m = -\\infty}^{\\infty} a_m v_{n - m}
It can be shown that a convolution :math:`x(t) * y(t)` in time/space
is equivalent to the multiplication :math:`X(f) Y(f)` in the Fourier
domain, after appropriate padding (padding is necessary to prevent
circular convolution). Since multiplication is more efficient (faster)
than convolution, the function `scipy.signal.fftconvolve` exploits the
FFT to calculate the convolution of large data-sets.
References
----------
.. [1] Wikipedia, "Convolution",
https://en.wikipedia.org/wiki/Convolution
Examples
--------
Note how the convolution operator flips the second array
before "sliding" the two across one another:
>>> np.convolve([1, 2, 3], [0, 1, 0.5])
array([0. , 1. , 2.5, 4. , 1.5])
Only return the middle values of the convolution.
Contains boundary effects, where zeros are taken
into account:
"""
# 返回函数的主体部分,用于执行一维序列的线性离散卷积
pass
# 使用 NumPy 的卷积函数 convolve 对数组 a 和 v 进行卷积运算,并返回指定模式下的结果
>>> np.convolve([1,2,3],[0,1,0.5], 'same')
# 在 'same' 模式下,返回与输入数组相同长度的卷积结果
array([1. , 2.5, 4. ])
# 由于两个数组长度相同,因此只有一个位置完全重叠:
>>> np.convolve([1,2,3],[0,1,0.5], 'valid')
# 在 'valid' 模式下,返回完全重叠部分的卷积结果
array([2.5])
"""
a, v = array(a, copy=None, ndmin=1), array(v, copy=None, ndmin=1)
if (len(v) > len(a)):
a, v = v, a
if len(a) == 0:
raise ValueError('a cannot be empty')
if len(v) == 0:
raise ValueError('v cannot be empty')
return multiarray.correlate(a, v[::-1], mode)
def _outer_dispatcher(a, b, out=None):
return (a, b, out)
@array_function_dispatch(_outer_dispatcher)
def outer(a, b, out=None):
"""
计算两个向量的外积。
给定长度分别为 ``M`` 和 ``N`` 的两个向量 `a` 和 `b`,外积 [1]_ 定义为::
[[a_0*b_0 a_0*b_1 ... a_0*b_{N-1} ]
[a_1*b_0 .
[ ... .
[a_{M-1}*b_0 a_{M-1}*b_{N-1} ]]
Parameters
----------
a : (M,) array_like
第一个输入向量。如果不是已经是 1 维的,则会被扁平化。
b : (N,) array_like
第二个输入向量。如果不是已经是 1 维的,则会被扁平化。
out : (M, N) ndarray, optional
结果存储的位置
.. versionadded:: 1.9.0
Returns
-------
out : (M, N) ndarray
``out[i, j] = a[i] * b[j]``
See also
--------
inner
einsum : ``einsum('i,j->ij', a.ravel(), b.ravel())`` 的等价形式。
ufunc.outer : 对于维度不限于 1D 和其他操作的泛化版本。``np.multiply.outer(a.ravel(), b.ravel())``
是其等价形式。
linalg.outer : ``np.outer`` 的一个兼容 Array API 的变体,仅接受 1 维输入。
tensordot : ``np.tensordot(a.ravel(), b.ravel(), axes=((), ()))``
是其等价形式。
References
----------
.. [1] G. H. Golub and C. F. Van Loan, *Matrix Computations*, 3rd
ed., Baltimore, MD, Johns Hopkins University Press, 1996,
pg. 8.
Examples
--------
创建一个 (*非常粗糙的*) 网格来计算 Mandelbrot 集合:
>>> rl = np.outer(np.ones((5,)), np.linspace(-2, 2, 5))
>>> rl
array([[-2., -1., 0., 1., 2.],
[-2., -1., 0., 1., 2.],
[-2., -1., 0., 1., 2.],
[-2., -1., 0., 1., 2.],
[-2., -1., 0., 1., 2.]])
>>> im = np.outer(1j*np.linspace(2, -2, 5), np.ones((5,)))
>>> im
array([[0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j, 0.+2.j],
[0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j, 0.+1.j],
[0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j, 0.+0.j],
[0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j, 0.-1.j],
[0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j, 0.-2.j]])
>>> grid = rl + im
>>> grid
array([[-2.+2.j, -1.+2.j, 0.+2.j, 1.+2.j, 2.+2.j],
[-2.+1.j, -1.+1.j, 0.+1.j, 1.+1.j, 2.+1.j],
[-2.+0.j, -1.+0.j, 0.+0.j, 1.+0.j, 2.+0.j],
[-2.-1.j, -1.-1.j, 0.-1.j, 1.-1.j, 2.-1.j],
[-2.-2.j, -1.-2.j, 0.-2.j, 1.-2.j, 2.-2.j]])
使用一个字母的 "向量" 的示例:
>>> x = np.array(['a', 'b', 'c'], dtype=object)
>>> np.outer(x, [1, 2, 3])
array([['a', 'aa', 'aaa'],
['b', 'bb', 'bbb'],
['c', 'cc', 'ccc']], dtype=object)
"""
a = asarray(a)
b = asarray(b)
return multiply(a.ravel()[:, newaxis], b.ravel()[newaxis, :], out)
def _tensordot_dispatcher(a, b, axes=None):
return (a, b)
@array_function_dispatch(_tensordot_dispatcher)
def tensordot(a, b, axes=2):
"""
Compute tensor dot product along specified axes.
Given two tensors, `a` and `b`, and an array_like object containing
two array_like objects, ``(a_axes, b_axes)``, sum the products of
`a`'s and `b`'s elements (components) over the axes specified by
``a_axes`` and ``b_axes``. The third argument can be a single non-negative
integer_like scalar, ``N``; if it is such, then the last ``N`` dimensions
of `a` and the first ``N`` dimensions of `b` are summed over.
Parameters
----------
a, b : array_like
Tensors to "dot".
axes : int or (2,) array_like
* integer_like
If an int N, sum over the last N axes of `a` and the first N axes
of `b` in order. The sizes of the corresponding axes must match.
* (2,) array_like
Or, a list of axes to be summed over, first sequence applying to `a`,
second to `b`. Both elements array_like must be of the same length.
Returns
-------
output : ndarray
The tensor dot product of the input.
See Also
--------
dot, einsum
Notes
-----
Three common use cases are:
* ``axes = 0`` : tensor product :math:`a\\otimes b`
* ``axes = 1`` : tensor dot product :math:`a\\cdot b`
* ``axes = 2`` : (default) tensor double contraction :math:`a:b`
When `axes` is a positive integer ``N``, the operation starts with
axis ``-N`` of `a` and axis ``0`` of `b`, and it continues through
axis ``-1`` of `a` and axis ``N-1`` of `b` (inclusive).
When there is more than one axis to sum over - and they are not the last
(first) axes of `a` (`b`) - the argument `axes` should consist of
two sequences of the same length, with the first axis to sum over given
first in both sequences, the second axis second, and so forth.
The shape of the result consists of the non-contracted axes of the
first tensor, followed by the non-contracted axes of the second.
Examples
--------
A "traditional" example:
>>> a = np.arange(60.).reshape(3,4,5)
>>> b = np.arange(24.).reshape(4,3,2)
>>> c = np.tensordot(a,b, axes=([1,0],[0,1]))
>>> c.shape
(5, 2)
>>> c
array([[4400., 4730.],
[4532., 4874.],
[4664., 5018.],
[4796., 5162.],
[4928., 5306.]])
>>> # A slower but equivalent way of computing the same...
>>> d = np.zeros((5,2))
>>> for i in range(5):
... for j in range(2):
... for k in range(3):
... for n in range(4):
... d[i,j] += a[k,n,i] * b[n,k,j]
>>> c == d
array([[ True, True],
[ True, True],
[ True, True],
[ True, True],
[ True, True]])
An extended example taking advantage of the overloading of + and \\*:
>>> a = np.array(range(1, 9))
"""
pass
>>> a.shape = (2, 2, 2)
>>> A = np.array(('a', 'b', 'c', 'd'), dtype=object)
>>> A.shape = (2, 2)
>>> a; A
array([[[1, 2],
[3, 4]],
[[5, 6],
[7, 8]]])
array([['a', 'b'],
['c', 'd']], dtype=object)
>>> np.tensordot(a, A)
array(['abbcccdddd', 'aaaaabbbbbbcccccccdddddddd'], dtype=object)
>>> np.tensordot(a, A, 1)
array([[['acc', 'bdd'],
['aaacccc', 'bbbdddd']],
[['aaaaacccccc', 'bbbbbdddddd'],
['aaaaaaacccccccc', 'bbbbbbbdddddddd']]], dtype=object)
>>> np.tensordot(a, A, 0)
array([[[[['a', 'b'],
['c', 'd']],
...
>>> np.tensordot(a, A, (0, 1))
array([[['abbbbb', 'cddddd'],
['aabbbbbb', 'ccdddddd']],
[['aaabbbbbbb', 'cccddddddd'],
['aaaabbbbbbbb', 'ccccdddddddd']]], dtype=object)
>>> np.tensordot(a, A, (2, 1))
array([[['abb', 'cdd'],
['aaabbbb', 'cccdddd']],
[['aaaaabbbbbb', 'cccccdddddd'],
['aaaaaaabbbbbbbb', 'cccccccdddddddd']]], dtype=object)
>>> np.tensordot(a, A, ((0, 1), (0, 1)))
array(['abbbcccccddddddd', 'aabbbbccccccdddddddd'], dtype=object)
>>> np.tensordot(a, A, ((2, 1), (1, 0)))
array(['acccbbdddd', 'aaaaacccccccbbbbbbdddddddd'], dtype=object)
try:
iter(axes)
except Exception:
axes_a = list(range(-axes, 0))
axes_b = list(range(0, axes))
else:
axes_a, axes_b = axes
try:
na = len(axes_a)
axes_a = list(axes_a)
except TypeError:
axes_a = [axes_a]
na = 1
try:
nb = len(axes_b)
axes_b = list(axes_b)
except TypeError:
axes_b = [axes_b]
nb = 1
a, b = asarray(a), asarray(b)
as_ = a.shape
nda = a.ndim
bs = b.shape
ndb = b.ndim
equal = True
if na != nb:
equal = False
else:
for k in range(na):
if as_[axes_a[k]] != bs[axes_b[k]]:
equal = False
break
if axes_a[k] < 0:
axes_a[k] += nda
if axes_b[k] < 0:
axes_b[k] += ndb
if not equal:
raise ValueError("shape-mismatch for sum")
notin = [k for k in range(nda) if k not in axes_a]
newaxes_a = notin + axes_a
N2 = math.prod(as_[axis] for axis in axes_a)
newshape_a = (math.prod([as_[ax] for ax in notin]), N2)
olda = [as_[axis] for axis in notin]
notin = [k for k in range(ndb) if k not in axes_b]
newaxes_b = axes_b + notin
N2 = math.prod(bs[axis] for axis in axes_b)
newshape_b = (N2, math.prod([bs[ax] for ax in notin]))
oldb = [bs[axis] for axis in notin]
at = a.transpose(newaxes_a).reshape(newshape_a)
bt = b.transpose(newaxes_b).reshape(newshape_b)
res = dot(at, bt)
return res.reshape(olda + oldb)
def _roll_dispatcher(a, shift, axis=None):
return (a,)
@array_function_dispatch(_roll_dispatcher)
def roll(a, shift, axis=None):
"""
Roll array elements along a given axis.
Elements that roll beyond the last position are re-introduced at
the first.
Parameters
----------
a : array_like
Input array.
shift : int or tuple of ints
The number of places by which elements are shifted. If a tuple,
then `axis` must be a tuple of the same size, and each of the
given axes is shifted by the corresponding number. If an int
while `axis` is a tuple of ints, then the same value is used for
all given axes.
axis : int or tuple of ints, optional
Axis or axes along which elements are shifted. By default, the
array is flattened before shifting, after which the original
shape is restored.
Returns
-------
res : ndarray
Output array, with the same shape as `a`.
See Also
--------
rollaxis : Roll the specified axis backwards, until it lies in a
given position.
Notes
-----
.. versionadded:: 1.12.0
Supports rolling over multiple dimensions simultaneously.
Examples
--------
>>> x = np.arange(10)
>>> np.roll(x, 2)
array([8, 9, 0, 1, 2, 3, 4, 5, 6, 7])
>>> np.roll(x, -2)
array([2, 3, 4, 5, 6, 7, 8, 9, 0, 1])
>>> x2 = np.reshape(x, (2, 5))
>>> x2
array([[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9]])
>>> np.roll(x2, 1)
array([[9, 0, 1, 2, 3],
[4, 5, 6, 7, 8]])
>>> np.roll(x2, -1)
array([[1, 2, 3, 4, 5],
[6, 7, 8, 9, 0]])
>>> np.roll(x2, 1, axis=0)
array([[5, 6, 7, 8, 9],
[0, 1, 2, 3, 4]])
>>> np.roll(x2, -1, axis=0)
array([[5, 6, 7, 8, 9],
[0, 1, 2, 3, 4]])
>>> np.roll(x2, 1, axis=1)
array([[4, 0, 1, 2, 3],
[9, 5, 6, 7, 8]])
>>> np.roll(x2, -1, axis=1)
array([[1, 2, 3, 4, 0],
[6, 7, 8, 9, 5]])
>>> np.roll(x2, (1, 1), axis=(1, 0))
array([[9, 5, 6, 7, 8],
[4, 0, 1, 2, 3]])
>>> np.roll(x2, (2, 1), axis=(1, 0))
array([[8, 9, 5, 6, 7],
[3, 4, 0, 1, 2]])
"""
a = asanyarray(a)
if axis is None:
return roll(a.ravel(), shift, 0).reshape(a.shape)
else:
axis = normalize_axis_tuple(axis, a.ndim, allow_duplicate=True)
broadcasted = broadcast(shift, axis)
if broadcasted.ndim > 1:
raise ValueError(
"'shift' and 'axis' should be scalars or 1D sequences")
shifts = {ax: 0 for ax in range(a.ndim)}
for sh, ax in broadcasted:
shifts[ax] += sh
rolls = [((slice(None), slice(None)),)] * a.ndim
for ax, offset in shifts.items():
offset %= a.shape[ax] or 1
if offset:
rolls[ax] = ((slice(None, -offset), slice(offset, None)),
(slice(-offset, None), slice(None, offset)))
result = empty_like(a)
for indices in itertools.product(*rolls):
arr_index, res_index = zip(*indices)
result[res_index] = a[arr_index]
return result
def _rollaxis_dispatcher(a, axis, start=None):
return (a,)
@array_function_dispatch(_rollaxis_dispatcher)
def rollaxis(a, axis, start=0):
"""
Roll the specified axis backwards, until it lies in a given position.
This function continues to be supported for backward compatibility, but you
should prefer `moveaxis`. The `moveaxis` function was added in NumPy
1.11.
Parameters
----------
a : ndarray
Input array.
axis : int
The axis to be rolled. The positions of the other axes do not
change relative to one another.
start : int, optional
When ``start <= axis``, the axis is rolled back until it lies in
this position. When ``start > axis``, the axis is rolled until it
lies before this position. The default, 0, results in a "complete"
roll. The following table describes how negative values of ``start``
are interpreted:
.. table::
:align: left
+-------------------+----------------------+
| ``start`` | Normalized ``start`` |
+===================+======================+
| ``-(arr.ndim+1)`` | raise ``AxisError`` |
+-------------------+----------------------+
| ``-arr.ndim`` | 0 |
+-------------------+----------------------+
| |vdots| | |vdots| |
+-------------------+----------------------+
| ``-1`` | ``arr.ndim-1`` |
+-------------------+----------------------+
| ``0`` | ``0`` |
+-------------------+----------------------+
| |vdots| | |vdots| |
+-------------------+----------------------+
| ``arr.ndim`` | ``arr.ndim`` |
+-------------------+----------------------+
| ``arr.ndim + 1`` | raise ``AxisError`` |
+-------------------+----------------------+
.. |vdots| unicode:: U+22EE .. Vertical Ellipsis
Returns
-------
res : ndarray
For NumPy >= 1.10.0 a view of `a` is always returned. For earlier
NumPy versions a view of `a` is returned only if the order of the
axes is changed, otherwise the input array is returned.
See Also
--------
moveaxis : Move array axes to new positions.
roll : Roll the elements of an array by a number of positions along a
given axis.
Examples
--------
>>> a = np.ones((3,4,5,6))
>>> np.rollaxis(a, 3, 1).shape
(3, 6, 4, 5)
>>> np.rollaxis(a, 2).shape
(5, 3, 4, 6)
>>> np.rollaxis(a, 1, 4).shape
(3, 5, 6, 4)
"""
n = a.ndim
axis = normalize_axis_index(axis, n)
if start < 0:
start += n
msg = "'%s' arg requires %d <= %s < %d, but %d was passed in"
if not (0 <= start < n + 1):
raise AxisError(msg % ('start', -n, 'start', n + 1, start))
if axis < start:
start -= 1
if axis == start:
return a[...]
axes = list(range(0, n))
axes.remove(axis)
axes.insert(start, axis)
return a.transpose(axes)
@set_module("numpy.lib.array_utils")
def normalize_axis_tuple(axis, ndim, argname=None, allow_duplicate=False):
"""
Normalizes an axis argument into a tuple of non-negative integer axes.
This handles shorthands such as ``1`` and converts them to ``(1,)``,
as well as performing the handling of negative indices covered by
`normalize_axis_index`.
By default, this forbids axes from being specified multiple times.
Used internally by multi-axis-checking logic.
.. versionadded:: 1.13.0
Parameters
----------
axis : int, iterable of int
The un-normalized index or indices of the axis.
ndim : int
The number of dimensions of the array that `axis` should be normalized
against.
argname : str, optional
A prefix to put before the error message, typically the name of the
argument.
allow_duplicate : bool, optional
If False, the default, disallow an axis from being specified twice.
Returns
-------
normalized_axes : tuple of int
The normalized axis index, such that `0 <= normalized_axis < ndim`
Raises
------
AxisError
If any axis provided is out of range
ValueError
If an axis is repeated
See also
--------
normalize_axis_index : normalizing a single scalar axis
"""
if type(axis) not in (tuple, list):
try:
axis = [operator.index(axis)]
except TypeError:
pass
axis = tuple([normalize_axis_index(ax, ndim, argname) for ax in axis])
if not allow_duplicate and len(set(axis)) != len(axis):
if argname:
raise ValueError('repeated axis in `{}` argument'.format(argname))
else:
raise ValueError('repeated axis')
return axis
def _moveaxis_dispatcher(a, source, destination):
return (a,)
@array_function_dispatch(_moveaxis_dispatcher)
def moveaxis(a, source, destination):
"""
Move axes of an array to new positions.
Other axes remain in their original order.
.. versionadded:: 1.11.0
Parameters
----------
a : np.ndarray
The array whose axes should be reordered.
source : int or sequence of int
Original positions of the axes to move. These must be unique.
destination : int or sequence of int
Destination positions for each of the original axes. These must also be
unique.
Returns
-------
result : np.ndarray
Array with moved axes. This array is a view of the input array.
See Also
--------
transpose : Permute the dimensions of an array.
swapaxes : Interchange two axes of an array.
Examples
--------
>>> x = np.zeros((3, 4, 5))
>>> np.moveaxis(x, 0, -1).shape
(4, 5, 3)
>>> np.moveaxis(x, -1, 0).shape
(5, 3, 4)
These all achieve the same result:
"""
>>> np.transpose(x).shape
(5, 4, 3)
>>> np.swapaxes(x, 0, -1).shape
(5, 4, 3)
>>> np.moveaxis(x, [0, 1], [-1, -2]).shape
(5, 4, 3)
>>> np.moveaxis(x, [0, 1, 2], [-1, -2, -3]).shape
(5, 4, 3)
"""
# 尝试从对象 `a` 中获取 `transpose` 属性,如果不存在则转换为数组再获取
try:
transpose = a.transpose
except AttributeError:
a = asarray(a)
transpose = a.transpose
# 规范化 `source` 和 `destination`,确保它们符合轴的范围
source = normalize_axis_tuple(source, a.ndim, 'source')
destination = normalize_axis_tuple(destination, a.ndim, 'destination')
# 检查 `source` 和 `destination` 是否具有相同数量的元素,否则引发异常
if len(source) != len(destination):
raise ValueError('`source` and `destination` arguments must have '
'the same number of elements')
# 创建一个排列 `order`,根据 `source` 和 `destination` 来重新排序轴
order = [n for n in range(a.ndim) if n not in source]
# 将 `destination` 和 `source` 组合并按 `destination` 的顺序插入 `order` 中
for dest, src in sorted(zip(destination, source)):
order.insert(dest, src)
# 应用排列 `order` 到 `transpose` 函数,并返回结果
result = transpose(order)
return result
# 使用数组函数调度器将函数 _cross_dispatcher 设置为 cross 函数的调度器,负责分发不同的输入情况
@array_function_dispatch(_cross_dispatcher)
def cross(a, b, axisa=-1, axisb=-1, axisc=-1, axis=None):
"""
Return the cross product of two (arrays of) vectors.
The cross product of `a` and `b` in :math:`R^3` is a vector perpendicular
to both `a` and `b`. If `a` and `b` are arrays of vectors, the vectors
are defined by the last axis of `a` and `b` by default, and these axes
can have dimensions 2 or 3. Where the dimension of either `a` or `b` is
2, the third component of the input vector is assumed to be zero and the
cross product calculated accordingly. In cases where both input vectors
have dimension 2, the z-component of the cross product is returned.
Parameters
----------
a : array_like
Components of the first vector(s).
b : array_like
Components of the second vector(s).
axisa : int, optional
Axis of `a` that defines the vector(s). By default, the last axis.
axisb : int, optional
Axis of `b` that defines the vector(s). By default, the last axis.
axisc : int, optional
Axis of `c` containing the cross product vector(s). Ignored if
both input vectors have dimension 2, as the return is scalar.
By default, the last axis.
axis : int, optional
If defined, the axis of `a`, `b` and `c` that defines the vector(s)
and cross product(s). Overrides `axisa`, `axisb` and `axisc`.
Returns
-------
c : ndarray
Vector cross product(s).
Raises
------
ValueError
When the dimension of the vector(s) in `a` and/or `b` does not
equal 2 or 3.
See Also
--------
inner : Inner product
outer : Outer product.
linalg.cross : An Array API compatible variation of ``np.cross``,
which accepts (arrays of) 3-element vectors only.
ix_ : Construct index arrays.
Notes
-----
.. versionadded:: 1.9.0
Supports full broadcasting of the inputs.
Dimension-2 input arrays were deprecated in 2.0.0. If you do need this
functionality, you can use::
def cross2d(x, y):
return x[..., 0] * y[..., 1] - x[..., 1] * y[..., 0]
Examples
--------
Vector cross-product.
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> np.cross(x, y)
array([-3, 6, -3])
One vector with dimension 2.
>>> x = [1, 2]
>>> y = [4, 5, 6]
>>> np.cross(x, y)
array([12, -6, -3])
Equivalently:
>>> x = [1, 2, 0]
>>> y = [4, 5, 6]
>>> np.cross(x, y)
array([12, -6, -3])
Both vectors with dimension 2.
>>> x = [1,2]
>>> y = [4,5]
>>> np.cross(x, y)
array(-3)
Multiple vector cross-products. Note that the direction of the cross
product vector is defined by the *right-hand rule*.
>>> x = np.array([[1,2,3], [4,5,6]])
>>> y = np.array([[4,5,6], [1,2,3]])
"""
# 直接返回输入的两个数组 a 和 b,这是一个默认的实现,实际的计算和处理由 _cross_dispatcher 函数进行分派处理
return (a, b)
"""
Calculate the cross product of vectors `a` and `b` in NumPy.
Parameters:
----------
a, b : array_like
Input arrays defining vectors.
axisc : int, optional
Specify the axis of `c` if provided (default is -1).
axisa, axisb : int, optional
Specify the axes of `a` and `b` respectively (default is -1).
Returns:
-------
cp : ndarray
Cross product of `a` and `b`.
Raises:
------
ValueError
- If either `a` or `b` has zero dimension.
- If the dimensions of `a` or `b` are not compatible for cross product (must be 2 or 3).
DeprecationWarning
- If either `a` or `b` are 2-dimensional arrays, as they are deprecated.
Notes:
------
The function calculates the cross product between vectors `a` and `b` along specified axes.
If `a` or `b` are 2-dimensional, a warning is issued, recommending the use of 3-dimensional vectors.
"""
# If `axis` is provided, assign its value to `axisa`, `axisb`, and `axisc`
if axis is not None:
axisa, axisb, axisc = (axis,) * 3
# Ensure `a` and `b` are numpy arrays
a = asarray(a)
b = asarray(b)
# Check if `a` or `b` has zero dimension
if (a.ndim < 1) or (b.ndim < 1):
raise ValueError("At least one array has zero dimension")
# Normalize `axisa` and `axisb` to ensure they are within bounds
axisa = normalize_axis_index(axisa, a.ndim, msg_prefix='axisa')
axisb = normalize_axis_index(axisb, b.ndim, msg_prefix='axisb')
# Move `axisa` and `axisb` to the end of the shape
a = moveaxis(a, axisa, -1)
b = moveaxis(b, axisb, -1)
# Check dimensions are compatible for cross product (must be 2 or 3)
msg = ("incompatible dimensions for cross product\n"
"(dimension must be 2 or 3)")
if a.shape[-1] not in (2, 3) or b.shape[-1] not in (2, 3):
raise ValueError(msg)
# Issue deprecation warning if `a` or `b` are 2-dimensional
if a.shape[-1] == 2 or b.shape[-1] == 2:
warnings.warn(
"Arrays of 2-dimensional vectors are deprecated. Use arrays of "
"3-dimensional vectors instead. (deprecated in NumPy 2.0)",
DeprecationWarning, stacklevel=2
)
# Create the output array `cp` with appropriate shape and dtype
shape = broadcast(a[..., 0], b[..., 0]).shape
if a.shape[-1] == 3 or b.shape[-1] == 3:
shape += (3,)
axisc = normalize_axis_index(axisc, len(shape), msg_prefix='axisc')
dtype = promote_types(a.dtype, b.dtype)
cp = empty(shape, dtype)
# Recast arrays `a` and `b` as `dtype` for uniform operations
a = a.astype(dtype)
b = b.astype(dtype)
# Create local aliases for readability
a0 = a[..., 0]
a1 = a[..., 1]
if a.shape[-1] == 3:
a2 = a[..., 2]
b0 = b[..., 0]
b1 = b[..., 1]
if b.shape[-1] == 3:
b2 = b[..., 2]
if cp.ndim != 0 and cp.shape[-1] == 3:
cp0 = cp[..., 0]
cp1 = cp[..., 1]
cp2 = cp[..., 2]
# Perform cross product calculation based on dimensions of `a` and `b`
if a.shape[-1] == 2:
if b.shape[-1] == 2:
# For 2-dimensional `a` and `b`, compute cross product
multiply(a0, b1, out=cp)
cp -= a1 * b0
return cp
else:
# For 2-dimensional `a` and 3-dimensional `b`, compute cross product
multiply(a1, b2, out=cp0)
multiply(a0, b2, out=cp1)
negative(cp1, out=cp1)
multiply(a0, b1, out=cp2)
cp2 -= a1 * b0
else:
# 确保数组 a 的最后一个维度是 3
assert a.shape[-1] == 3
if b.shape[-1] == 3:
# 如果数组 b 的最后一个维度也是 3,则计算叉乘结果
# cp0 = a1 * b2 - a2 * b1
# cp1 = a2 * b0 - a0 * b2
# cp2 = a0 * b1 - a1 * b0
multiply(a1, b2, out=cp0)
# 计算临时变量 tmp = a2 * b1
tmp = array(a2 * b1)
cp0 -= tmp
multiply(a2, b0, out=cp1)
multiply(a0, b2, out=tmp)
cp1 -= tmp
multiply(a0, b1, out=cp2)
multiply(a1, b0, out=tmp)
cp2 -= tmp
else:
# 如果数组 b 的最后一个维度是 2,则按照特定情况计算叉乘结果
assert b.shape[-1] == 2
# cp0 = 0 - a2 * b1 (因为 b2 = 0)
# cp1 = a2 * b0 - 0 (因为 b2 = 0)
# cp2 = a0 * b1 - a1 * b0
multiply(a2, b1, out=cp0)
negative(cp0, out=cp0)
multiply(a2, b0, out=cp1)
multiply(a0, b1, out=cp2)
cp2 -= a1 * b0
# 将计算结果 cp 的最后一个维度移到指定的轴向 axisc 处并返回
return moveaxis(cp, -1, axisc)
# 根据系统的字节顺序确定是否为小端序
little_endian = (sys.byteorder == 'little')
@set_module('numpy')
# 将当前函数注册为 numpy 模块的 indices 函数
def indices(dimensions, dtype=int, sparse=False):
"""
Return an array representing the indices of a grid.
Compute an array where the subarrays contain index values 0, 1, ...
varying only along the corresponding axis.
Parameters
----------
dimensions : sequence of ints
The shape of the grid.
dtype : dtype, optional
Data type of the result.
sparse : boolean, optional
Return a sparse representation of the grid instead of a dense
representation. Default is False.
.. versionadded:: 1.17
Returns
-------
grid : one ndarray or tuple of ndarrays
If sparse is False:
Returns one array of grid indices,
``grid.shape = (len(dimensions),) + tuple(dimensions)``.
If sparse is True:
Returns a tuple of arrays, with
``grid[i].shape = (1, ..., 1, dimensions[i], 1, ..., 1)`` with
dimensions[i] in the ith place
See Also
--------
mgrid, ogrid, meshgrid
Notes
-----
The output shape in the dense case is obtained by prepending the number
of dimensions in front of the tuple of dimensions, i.e. if `dimensions`
is a tuple ``(r0, ..., rN-1)`` of length ``N``, the output shape is
``(N, r0, ..., rN-1)``.
The subarrays ``grid[k]`` contains the N-D array of indices along the
``k-th`` axis. Explicitly::
grid[k, i0, i1, ..., iN-1] = ik
Examples
--------
>>> grid = np.indices((2, 3))
>>> grid.shape
(2, 2, 3)
>>> grid[0]
array([[0, 0, 0],
[1, 1, 1]])
>>> grid[1]
array([[0, 1, 2],
[0, 1, 2]])
The indices can be used as an index into an array.
>>> x = np.arange(20).reshape(5, 4)
>>> row, col = np.indices((2, 3))
>>> x[row, col]
array([[0, 1, 2],
[4, 5, 6]])
Note that it would be more straightforward in the above example to
extract the required elements directly with ``x[:2, :3]``.
If sparse is set to true, the grid will be returned in a sparse
representation.
>>> i, j = np.indices((2, 3), sparse=True)
>>> i.shape
(2, 1)
>>> j.shape
(1, 3)
>>> i
array([[0],
[1]])
>>> j
array([[0, 1, 2]])
"""
dimensions = tuple(dimensions)
N = len(dimensions)
shape = (1,)*N
# 根据 sparse 参数选择返回稠密或稀疏表示的结果数组
if sparse:
res = tuple()
else:
res = empty((N,)+dimensions, dtype=dtype)
for i, dim in enumerate(dimensions):
# 创建包含索引值的数组,每个子数组沿相应轴变化
idx = arange(dim, dtype=dtype).reshape(
shape[:i] + (dim,) + shape[i+1:]
)
if sparse:
res = res + (idx,)
else:
res[i] = idx
# 返回结果数组或元组
return res
@set_array_function_like_doc
@set_module('numpy')
def fromfunction(function, shape, *, dtype=float, like=None, **kwargs):
"""
Construct an array by executing a function over each coordinate.
The resulting array therefore has a value ``fn(x, y, z)`` at
coordinate ``(x, y, z)``.
Parameters
----------
function : callable
The function is called with N parameters, where N is the rank of
`shape`. Each parameter represents the coordinates of the array
varying along a specific axis. For example, if `shape`
were ``(2, 2)``, then the parameters would be
``array([[0, 0], [1, 1]])`` and ``array([[0, 1], [0, 1]])``
shape : (N,) tuple of ints
Shape of the output array, which also determines the shape of
the coordinate arrays passed to `function`.
dtype : data-type, optional
Data-type of the coordinate arrays passed to `function`.
By default, `dtype` is float.
${ARRAY_FUNCTION_LIKE}
.. versionadded:: 1.20.0
Returns
-------
fromfunction : any
The result of the call to `function` is passed back directly.
Therefore the shape of `fromfunction` is completely determined by
`function`. If `function` returns a scalar value, the shape of
`fromfunction` would not match the `shape` parameter.
See Also
--------
indices, meshgrid
Notes
-----
Keywords other than `dtype` and `like` are passed to `function`.
Examples
--------
>>> np.fromfunction(lambda i, j: i, (2, 2), dtype=float)
array([[0., 0.],
[1., 1.]])
>>> np.fromfunction(lambda i, j: j, (2, 2), dtype=float)
array([[0., 1.],
[0., 1.]])
>>> np.fromfunction(lambda i, j: i == j, (3, 3), dtype=int)
array([[ True, False, False],
[False, True, False],
[False, False, True]])
>>> np.fromfunction(lambda i, j: i + j, (3, 3), dtype=int)
array([[0, 1, 2],
[1, 2, 3],
[2, 3, 4]])
"""
# 如果给定了 like 参数,则调用 _fromfunction_with_like 函数处理
if like is not None:
return _fromfunction_with_like(
like, function, shape, dtype=dtype, **kwargs)
# 根据 shape 和 dtype 参数生成坐标数组 args
args = indices(shape, dtype=dtype)
# 调用 function 函数,并传入生成的坐标数组 args 和其他关键字参数 kwargs
return function(*args, **kwargs)
# 将 `fromfunction` 函数注册为具有数组功能分派的函数,并赋值给 `_fromfunction_with_like`
_fromfunction_with_like = array_function_dispatch()(fromfunction)
# 从给定的缓冲区 `buf` 中创建一个数组,指定数据类型 `dtype`、形状 `shape` 和存储顺序 `order`,
# 然后将其重新塑形为指定形状和顺序的数组
def _frombuffer(buf, dtype, shape, order):
return frombuffer(buf, dtype=dtype).reshape(shape, order=order)
# 将当前函数标记为属于 'numpy' 模块的函数
@set_module('numpy')
def isscalar(element):
"""
Returns True if the type of `element` is a scalar type.
Parameters
----------
element : any
Input argument, can be of any type and shape.
Returns
-------
val : bool
True if `element` is a scalar type, False if it is not.
See Also
--------
ndim : Get the number of dimensions of an array
Notes
-----
If you need a stricter way to identify a *numerical* scalar, use
``isinstance(x, numbers.Number)``, as that returns ``False`` for most
non-numerical elements such as strings.
In most cases ``np.ndim(x) == 0`` should be used instead of this function,
as that will also return true for 0d arrays. This is how numpy overloads
functions in the style of the ``dx`` arguments to `gradient` and
the ``bins`` argument to `histogram`. Some key differences:
+------------------------------------+---------------+-------------------+
| x |``isscalar(x)``|``np.ndim(x) == 0``|
+====================================+===============+===================+
| PEP 3141 numeric objects | ``True`` | ``True`` |
| (including builtins) | | |
+------------------------------------+---------------+-------------------+
| builtin string and buffer objects | ``True`` | ``True`` |
+------------------------------------+---------------+-------------------+
| other builtin objects, like | ``False`` | ``True`` |
| `pathlib.Path`, `Exception`, | | |
| the result of `re.compile` | | |
+------------------------------------+---------------+-------------------+
| third-party objects like | ``False`` | ``True`` |
| `matplotlib.figure.Figure` | | |
+------------------------------------+---------------+-------------------+
| zero-dimensional numpy arrays | ``False`` | ``True`` |
+------------------------------------+---------------+-------------------+
| other numpy arrays | ``False`` | ``False`` |
+------------------------------------+---------------+-------------------+
| `list`, `tuple`, and other | ``False`` | ``False`` |
| sequence objects | | |
+------------------------------------+---------------+-------------------+
Examples
--------
>>> np.isscalar(3.1)
True
>>> np.isscalar(np.array(3.1))
False
>>> np.isscalar([3.1])
False
>>> np.isscalar(False)
True
"""
# 检查给定元素是否是标量(scalar)
>>> np.isscalar('numpy')
# 返回 True,因为字符串 'numpy' 是一个标量
NumPy 支持 PEP 3141 标量数值:
# 导入 Fraction 类
>>> from fractions import Fraction
# 检查 Fraction(5, 17) 是否是标量
>>> np.isscalar(Fraction(5, 17))
# 返回 True,因为 Fraction(5, 17) 是一个标量
# 导入 Number 类
>>> from numbers import Number
# 检查 Number() 是否是标量
>>> np.isscalar(Number())
# 返回 True,因为 Number() 是一个标量
"""
返回一个布尔值,判断 element 是否是标量类型 generic 中的实例,
或者 element 的类型是否在 ScalarType 中,
或者 element 是否是 numbers.Number 的实例。
"""
return (isinstance(element, generic)
or type(element) in ScalarType
or isinstance(element, numbers.Number))
@set_module('numpy')
# 设置模块为 'numpy',这是一个装饰器函数,用于在函数定义时设置模块信息
def binary_repr(num, width=None):
"""
Return the binary representation of the input number as a string.
For negative numbers, if width is not given, a minus sign is added to the
front. If width is given, the two's complement of the number is
returned, with respect to that width.
In a two's-complement system negative numbers are represented by the two's
complement of the absolute value. This is the most common method of
representing signed integers on computers [1]_. A N-bit two's-complement
system can represent every integer in the range
:math:`-2^{N-1}` to :math:`+2^{N-1}-1`.
Parameters
----------
num : int
Only an integer decimal number can be used.
width : int, optional
The length of the returned string if `num` is positive, or the length
of the two's complement if `num` is negative, provided that `width` is
at least a sufficient number of bits for `num` to be represented in
the designated form. If the `width` value is insufficient, an error is
raised.
Returns
-------
bin : str
Binary representation of `num` or two's complement of `num`.
See Also
--------
base_repr: Return a string representation of a number in the given base
system.
bin: Python's built-in binary representation generator of an integer.
Notes
-----
`binary_repr` is equivalent to using `base_repr` with base 2, but about 25x
faster.
References
----------
.. [1] Wikipedia, "Two's complement",
https://en.wikipedia.org/wiki/Two's_complement
Examples
--------
>>> np.binary_repr(3)
'11'
>>> np.binary_repr(-3)
'-11'
>>> np.binary_repr(3, width=4)
'0011'
The two's complement is returned when the input number is negative and
width is specified:
>>> np.binary_repr(-3, width=3)
'101'
>>> np.binary_repr(-3, width=5)
'11101'
"""
def err_if_insufficient(width, binwidth):
if width is not None and width < binwidth:
raise ValueError(
f"Insufficient bit {width=} provided for {binwidth=}"
)
num = operator.index(num)
if num == 0:
return '0' * (width or 1)
elif num > 0:
binary = bin(num)[2:]
binwidth = len(binary)
outwidth = (binwidth if width is None
else builtins.max(binwidth, width))
err_if_insufficient(width, binwidth)
return binary.zfill(outwidth)
else:
if width is None:
return '-' + bin(-num)[2:]
else:
poswidth = len(bin(-num)[2:])
if 2**(poswidth - 1) == -num:
poswidth -= 1
twocomp = 2**(poswidth + 1) + num
binary = bin(twocomp)[2:]
binwidth = len(binary)
outwidth = builtins.max(binwidth, width)
err_if_insufficient(width, binwidth)
return '1' * (outwidth - binwidth) + binary
@set_module('numpy')
def base_repr(number, base=2, padding=0):
"""
Return a string representation of a number in the given base system.
Parameters
----------
number : int
The value to convert. Positive and negative values are handled.
base : int, optional
Convert `number` to the `base` number system. The valid range is 2-36,
the default value is 2.
padding : int, optional
Number of zeros padded on the left. Default is 0 (no padding).
Returns
-------
out : str
String representation of `number` in `base` system.
See Also
--------
binary_repr : Faster version of `base_repr` for base 2.
Examples
--------
>>> np.base_repr(5)
'101'
>>> np.base_repr(6, 5)
'11'
>>> np.base_repr(7, base=5, padding=3)
'00012'
>>> np.base_repr(10, base=16)
'A'
>>> np.base_repr(32, base=16)
'20'
"""
digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'
if base > len(digits):
raise ValueError("Bases greater than 36 not handled in base_repr.")
elif base < 2:
raise ValueError("Bases less than 2 not handled in base_repr.")
num = abs(int(number))
res = []
while num:
res.append(digits[num % base])
num //= base
if padding:
res.append('0' * padding)
if number < 0:
res.append('-')
return ''.join(reversed(res or '0'))
def _maketup(descr, val):
dt = dtype(descr)
fields = dt.fields
if fields is None:
return val
else:
res = [_maketup(fields[name][0], val) for name in dt.names]
return tuple(res)
@set_array_function_like_doc
@set_module('numpy')
def identity(n, dtype=None, *, like=None):
"""
Return the identity array.
The identity array is a square array with ones on
the main diagonal.
Parameters
----------
n : int
Number of rows (and columns) in `n` x `n` output.
dtype : data-type, optional
Data-type of the output. Defaults to ``float``.
${ARRAY_FUNCTION_LIKE}
.. versionadded:: 1.20.0
Returns
-------
out : ndarray
`n` x `n` array with its main diagonal set to one,
and all other elements 0.
Examples
--------
>>> np.identity(3)
array([[1., 0., 0.],
[0., 1., 0.],
[0., 0., 1.]])
"""
if like is not None:
return _identity_with_like(like, n, dtype=dtype)
from numpy import eye
return eye(n, dtype=dtype, like=like)
_identity_with_like = array_function_dispatch()(identity)
def _allclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
return (a, b, rtol, atol)
@array_function_dispatch(_allclose_dispatcher)
def allclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
"""
# 比较两个数组是否在容差范围内逐元素相等。
# 容差值为正数,通常是非常小的数。相对差异 (`rtol` * abs(`b`)) 和绝对差异 `atol` 被加在一起,用来与 `a` 和 `b` 的绝对差异比较。
# .. warning:: 默认的 `atol` 不适用于比较远小于一的数值(参见注释)。
# 如果NaN在同一位置且 ``equal_nan=True``,则被视为相等。如果Inf在同一位置且在两个数组中的符号相同,则被视为相等。
# 参数
# ----------
# a, b : array_like
# 要比较的输入数组。
# rtol : array_like
# 相对容差参数(见注释)。
# atol : array_like
# 绝对容差参数(见注释)。
# equal_nan : bool
# 是否将NaN视为相等。如果为True,则 `a` 中的NaN将与 `b` 中的NaN在输出数组中被视为相等。
# .. versionadded:: 1.10.0
# 返回
# -------
# allclose : bool
# 如果两个数组在给定的容差内相等,则返回True;否则返回False。
# 参见
# --------
# isclose, all, any, equal
# 注释
# -----
# 如果以下方程逐元素为True,则 `allclose` 返回True。::
# absolute(a - b) <= (atol + rtol * absolute(b))
# 上述方程在 `a` 和 `b` 中不对称,因此在某些罕见情况下,``allclose(a, b)`` 可能与 ``allclose(b, a)`` 不同。
# 当参考值 `b` 的幅度小于一时,默认值 `atol` 是不合适的。例如, ``a = 1e-9`` 和 ``b = 2e-9`` 可能不应被视为 "接近",但是 ``allclose(1e-9, 2e-9)`` 在默认设置下返回True。请确保根据具体情况选择 `atol`,特别是用于定义 `a` 中非零值与 `b` 中非常小或零值之间的阈值。
# `a` 和 `b` 的比较使用标准的广播方式,这意味着 `a` 和 `b` 不需要具有相同的形状才能使 ``allclose(a, b)`` 评估为True。对于 `equal` 也是如此,但对于 `array_equal` 则不是。
# `allclose` 对于非数值数据类型未定义。
# 对于此目的,`bool` 被视为数值数据类型。
# 示例
# --------
# >>> np.allclose([1e10,1e-7], [1.00001e10,1e-8])
# False
# >>> np.allclose([1e10,1e-8], [1.00001e10,1e-9])
# True
# >>> np.allclose([1e10,1e-8], [1.0001e10,1e-9])
# False
# >>> np.allclose([1.0, np.nan], [1.0, np.nan])
# False
# >>> np.allclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
# True
# 根据输入参数创建一个调度器,用于分派到合适的 isclose 函数
def _isclose_dispatcher(a, b, rtol=None, atol=None, equal_nan=None):
# 返回输入参数元组,用于后续的分派
return (a, b, rtol, atol)
# 使用 array_function_dispatch 装饰器,将 _isclose_dispatcher 函数作为分派器,用于 isclose 函数
@array_function_dispatch(_isclose_dispatcher)
def isclose(a, b, rtol=1.e-5, atol=1.e-8, equal_nan=False):
"""
Returns a boolean array where two arrays are element-wise equal within a
tolerance.
The tolerance values are positive, typically very small numbers. The
relative difference (`rtol` * abs(`b`)) and the absolute difference
`atol` are added together to compare against the absolute difference
between `a` and `b`.
.. warning:: The default `atol` is not appropriate for comparing numbers
with magnitudes much smaller than one (see Notes).
Parameters
----------
a, b : array_like
Input arrays to compare.
rtol : array_like
The relative tolerance parameter (see Notes).
atol : array_like
The absolute tolerance parameter (see Notes).
equal_nan : bool
Whether to compare NaN's as equal. If True, NaN's in `a` will be
considered equal to NaN's in `b` in the output array.
Returns
-------
y : array_like
Returns a boolean array of where `a` and `b` are equal within the
given tolerance. If both `a` and `b` are scalars, returns a single
boolean value.
See Also
--------
allclose
math.isclose
Notes
-----
.. versionadded:: 1.7.0
For finite values, isclose uses the following equation to test whether
two floating point values are equivalent.::
absolute(a - b) <= (atol + rtol * absolute(b))
Unlike the built-in `math.isclose`, the above equation is not symmetric
in `a` and `b` -- it assumes `b` is the reference value -- so that
`isclose(a, b)` might be different from `isclose(b, a)`.
The default value of `atol` is not appropriate when the reference value
`b` has magnitude smaller than one. For example, it is unlikely that
``a = 1e-9`` and ``b = 2e-9`` should be considered "close", yet
``isclose(1e-9, 2e-9)`` is ``True`` with default settings. Be sure
to select `atol` for the use case at hand, especially for defining the
threshold below which a non-zero value in `a` will be considered "close"
to a very small or zero value in `b`.
`isclose` is not defined for non-numeric data types.
:class:`bool` is considered a numeric data-type for this purpose.
Examples
--------
>>> np.isclose([1e10,1e-7], [1.00001e10,1e-8])
array([ True, False])
>>> np.isclose([1e10,1e-8], [1.00001e10,1e-9])
array([ True, True])
>>> np.isclose([1e10,1e-8], [1.0001e10,1e-9])
array([False, True])
>>> np.isclose([1.0, np.nan], [1.0, np.nan])
array([ True, False])
>>> np.isclose([1.0, np.nan], [1.0, np.nan], equal_nan=True)
array([ True, True])
>>> np.isclose([1e-8, 1e-7], [0.0, 0.0])
array([ True, False])
>>> np.isclose([1e-100, 1e-7], [0.0, 0.0], atol=0.0)
array([False, False])
"""
# 使用 NumPy 的 isclose 函数比较两个数组的元素是否在误差范围内相等
>>> np.isclose([1e-10, 1e-10], [1e-20, 0.0])
array([ True, True])
# 使用 NumPy 的 isclose 函数比较两个数组的元素是否在指定的绝对误差范围内相等
>>> np.isclose([1e-10, 1e-10], [1e-20, 0.999999e-10], atol=0.0)
array([False, True])
"""
# 将除了 Python 标量之外的对象转换为数组
x, y, atol, rtol = (
a if isinstance(a, (int, float, complex)) else asanyarray(a)
for a in (a, b, atol, rtol))
# 确保 y 是一个非精确类型,以避免在 abs(MIN_INT) 上出现错误行为
# 这将导致稍后将 x 转换为该类型。同时,确保允许子类(例如 numpy.ma)
# 注意:我们明确允许 timedelta,这在过去有效。这可能会被弃用。另请参见 gh-18286。
# timedelta 在 `atol` 是整数或 timedelta 时有效。
# 尽管如此,默认的公差可能不太有用
if (dtype := getattr(y, "dtype", None)) is not None and dtype.kind != "m":
dt = multiarray.result_type(y, 1.)
y = asanyarray(y, dtype=dt)
elif isinstance(y, int):
y = float(y)
# 使用 errstate 来忽略无效值的警告,并通过 _no_nep50_warning 确保不显示 NEP 50 的警告
with errstate(invalid='ignore'), _no_nep50_warning():
# 计算两数组之间的相等性
result = (less_equal(abs(x-y), atol + rtol * abs(y))
& isfinite(y)
| (x == y))
# 如果需要,处理 NaN 的情况
if equal_nan:
result |= isnan(x) & isnan(y)
# 返回扁平化的零维数组结果作为标量
return result[()]
def _array_equal_dispatcher(a1, a2, equal_nan=None):
# 将输入的两个数组作为一个元组返回,用于数组相等性判断的调度器
return (a1, a2)
_no_nan_types = {
# 不包含可以容纳 NaN 值的数据类型集合,这些类型不支持 NaN 比较
# 应该使用 np.dtype.BoolDType,但在写作时未通过重新加载测试
type(dtype(nt.bool)),
type(dtype(nt.int8)),
type(dtype(nt.int16)),
type(dtype(nt.int32)),
type(dtype(nt.int64)),
}
def _dtype_cannot_hold_nan(dtype):
# 判断给定的数据类型是否在 _no_nan_types 集合中,即是否不能容纳 NaN 值
return type(dtype) in _no_nan_types
@array_function_dispatch(_array_equal_dispatcher)
def array_equal(a1, a2, equal_nan=False):
"""
如果两个数组具有相同的形状和元素,则返回 True,否则返回 False。
Parameters
----------
a1, a2 : array_like
输入数组。
equal_nan : bool
是否将 NaN 视为相等。如果 a1 和 a2 的 dtype 是复数,则如果给定值的实部或虚部为 NaN,则视为相等。
.. versionadded:: 1.19.0
Returns
-------
b : bool
如果数组相等则返回 True。
See Also
--------
allclose: 如果两个数组在容差范围内逐元素相等,则返回 True。
array_equiv: 如果输入数组在形状上一致且所有元素相等,则返回 True。
Examples
--------
>>> np.array_equal([1, 2], [1, 2])
True
>>> np.array_equal(np.array([1, 2]), np.array([1, 2]))
True
>>> np.array_equal([1, 2], [1, 2, 3])
False
>>> np.array_equal([1, 2], [1, 4])
False
>>> a = np.array([1, np.nan])
>>> np.array_equal(a, a)
False
>>> np.array_equal(a, a, equal_nan=True)
True
当 equal_nan 为 True 时,如果复数值的组成部分为 NaN,则认为它们是相等的。
>>> a = np.array([1 + 1j])
>>> b = a.copy()
>>> a.real = np.nan
>>> b.imag = np.nan
>>> np.array_equal(a, b, equal_nan=True)
True
"""
try:
a1, a2 = asarray(a1), asarray(a2)
except Exception:
return False
if a1.shape != a2.shape:
return False
if not equal_nan:
return builtins.bool((a1 == a2).all())
cannot_have_nan = (_dtype_cannot_hold_nan(a1.dtype)
and _dtype_cannot_hold_nan(a2.dtype))
if cannot_have_nan:
if a1 is a2:
return True
return builtins.bool((a1 == a2).all())
if a1 is a2:
# NaN 将被视为相等,因此数组将与自身比较相等。
return True
# 如果 equal_nan 为 True,则处理 NaN 值
a1nan, a2nan = isnan(a1), isnan(a2)
# NaN 出现在不同位置
if not (a1nan == a2nan).all():
return False
# 到这一步,a1、a2 和掩码的形状保证一致
return builtins.bool((a1[~a1nan] == a2[~a1nan]).all())
def _array_equiv_dispatcher(a1, a2):
# 将输入的两个数组作为一个元组返回,用于数组等价性判断的调度器
return (a1, a2)
@array_function_dispatch(_array_equiv_dispatcher)
def array_equiv(a1, a2):
"""
Returns True if input arrays are shape consistent and all elements equal.
Shape consistent means they are either the same shape, or one input array
can be broadcasted to create the same shape as the other one.
Parameters
----------
a1, a2 : array_like
Input arrays.
Returns
-------
out : bool
True if equivalent, False otherwise.
Examples
--------
>>> np.array_equiv([1, 2], [1, 2])
True
>>> np.array_equiv([1, 2], [1, 3])
False
Showing the shape equivalence:
>>> np.array_equiv([1, 2], [[1, 2], [1, 2]])
True
>>> np.array_equiv([1, 2], [[1, 2, 1, 2], [1, 2, 1, 2]])
False
>>> np.array_equiv([1, 2], [[1, 2], [1, 3]])
False
"""
# 尝试将输入的 a1 和 a2 转换为数组
try:
a1, a2 = asarray(a1), asarray(a2)
except Exception:
# 转换失败则返回 False
return False
# 尝试使用广播来匹配数组的形状
try:
multiarray.broadcast(a1, a2)
except Exception:
# 广播失败则返回 False
return False
# 检查数组 a1 和 a2 的所有元素是否完全相等,返回比较结果
return builtins.bool((a1 == a2).all())
# 定义一个函数 _astype_dispatcher,用于类型分发,接收参数 x, dtype 和可选的 copy
def _astype_dispatcher(x, dtype, /, *, copy=None):
# 返回一个元组,包含参数 x 和 dtype
return (x, dtype)
# 使用 array_function_dispatch 装饰器将 _astype_dispatcher 函数注册为 astype 函数的分发器
@array_function_dispatch(_astype_dispatcher)
# 定义 astype 函数,用于将数组复制到指定的数据类型
def astype(x, dtype, /, *, copy = True):
"""
Copies an array to a specified data type.
This function is an Array API compatible alternative to
`numpy.ndarray.astype`.
Parameters
----------
x : ndarray
Input NumPy array to cast. ``array_likes`` are explicitly not
supported here.
dtype : dtype
Data type of the result.
copy : bool, optional
Specifies whether to copy an array when the specified dtype matches
the data type of the input array ``x``. If ``True``, a newly allocated
array must always be returned. If ``False`` and the specified dtype
matches the data type of the input array, the input array must be
returned; otherwise, a newly allocated array must be returned.
Defaults to ``True``.
Returns
-------
out : ndarray
An array having the specified data type.
See Also
--------
ndarray.astype
Examples
--------
>>> arr = np.array([1, 2, 3]); arr
array([1, 2, 3])
>>> np.astype(arr, np.float64)
array([1., 2., 3.])
Non-copy case:
>>> arr = np.array([1, 2, 3])
>>> arr_noncpy = np.astype(arr, arr.dtype, copy=False)
>>> np.shares_memory(arr, arr_noncpy)
True
"""
# 如果输入不是 NumPy 数组,则抛出 TypeError 异常
if not isinstance(x, np.ndarray):
raise TypeError(
f"Input should be a NumPy array. It is a {type(x)} instead."
)
# 调用输入数组 x 的 astype 方法,将其转换为指定的数据类型 dtype,并根据 copy 参数决定是否复制数组
return x.astype(dtype, copy=copy)
# 定义 inf 为正无穷大常量 PINF
inf = PINF
# 定义 nan 为 NaN 常量 NAN
nan = NAN
# 定义 False_ 为布尔类型 False 的别名
False_ = nt.bool(False)
# 定义 True_ 为布尔类型 True 的别名
True_ = nt.bool(True)
# 定义 extend_all 函数,用于向 __all__ 中扩展模块的所有内容
def extend_all(module):
# 获取当前 __all__ 的内容,并转换为集合
existing = set(__all__)
# 获取给定模块的 __all__ 属性
mall = getattr(module, '__all__')
# 遍历模块的 __all__ 中的每个元素
for a in mall:
# 如果元素不在现有的 __all__ 中,则将其添加到 __all__ 中
if a not in existing:
__all__.append(a)
# 导入 umath 模块中的所有内容
from .umath import *
# 导入 numerictypes 模块中的所有内容
from .numerictypes import *
# 导入 fromnumeric 模块
from . import fromnumeric
# 从 fromnumeric 模块中导入所有内容
from .fromnumeric import *
# 导入 arrayprint 模块
from . import arrayprint
# 从 arrayprint 模块中导入所有内容
from .arrayprint import *
# 导入 _asarray 模块
from . import _asarray
# 从 _asarray 模块中导入所有内容
from ._asarray import *
# 导入 _ufunc_config 模块
from . import _ufunc_config
# 从 _ufunc_config 模块中导入所有内容
from ._ufunc_config import *
# 扩展 __all__ 列表以包含来自不同模块的内容
extend_all(fromnumeric)
extend_all(umath)
extend_all(numerictypes)
extend_all(arrayprint)
extend_all(_asarray)
extend_all(_ufunc_config)
.\numpy\numpy\_core\numeric.pyi
from collections.abc import Callable, Sequence
from typing import (
Any,
overload,
TypeVar,
Literal as L,
SupportsAbs,
SupportsIndex,
NoReturn,
)
if sys.version_info >= (3, 10):
from typing import TypeGuard
else:
from typing_extensions import TypeGuard
import numpy as np
from numpy import (
ComplexWarning as ComplexWarning,
generic,
unsignedinteger,
signedinteger,
floating,
complexfloating,
int_,
intp,
float64,
timedelta64,
object_,
_OrderKACF,
_OrderCF,
)
from numpy._typing import (
ArrayLike,
NDArray,
DTypeLike,
_ShapeLike,
_DTypeLike,
_ArrayLike,
_SupportsArrayFunc,
_ScalarLike_co,
_ArrayLikeBool_co,
_ArrayLikeUInt_co,
_ArrayLikeInt_co,
_ArrayLikeFloat_co,
_ArrayLikeComplex_co,
_ArrayLikeTD64_co,
_ArrayLikeObject_co,
_ArrayLikeUnknown,
)
_T = TypeVar("_T")
_SCT = TypeVar("_SCT", bound=generic)
_ArrayType = TypeVar("_ArrayType", bound=NDArray[Any])
_CorrelateMode = L["valid", "same", "full"]
__all__: list[str] = []
@overload
def zeros_like(
a: _ArrayType,
dtype: None = ...,
order: _OrderKACF = ...,
subok: L[True] = ...,
shape: None = ...,
*,
device: None | L["cpu"] = ...,
) -> _ArrayType: ...
@overload
def zeros_like(
a: _ArrayLike[_SCT],
dtype: None = ...,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike = ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...
@overload
def zeros_like(
a: object,
dtype: None = ...,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike = ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...
@overload
def zeros_like(
a: Any,
dtype: _DTypeLike[_SCT],
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike = ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...
@overload
def zeros_like(
a: Any,
dtype: DTypeLike,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike = ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...
@overload
def ones(
shape: _ShapeLike,
dtype: None = ...,
order: _OrderCF = ...,
*,
device: None | L["cpu"] = ...,
like: _SupportsArrayFunc = ...,
) -> NDArray[float64]: ...
@overload
def ones(
shape: _ShapeLike,
dtype: _DTypeLike[_SCT],
order: _OrderCF = ...,
*,
device: None | L["cpu"] = ...,
like: _SupportsArrayFunc = ...,
) -> NDArray[_SCT]: ...
@overload
def ones(
shape: _ShapeLike,
dtype: DTypeLike,
order: _OrderCF = ...,
*,
device: None | L["cpu"] = ...,
like: _SupportsArray
a: _ArrayLike[_SCT],
dtype: None = ...,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike = ...,
*,
device: None | L["cpu"] = ...,
def ones_like(
a: object,
dtype: None = ...,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike= ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...
@overload
def ones_like(
a: Any,
dtype: _DTypeLike[_SCT],
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike= ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...
@overload
def ones_like(
a: Any,
dtype: DTypeLike,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike= ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...
def full(
shape: _ShapeLike,
fill_value: Any,
dtype: None = ...,
order: _OrderCF = ...,
*,
device: None | L["cpu"] = ...,
like: _SupportsArrayFunc = ...,
) -> NDArray[Any]: ...
@overload
def full(
shape: _ShapeLike,
fill_value: Any,
dtype: _DTypeLike[_SCT],
order: _OrderCF = ...,
*,
device: None | L["cpu"] = ...,
like: _SupportsArrayFunc = ...,
) -> NDArray[_SCT]: ...
@overload
def full(
shape: _ShapeLike,
fill_value: Any,
dtype: DTypeLike,
order: _OrderCF = ...,
*,
device: None | L["cpu"] = ...,
like: _SupportsArrayFunc = ...,
) -> NDArray[Any]: ...
@overload
def full_like(
a: _ArrayType,
fill_value: Any,
dtype: None = ...,
order: _OrderKACF = ...,
subok: L[True] = ...,
shape: None = ...,
*,
device: None | L["cpu"] = ...,
) -> _ArrayType: ...
@overload
def full_like(
a: _ArrayLike[_SCT],
fill_value: Any,
dtype: None = ...,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike = ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...
@overload
def full_like(
a: object,
fill_value: Any,
dtype: None = ...,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike= ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...
@overload
def full_like(
a: Any,
fill_value: Any,
dtype: _DTypeLike[_SCT],
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike= ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[_SCT]: ...
@overload
def full_like(
a: Any,
fill_value: Any,
dtype: DTypeLike,
order: _OrderKACF = ...,
subok: bool = ...,
shape: None | _ShapeLike= ...,
*,
device: None | L["cpu"] = ...,
) -> NDArray[Any]: ...
@overload
def count_nonzero(
a: ArrayLike,
axis: None = ...,
*,
keepdims: L[False] = ...,
) -> int: ...
@overload
def count_nonzero(
a: ArrayLike,
axis: _ShapeLike = ...,
*,
keepdims: bool = ...,
) -> Any: ...
def isfortran(a: NDArray[Any] | generic) -> bool: ...
def argwhere(a: ArrayLike) -> NDArray[intp]: ...
def flatnonzero(a: ArrayLike) -> NDArray[intp]: ...
@overload
def correlate(
a: _ArrayLikeUnknown,
v: _ArrayLikeUnknown,
mode: _CorrelateMode = ...,
@overload
def correlate(
a: _ArrayLikeBool_co,
v: _ArrayLikeBool_co,
mode: _CorrelateMode = ...,
) -> NDArray[np.bool]: ...
@overload
def correlate(
a: _ArrayLikeUInt_co,
v: _ArrayLikeUInt_co,
mode: _CorrelateMode = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def correlate(
a: _ArrayLikeInt_co,
v: _ArrayLikeInt_co,
mode: _CorrelateMode = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def correlate(
a: _ArrayLikeFloat_co,
v: _ArrayLikeFloat_co,
mode: _CorrelateMode = ...,
) -> NDArray[floating[Any]]: ...
@overload
def correlate(
a: _ArrayLikeComplex_co,
v: _ArrayLikeComplex_co,
mode: _CorrelateMode = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def correlate(
a: _ArrayLikeTD64_co,
v: _ArrayLikeTD64_co,
mode: _CorrelateMode = ...,
) -> NDArray[timedelta64]: ...
@overload
def correlate(
a: _ArrayLikeObject_co,
v: _ArrayLikeObject_co,
mode: _CorrelateMode = ...,
) -> NDArray[object_]: ...
@overload
def convolve(
a: _ArrayLikeUnknown,
v: _ArrayLikeUnknown,
mode: _CorrelateMode = ...,
) -> NDArray[Any]: ...
@overload
def convolve(
a: _ArrayLikeBool_co,
v: _ArrayLikeBool_co,
mode: _CorrelateMode = ...,
) -> NDArray[np.bool]: ...
@overload
def convolve(
a: _ArrayLikeUInt_co,
v: _ArrayLikeUInt_co,
mode: _CorrelateMode = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def convolve(
a: _ArrayLikeInt_co,
v: _ArrayLikeInt_co,
mode: _CorrelateMode = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def convolve(
a: _ArrayLikeFloat_co,
v: _ArrayLikeFloat_co,
mode: _CorrelateMode = ...,
) -> NDArray[floating[Any]]: ...
@overload
def convolve(
a: _ArrayLikeComplex_co,
v: _ArrayLikeComplex_co,
mode: _CorrelateMode = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def convolve(
a: _ArrayLikeTD64_co,
v: _ArrayLikeTD64_co,
mode: _CorrelateMode = ...,
) -> NDArray[timedelta64]: ...
@overload
def convolve(
a: _ArrayLikeObject_co,
v: _ArrayLikeObject_co,
mode: _CorrelateMode = ...,
) -> NDArray[object_]: ...
@overload
def outer(
a: _ArrayLikeUnknown,
b: _ArrayLikeUnknown,
out: None = ...,
) -> NDArray[Any]: ...
@overload
def outer(
a: _ArrayLikeBool_co,
b: _ArrayLikeBool_co,
out: None = ...,
) -> NDArray[np.bool]: ...
@overload
def outer(
a: _ArrayLikeUInt_co,
b: _ArrayLikeUInt_co,
out: None = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def outer(
a: _ArrayLikeInt_co,
b: _ArrayLikeInt_co,
out: None = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def outer(
a: _ArrayLikeFloat_co,
b: _ArrayLikeFloat_co,
out: None = ...,
) -> NDArray[floating[Any]]: ...
@overload
def outer(
a: _ArrayLikeComplex_co,
b: _ArrayLikeComplex_co,
out: None = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def outer(
a: _ArrayLikeTD64_co,
b: _ArrayLikeTD64_co,
out: None = ...,
) -> NDArray[timedelta64]: ...
@overload
def outer(
a: _ArrayLikeObject_co,
b: _ArrayLikeObject_co,
out: None = ...,
) -> NDArray[object_]: ...
b: _ArrayLikeTD64_co,
out: None = ...,
b: _ArrayLikeTD64_co,
out: None = ...,
) -> NDArray[timedelta64]: ...
@overload
def outer(
a: _ArrayLikeObject_co,
b: _ArrayLikeObject_co,
out: None = ...,
) -> NDArray[object_]: ...
@overload
def outer(
a: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeObject_co,
b: _ArrayLikeComplex_co | _ArrayLikeTD64_co | _ArrayLikeObject_co,
out: _ArrayType,
) -> _ArrayType: ...
@overload
def tensordot(
a: _ArrayLikeUnknown,
b: _ArrayLikeUnknown,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[Any]: ...
@overload
def tensordot(
a: _ArrayLikeBool_co,
b: _ArrayLikeBool_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[np.bool]: ...
@overload
def tensordot(
a: _ArrayLikeUInt_co,
b: _ArrayLikeUInt_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def tensordot(
a: _ArrayLikeInt_co,
b: _ArrayLikeInt_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[signedinteger[Any]]: ...
@overload
def tensordot(
a: _ArrayLikeFloat_co,
b: _ArrayLikeFloat_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[floating[Any]]: ...
@overload
def tensordot(
a: _ArrayLikeComplex_co,
b: _ArrayLikeComplex_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
@overload
def tensordot(
a: _ArrayLikeTD64_co,
b: _ArrayLikeTD64_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[timedelta64]: ...
@overload
def tensordot(
a: _ArrayLikeObject_co,
b: _ArrayLikeObject_co,
axes: int | tuple[_ShapeLike, _ShapeLike] = ...,
) -> NDArray[object_]: ...
@overload
def roll(
a: _ArrayLike[_SCT],
shift: _ShapeLike,
axis: None | _ShapeLike = ...,
) -> NDArray[_SCT]: ...
@overload
def roll(
a: ArrayLike,
shift: _ShapeLike,
axis: None | _ShapeLike = ...,
) -> NDArray[Any]: ...
def rollaxis(
a: NDArray[_SCT],
axis: int,
start: int = ...,
) -> NDArray[_SCT]: ...
def moveaxis(
a: NDArray[_SCT],
source: _ShapeLike,
destination: _ShapeLike,
) -> NDArray[_SCT]: ...
@overload
def cross(
x1: _ArrayLikeUnknown,
x2: _ArrayLikeUnknown,
axisa: int = ...,
axisb: int = ...,
axisc: int = ...,
axis: None | int = ...,
) -> NDArray[Any]: ...
@overload
def cross(
x1: _ArrayLikeBool_co,
x2: _ArrayLikeBool_co,
axisa: int = ...,
axisb: int = ...,
axisc: int = ...,
axis: None | int = ...,
) -> NoReturn: ...
@overload
def cross(
x1: _ArrayLikeUInt_co,
x2: _ArrayLikeUInt_co,
axisa: int = ...,
axisb: int = ...,
axisc: int = ...,
axis: None | int = ...,
) -> NDArray[unsignedinteger[Any]]: ...
@overload
def cross(
x1: _ArrayLikeInt_co,
x2: _ArrayLikeInt_co,
axisa: int = ...,
axisb: int = ...,
axisc: int = ...,
axis: None | int = ...,
) -> NDArray[signedinteger[Any]]: ...
x2: _ArrayLikeFloat_co,
axisa: int = ...,
axisb: int = ...,
axisc: int = ...,
axis: None | int = ...,
def cross(
x1: _ArrayLikeComplex_co,
x2: _ArrayLikeComplex_co,
axisa: int = ...,
axisb: int = ...,
axisc: int = ...,
axis: None | int = ...,
) -> NDArray[complexfloating[Any, Any]]: ...
def indices(
dimensions: Sequence[int],
dtype: type[int] = ...,
sparse: L[False] = ...,
) -> NDArray[int_]: ...
def fromfunction(
function: Callable[..., _T],
shape: Sequence[int],
*,
dtype: DTypeLike = ...,
like: _SupportsArrayFunc = ...,
**kwargs: Any,
) -> _T: ...
def isscalar(element: object) -> TypeGuard[
generic | bool | int | float | complex | str | bytes | memoryview
]: ...
def binary_repr(num: SupportsIndex, width: None | int = ...) -> str: ...
def base_repr(
number: SupportsAbs[float],
base: float = ...,
padding: SupportsIndex = ...,
) -> str: ...
def identity(
n: int,
dtype: None = ...,
*,
like: _SupportsArrayFunc = ...,
) -> NDArray[float64]: ...
def allclose(
a: ArrayLike,
b: ArrayLike,
rtol: ArrayLike = ...,
atol: ArrayLike = ...,
equal_nan: bool = ...,
) -> bool: ...
def isclose(
a: _ScalarLike_co,
b: _ScalarLike_co,
rtol: ArrayLike = ...,
atol: ArrayLike = ...,
equal_nan: bool = ...,
) -> np.bool: ...
def array_equal(a1: ArrayLike, a2: ArrayLike, equal_nan: bool = ...) -> bool: ...
def array_equiv(a1: ArrayLike, a2: ArrayLike) -> bool: ...
def astype(
x: NDArray[Any],
dtype: _DTypeLike[_SCT],
copy: bool = ...,
) -> NDArray[_SCT]: ...
) -> NDArray[Any]: ...
.\numpy\numpy\_core\numerictypes.py
"""
numerictypes: Define the numeric type objects
This module is designed so "from numerictypes import \\*" is safe.
Exported symbols include:
Dictionary with all registered number types (including aliases):
sctypeDict
Type objects (not all will be available, depends on platform):
see variable sctypes for which ones you have
Bit-width names
int8 int16 int32 int64 int128
uint8 uint16 uint32 uint64 uint128
float16 float32 float64 float96 float128 float256
complex32 complex64 complex128 complex192 complex256 complex512
datetime64 timedelta64
c-based names
bool
object_
void, str_
byte, ubyte,
short, ushort
intc, uintc,
intp, uintp,
int_, uint,
longlong, ulonglong,
single, csingle,
double, cdouble,
longdouble, clongdouble,
As part of the type-hierarchy: xx -- is bit-width
generic
+-> bool (kind=b)
+-> number
| +-> integer
| | +-> signedinteger (intxx) (kind=i)
| | | byte
| | | short
| | | intc
| | | intp
| | | int_
| | | longlong
| | \\-> unsignedinteger (uintxx) (kind=u)
| | ubyte
| | ushort
| | uintc
| | uintp
| | uint
| | ulonglong
| +-> inexact
| +-> floating (floatxx) (kind=f)
| | half
| | single
| | double
| | longdouble
| \\-> complexfloating (complexxx) (kind=c)
| csingle
| cdouble
| clongdouble
+-> flexible
| +-> character
| | bytes_ (kind=S)
| | str_ (kind=U)
| |
| \\-> void (kind=V)
\\-> object_ (not used much) (kind=O)
"""
import numbers
import warnings
from . import multiarray as ma
from .multiarray import (
ndarray, array, dtype, datetime_data, datetime_as_string,
busday_offset, busday_count, is_busday, busdaycalendar
)
from .._utils import set_module
__all__ = [
'ScalarType', 'typecodes', 'issubdtype', 'datetime_data',
'datetime_as_string', 'busday_offset', 'busday_count',
'is_busday', 'busdaycalendar', 'isdtype'
]
from ._string_helpers import (
english_lower, english_upper, english_capitalize, LOWER_TABLE, UPPER_TABLE
)
from ._type_aliases import (
sctypeDict, allTypes, sctypes
)
from ._dtype import _kind_name
from builtins import bool, int, float, complex, object, str, bytes
generic = allTypes['generic']
genericTypeRank = ['bool', 'int8', 'uint8', 'int16', 'uint16',
'int32', 'uint32', 'int64', 'uint64', 'int128',
'uint128', 'float16',
'float32', 'float64', 'float80', 'float96', 'float128',
'float256',
'complex32', 'complex64', 'complex128', 'complex160',
'complex192', 'complex256', 'complex512', 'object']
@set_module('numpy')
def maximum_sctype(t):
"""
根据输入的类型,返回同种类中最高精度的标量类型。
.. deprecated:: 2.0
建议改用显式的 dtype,如 int64 或 float64。
Parameters
----------
t : dtype 或 dtype 指定符
输入的数据类型。可以是一个 `dtype` 对象或可以转换为 `dtype` 的对象。
Returns
-------
out : dtype
与 `t` 同类 (`dtype.kind`) 中最高精度的数据类型。
See Also
--------
obj2sctype, mintypecode, sctype2char
dtype
Examples
--------
>>> from numpy._core.numerictypes import maximum_sctype
>>> maximum_sctype(int)
<class 'numpy.int64'>
>>> maximum_sctype(np.uint8)
<class 'numpy.uint64'>
>>> maximum_sctype(complex)
<class 'numpy.complex256'> # 结果可能会有所不同
>>> maximum_sctype(str)
<class 'numpy.str_'>
>>> maximum_sctype('i2')
<class 'numpy.int64'>
>>> maximum_sctype('f4')
<class 'numpy.float128'> # 结果可能会有所不同
"""
warnings.warn(
"`maximum_sctype` 已弃用。建议改用显式的 dtype,如 int64 或 float64。"
" (在 NumPy 2.0 中弃用)",
DeprecationWarning,
stacklevel=2
)
g = obj2sctype(t)
if g is None:
return t
t = g
base = _kind_name(dtype(t))
if base in sctypes:
return sctypes[base][-1]
else:
return t
@set_module('numpy')
def issctype(rep):
"""
判断给定对象是否表示标量数据类型。
Parameters
----------
rep : 任意类型
如果 `rep` 是标量数据类型的实例,则返回 True。否则返回 False。
Returns
-------
out : bool
检查 `rep` 是否为标量数据类型的布尔结果。
See Also
--------
issubsctype, issubdtype, obj2sctype, sctype2char
Examples
--------
>>> from numpy._core.numerictypes import issctype
>>> issctype(np.int32)
True
>>> issctype(list)
False
>>> issctype(1.1)
False
字符串也是标量类型:
>>> issctype(np.dtype('str'))
True
"""
if not isinstance(rep, (type, dtype)):
return False
try:
res = obj2sctype(rep)
if res and res != object_:
return True
return False
except Exception:
return False
@set_module('numpy')
def obj2sctype(rep, default=None):
"""
将输入转换为其对应的标量数据类型。
# 返回对象的标量数据类型或者其在 NumPy 中的等效类型
Parameters
----------
rep : any
要获取其类型的对象。
default : any, optional
如果提供,则用于无法确定类型的对象。如果未提供,则对于这些对象返回 None。
Returns
-------
dtype : dtype or Python type
`rep` 的数据类型。
See Also
--------
sctype2char, issctype, issubsctype, issubdtype
Examples
--------
>>> from numpy._core.numerictypes import obj2sctype
>>> obj2sctype(np.int32)
<class 'numpy.int32'>
>>> obj2sctype(np.array([1., 2.]))
<class 'numpy.float64'>
>>> obj2sctype(np.array([1.j]))
<class 'numpy.complex128'>
>>> obj2sctype(dict)
<class 'numpy.object_'>
>>> obj2sctype('string')
>>> obj2sctype(1, default=list)
<class 'list'>
"""
if isinstance(rep, type) and issubclass(rep, generic):
return rep
if isinstance(rep, ndarray):
return rep.dtype.type
try:
res = dtype(rep)
except Exception:
return default
else:
return res.type
@set_module('numpy')
def issubclass_(arg1, arg2):
"""
Determine if a class is a subclass of a second class.
`issubclass_` is equivalent to the Python built-in ``issubclass``,
except that it returns False instead of raising a TypeError if one
of the arguments is not a class.
Parameters
----------
arg1 : class
Input class. True is returned if `arg1` is a subclass of `arg2`.
arg2 : class or tuple of classes.
Input class. If a tuple of classes, True is returned if `arg1` is a
subclass of any of the tuple elements.
Returns
-------
out : bool
Whether `arg1` is a subclass of `arg2` or not.
See Also
--------
issubsctype, issubdtype, issctype
Examples
--------
>>> np.issubclass_(np.int32, int)
False
>>> np.issubclass_(np.int32, float)
False
>>> np.issubclass_(np.float64, float)
True
"""
try:
return issubclass(arg1, arg2)
except TypeError:
return False
@set_module('numpy')
def issubsctype(arg1, arg2):
"""
Determine if the first argument is a subclass of the second argument.
Parameters
----------
arg1, arg2 : dtype or dtype specifier
Data-types.
Returns
-------
out : bool
The result.
See Also
--------
issctype, issubdtype, obj2sctype
Examples
--------
>>> from numpy._core import issubsctype
>>> issubsctype('S8', str)
False
>>> issubsctype(np.array([1]), int)
True
>>> issubsctype(np.array([1]), float)
False
"""
return issubclass(obj2sctype(arg1), obj2sctype(arg2))
class _PreprocessDTypeError(Exception):
pass
def _preprocess_dtype(dtype):
"""
Preprocess dtype argument by:
1. fetching type from a data type
2. verifying that types are built-in NumPy dtypes
"""
if isinstance(dtype, ma.dtype):
dtype = dtype.type
if isinstance(dtype, ndarray) or dtype not in allTypes.values():
raise _PreprocessDTypeError()
return dtype
@set_module('numpy')
def isdtype(dtype, kind):
"""
Determine if a provided dtype is of a specified data type ``kind``.
This function only supports built-in NumPy's data types.
Third-party dtypes are not yet supported.
Parameters
----------
dtype : dtype
The input dtype.
kind : dtype or str or tuple of dtypes/strs.
dtype or dtype kind. Allowed dtype kinds are:
* ``'bool'`` : boolean kind
* ``'signed integer'`` : signed integer data types
* ``'unsigned integer'`` : unsigned integer data types
* ``'integral'`` : integer data types
* ``'real floating'`` : real-valued floating-point data types
* ``'complex floating'`` : complex floating-point data types
* ``'numeric'`` : numeric data types
Returns
-------
out : bool
See Also
--------
issubdtype
Examples
--------
>>> import numpy as np
"""
return issubclass(obj2sctype(dtype), obj2sctype(kind))
>>> np.isdtype(np.float32, np.float64)
False
>>> np.isdtype(np.float32, "real floating")
True
>>> np.isdtype(np.complex128, ("real floating", "complex floating"))
True
"""
尝试对 dtype 进行预处理,确保其为 NumPy 的 dtype 类型
"""
try:
dtype = _preprocess_dtype(dtype)
except _PreprocessDTypeError:
raise TypeError(
"dtype argument must be a NumPy dtype, "
f"but it is a {type(dtype)}."
) from None
input_kinds = kind if isinstance(kind, tuple) else (kind,)
processed_kinds = set()
for kind in input_kinds:
if kind == "bool":
processed_kinds.add(allTypes["bool"])
elif kind == "signed integer":
processed_kinds.update(sctypes["int"])
elif kind == "unsigned integer":
processed_kinds.update(sctypes["uint"])
elif kind == "integral":
processed_kinds.update(sctypes["int"] + sctypes["uint"])
elif kind == "real floating":
processed_kinds.update(sctypes["float"])
elif kind == "complex floating":
processed_kinds.update(sctypes["complex"])
elif kind == "numeric":
processed_kinds.update(
sctypes["int"] + sctypes["uint"] +
sctypes["float"] + sctypes["complex"]
)
elif isinstance(kind, str):
raise ValueError(
"kind argument is a string, but"
f" {repr(kind)} is not a known kind name."
)
else:
try:
kind = _preprocess_dtype(kind)
except _PreprocessDTypeError:
raise TypeError(
"kind argument must be comprised of "
"NumPy dtypes or strings only, "
f"but is a {type(kind)}."
) from None
processed_kinds.add(kind)
return dtype in processed_kinds
@set_module('numpy')
def issubdtype(arg1, arg2):
if not issubclass_(arg1, generic):
arg1 = dtype(arg1).type
if not issubclass_(arg2, generic):
arg2 = dtype(arg2).type
return issubclass(arg1, arg2)
@set_module('numpy')
def sctype2char(sctype):
sctype = obj2sctype(sctype)
if sctype is None:
raise ValueError("unrecognized type")
if sctype not in sctypeDict.values():
raise KeyError(sctype)
return dtype(sctype).char
def _scalar_type_key(typ):
dt = dtype(typ)
return (dt.kind.lower(), dt.itemsize)
ScalarType = [int, float, complex, bool, bytes, str, memoryview]
ScalarType += sorted(set(sctypeDict.values()), key=_scalar_type_key)
ScalarType = tuple(ScalarType)
for key in allTypes:
globals()[key] = allTypes[key]
__all__.append(key)
del key
typecodes = {
'Character': 'c',
'Integer': 'bhilqnp',
'UnsignedInteger': 'BHILQNP',
'Float': 'efdg',
'Complex': 'FDG',
'AllInteger': 'bBhHiIlLqQnNpP',
'AllFloat': 'efdgFDG',
'Datetime': 'Mm',
'All': '?bhilqnpBHILQNPefdgFDGSUVOMm'
}
typeDict = sctypeDict
def _register_types():
numbers.Integral.register(integer)
numbers.Complex.register(inexact)
numbers.Real.register(floating)
_register_types()
.\numpy\numpy\_core\numerictypes.pyi
```python`
from typing import (
Literal as L,
Any,
TypeVar,
TypedDict,
)
import numpy as np
from numpy import (
dtype,
generic,
ubyte, ushort, uintc, ulong, ulonglong,
byte, short, intc, long, longlong,
half, single, double, longdouble,
csingle, cdouble, clongdouble,
datetime64, timedelta64,
object_, str_, bytes_, void,
)
from numpy._core._type_aliases import (
sctypeDict as sctypeDict,
)
from numpy._typing import DTypeLike
_T = TypeVar("_T")
_SCT = TypeVar("_SCT", bound=generic)
class _TypeCodes(TypedDict):
Character: L['c']
Integer: L['bhilqp']
UnsignedInteger: L['BHILQP']
Float: L['efdg']
Complex: L['FDG']
AllInteger: L['bBhHiIlLqQpP']
AllFloat: L['efdgFDG']
Datetime: L['Mm']
All: L['?bhilqpBHILQPefdgFDGSUVOMm']
__all__: list[str]
def isdtype(
dtype: dtype[Any] | type[Any],
kind: DTypeLike | tuple[DTypeLike, ...]
) -> bool:
def issubdtype(arg1: DTypeLike, arg2: DTypeLike) -> bool:
typecodes: _TypeCodes
ScalarType: tuple[
type[int], type[float], type[complex],
type[bool], type[bytes], type[str],
type[memoryview], type[np.bool],
type[csingle], type[cdouble], type[clongdouble],
type[half], type[single], type[double], type[longdouble],
type[byte], type[short], type[intc], type[long],
type[longlong], type[timedelta64], type[datetime64],
type[object_], type[bytes_], type[str_],
type[ubyte], type[ushort], type[uintc], type[ulong], type[ulonglong], type[void],
]
.\numpy\numpy\_core\overrides.py
"""Implementation of __array_function__ overrides from NEP-18."""
from numpy._core._multiarray_umath import (
add_docstring, _get_implementing_args, _ArrayFunctionDispatcher
)
ARRAY_FUNCTIONS = set()
array_function_like_doc = (
"""like : array_like, optional
Reference object to allow the creation of arrays which are not
NumPy arrays. If an array-like passed in as ``like`` supports
the ``__array_function__`` protocol, the result will be defined
by it. In this case, it ensures the creation of an array object
compatible with that passed in via this argument."""
)
def set_array_function_like_doc(public_api):
if public_api.__doc__ is not None:
public_api.__doc__ = public_api.__doc__.replace(
"${ARRAY_FUNCTION_LIKE}",
array_function_like_doc,
)
return public_api
add_docstring(
_ArrayFunctionDispatcher,
"""
Class to wrap functions with checks for __array_function__ overrides.
All arguments are required, and can only be passed by position.
Parameters
----------
dispatcher : function or None
The dispatcher function that returns a single sequence-like object
of all arguments relevant. It must have the same signature (except
the default values) as the actual implementation.
If ``None``, this is a ``like=`` dispatcher and the
``_ArrayFunctionDispatcher`` must be called with ``like`` as the
first (additional and positional) argument.
implementation : function
Function that implements the operation on NumPy arrays without
overrides. Arguments passed calling the ``_ArrayFunctionDispatcher``
will be forwarded to this (and the ``dispatcher``) as if using
``*args, **kwargs``.
Attributes
----------
_implementation : function
The original implementation passed in.
"""
)
add_docstring(
_get_implementing_args,
"""
Collect arguments on which to call __array_function__.
Parameters
----------
relevant_args : iterable of array-like
Iterable of possibly array-like arguments to check for
__array_function__ methods.
Returns
-------
Sequence of arguments with __array_function__ methods, in the order in
which they should be called.
"""
)
ArgSpec = collections.namedtuple('ArgSpec', 'args varargs keywords defaults')
def verify_matching_signatures(implementation, dispatcher):
"""Verify that a dispatcher function has the right signature."""
implementation_spec = ArgSpec(*getargspec(implementation))
dispatcher_spec = ArgSpec(*getargspec(dispatcher))
if (implementation_spec.args != dispatcher_spec.args or
implementation_spec.varargs != dispatcher_spec.varargs or
implementation_spec.keywords != dispatcher_spec.keywords or
(bool(implementation_spec.defaults) !=
bool(dispatcher_spec.defaults)) or
(implementation_spec.defaults is not None and
len(implementation_spec.defaults) !=
len(dispatcher_spec.defaults))):
raise RuntimeError('implementation and dispatcher for %s have '
'different function signatures' % implementation)
if implementation_spec.defaults is not None:
if dispatcher_spec.defaults != (None,) * len(dispatcher_spec.defaults):
raise RuntimeError('dispatcher functions can only use None for '
'default argument values')
def array_function_dispatch(dispatcher=None, module=None, verify=True,
docs_from_dispatcher=False):
"""Decorator for adding dispatch with the __array_function__ protocol.
See NEP-18 for example usage.
Parameters
----------
dispatcher : callable or None
Function that when called like ``dispatcher(*args, **kwargs)`` with
arguments from the NumPy function call returns an iterable of
array-like arguments to check for ``__array_function__``.
If `None`, the first argument is used as the single `like=` argument
and not passed on. A function implementing `like=` must call its
dispatcher with `like` as the first non-keyword argument.
module : str, optional
__module__ attribute to set on new function, e.g., ``module='numpy'``.
By default, module is copied from the decorated function.
verify : bool, optional
If True, verify the that the signature of the dispatcher and decorated
function signatures match exactly: all required and optional arguments
should appear in order with the same names, but the default values for
all optional arguments should be ``None``. Only disable verification
if the dispatcher's signature needs to deviate for some particular
reason, e.g., because the function has a signature like
``func(*args, **kwargs)``.
docs_from_dispatcher : bool, optional
If True, copy docs from the dispatcher function onto the dispatched
function, rather than from the implementation. This is useful for
functions defined in C, which otherwise don't have docstrings.
Returns
-------
Function suitable for decorating the implementation of a NumPy function.
"""
def decorator(implementation):
if verify:
if dispatcher is not None:
verify_matching_signatures(implementation, dispatcher)
else:
co = implementation.__code__
last_arg = co.co_argcount + co.co_kwonlyargcount - 1
last_arg = co.co_varnames[last_arg]
if last_arg != "like" or co.co_kwonlyargcount == 0:
raise RuntimeError(
"__array_function__ expects `like=` to be the last "
"argument and a keyword-only argument. "
f"{implementation} does not seem to comply.")
if docs_from_dispatcher:
add_docstring(implementation, dispatcher.__doc__)
public_api = _ArrayFunctionDispatcher(dispatcher, implementation)
public_api = functools.wraps(implementation)(public_api)
if module is not None:
public_api.__module__ = module
ARRAY_FUNCTIONS.add(public_api)
return public_api
return decorator
def array_function_from_dispatcher(
implementation, module=None, verify=True, docs_from_dispatcher=True):
"""Like array_function_dispatcher, but with function arguments flipped."""
def decorator(dispatcher):
return array_function_dispatch(
dispatcher, module, verify=verify,
docs_from_dispatcher=docs_from_dispatcher)(implementation)
return decorator
.\numpy\numpy\_core\records.py
"""
This module contains a set of functions for record arrays.
"""
import os
import warnings
from collections import Counter
from contextlib import nullcontext
from .._utils import set_module
from . import numeric as sb
from . import numerictypes as nt
from .arrayprint import _get_legacy_print_mode
__all__ = [
'record', 'recarray', 'format_parser', 'fromarrays', 'fromrecords',
'fromstring', 'fromfile', 'array', 'find_duplicate',
]
ndarray = sb.ndarray
_byteorderconv = {'b': '>',
'l': '<',
'n': '=',
'B': '>',
'L': '<',
'N': '=',
'S': 's',
's': 's',
'>': '>',
'<': '<',
'=': '=',
'|': '|',
'I': '|',
'i': '|'}
numfmt = nt.sctypeDict
@set_module('numpy.rec')
def find_duplicate(list):
"""Find duplication in a list, return a list of duplicated elements"""
return [
item
for item, counts in Counter(list).items()
if counts > 1
]
@set_module('numpy.rec')
class format_parser:
"""
Class to convert formats, names, titles description to a dtype.
After constructing the format_parser object, the dtype attribute is
the converted data-type:
``dtype = format_parser(formats, names, titles).dtype``
Attributes
----------
dtype : dtype
The converted data-type.
Parameters
----------
formats : str or list of str
The format description, either specified as a string with
comma-separated format descriptions in the form ``'f8, i4, S5'``, or
a list of format description strings in the form
``['f8', 'i4', 'S5']``.
names : str or list/tuple of str
The field names, either specified as a comma-separated string in the
form ``'col1, col2, col3'``, or as a list or tuple of strings in the
form ``['col1', 'col2', 'col3']``.
An empty list can be used, in that case default field names
('f0', 'f1', ...) are used.
titles : sequence
Sequence of title strings. An empty list can be used to leave titles
out.
aligned : bool, optional
If True, align the fields by padding as the C-compiler would.
Default is False.
byteorder : str, optional
If specified, all the fields will be changed to the
provided byte-order. Otherwise, the default byte-order is
used. For all available string specifiers, see `dtype.newbyteorder`.
See Also
--------
numpy.dtype, numpy.typename
Examples
--------
>>> np.rec.format_parser(['<f8', '<i4'], ['col1', 'col2'],
"""
"""
`names` and/or `titles` can be empty lists. If `titles` is an empty list,
titles will simply not appear. If `names` is empty, default field names
will be used.
>>> np.rec.format_parser(['f8', 'i4', 'a5'], ['col1', 'col2', 'col3'],
... []).dtype
dtype([('col1', '<f8'), ('col2', '<i4'), ('col3', '<S5')])
>>> np.rec.format_parser(['<f8', '<i4', '<a5'], [], []).dtype
dtype([('f0', '<f8'), ('f1', '<i4'), ('f2', 'S5')])
"""
def __init__(self, formats, names, titles, aligned=False, byteorder=None):
""" Initialize the record parser object with formats, field names, titles, alignment, and byte order """
self._parseFormats(formats, aligned)
self._setfieldnames(names, titles)
self._createdtype(byteorder)
def _parseFormats(self, formats, aligned=False):
""" Parse the field formats based on input formats and alignment """
if formats is None:
raise ValueError("Need formats argument")
if isinstance(formats, list):
dtype = sb.dtype(
[
('f{}'.format(i), format_)
for i, format_ in enumerate(formats)
],
aligned,
)
else:
dtype = sb.dtype(formats, aligned)
fields = dtype.fields
if fields is None:
dtype = sb.dtype([('f1', dtype)], aligned)
fields = dtype.fields
keys = dtype.names
self._f_formats = [fields[key][0] for key in keys]
self._offsets = [fields[key][1] for key in keys]
self._nfields = len(keys)
def _setfieldnames(self, names, titles):
""" Convert input field names into a list and assign to the _names attribute """
if names:
if type(names) in [list, tuple]:
pass
elif isinstance(names, str):
names = names.split(',')
else:
raise NameError("illegal input names %s" % repr(names))
self._names = [n.strip() for n in names[:self._nfields]]
else:
self._names = []
self._names += ['f%d' % i for i in range(len(self._names),
self._nfields)]
_dup = find_duplicate(self._names)
if _dup:
raise ValueError("Duplicate field names: %s" % _dup)
if titles:
self._titles = [n.strip() for n in titles[:self._nfields]]
else:
self._titles = []
titles = []
if self._nfields > len(titles):
self._titles += [None] * (self._nfields - len(titles))
def _createdtype(self, byteorder):
dtype = sb.dtype({
'names': self._names,
'formats': self._f_formats,
'offsets': self._offsets,
'titles': self._titles,
})
if byteorder is not None:
byteorder = _byteorderconv[byteorder[0]]
dtype = dtype.newbyteorder(byteorder)
self.dtype = dtype
class record(nt.void):
"""A data-type scalar that allows field access as attribute lookup.
"""
__name__ = 'record'
__module__ = 'numpy'
def __repr__(self):
if _get_legacy_print_mode() <= 113:
return self.__str__()
return super().__repr__()
def __str__(self):
if _get_legacy_print_mode() <= 113:
return str(self.item())
return super().__str__()
def __getattribute__(self, attr):
if attr in ('setfield', 'getfield', 'dtype'):
return nt.void.__getattribute__(self, attr)
try:
return nt.void.__getattribute__(self, attr)
except AttributeError:
pass
fielddict = nt.void.__getattribute__(self, 'dtype').fields
res = fielddict.get(attr, None)
if res:
obj = self.getfield(*res[:2])
try:
dt = obj.dtype
except AttributeError:
return obj
if dt.names is not None:
return obj.view((self.__class__, obj.dtype))
return obj
else:
raise AttributeError("'record' object has no "
"attribute '%s'" % attr)
def __setattr__(self, attr, val):
if attr in ('setfield', 'getfield', 'dtype'):
raise AttributeError("Cannot set '%s' attribute" % attr)
fielddict = nt.void.__getattribute__(self, 'dtype').fields
res = fielddict.get(attr, None)
if res:
return self.setfield(val, *res[:2])
else:
if getattr(self, attr, None):
return nt.void.__setattr__(self, attr, val)
else:
raise AttributeError("'record' object has no "
"attribute '%s'" % attr)
def __getitem__(self, indx):
obj = nt.void.__getitem__(self, indx)
if isinstance(obj, nt.void) and obj.dtype.names is not None:
return obj.view((self.__class__, obj.dtype))
else:
return obj
def pprint(self):
"""Pretty-print all fields."""
names = self.dtype.names
maxlen = max(len(name) for name in names)
fmt = '%% %ds: %%s' % maxlen
rows = [fmt % (name, getattr(self, name)) for name in names]
return "\n".join(rows)
@set_module("numpy.rec")
class recarray(ndarray):
"""Construct an ndarray that allows field access using attributes.
Arrays may have a data-types containing fields, analogous
to columns in a spread sheet. An example is ``[(x, int), (y, float)]``,
where each entry in the array is a pair of ``(int, float)``. Normally,
these attributes are accessed using dictionary lookups such as ``arr['x']``
and ``arr['y']``. Record arrays allow the fields to be accessed as members
of the array, using ``arr.x`` and ``arr.y``.
Parameters
----------
shape : tuple
Shape of output array.
dtype : data-type, optional
The desired data-type. By default, the data-type is determined
from `formats`, `names`, `titles`, `aligned` and `byteorder`.
formats : list of data-types, optional
A list containing the data-types for the different columns, e.g.
``['i4', 'f8', 'i4']``. `formats` does *not* support the new
convention of using types directly, i.e. ``(int, float, int)``.
Note that `formats` must be a list, not a tuple.
Given that `formats` is somewhat limited, we recommend specifying
`dtype` instead.
names : tuple of str, optional
The name of each column, e.g. ``('x', 'y', 'z')``.
buf : buffer, optional
By default, a new array is created of the given shape and data-type.
If `buf` is specified and is an object exposing the buffer interface,
the array will use the memory from the existing buffer. In this case,
the `offset` and `strides` keywords are available.
Other Parameters
----------------
titles : tuple of str, optional
Aliases for column names. For example, if `names` were
``('x', 'y', 'z')`` and `titles` is
``('x_coordinate', 'y_coordinate', 'z_coordinate')``, then
``arr['x']`` is equivalent to both ``arr.x`` and ``arr.x_coordinate``.
byteorder : {'<', '>', '='}, optional
Byte-order for all fields.
aligned : bool, optional
Align the fields in memory as the C-compiler would.
strides : tuple of ints, optional
Buffer (`buf`) is interpreted according to these strides (strides
define how many bytes each array element, row, column, etc.
occupy in memory).
offset : int, optional
Start reading buffer (`buf`) from this offset onwards.
order : {'C', 'F'}, optional
Row-major (C-style) or column-major (Fortran-style) order.
Returns
-------
rec : recarray
Empty array of the given shape and type.
See Also
--------
numpy.rec.fromrecords : Construct a record array from data.
numpy.record : fundamental data-type for `recarray`.
numpy.rec.format_parser : determine data-type from formats, names, titles.
Notes
-----
This constructor can be compared to ``empty``: it creates a new record
"""
def __init__(self, shape, dtype=None, formats=None, names=None,
buf=None, **kwargs):
super(recarray, self).__new__(recarray, shape, dtype, buffer=buf)
if formats is not None and names is not None:
if not isinstance(formats, list):
raise TypeError("formats must be a list")
if not isinstance(names, tuple):
raise TypeError("names must be a tuple")
self._fieldnames = names
self._formats = formats
if len(self._fieldnames) != len(self._formats):
raise ValueError("Length of formats and names must be equal")
elif dtype is None:
self._fieldnames = []
self._formats = []
else:
raise ValueError("Both formats and names must be specified if dtype is provided")
def __setattr__(self, attr, value):
if attr in self._fieldnames:
idx = self._fieldnames.index(attr)
self[idx] = value
else:
super(recarray, self).__setattr__(attr, value)
def __getattr__(self, attr):
if attr in self._fieldnames:
idx = self._fieldnames.index(attr)
return self[idx]
else:
return super(recarray, self).__getattribute__(attr)
def __getitem__(self, key):
if isinstance(key, str):
if key in self._fieldnames:
idx = self._fieldnames.index(key)
return self[idx]
else:
raise KeyError(f"Field '{key}' not found in recarray")
else:
return super(recarray, self).__getitem__(key)
def __setitem__(self, key, value):
if isinstance(key, str):
if key in self._fieldnames:
idx = self._fieldnames.index(key)
self[idx] = value
else:
raise KeyError(f"Field '{key}' not found in recarray")
else:
super(recarray, self).__setitem__(key, value)
def __reduce__(self):
pickled_state = super(recarray, self).__reduce__()
new_state = pickled_state[2] + (self._fieldnames, self._formats)
return pickled_state[0], pickled_state[1], new_state
def __repr__(self):
return "recarray(shape={}, dtype={}, formats={}, names={})".format(
self.shape, self.dtype, self._formats, self._fieldnames)
def __str__(self):
return self.__repr__()
@set_module("numpy.rec")
class recarray(ndarray):
"""Construct an ndarray that allows field access using attributes.
Arrays may have a data-types containing fields, analogous
to columns in a spread sheet. An example is ``[(x, int), (y, float)]``,
where each entry in the array is a pair of ``(int, float)``. Normally,
these attributes are accessed using dictionary lookups such as ``arr['x']``
and ``arr['y']``. Record arrays allow the fields to be accessed as members
of the array, using ``arr.x`` and ``arr.y``.
Parameters
----------
shape : tuple
Shape of output array.
dtype : data-type, optional
The desired data-type. By default, the data-type is determined
from `formats`, `names`, `titles`, `aligned` and `byteorder`.
formats : list of data-types, optional
A list containing the data-types for the different columns, e.g.
``['i4', 'f8', 'i4']``. `formats` does *not* support the new
convention of using types directly, i.e. ``(int, float, int)``.
Note that `formats` must be a list, not a tuple.
Given that `formats` is somewhat limited, we recommend specifying
`dtype` instead.
names : tuple of str, optional
The name of each column, e.g. ``('x', 'y', 'z')``.
buf : buffer, optional
By default, a new array is created of the given shape and data-type.
If `buf` is specified and is an object exposing the buffer interface,
the array will use the memory from the existing buffer. In this case,
the `offset` and `strides` keywords are available.
Other Parameters
----------------
titles : tuple of str, optional
Aliases for column names. For example, if `names` were
``('x', 'y', 'z')`` and `titles` is
``('x_coordinate', 'y_coordinate', 'z_coordinate')``, then
``arr['x']`` is equivalent to both ``arr.x`` and ``arr.x_coordinate``.
byteorder : {'<', '>', '='}, optional
Byte-order for all fields.
aligned : bool, optional
Align the fields in memory as the C-compiler would.
strides : tuple of ints, optional
Buffer (`buf`) is interpreted according to these strides (strides
define how many bytes each array element, row, column, etc.
occupy in memory).
offset : int, optional
Start reading buffer (`buf`) from this offset onwards.
order : {'C', 'F'}, optional
Row-major (C-style) or column-major (Fortran-style) order.
Returns
-------
rec : recarray
Empty array of the given shape and type.
See Also
--------
numpy.rec.fromrecords : Construct a record array from data.
numpy.record : fundamental data-type for `recarray`.
numpy.rec.format_parser : determine data-type from formats, names, titles.
Notes
-----
This constructor can be compared to ``empty``: it creates a new record
"""
def __init__(self, shape, dtype=None, formats=None, names=None,
buf=None, **kwargs):
super(recarray, self).__new__(recarray, shape, dtype, buffer=buf)
if formats is not None and names is not None:
if not isinstance(formats, list):
raise TypeError("formats must be a list")
if not isinstance(names, tuple):
raise TypeError("names must be a tuple")
self._fieldnames = names
self._formats = formats
if len(self._fieldnames) != len(self._formats):
raise ValueError("Length of formats and names must be equal")
elif dtype is None:
self._fieldnames = []
self._formats = []
else:
raise ValueError("Both formats and names must be specified if dtype is provided")
def __setattr__(self, attr, value):
if attr in self._fieldnames:
idx = self._fieldnames.index(attr)
self[idx] = value
else:
super(recarray, self).__setattr__(attr, value)
def __getattr__(self, attr):
if attr in self._fieldnames:
idx = self._fieldnames.index(attr)
return self[idx]
else:
return super(recarray, self).__getattribute__(attr)
def __getitem__(self, key):
if isinstance(key, str):
if key in self._fieldnames:
idx = self._fieldnames.index(key)
return self[idx]
else:
raise KeyError(f"Field '{key}' not found in recarray")
else:
return super(recarray, self).__getitem__(key)
def __setitem__(self, key, value):
if isinstance(key, str):
if key
"""
Create a new subclass of ndarray for structured arrays, optionally filled
with data from a buffer.
Parameters
----------
subtype : type
The subclass type.
shape : tuple
Shape of the new array.
dtype : dtype, optional
Data type descriptor for the array. If not provided, it is inferred
from other parameters.
buf : buffer-like, optional
Object exposing buffer interface for data storage.
offset : int, optional
Offset in bytes from the start of the buffer to the beginning of the
array data.
strides : tuple, optional
Strides of the array data in memory.
formats : sequence, optional
Format descriptors for structured data.
names : sequence, optional
Names for the fields of structured data.
titles : sequence, optional
Titles for the fields of structured data.
byteorder : {'=', '|', '>', '<', 'little', 'big'}, optional
Byte order of the data. Default is native byte order.
aligned : bool, optional
Whether the data should be aligned.
order : {'C', 'F'}, optional
Whether to store multi-dimensional data in row-major (C-style) or
column-major (Fortran-style) order.
Returns
-------
self : ndarray
A new instance of the structured array subclass.
Notes
-----
This constructor initializes a structured array subclass similar to
ndarray, but with additional support for structured data types. It can
create an empty array structure or initialize it from provided data.
See Also
--------
np.recarray : View a standard ndarray as a record array.
"""
def __new__(subtype, shape, dtype=None, buf=None, offset=0, strides=None,
formats=None, names=None, titles=None,
byteorder=None, aligned=False, order='C'):
"""
Create a new instance of the structured array subclass.
Parameters
----------
subtype : type
The subclass type.
shape : tuple
Shape of the new array.
dtype : dtype, optional
Data type descriptor for the array. If not provided, it is inferred
from other parameters.
buf : buffer-like, optional
Object exposing buffer interface for data storage.
offset : int, optional
Offset in bytes from the start of the buffer to the beginning of the
array data.
strides : tuple, optional
Strides of the array data in memory.
formats : sequence, optional
Format descriptors for structured data.
names : sequence, optional
Names for the fields of structured data.
titles : sequence, optional
Titles for the fields of structured data.
byteorder : {'=', '|', '>', '<', 'little', 'big'}, optional
Byte order of the data. Default is native byte order.
aligned : bool, optional
Whether the data should be aligned.
order : {'C', 'F'}, optional
Whether to store multi-dimensional data in row-major (C-style) or
column-major (Fortran-style) order.
Returns
-------
self : ndarray
A new instance of the structured array subclass.
Notes
-----
This method is responsible for creating a new structured array
instance based on the provided parameters. It initializes the array
either from a specified buffer or as an empty structure if no buffer
is provided.
If `dtype` is specified, it converts it to a data type descriptor.
If `buf` is provided, it initializes the array using the buffer's
data.
"""
if dtype is not None:
descr = sb.dtype(dtype)
else:
descr = format_parser(
formats, names, titles, aligned, byteorder
).dtype
if buf is None:
self = ndarray.__new__(
subtype, shape, (record, descr), order=order
)
else:
self = ndarray.__new__(
subtype, shape, (record, descr), buffer=buf,
offset=offset, strides=strides, order=order
)
return self
def __array_finalize__(self, obj):
"""
Finalizes the creation of a structured array instance.
Parameters
----------
self : ndarray
The newly created structured array instance.
obj : ndarray or None
An object from which the structured array instance was derived.
Notes
-----
This method is called after the instance has been created and is
responsible for finalizing its initialization. It checks if the
dtype of the array is a record dtype and ensures that if it has
names defined, it properly sets the dtype.
If `self.dtype` is not a record dtype but has names, it invokes
`__setattr__` to convert it to a record dtype.
"""
if self.dtype.type is not record and self.dtype.names is not None:
self.dtype = self.dtype
def __getattribute__(self, attr):
try:
return object.__getattribute__(self, attr)
except AttributeError:
pass
fielddict = ndarray.__getattribute__(self, 'dtype').fields
try:
res = fielddict[attr][:2]
except (TypeError, KeyError) as e:
raise AttributeError("recarray has no attribute %s" % attr) from e
obj = self.getfield(*res)
if obj.dtype.names is not None:
if issubclass(obj.dtype.type, nt.void):
return obj.view(dtype=(self.dtype.type, obj.dtype))
return obj
else:
return obj.view(ndarray)
def __setattr__(self, attr, val):
if (
attr == 'dtype' and
issubclass(val.type, nt.void) and
val.names is not None
):
val = sb.dtype((record, val))
newattr = attr not in self.__dict__
try:
ret = object.__setattr__(self, attr, val)
except Exception:
fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
if attr not in fielddict:
raise
else:
fielddict = ndarray.__getattribute__(self, 'dtype').fields or {}
if attr not in fielddict:
return ret
if newattr:
try:
object.__delattr__(self, attr)
except Exception:
return ret
try:
res = fielddict[attr][:2]
except (TypeError, KeyError) as e:
raise AttributeError(
"record array has no attribute %s" % attr
) from e
return self.setfield(val, *res)
def __getitem__(self, indx):
obj = super().__getitem__(indx)
if isinstance(obj, ndarray):
if obj.dtype.names is not None:
obj = obj.view(type(self))
if issubclass(obj.dtype.type, np.void):
return obj.view(dtype=(self.dtype.type, obj.dtype))
return obj
else:
return obj.view(type=ndarray)
else:
return obj
def __repr__(self):
repr_dtype = self.dtype
if (
self.dtype.type is np.record or
not issubclass(self.dtype.type, np.void)
):
if repr_dtype.type is np.record:
repr_dtype = np.dtype((np.void, repr_dtype))
prefix = "rec.array("
fmt = 'rec.array(%s,%sdtype=%s)'
else:
prefix = "array("
fmt = 'array(%s,%sdtype=%s).view(numpy.recarray)'
if self.size > 0 or self.shape == (0,):
lst = np.array2string(
self, separator=', ', prefix=prefix, suffix=',')
else:
lst = "[], shape=%s" % (repr(self.shape),)
lf = '\n'+' '*len(prefix)
if _get_legacy_print_mode() <= 113:
lf = ' ' + lf
return fmt % (lst, lf, repr_dtype)
def field(self, attr, val=None):
if isinstance(attr, int):
names = ndarray.__getattribute__(self, 'dtype').names
attr = names[attr]
fielddict = ndarray.__getattribute__(self, 'dtype').fields
res = fielddict[attr][:2]
if val is None:
obj = self.getfield(*res)
if obj.dtype.names is not None:
return obj
return obj.view(ndarray)
else:
return self.setfield(val, *res)
def _deprecate_shape_0_as_None(shape):
if shape == 0:
warnings.warn(
"Passing `shape=0` to have the shape be inferred is deprecated, "
"and in future will be equivalent to `shape=(0,)`. To infer "
"the shape and suppress this warning, pass `shape=None` instead.",
FutureWarning, stacklevel=3)
return None
else:
return shape
@set_module("numpy.rec")
def fromarrays(arrayList, dtype=None, shape=None, formats=None,
names=None, titles=None, aligned=False, byteorder=None):
"""Create a record array from a (flat) list of arrays
Parameters
----------
arrayList : list or tuple
List of array-like objects (such as lists, tuples,
and ndarrays).
dtype : data-type, optional
valid dtype for all arrays
shape : int or tuple of ints, optional
Shape of the resulting array. If not provided, inferred from
``arrayList[0]``.
formats, names, titles, aligned, byteorder :
If `dtype` is ``None``, these arguments are passed to
`numpy.rec.format_parser` to construct a dtype. See that function for
detailed documentation.
Returns
-------
np.recarray
Record array consisting of given arrayList columns.
Examples
--------
>>> x1=np.array([1,2,3,4])
>>> x2=np.array(['a','dd','xyz','12'])
>>> x3=np.array([1.1,2,3,4])
>>> r = np.rec.fromarrays([x1,x2,x3],names='a,b,c')
>>> print(r[1])
(2, 'dd', 2.0) # may vary
>>> x1[1]=34
>>> r.a
array([1, 2, 3, 4])
>>> x1 = np.array([1, 2, 3, 4])
>>> x2 = np.array(['a', 'dd', 'xyz', '12'])
>>> x3 = np.array([1.1, 2, 3,4])
>>> r = np.rec.fromarrays(
... [x1, x2, x3],
... dtype=np.dtype([('a', np.int32), ('b', 'S3'), ('c', np.float32)]))
>>> r
rec.array([(1, b'a', 1.1), (2, b'dd', 2. ), (3, b'xyz', 3. ),
(4, b'12', 4. )],
dtype=[('a', '<i4'), ('b', 'S3'), ('c', '<f4')])
"""
arrayList = [sb.asarray(x) for x in arrayList]
shape = _deprecate_shape_0_as_None(shape)
if shape is None:
shape = arrayList[0].shape
elif isinstance(shape, int):
shape = (shape,)
if formats is None and dtype is None:
formats = [obj.dtype for obj in arrayList]
if dtype is not None:
descr = sb.dtype(dtype)
else:
descr = format_parser(formats, names, titles, aligned, byteorder).dtype
_names = descr.names
if len(descr) != len(arrayList):
raise ValueError("mismatch between the number of fields "
"and the number of arrays")
d0 = descr[0].shape
nn = len(d0)
if nn > 0:
shape = shape[:-nn]
_array = recarray(shape, descr)
for k, obj in enumerate(arrayList):
nn = descr[k].ndim
testshape = obj.shape[:obj.ndim - nn]
name = _names[k]
if testshape != shape:
raise ValueError(f'array-shape mismatch in array {k} ("{name}")')
_array[name] = obj
return _array
@set_module("numpy.rec")
def fromrecords(recList, dtype=None, shape=None, formats=None, names=None,
titles=None, aligned=False, byteorder=None):
"""从文本形式的记录列表创建一个 recarray。
Parameters
----------
recList : sequence
包含记录的列表,可以是异构的数据 - 将会提升到最高的数据类型。
dtype : data-type, optional
所有数组的有效数据类型。
shape : int or tuple of ints, optional
每个数组的形状。
formats, names, titles, aligned, byteorder :
如果 `dtype` 是 ``None``,这些参数将传递给 `numpy.format_parser` 来构建数据类型。
详细文档请参考该函数。
如果 `formats` 和 `dtype` 都是 `None`,则会自动检测格式。使用元组列表而不是列表列表可以提高处理速度。
Returns
-------
np.recarray
包含给定 recList 行的记录数组。
Examples
--------
>>> r=np.rec.fromrecords([(456,'dbe',1.2),(2,'de',1.3)],
... names='col1,col2,col3')
>>> print(r[0])
(456, 'dbe', 1.2)
>>> r.col1
array([456, 2])
>>> r.col2
array(['dbe', 'de'], dtype='<U3')
>>> import pickle
>>> pickle.loads(pickle.dumps(r))
rec.array([(456, 'dbe', 1.2), ( 2, 'de', 1.3)],
dtype=[('col1', '<i8'), ('col2', '<U3'), ('col3', '<f8')])
"""
if formats is None and dtype is None:
obj = sb.array(recList, dtype=object)
arrlist = [
sb.array(obj[..., i].tolist()) for i in range(obj.shape[-1])
]
return fromarrays(arrlist, formats=formats, shape=shape, names=names,
titles=titles, aligned=aligned, byteorder=byteorder)
if dtype is not None:
descr = sb.dtype((record, dtype))
else:
descr = format_parser(
formats, names, titles, aligned, byteorder
).dtype
try:
retval = sb.array(recList, dtype=descr)
except (TypeError, ValueError):
shape = _deprecate_shape_0_as_None(shape)
if shape is None:
shape = len(recList)
if isinstance(shape, int):
shape = (shape,)
if len(shape) > 1:
raise ValueError("Can only deal with 1-d array.")
_array = recarray(shape, descr)
for k in range(_array.size):
_array[k] = tuple(recList[k])
warnings.warn(
"fromrecords expected a list of tuples, may have received a list "
"of lists instead. In the future that will raise an error",
FutureWarning, stacklevel=2)
return _array
else:
if shape is not None and retval.shape != shape:
retval.shape = shape
res = retval.view(recarray)
return res
@set_module("numpy.rec")
def fromstring(datastring, dtype=None, shape=None, offset=0, formats=None,
names=None, titles=None, aligned=False, byteorder=None):
r"""Create a record array from binary data
Note that despite the name of this function it does not accept `str`
instances.
Parameters
----------
datastring : bytes-like
Buffer of binary data
dtype : data-type, optional
Valid dtype for all arrays
shape : int or tuple of ints, optional
Shape of each array.
offset : int, optional
Position in the buffer to start reading from.
formats, names, titles, aligned, byteorder :
If `dtype` is ``None``, these arguments are passed to
`numpy.format_parser` to construct a dtype. See that function for
detailed documentation.
Returns
-------
np.recarray
Record array view into the data in datastring. This will be readonly
if `datastring` is readonly.
See Also
--------
numpy.frombuffer
Examples
--------
>>> a = b'\x01\x02\x03abc'
>>> np.rec.fromstring(a, dtype='u1,u1,u1,S3')
rec.array([(1, 2, 3, b'abc')],
dtype=[('f0', 'u1'), ('f1', 'u1'), ('f2', 'u1'), ('f3', 'S3')])
>>> grades_dtype = [('Name', (np.str_, 10)), ('Marks', np.float64),
... ('GradeLevel', np.int32)]
>>> grades_array = np.array([('Sam', 33.3, 3), ('Mike', 44.4, 5),
... ('Aadi', 66.6, 6)], dtype=grades_dtype)
>>> np.rec.fromstring(grades_array.tobytes(), dtype=grades_dtype)
rec.array([('Sam', 33.3, 3), ('Mike', 44.4, 5), ('Aadi', 66.6, 6)],
dtype=[('Name', '<U10'), ('Marks', '<f8'), ('GradeLevel', '<i4')])
>>> s = '\x01\x02\x03abc'
>>> np.rec.fromstring(s, dtype='u1,u1,u1,S3')
Traceback (most recent call last):
...
TypeError: a bytes-like object is required, not 'str'
"""
if dtype is None and formats is None:
raise TypeError("fromstring() needs a 'dtype' or 'formats' argument")
if dtype is not None:
descr = sb.dtype(dtype)
else:
descr = format_parser(formats, names, titles, aligned, byteorder).dtype
itemsize = descr.itemsize
shape = _deprecate_shape_0_as_None(shape)
if shape in (None, -1):
shape = (len(datastring) - offset) // itemsize
_array = recarray(shape, descr, buf=datastring, offset=offset)
return _array
def get_remaining_size(fd):
pos = fd.tell()
try:
fd.seek(0, 2)
return fd.tell() - pos
finally:
fd.seek(pos, 0)
@set_module("numpy.rec")
def fromfile(fd, dtype=None, shape=None, offset=0, formats=None,
names=None, titles=None, aligned=False, byteorder=None):
"""Create an array from binary file data
Parameters
----------
fd : file-like object
File object containing binary data
dtype : data-type, optional
Valid dtype for all arrays
shape : int or tuple of ints, optional
Shape of each array.
offset : int, optional
Position in the file to start reading from.
formats, names, titles, aligned, byteorder :
If `dtype` is ``None``, these arguments are passed to
`numpy.format_parser` to construct a dtype. See that function for
detailed documentation.
"""
fd : str or file type
dtype : data-type, optional
shape : int or tuple of ints, optional
offset : int, optional
formats, names, titles, aligned, byteorder :
Returns
-------
np.recarray
Examples
--------
>>> from tempfile import TemporaryFile
>>> a = np.empty(10,dtype='f8,i4,a5')
>>> a[5] = (0.5,10,'abcde')
>>>
>>> fd=TemporaryFile()
>>> a = a.view(a.dtype.newbyteorder('<'))
>>> a.tofile(fd)
>>>
>>> _ = fd.seek(0)
>>> r=np.rec.fromfile(fd, formats='f8,i4,a5', shape=10,
... byteorder='<')
>>> print(r[5])
(0.5, 10, b'abcde')
>>> r.shape
(10,)
"""
if dtype is None and formats is None:
raise TypeError("fromfile() needs a 'dtype' or 'formats' argument")
# NumPy 1.19.0, 2020-01-01
shape = _deprecate_shape_0_as_None(shape)
# 使用_deprecate_shape_0_as_None函数处理shape参数,将形状为0的情况处理为None。
if shape is None:
shape = (-1,)
elif isinstance(shape, int):
shape = (shape,)
# 如果shape为None,则设置为(-1,);如果shape是整数,则转换为元组。
if hasattr(fd, 'readinto'):
# GH issue 2504. fd supports io.RawIOBase or io.BufferedIOBase
# interface. Example of fd: gzip, BytesIO, BufferedReader
# file already opened
ctx = nullcontext(fd)
# 如果fd支持io.RawIOBase或io.BufferedIOBase接口,则使用nullcontext来创建上下文。
else:
# open file
ctx = open(os.fspath(fd), 'rb')
# 否则,通过os.fspath将fd转换为路径字符串,并以二进制只读模式打开文件。
with ctx as fd:
if offset > 0:
fd.seek(offset, 1)
# 如果offset大于0,则在文件中移动读取位置。
size = get_remaining_size(fd)
# 获取文件中剩余的字节数。
if dtype is not None:
descr = sb.dtype(dtype)
# 如果dtype不为None,则使用sb.dtype处理dtype参数。
else:
descr = format_parser(
formats, names, titles, aligned, byteorder
).dtype
# 否则,使用format_parser函数根据formats、names、titles、aligned、byteorder构造dtype。
itemsize = descr.itemsize
# 获取dtype的每个元素的字节大小。
shapeprod = sb.array(shape).prod(dtype=nt.intp)
# 计算shape中所有元素的乘积,并将结果的数据类型设为nt.intp。
shapesize = shapeprod * itemsize
# 计算总的形状大小(字节数)。
if shapesize < 0:
shape = list(shape)
shape[shape.index(-1)] = size // -shapesize
shape = tuple(shape)
shapeprod = sb.array(shape).prod(dtype=nt.intp)
# 如果shapesize小于0,则根据文件中剩余的字节数调整shape的值。
nbytes = shapeprod * itemsize
# 计算总的字节数。
if nbytes > size:
raise ValueError(
"Not enough bytes left in file for specified "
"shape and type."
)
# 如果需要读取的字节数大于文件中剩余的字节数,则引发ValueError异常。
# create the array
_array = recarray(shape, descr)
# 创建一个形状为shape、数据类型为descr的记录数组。
nbytesread = fd.readinto(_array.data)
# 将文件中的数据读取到记录数组的数据部分。
if nbytesread != nbytes:
raise OSError("Didn't read as many bytes as expected")
# 如果实际读取的字节数与预期的不符,则引发OSError异常。
return _array
# 设置模块名称为 "numpy.rec"
@set_module("numpy.rec")
# 定义一个名为 array 的函数,用于构建记录数组
def array(obj, dtype=None, shape=None, offset=0, strides=None, formats=None,
names=None, titles=None, aligned=False, byteorder=None, copy=True):
"""
Construct a record array from a wide-variety of objects.
A general-purpose record array constructor that dispatches to the
appropriate `recarray` creation function based on the inputs (see Notes).
Parameters
----------
obj : any
Input object. See Notes for details on how various input types are
treated.
dtype : data-type, optional
Valid dtype for array.
shape : int or tuple of ints, optional
Shape of each array.
offset : int, optional
Position in the file or buffer to start reading from.
strides : tuple of ints, optional
Buffer (`buf`) is interpreted according to these strides (strides
define how many bytes each array element, row, column, etc.
occupy in memory).
formats, names, titles, aligned, byteorder :
If `dtype` is ``None``, these arguments are passed to
`numpy.format_parser` to construct a dtype. See that function for
detailed documentation.
copy : bool, optional
Whether to copy the input object (True), or to use a reference instead.
This option only applies when the input is an ndarray or recarray.
Defaults to True.
Returns
-------
np.recarray
Record array created from the specified object.
Notes
-----
If `obj` is ``None``, then call the `~numpy.recarray` constructor. If
`obj` is a string, then call the `fromstring` constructor. If `obj` is a
list or a tuple, then if the first object is an `~numpy.ndarray`, call
`fromarrays`, otherwise call `fromrecords`. If `obj` is a
`~numpy.recarray`, then make a copy of the data in the recarray
(if ``copy=True``) and use the new formats, names, and titles. If `obj`
is a file, then call `fromfile`. Finally, if obj is an `ndarray`, then
return ``obj.view(recarray)``, making a copy of the data if ``copy=True``.
Examples
--------
>>> a = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]])
>>> a
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> np.rec.array(a)
rec.array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]],
dtype=int64)
>>> b = [(1, 1), (2, 4), (3, 9)]
>>> c = np.rec.array(b, formats = ['i2', 'f2'], names = ('x', 'y'))
>>> c
rec.array([(1, 1.), (2, 4.), (3, 9.)],
dtype=[('x', '<i2'), ('y', '<f2')])
>>> c.x
array([1, 2, 3], dtype=int16)
>>> c.y
array([1., 4., 9.], dtype=float16)
>>> r = np.rec.array(['abc','def'], names=['col1','col2'])
>>> print(r.col1)
abc
>>> r.col1
array('abc', dtype='<U3')
>>> r.col2
array('def', dtype='<U3')
"""
# 检查对象是否为None、字符串或具有'readinto'属性,并且formats和dtype都未定义时,抛出值错误异常
if ((isinstance(obj, (type(None), str)) or hasattr(obj, 'readinto')) and
formats is None and dtype is None):
raise ValueError("Must define formats (or dtype) if object is "
"None, string, or an open file")
# 初始化一个空字典用于存储关键字参数
kwds = {}
# 如果定义了dtype,则将其转换为dtype对象
if dtype is not None:
dtype = sb.dtype(dtype)
# 如果formats不为None,则使用format_parser函数解析formats参数,并获取其dtype
elif formats is not None:
dtype = format_parser(formats, names, titles,
aligned, byteorder).dtype
# 如果formats和dtype都未定义,则将关键字参数设置为包含这些参数的字典
else:
kwds = {'formats': formats,
'names': names,
'titles': titles,
'aligned': aligned,
'byteorder': byteorder
}
# 如果obj为None,则根据指定的shape创建一个recarray对象,使用给定的dtype、buf、offset和strides参数
if obj is None:
if shape is None:
raise ValueError("Must define a shape if obj is None")
return recarray(shape, dtype, buf=obj, offset=offset, strides=strides)
# 如果obj是字节串,则调用fromstring函数解析为数组对象,使用给定的dtype、shape和kwds参数
elif isinstance(obj, bytes):
return fromstring(obj, dtype, shape=shape, offset=offset, **kwds)
# 如果obj是列表或元组,则根据其第一个元素的类型判断调用fromrecords或fromarrays函数,使用给定的dtype、shape和kwds参数
elif isinstance(obj, (list, tuple)):
if isinstance(obj[0], (tuple, list)):
return fromrecords(obj, dtype=dtype, shape=shape, **kwds)
else:
return fromarrays(obj, dtype=dtype, shape=shape, **kwds)
# 如果obj是recarray类型,则根据情况进行视图转换和复制操作,并返回新的对象
elif isinstance(obj, recarray):
if dtype is not None and (obj.dtype != dtype):
new = obj.view(dtype)
else:
new = obj
if copy:
new = new.copy()
return new
# 如果obj具有'readinto'属性,则调用fromfile函数从文件对象创建数组对象,使用给定的dtype、shape和offset参数
elif hasattr(obj, 'readinto'):
return fromfile(obj, dtype=dtype, shape=shape, offset=offset)
# 如果obj是ndarray类型,则根据情况进行视图转换和复制操作,并返回新的recarray视图对象
elif isinstance(obj, ndarray):
if dtype is not None and (obj.dtype != dtype):
new = obj.view(dtype)
else:
new = obj
if copy:
new = new.copy()
return new.view(recarray)
# 对于其他情况,尝试获取obj的__array_interface__属性,如果未定义或者不是字典类型,则抛出值错误异常
else:
interface = getattr(obj, "__array_interface__", None)
if interface is None or not isinstance(interface, dict):
raise ValueError("Unknown input type")
# 将obj转换为数组对象,并根据情况进行视图转换操作,返回recarray视图对象
obj = sb.array(obj)
if dtype is not None and (obj.dtype != dtype):
obj = obj.view(dtype)
return obj.view(recarray)