Numpy 教程学习

什么是NumPy?

NumPy 是 Python 科学计算的基础包。它是一个 Python 库,提供了一个多维数组对象、各种派生对象(例如掩码数组和矩阵),以及用于对数组进行快速操作的各种例程,包括数学、逻辑、形状操作、排序、选择、I/O 、离散傅立叶变换、基本线性代数、基本统计运算、随机模拟等等。

NumPy 包的核心是 ndarray 对象。其封装了同类型数据的 n维数组,许多操作在编译代码中执行以提高性能。NumPy 数组和标准 Python 序列之间有几个重要的区别:

  • 与 Python 列表(可以动态增长)不同,NumPy 数组在创建时具有固定大小。更改ndarray的大小将创建一个新数组并删除原始数组。
  • NumPy 数组中的元素都需要具有相同的数据类型,因此在内存中的大小相同。例外:可以有(Python,包括 NumPy)对象的数组,从而允许不同大小元素的数组。
  • NumPy 数组有助于对大量数据进行高级数学运算和其他类型的运算。通常,与使用 Python 的内置序列相比,此类操作的执行效率更高,代码更少。
  • 越来越多的基于 Python 的科学和数学包正在使用 NumPy 数组;尽管这些通常支持 Python 序列输入,但它们在处理之前将此类输入转换为 NumPy 数组,并且通常输出 NumPy 数组。换句话说,为了有效地使用大部分基于 Python 的科学/数学软件,仅仅知道如何使用 Python 的内置序列类型是不够的——还需要知道如何使用 NumPy 数组。

关于序列大小和速度的要点在科学计算中尤为重要。作为一个简单的例子,考虑将一维序列中的每个元素与另一个相同长度序列中的相应元素相乘的情况。如果数据存储在两个 Python 列表a和 中b,我们可以遍历每个元素:

c = []
for i in range(len(a)):
    c.append(a[i]*b[i])

得出了正确的答案,但如果a和b每一个都包含数以百万计的数字,我们会因为 Python 中循环的的低效率而付出代价。我们可以在 C 中通过编写代码更快地完成相同的任务(为清楚起见,我们忽略了变量声明和初始化、内存分配等):

for (i = 0; i < rows; i++): {
  c[i] = a[i]*b[i];
}

节省了解释 Python 代码和操作 Python 对象所涉及的所有开销,但代价是牺牲了使用 Python 编码所带来的好处。此外,所需的编码工作随着数据维度的增加而增加。例如,在二维数组的情况下,C 代码(如前所述缩写)扩展为:

for (i = 0; i < rows; i++): {
  for (j = 0; j < columns; j++): {
    c[i][j] = a[i][j]*b[i][j];
  }
}

NumPy 为我们提供了两全其美的方法:当涉及 ndarray 时,逐元素操作是"默认模式",但逐元素操作由预编译的 C 代码快速执行。 在 NumPy 中:

c = a * b

以接近 C 的速度执行前面的示例所做的事情,而且代码的简单性又符合我们希望和 Python 一样。事实上,NumPy 习惯用法更简单!最后一个示例说明了 NumPy 的两个功能,这两个功能是其大部分强大功能的基础:矢量化和广播

为什么NumPy更快?

矢量化描述了代码中没有任何显式循环、索引等。当然,这些事情只是在优化、预编译 C 代码的"幕后"发生的。矢量化代码有很多优点,其中包括:

  • 矢量化代码更简洁易读
  • 更少的代码通常意味着更少的错误
  • 代码更接近标准数学符号(通常更容易正确编码数学结构)
  • 矢量化会产生更多的Pythonic代码。如果没有矢量化,我们的代码将充斥着低效且难以阅读的for循环。

广播是用于描述操作的隐式逐元素行为的术语;一般而言,在 NumPy 中,所有操作,不仅是算术运算,还有逻辑、按位、函数等,都以这种隐式的逐元素方式表现,即它们正在广播。此外,在上面的例子中,a和b可以是相同形状的多维数组,或者一个标量和一个数组,甚至两个不同形状的数组,前提是较小的数组可以"扩展"到较大的数组中,由此产生的广播是明确的。

