1.什么是Nmupy
NumPy是Python中科学计算的基础包。它是一个Python库,提供多维数组对象,各种派生对象(如掩码数组和矩阵),以及用于数组快速操作的各种API,有包括数学、逻辑、形状操作、排序、选择、输入输出、离散傅立叶变换、基本线性代数,基本统计运算和随机模拟等等。
NumPy包的核心是ndarray 对象。它封装了python原生的同数据类型的n维数组,为了保证其性能优良,其中有许多操作都是代码在本地进行编译后执行的。
Numpy数组和原生Python 数组之间的区别
- NumPy 数组在创建时具有固定的大小,与Python的原生数组对象(可以动态增长)不同。更改ndarray的大小将创建一个新数组并删除原来的数组。
- NumPy 数组中的元素都需要具有相同的数据类型,因此在内存中的大小相同。 例外情况:Python的原生数组里包含了NumPy的对象的时候,这种情况下就允许不同大小元素的数组。
- NumPy 数组有助于对大量数据进行高级数学和其他类型的操作。通常,这些操作的执行效率更高,比使用Python原生数组的代码更少。
- 越来越多的基于Python的科学和数学软件包使用NumPy数组; 虽然这些工具通常都支持Python的原生数组作为参数,但它们在处理之前会还是会将输入的数组转换为NumPy的数组,而且也通常输出为NumPy数组。
下面是一个具体的例子:
将1维数组中的每个元素与相同长度的另一个序列中的相应元素相乘的情况。一般情况下,如果数据存储在两个Python 列表a
和 b
中,我们可以迭代每个元素,如下所示:
c = []
for i in range(len(a)):
c.append(a[i]*b[i])
正常这样写,完全没有问题。但是如果a
和b
的长度都是几百万的话,这样的效率就比较低了,我们可以通过在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的速度执行前面的示例所做的事情!
2. numpy基础属性
NmuPy
主要处理的是同构多维数组。它是一个所有类型都相同的元素表(通常是数字)。数组中的元素由非负整数元组索引。在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
- 数组的轴(维度)的个数。在Python世界中,维度的数量被称为rank
。ndarray.shape
- 数组的维度。这是一个整数的元组,表示每个维度中数组的大小。对于有 n 行和 m 列的矩阵,shape 将是 (n,m)。因此,shape 元组的长度就是rank或维度的个数 ndim。ndarray.size
- 数组元素的总数。这等于 shape 的元素的乘积。ndarray.dtype
- 一个描述数组中元素类型的对象。可以使用标准的Python类型创建或指定dtype。另外NumPy提供它自己的类型。例如numpy.int32
、numpy.int16
和numpy.float64
。ndarray.itemsize
- 数组中每个元素的字节大小。例如,元素为float64
类型的数组的itemsize
为8(=64/8),而complex32
类型的数组的itemsize
为4(=32/8)。它等于ndarray.dtype.itemsize
。ndarray.data
- 该缓冲区包含数组的实际元素。通常,我们不需要使用此属性,因为我们将使用索引访问数组中的元素。
下面是一些使用numpy
的例子:
>>> 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
'int32'
>>> a.itemsize
4
>>> a.size
15
>>> type(a)
<class 'numpy.ndarray'>
3. 特定array的创建
在实际上的项目工程中,我们常常会需要一些特定的数据,NumPy中提供了这么一些辅助函数:
zeros
:用来创建元素全部是0的数组ones
:用来创建元素全部是1的数组empty
:用来创建未初始化的数据,因此是内容是不确定的arange
:通过指定范围和步长来创建数组linespace
:通过指定范围和元素数量来创建数组random
:用来生成随机数
# create_specific_array.py
import numpy as np
a = np.zeros((2,3))
print('np.zeros((2,3)= \n{}\n'.format(a))
b = np.ones((2,3))
print('np.ones((2,3))= \n{}\n'.format(b))
c = np.empty((2,3))
print('np.empty((2,3))= \n{}\n'.format(c))
d = np.arange(1, 2, 0.3)
print('np.arange(1, 2, 0.3)= \n{}\n'.format(d))
e = np.linspace(1, 2, 7)
print('np.linspace(1, 2, 7)= \n{}\n'.format(e))
f = np.random.random((2,3))
print('np.random.random((2,3))= \n{}\n'.format(f))
这段代码的输出如下
np.zeros((2,3)=
[[ 0. 0. 0.]
[ 0. 0. 0.]]
np.ones((2,3))=
[[ 1. 1. 1.]
[ 1. 1. 1.]]
np.empty((2,3))=
[[ 1. 1. 1.]
[ 1. 1. 1.]]
np.arange(1, 2, 0.3)=
[ 1. 1.3 1.6 1.9]
np.linspace(1, 2, 7)=
[ 1. 1.16666667 1.33333333 1.5 1.66666667 1.83333333
2. ]
np.random.random((2,3))=
[[ 0.5744616 0.58700653 0.59609648]
[ 0.0417809 0.23810732 0.38372978]]
4.Shape与操作
除了生成数组之外,当我们已经持有某个数据之后,我们可能会需要根据已有数组来产生一些新的数据结构,这时候我们可以使用下面这些函数:
reshape
:根据已有数组和指定的shape,生成一个新的数组vstack
:用来将多个数组在垂直(v代表vertical)方向拼接(数组的维度必须匹配)hstack
:用来将多个数组在水平(h代表horizontal)方向拼接(数组的维度必须匹配)hsplit
:用来将数组在水平方向拆分vsplit
:用来将数组在垂直方向拆分
下面我们通过一些例子来进行说明。
为了便于测试,我们先创建几个数据。这里我们创建了:
zero_line
:一行包含3个0的数组
one_column
:一列包含3个1的数组
a
:一个2行3列的矩阵
b
:[11, 20)区间的整数数组
# shape_manipulation.py
zero_line = np.zeros((1,3))
one_column = np.ones((3,1))
print("zero_line = \n{}\n".format(zero_line))
print("one_column = \n{}\n".format(one_col