1、什么是Numpy?
Numpy是Python中科学计算的基础软件包。
它提供多维数组对象、多种派生对象(如掩码数组、矩阵)以及用于快速操作数组的函数,包括数学、逻辑、数组形状变换、排序、选择、统计运算等等。
Numpy包的核心是ndarray
对象。
它封装了python原生的同数据类型的n维数组,为了保证其性能优良,其中许多操作都是在本地编译后代码中执行的。
Numpy数组相比python内置序列主要区别如下:
- Numpy数组在创建时固定大小,更改ndarray的大小将创建一个新数组并销毁原数组;
- Numpy数组元素具有相同数据类型,占用相同内存;
- Numpy数组有助于对大量数据高效地完成高级数学运算和其他类型操作;
对于涉及ndarray
对象的算术、逻辑、位运算等,Numpy默认执行预编译的C代码对逐个元素操作,如:
c = a * b
上式中,若a和b是形状相同的多维数组 ,或是一个标量和一个多维数组,甚至是两个不同形状的数组(较小数组可通过某种方式扩展到较大数组),Numpy对其均是逐个元素操作。这说明了Numpy的两个特征:矢量化
和广播
。矢量化指代码中无任何显式的循环、索引等,这些事情在优化的、预编译的C代码中完成。广播指隐式地对元素逐个操作的术语。
2、ndarray介绍
ndarray
对象是Numpy科学工具包的核心,其本质是一个包含具有相同类型和内存大小的元素的多维容器。
多维数组的维度和各维度元素的数量由shape属性指定,数组的元素类型由dtype属性指定。
Numpy提供多种方法用于多维数组的创建、拼接、拆分等,具体可参考博文《Numpy数组的创建、变形、拼接及拆分》。
Numpy中的多维数组除具有python中其他容器的索引功能之外,还具有更强大的切片、整数数组、布尔数组等索引功能,具体实现可参考相关博文《Numpy数组的索引与切片:取数组的特定行列》。
不同ndarrays
之间可以共享数据,即一个ndarray
对象可能是另一个ndarray
对象的视图,视图引用的数据由“base”ndarray处理。ndarrays
还可以是python所拥有的内存视图或实现buffer或数组接口的对象。
ndarray的常用属性与方法
属性 | 功能 |
---|---|
ndarray.ndim | 数组的轴(维度)的个数 |
ndarray.shape | 数组的形状,元组 |
ndarray.size | 数组元素的总数,等于shape中各元素的乘积 |
ndarray.dtype | 描述数组中元素类型的对象,可使用标准python数据类型创建 |
ndarray.itemsize | 数组中每个元素的字节大小,如float64 类型的数组,它等于64/8=8 |
ndarray.data | 该缓冲区包含数组的实际元素,可使用索引替代,一般不直接使用 |
ndarray.strides | 遍历数组时,每个维度上单步执行的步长 |
ndarray.base | 若对象为视图则返回原始数组,若数据为其自身所有则返回None |
ndarray.T | 数组的转置 |
ndarray.flat | 所有数据的一维迭代器 |
ndarray的转换方法
属性 | 功能 |
---|---|
ndarray.item(*args) | 返回数组指定位置的元素,位置可以是标量或元组 |
ndarray.tolist() | 以列表(可能嵌套)的形式返回数组 |
ndarray.itemset(*args) | 替换数组指定位置的元素,位置可以是标量或元组 |
ndarray.tostring(order=‘C’) | 返回数组原始数据的字节序列 |
ndarray.tofile(fid, sep="", format="%s") | 将数组作为文本或二进制(默认)写入文件 |
ndarray.dump(file) | 将数组pickle到指定文件,对应load指令读取到内存 |
ndarray.dumps() | 以字符串形式返回数组的pickle,对应loads指定从字符串读取为ndarry对象 |
ndarray.astype(dtype, order=‘K’, casting=‘unsafe’, subok=True, copy=True) | 返回数组转换数据类型后副本 |
ndarray.byteswap(inplace=False) | 交换数组元素的字节 |
ndarray.copy(order=‘C’) | 返回数组的副本 |
ndarray.view(dtype=None, type=None) | 返回数组的视图 |
ndarray.getfield(dtype, offset=0) | 以某种类型返回数组的字段 |
ndarray.fill(value) | 用标量值填充数组 |
3、数组运算
数组运算的注意事项:
- 当使用不同类型的数组操作时,结果数组的类型对应于更一般或更精确的数组,即向上转换,因此不能对低精度的数组元素赋高精度的值;
- 基本的算术、逻辑、位以及比较运算,需要创建新数组,并填充结果;
- 复合运算符,如+=,为就地修改原数组,因此操作符右值不能是高精度的数据;
- 普通乘法运算符
*
是元素级别运算,若需执行矩阵乘法运算,可使用@
操作符或dot
函数;
操作符/函数 | 功能 |
---|---|
+ - * / ** >> << > < | & | 算术、逻辑、位以及比较运算符使用元素级别,创建新数据并填充结果 |
+= -= *= /= >>= <<= | 复合运算符,就地修改原数组数据 |
@ dot | 矩阵乘法运算符 |
"""算术、逻辑、位以及比较运算符"""
>>> a = np.array( [20,30,40,50] )
>>> b = np.arange( 4 )
>>> b
array([0, 1, 2, 3])
>>> c = a - b
>>> c
array([20, 29, 38, 47])
>>> b**2
array([0, 1, 4, 9])
>>> 10*np.sin(a)
array([ 9.12945251, -9.88031624, 7.4511316 , -2.62374854])
>>> a < 35
array([ True, True, False, False])
>>> np.array([1,0,2]) & 1
array([1, 0, 0], dtype=int32)
"""复合运算符"""
>>> a = np.ones((2,3), dtype=int)
>>> b = np.random.random((2,3))
>>> a *= 3
>>> a
array([[3, 3, 3],
[3, 3, 3]])
>>> b += a
>>> b
array([[ 3.417022 , 3.72032449, 3.00011437],
[ 3.30233257, 3.14675589, 3.09233859]])
>>> a += b # b is not automatically converted to integer type
Traceback (most recent call last):
...
TypeError: Cannot cast ufunc add output from dtype('float64') to dtype('int64') with casting rule 'same_kind'
"""普通乘法运算与矩阵乘法"""
>>> A = np.array([[1,1],[0,1]])
>>> B = np.array([[2,0],[3,4]])
>>> A * B
array([[2, 0],
[0, 4]])
>>> A @ B
array([[5, 4],
[3, 4]])
>>> np.dot(A,B)
array([[5, 4],
[3, 4]])