还有谁在使用NumPy?

NumPy 完全支持面向对象的方法,再次从 ndarray 开始。例如,ndarray是一个类,拥有许多方法和属性。它的许多方法由最外层 NumPy 命名空间中的函数镜像,允许程序员以他们喜欢的任何样式进行编码。这种灵活性使 NumPy 数组方言和NumPy ndarray类成为 Python 中使用的多维数据交换的事实上的语言。

NumPy 安装

安装 NumPy 的唯一先决条件是 Python 本身。如果你还没有 Python 并且想要以最简单的方式开始,我们建议使用 Anaconda Distribution – 它包括 Python、NumPy 和许多其他用于科学计算和数据科学的常用包。

NumPy 可以通过conda、pip、 macOS 和 Linux 上的包管理器安装,或者从来源处安装。有关更详细的说明,请参阅下面的Python 和 NumPy 安装指南。

conda

如果使用conda(Conda 是一个开源的软件包管理系统和环境管理系统,Conda 是为 Python 程序创建的,适用于 Linux,OS X 和Windows,也可以打包和分发其他软件),则可以用defaults或conda-forge 方法安装 NumPy :

# Best practice, use an environment rather than install in the base env
conda create -n my-env
conda activate my-env
# If you want to install from conda-forge
conda config --env --add channels conda-forge
# The actual install command
conda install numpy
pip

如果使用pip,则可以使用以下命令安装 NumPy:

pip install numpy

此外,在使用 pip 时,最好使用虚拟环境 - 请参阅下面的可重复安装了解有关使用虚拟环境的详细信息。

Python 和 NumPy 安装指南

在 Python 中安装和管理包很复杂,对于大多数任务,有许多替代解决方案。本指南将会帮助读者了解最佳(或最受欢迎)的解决方案,并给出明确的建议。它侧重于Python、NumPy 和 PyData(或数值计算)堆栈在常见操作系统和硬件上的用户。

建议

我们将从基于用户体验水平和感兴趣的操作系统的建议开始。如果您介于"初级"和"高级"之间,且您只是要简单的了解一下,请选择"初级";如果您想根据未来走得更远的最佳实践工作,请选择"高级"。

初级用户

在所有 Windows、macOS 和 Linux 上:

  • 安装Anaconda(它会安装您需要的所有软件包以及下面提到的所有其他工具)。
  • 对于编写和执行代码,在JupyterLab 中使用 notebooks 进行探索性和交互式计算,使用 Spyder或Visual Studio Code 编写脚本和包。
  • 使用Anaconda Navigator管理您的包并启动 JupyterLab、Spyder 或 Visual Studio Code。
高级用户
Windows 或 macOS
  • 安装Miniconda。
  • 保持base最小的conda 环境,并使用一个或多个 conda 环境来安装您正在处理的任务或项目所需的包。
  • 除非您只对defaults频道中的软件包感到满意,否则请通过conda-forge 设置频道优先级来设置您的默认频道。
Linux

如果你觉得稍微过时的软件包没问题,并且更喜欢稳定性,可以不用直接去使用最新版本的库:

  • 尽可能多地使用你的操作系统包管理器(Python 本身、NumPy 和其他库)。
  • 使用pip install somepackage --user.

如果使用 GPU:

  • 安装Miniconda。
  • 保持base最小的conda 环境,并使用一个或多个 conda 环境 来安装您正在处理的任务或项目所需的包。
  • 使用defaultsconda 通道(conda-forge对 GPU 包还没有很好的支持)。
Python 包管理

管理包是一个具有挑战性的问题,因此有很多工具。对于 Web 和通用 Python 开发,有大量与 pip 互补的工具。对于高性能计算(HPC), Spack 值得考虑。不过对于大多数 NumPy 用户来说,conda 和 pip 是两个最流行的工具。

pip 和 conda

安装 Python 包的两个主要工具是 pip 和 conda。它们的功能部分重叠(例如,两者都可以安装numpy),但是,它们也可以一起工作。我们将在这里讨论 pip 和 conda 之间的主要区别 。如果想有效地管理包,这对于理解这一点很重要。

第一个区别是 conda 是跨语言的,它可以安装 Python,而 pip 是为系统上的特定 Python 安装的,并且仅将其他软件包安装到同一个 Python 安装中。这也意味着 conda 可以安装您可能需要的非 Python 库和工具(例如编译器、CUDA、HDF5),而 pip 不能。

第二个区别是 pip 从 Python Packaging Index (PyPI) 安装,而 conda 从它自己的渠道安装(通常是"defaults"或"conda-forge")。PyPI 是迄今为止最大的软件包集合,但是,所有流行的软件包也可用于 conda。

第三个区别是 conda 是用于管理包、依赖项和环境的集成解决方案,而使用 pip 您可能需要另一个工具(有很多!)来处理环境或复杂的依赖项。

选择 pip/PyPI

对于那些从个人喜好或者了解了上面关于 conda 和 pip 之间的主要区别,确定自己更喜欢基于 pip/PyPI 的解决方案的用户,我们建议:

  • 从python.org、 Homebrew或您的 Linux 包管理器安装 Python 。
  • 使用 Poetry 作为维护最良好的工具,它以与 conda 类似的方式提供依赖项解析器和环境管理功能。
可重复安装

随着库的更新,运行代码的结果可能会发生变化,或者您的代码可能会完全中断。能够重建您正在使用的软件包和版本集非常重要。最佳做法是:

  • 为您正在处理的每个项目使用不同的环境,
  • 使用您的软件包安装程序记录软件包名称和版本;

每个都有自己的元数据格式:

  • Conda:conda 环境和 environment.yml
  • Pip:虚拟环境和 requirements.txt
  • Poetry:虚拟环境和 pyproject.toml

NumPy 包和加速线性代数库

NumPy 不依赖于任何其他 Python 包,但是,它依赖于加速线性代数库,通常是 Intel MKL或 OpenBLAS。用户不必担心安装这些(它们会自动包含在所有 NumPy 安装方法中)。高级用户可能仍然想知道详细信息,因为使用的 BLAS 会影响磁盘上的性能、行为和大小:

  • pip 安装的 PyPI 上的 NumPy 轮子是使用 OpenBLAS 构建的。OpenBLAS 库包含在轮子中。这使得轮子更大,如果用户也安装(例如)SciPy,他们现在将在磁盘上拥有 OpenBLAS 的两个副本。
  • 在 conda 默认通道中,NumPy 是针对 Intel MKL 构建的。MKL 是一个单独的包,将在用户安装 NumPy 时安装在用户的环境中。
  • 在 conda-forge 频道中,NumPy 是针对虚拟的"BLAS"包构建的。当用户从 conda-forge 安装 NumPy 时,该 BLAS 包将与实际库一起安装 - 这默认为 OpenBLAS,但它也可以是 MKL(来自默认通道),甚至 BLIS或参考 BLAS。
  • MKL 包比 OpenBLAS 大很多,它在磁盘上大约有 700 MB,而 OpenBLAS 大约有 30 MB。
  • MKL 通常比 OpenBLAS 更快、更健壮。

除了安装尺寸、性能和稳健性之外,还有两件事情需要考虑:

  • 英特尔 MKL 不是开源的。对于正常使用,这不是问题,但如果用户需要重新分发使用 NumPy 构建的应用程序,这可能是一个问题。
  • MKL 和 OpenBLAS 都将使用多线程进行函数调用,如 np.dot,线程数由构建时选项和环境变量决定。通常会使用所有 CPU 内核。这有时对用户来说是意料之外的;NumPy 本身不会自动并行化任何函数调用。它通常会产生更好的性能,但也可能是有害的——例如,当使用 Dask、scikit-learn 或多处理的另一个级别的并行化时。
故障排除

如果安装失败并显示以下消息,请参阅疑难解答 ImportError。

IMPORTANT: PLEASE READ THIS FOR ADVICE ON HOW TO SOLVE THIS ISSUE!


Importing the numpy c-extensions failed. This error can happen for
different reasons, often due to issues with your setup.

NumPy 基础知识

NumPy 的主要对象是同构多维数组。它是一个元素表(通常是数字),所有类型都相同,由非负整数元组索引。在 NumPy 中,维度称为轴。 例如,3D 空间中一个点的坐标[1, 2, 1]只有一个轴。该轴有 3 个元素,因此我们说它的长度为 3。在下图中的示例中,数组有 2 个轴。第一个轴的长度为 2,第二个轴的长度为 3。

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

NumPy 的数组类称为ndarray。它也被称为别名 array。请注意,numpy.array这与标准 Python 库类不同array.array,后者仅处理一维数组并提供较少的功能。ndarray对象更重要的属性是:

  • ndarray.ndim 数组的轴数(维度)。
  • ndarray.shape 数组的维度。这是一个整数元组,象征着每个维度中数组的大小。对于具有n行和m列的矩阵,shape将为(n,m)。因此,元组shape的长度是轴的数量,ndim。
  • 数组大小 数组的元素总数。这等于shape元素的乘积。
  • ndarray.dtype 描述数组中元素类型的对象。可以使用标准 Python 类型创建或指定 dtype。此外,NumPy 提供了自己的类型。numpy.int32numpy.int16numpy.float64 是一些示例。
  • ndarray.itemsize 数组每个元素的大小(以字节为单位)。例如,一个类型元素的数组float64有itemsize8 个(=64/8),而一个类型的元素complex32itemsize4 个(=32/8)。它相当于ndarray.dtype.itemsize
  • ndarray.data 包含数组实际元素的缓冲区。通常,我们不需要使用此属性,因为我们将使用索引工具访问数组中的元素。
    例子:
import numpy as np
>>> a = np.arange(15).reshape(3, 5)
>>> a
array([[ 0,  1,  2,  3,  4],
       [ 5,  6,  7,  8,  9],
       [10, 11, 12, 13, 14]])
>>> a.shape
(3, 5)
>>> a.ndim
2
>>> a.dtype.name
'int64'
>>> a.itemsize
8
>>> a.size
15
>>> type(a)
<class 'numpy.ndarray'>
>>> b = np.array([6, 7, 8])
>>> b
array([6, 7, 8])
>>> type(b)
<class 'numpy.ndarray'>
>>> import numpy as np
>>> a= np.arange(10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.reshape(5,2)
array([[0, 1],
       [2, 3],
       [4, 5],
       [6, 7],
       [8, 9]])
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a=a.reshape(2,5)
>>> a
array([[0, 1, 2, 3, 4],
       [5, 6, 7, 8, 9]])
>>> a=a.reshape(4,3)   # 不能等分会报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: cannot reshape array of size 10 into shape (4,3)
>>> b=np.arange(10)
>>> b
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> b=b.reshape(4,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: cannot reshape array of size 10 into shape (4,3)
>>> c=np.arange(12)
>>> c
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11])
>>> c=c.reshape(4,3)
>>> c
array([[ 0,  1,  2],
       [ 3,  4,  5],
       [ 6,  7,  8],
       [ 9, 10, 11]])
>>> 

NumPy 数组创建

数组创建

有几种方法可以创建数组。

创建一维数组

例如,可以使用array函数从常规 Python 列表或元组创建数组。结果数组的类型是从序列中元素的类型推导出来的。

>>> import numpy as np
>>> a = np.array([2, 3, 4])
>>> a
array([2, 3, 4])
>>> a.dtype
dtype('int64')
>>> b = np.array([1.2, 3.5, 5.1])
>>> b.dtype
dtype('float64')

# array() 只需要一个实参,且数据类型必须是元组或列表
>>> c=np.array(1,2,3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: array() takes from 1 to 2 positional arguments but 3 were given
>>> c=np.array((1,2,3))
>>> c
array([1, 2, 3])

一个常见的错误在于array使用多个参数调用,而不是提供单个序列作为参数。

>>> a = np.array(1, 2, 3, 4)    # WRONG
Traceback (most recent call last):
  ...
TypeError: array() takes from 1 to 2 positional arguments but 4 were given
>>> a = np.array([1, 2, 3, 4])  # RIGHT

创建多维数组

array 将序列的序列转换为二维数组,将序列的序列的序列转换为三维数组,依此类推。

>>> b = np.array([(1.5, 2, 3), (4, 5, 6)])
>>> b
array([[1.5, 2. , 3. ],
       [4. , 5. , 6. ]])

>>> d=np.array(([1,2],[3,4],[5,6]))
>>> d
array([[1, 2],
       [3, 4],
       [5, 6]])
>>> e=np.array(([1,2],[3,4],[5]))   # 
<stdin>:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray.
>>> 

数组的类型也可以在创建时显式指定:

>>> c = np.array([[1, 2], [3, 4]], dtype=complex)
>>> c
array([[1.+0.j, 2.+0.j],
       [3.+0.j, 4.+0.j]])

其他创建数组的方法

占位数组

通常,数组的元素最初是未知的,但其大小是已知的。因此,NumPy 提供了几个函数来创建具有初始占位符内容的数组。这些最大限度地减少了增长阵列的必要性,这是一项昂贵的操作。

该函数zeros创建一个全零数组,该函数 ones创建一个全1数组,该函数empty 创建一个初始内容随机且取决于内存状态的数组。默认情况下,创建的数组的 dtype 是 float64,但可以通过关键字参数指定dtype。

>>> np.zeros((3, 4))
array([[0., 0., 0., 0.],
       [0., 0., 0., 0.],
       [0., 0., 0., 0.]])
>>> np.ones((2, 3, 4), dtype=np.int16)
array([[[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]],
       [[1, 1, 1, 1],
        [1, 1, 1, 1],
        [1, 1, 1, 1]]], dtype=int16)
>>> np.empty((2, 3))
array([[3.73603959e-262, 6.02658058e-154, 6.55490914e-260],  # may vary
       [5.30498948e-313, 3.14673309e-307, 1.00000000e+000]])
序列数组

为了创建数字序列,NumPy 提供了arange类似于 Python 内置的函数range,但返回一个数组。

>>> np.arange(10, 30, 5)
array([10, 15, 20, 25])
>>> np.arange(0, 2, 0.3)  # it accepts float arguments
array([0. , 0.3, 0.6, 0.9, 1.2, 1.5, 1.8])

当arange与浮点参数一起使用时,由于浮点精度有限,通常无法预测获得的元素数量。出于这个原因,通常最好使用linspace接收我们想要的元素数量作为参数的函数,而不是步骤:

>>> from numpy import pi
>>> np.linspace(0, 2, 9)                   # 9 numbers from 0 to 2
array([0.  , 0.25, 0.5 , 0.75, 1.  , 1.25, 1.5 , 1.75, 2.  ])
>>> x = np.linspace(0, 2 * pi, 100)        # useful to evaluate function at lots of points
>>> f = np.sin(x)

NumPy 打印数组

打印数组时,NumPy 以类似于嵌套列表的方式显示它,但具有以下布局:

  • 最后一个轴从左到右打印,
  • 倒数第二个是从上到下打印的,
  • 其余的也从上到下打印,每个切片与下一个切片用空行分隔。

然后将一维数组打印为行,将二维打印为矩阵,将三维打印为矩阵列表。

>>> a = np.arange(6)                    # 1d array
>>> print(a)
[0 1 2 3 4 5]
>>>
>>> b = np.arange(12).reshape(4, 3)     # 2d array
>>> print(b)
[[ 0  1  2]
 [ 3  4  5]
 [ 6  7  8]
 [ 9 10 11]]
>>>
# reshape(2, 3, 4) 中的2是打印时均分为2个,3指三行,4指4列
>>> c = np.arange(24).reshape(2, 3, 4)  # 3d array 
>>> print(c)
[[[ 0  1  2  3]
  [ 4  5  6  7]
  [ 8  9 10 11]]

 [[12 13 14 15]
  [16 17 18 19]
  [20 21 22 23]]]

>>> import numpy as np
>>> d=np.arange(24)
>>> d
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
       17, 18, 19, 20, 21, 22, 23])
>>> d=d.reshape(3,2,4)
>>> d
array([[[ 0,  1,  2,  3],
        [ 4,  5,  6,  7]],

       [[ 8,  9, 10, 11],
        [12, 13, 14, 15]],

       [[16, 17, 18, 19],
        [20, 21, 22, 23]]])
>>> 

请参阅下文以获取有关reshape的更多详细信息。

如果数组太大而无法打印,NumPy 会自动跳过数组的中心部分,只打印角落:

>>> print(np.arange(10000))
[   0    1    2 ... 9997 9998 9999]
>>>
>>> print(np.arange(10000).reshape(100, 100))
[[   0    1    2 ...   97   98   99]
 [ 100  101  102 ...  197  198  199]
 [ 200  201  202 ...  297  298  299]
 ...
 [9700 9701 9702 ... 9797 9798 9799]
 [9800 9801 9802 ... 9897 9898 9899]
 [9900 9901 9902 ... 9997 9998 9999]]

想要禁用此行为并强制 NumPy 打印整个数组,您可以使用set_printoptions.

>>> np.set_printoptions(threshold=sys.maxsize)  # sys module should be imported

NumPy 基本运算

数组上的算术运算符按元素应用。创建一个新数组并填充结果。

加减乘除

>>> import numpy as np
>>> a=np.array([20,30,40,50])
>>> a
array([20, 30, 40, 50])
>>> b=np.arange(4)
>>> b
array([0, 1, 2, 3])
>>> a+b   # 加法
array([20, 31, 42, 53])
>>> a-b   # 减法
array([20, 29, 38, 47])
>>> a*b   # 乘法
array([  0,  30,  80, 150])
>>> a/b  # 除法
<stdin>:1: RuntimeWarning: divide by zero encountered in divide
array([        inf, 30.        , 20.        , 16.66666667])
>>> a//b   
<stdin>:1: RuntimeWarning: divide by zero encountered in floor_divide
array([ 0, 30, 20, 16])

除法的几种形式

  • / 相当于np.divide()
  • // 相当于np.floor_divide()
>>> import numpy as np
>>> a=np.array([20,30,40,50])
>>> a
array([20, 30, 40, 50])
>>> b=np.arange(1,5)
>>> b
array([1, 2, 3, 4])
>>> a/b
array([20.        , 15.        , 13.33333333, 12.5       ])
>>> np.divide(a,b)
array([20.        , 15.        , 13.33333333, 12.5       ])
>>> a//b
array([20, 15, 13, 12])
>>> np.floor_divide(a,b)
array([20, 15, 13, 12])
>>> np.true_divide(a,b)
array([20.        , 15.        , 13.33333333, 12.5       ])

矩阵乘积

与许多矩阵语言不同,乘积运算符*在 NumPy 数组中按元素进行运算。可以使用@运算符(在python>=3.5中)或dot函数或方法来执行矩阵乘积,规则如下图:
在这里插入图片描述

实例:

>>> A = np.array([[1, 1],
...               [0, 1]])
>>> B = np.array([[2, 0],
...               [3, 4]])
>>> A * B     # elementwise product
array([[2, 0],
       [0, 4]])
>>> A @ B     # matrix product
array([[5, 4],
       [3, 4]])
>>> A.dot(B)  # another matrix product
array([[5, 4],
       [3, 4]])

+= *= -= //=

此类操作修改现有数组而不是创建新数组

>>> import numpy as np
>>> a = np.ones((2, 3), dtype=int)
>>> a
array([[1, 1, 1],
       [1, 1, 1]])
>>> rg = np.random.default_rng(1)
>>> rg
Generator(PCG64) at 0x1075C5F20
>>> b = rg.random((2, 3))
>>> b
array([[0.51182162, 0.9504637 , 0.14415961],
       [0.94864945, 0.31183145, 0.42332645]])
>>> a *= 3
>>> a
array([[3, 3, 3],
       [3, 3, 3]])
>>> a -= 1
>>> a
array([[2, 2, 2],
       [2, 2, 2]])
>>> b += a
>>> b
array([[2.51182162, 2.9504637 , 2.14415961],
       [2.94864945, 2.31183145, 2.42332645]])
>>> a /= 2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.UFuncTypeError: Cannot cast ufunc 'divide' output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
>>> a //= 2
>>> a
array([[1, 1, 1],
       [1, 1, 1]])

不同类型的数组不允许乘除

>>> a
array([[2, 2, 2],
       [2, 2, 2]])
>>> a /= 2.0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.UFuncTypeError: Cannot cast ufunc 'divide' output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
>>> a *= 1.1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
numpy.core._exceptions.UFuncTypeError: Cannot cast ufunc 'multiply' output from dtype('float64') to dtype('int64') with casting rule 'same_kind'

不同类型的加减运算

当处理不同类型的数组时,结果数组的类型对应于更一般或更精确的类型(一种称为向上转换的行为)。

>>> import numpy as np
>>> a = np.ones(3, dtype=np.int32)
>>> b = np.linspace(0, pi, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'pi' is not defined
>>> import math
>>> b = np.linspace(0, math.pi, 3)
>>> b
array([0.        , 1.57079633, 3.14159265])
>>> 
>>> a
array([1, 1, 1], dtype=int32)
>>> b.dtype.name
'float64'
>>> c = a+ b
>>> c
array([1.        , 2.57079633, 4.14159265])
>>> c.dtype.name
'float64'
>>> d = np.exp(c * 1j)   # np.exp(c* 1j) 复数运算
>>> d
array([ 0.54030231+0.84147098j, -0.84147098+0.54030231j,
       -0.54030231-0.84147098j])
>>> d.dtype.name
'complex128'
>>> 

具体参考:https://blog.csdn.net/zl_1987/article/details/83238947

数组内一元运算

许多一元运算,例如计算数组中所有元素的总和,都是作为ndarray类的方法实现的。

>>> import numpy as np
>>> a = rg.random((2, 3))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'rg' is not defined
>>>  rg = np.random.default_rng(1)
  File "<stdin>", line 1
    rg = np.random.default_rng(1)
    ^
IndentationError: unexpected indent
>>> rg = np.random.default_rng(1)
>>> a = rg.random((2, 3))
>>> a
array([[0.51182162, 0.9504637 , 0.14415961],
       [0.94864945, 0.31183145, 0.42332645]])
>>> a.sum()
3.290252281866131
>>> a.min()
0.14415961271963373
>>> a.max()
0.9504636963259353

数组轴向运算

通过指定axis 参数,可以沿数组的指定轴应用操作:

>>> import numpy as np
>>> b = np.arange(12).reshape(3, 4)
>>> b
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11]])
>>> b.sum(axis=0)  # 列累加
array([12, 15, 18, 21])
>>> b.sum(axis=1)  # 行累加
array([ 6, 22, 38])
>>> b.cumsum(axis=1)  # 行当前元素与之前元素的累加
array([[ 0,  1,  3,  6],
       [ 4,  9, 15, 22],
       [ 8, 17, 27, 38]])
>>> b.cumsum(axis=0)  # 列当前元素与之前元素的累加
array([[ 0,  1,  2,  3],
       [ 4,  6,  8, 10],
       [12, 15, 18, 21]])
>>> 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值