携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情
基础
NumPy提供的主要对象就是同数据类型的多维数组(homogeneous multidimensional array)。他实际上可以被理解成一张表元素 通常是数字 所有元素具有相同的类型 这些元素可以使用由正整数构成的元组(tuple)来索引 。在NumPy中,各个维度被称为轴(axes)。轴的总数被称为秩(rank)。
举例子,三维空间中的一个点的坐标是[1 , 2, 1],它就是一个rank是1的一个数组。因为它只有一个axis,这个axis的长度是3. [[1., 0., 0.], [0., 1., 2.]] 该数组的rank是2(两个维度),第一个维度的长度是2(2行),第二个的维度是3(3列).
NumPy的数组叫做ndarray。同时也有个别名array。numpy.array和 Python标准库中的array.array完全不是一个东西,后者仅仅支持一维数组提供的功能较少。ndaary对象比较重要的属性有:
ndarray.ndim 数组的axes的数目
ndarray.shape 数组的形状,如一个 n*m 的矩阵,它的shape就是(n,m)。而且len(ndarray.shape)==ndarray.ndim
ndarray.size 数组中所有元素的个数。它实际上是ndarray.shape中的所有值的乘积。
ndarray.dtype 用于描述数组中元素类型的对象。我们可以使用Python标准类型来创建或指定dtype。不过NumPy也提供了一些它自己的类型,比如:numpy.int32,numpy.int16,numpy.float64 。。。
ndarray.itemsize 数组中单个元素以字节计的大小。比如类型是float64,则itemsize就是8=(64/8)。它跟ndarray.dtype.itemsize是等价的。
ndarray.data 存储数组中实际的数据。通常我们不会直接用到这个属性,因为当我们需要访问数据时几乎总是提供的索引功能。
import numpy as np
a = np.arange(15).reshape(3,5)
a.shape
(3, 5)
a.ndim
2
a.dtype.name, a.itemsize
('int32', 4)
type(a)
numpy.ndarray
b = np.array([6,7,8])
b
array([6, 7, 8])
type(b)
numpy.ndarray
创建数组
比如:通过array,我们可以从普通的Python列表或元组直接创建。元素的类型根据原类型推断。
a = np.array([2,3,4])
a
array([2, 3, 4])
b = np.array([1.2, 3.5, 5.1])
b.dtype
dtype('float64')
一个常见的错误是,把数组内容当做参数直接传给array,而不是作为一个列表或元组:
a = np.array(1, 2, 3, 4) #错误
a = np.array([1, 2, 3, 4]) #正确
# array将两层嵌套序列转成二维数组,三层嵌套序列转成三维数组,以此类推:
b = np.array([(1.5, 2, 3), (4, 5, 6)])
b
array([[1.5, 2. , 3. ],
[4. , 5. , 6. ]])
数组类型在创建时也可以指定
c = np.array([ [1,2], [3, 4]], dtype=complex)
c
array([[1.+0.j, 2.+0.j],
[3.+0.j, 4.+0.j]])
需要固定形状的数组,但在定义数组时还没有加载数据。 NumPy为我们提供了一些包含占位符的数组创建函数。这样我们就可以避免使用动态数组(因为动态数组加载耗时)
- zereos函数可以创建所有元素均为0的数组
- ones函数可以创建所有元素均为1的数组
- empty函数创建的数组,其元素都是随机的!!!
默认情况下,创建的dtype都是float64
np.zeros( (3,4) ) # 它的参数并不是数据,而是数组的形状(shape)
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,4) )
array([[0.00000000e+000, 0.00000000e+000, 0.00000000e+000,
0.00000000e+000],
[0.00000000e+000, 7.92481296e-321, 3.11525958e-307,
1.24610723e-306]])
np.arange(10, 30, 5)
array([10, 15, 20, 25])
np.arange(0,2,0.5)
array([0. , 0.5, 1. , 1.5])
因为浮点数的有限精度问题,arrange返回长度可能无法预知。最好使用linspace,它可以指定所需要的数组长度,而不需要设定步长:
np.linspace(0, 2, 9)
array([0. , 0.25, 0.5 , 0.75, 1. , 1.25, 1.5 , 1.75, 2. ])
from numpy import pi
x = np.linspace(0, 2*pi, 100) # 对于要采样很多点的时候特别有用
f = np.sin(x)
f
array([ 0.00000000e+00, 6.34239197e-02, 1.26592454e-01, 1.89251244e-01,
2.51147987e-01, 3.12033446e-01, 3.71662456e-01, 4.29794912e-01,
4.86196736e-01, 5.40640817e-01, 5.92907929e-01, 6.42787610e-01,
6.90079011e-01, 7.34591709e-01, 7.76146464e-01, 8.14575952e-01,
8.49725430e-01, 8.81453363e-01, 9.09631995e-01, 9.34147860e-01,
9.54902241e-01, 9.71811568e-01, 9.84807753e-01, 9.93838464e-01,
9.98867339e-01, 9.99874128e-01, 9.96854776e-01, 9.89821442e-01,
9.78802446e-01, 9.63842159e-01, 9.45000819e-01, 9.22354294e-01,
8.95993774e-01, 8.66025404e-01, 8.32569855e-01, 7.95761841e-01,
7.55749574e-01, 7.12694171e-01, 6.66769001e-01, 6.18158986e-01,
5.67059864e-01, 5.13677392e-01, 4.58226522e-01, 4.00930535e-01,
3.42020143e-01, 2.81732557e-01, 2.20310533e-01, 1.58001396e-01,
9.50560433e-02, 3.17279335e-02, -3.17279335e-02, -9.50560433e-02,
-1.58001396e-01, -2.20310533e-01, -2.81732557e-01, -3.42020143e-01,
-4.00930535e-01, -4.58226522e-01, -5.13677392e-01, -5.67059864e-01,
-6.18158986e-01, -6.66769001e-01, -7.12694171e-01, -7.55749574e-01,
-7.95761841e-01, -8.32569855e-01, -8.66025404e-01, -8.95993774e-01,
-9.22354294e-01, -9.45000819e-01, -9.63842159e-01, -9.78802446e-01,
-9.89821442e-01, -9.96854776e-01, -9.99874128e-01, -9.98867339e-01,
-9.93838464e-01, -9.84807753e-01, -9.71811568e-01, -9.54902241e-01,
-9.34147860e-01, -9.09631995e-01, -8.81453363e-01, -8.49725430e-01,
-8.14575952e-01, -7.76146464e-01, -7.34591709e-01, -6.90079011e-01,
-6.42787610e-01, -5.92907929e-01, -5.40640817e-01, -4.86196736e-01,
-4.29794912e-01, -3.71662456e-01, -3.12033446e-01, -2.51147987e-01,
-1.89251244e-01, -1.26592454e-01, -6.34239197e-02, -2.44929360e-16])
array,zeros,zeros_likee,ones_like,empty,empty_like,arange,linspace,numpy,random ...
可以在notebook里面直接np.array?阅读,也可以去NumPy的管方文档
打印数组
打印出来非常类似于嵌套列表
a = np.arange(6) # 一维
print(a)
[0 1 2 3 4 5]
b = np.arange(12).reshape(3,4) # 二维
print(b)
[[ 0 1 2 3]
[ 4 5 6 7]
[ 8 9 10 11]]
c = np.arange(24).reshape(2,3,4) # 三维
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]]]
如果数组太长,NumPy会自动忽略中间部分的数据,只打印首位:
我们可以通过设置set_printoptions选项来关闭功能: np.set_printoptions(threshold='nan')
print(np.arange(100000))
[ 0 1 2 ... 99997 99998 99999]
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]]
基础操作
在数组上进行的算术操作都是元素级别的(elementwise)。
a = np.array([20, 30, 40, 50])
b = np.arange(4) # 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])
在线性代数中,乘号*一般表达的是矩阵乘法,但在NumPy中它表示元素级别的乘法。
矩阵乘法在NumPy中使用dot:
A = np.array([ [1, 1],
[0, 1]] )
B = np.array( [[2, 0],
[3, 4]])
A*B # 元素级乘法
array([[2, 0],
[0, 4]])
A.dot(B) # 矩阵乘法
array([[5, 4],
[3, 4]])
np.dot(A,B)
array([[5, 4],
[3, 4]])
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.62220496, 3.85951178, 3.62499834],
[3.51389196, 3.57738806, 3.47357054]])
a +=b
---------------------------------------------------------------------------
UFuncTypeError Traceback (most recent call last)
Input In [33], in <cell line: 1>()
----> 1 a +=b
UFuncTypeError: Cannot cast ufunc 'add' output from dtype('float64') to dtype('int32') with casting rule 'same_kind'
print(a.sum(), a.min(), a.max())
a
b = np.arange(12).reshape(3,4)
b
b.sum(axis=0) # 每一列的和
b.min(axis=1) # 每一行的最小值
b.cumsum(axis=1) # 每一行当累加和
通用函数(Univeersal Functions)
NumPy提供了一些常用的数学函数,如:sin,cos,exp等。在NumPy中,它们被称为“通用函数”(ufunc)。在NumPy中,这些函数的作用在数组上时,都是作用在每个单独的元素上,并产生一个新的数组。
B = np.arange(3)
B
np.exp(B)
np.sqrt(B)
C = np.array([2., -1., 4.])
np.add(B,C)
索引,切片以及遍历
一维数组非常类似于Pyton的序列(list,tuple),它们可以被索引(index),被切片(slice),被遍历(iterate)。
a = np.arange(10)**3
a
a[2]
a[2:5]
a[:6:2] = -1000
a
a[::-1]
for i in a:
print(i**(1/3.0))
多维数组每一个轴(axis)均有一个索引(index)。这些索引使用","(半角逗号)分隔,以元组(tuple)的形式表现:
def f(x, y):
return 10*x + y
b = np.fromfunction(f,(5, 4),dtype=int)
b
b[2,3]
b[0:5,1] # 第二列,0,1,2,3,4行
b[:,1] #第二列,所用行
b[1:3, :] # 第1,2行,所有列
另外,NumPy还有...这种写法,它会自动判断所需要填补的索引: 比如,我们现在有一个拥有五个轴(axis)的数组:
- x[1, 2, ...]等价于x[1,2,:,:,:]
- x[...,3]等价于 x[:,:,:,:,3]
- x[4,...,5,:]等价于 x[4,:,:,5,:]
c = np.array( [[[ 0, 1, 2],
[ 10,12, 13]],
[[100, 101, 102],
[110, 112, 113]]])
c.shape
c[1,...]
c[...,2]
遍历是从第一轴开始的:
for row in b:
print(row)
for element in b.flat: # 打平访问
print(element,end=",")
形状操作
修改一个数组的形状
a = np.floor(10*np.random.random( (3, 4)))
a
a.shape
a
在NunPy中有很多方法可以改变一个数组的形状。 请注意,下面三种方式均返回一个修改后的数组,但又不改变原来的数组:
a.ravel() # 返回打平的数组的形状
a.reshape(6,2) # 返回目标形状的数组
a.T # 返回它的转置
a
a.resize((2,6))
a
a.reshape(3,-1)
将不同的数组堆叠(stacking)起来
多个数组可以沿着不同的轴堆叠起来:
a = np.floor(10*np.random.random((2,2)))
b = np.floor(10*np.random.random((2,2)))
print(a)
print(b)
np.vstack((a,b))
np.hstack((a,b))
c = np.array([3,3])
np.column_stack((a,c))
将一个数组切分成多个
使用split,我们可以将一个数组沿水平方向进行切分。切分时可以指定:
- 目标数组个数---将自动计算切分数组的形状
- 切分列下标---将在指定的列下标进行切分
a = np.floor(10*np.random.random((2, 12)))
a
np.hsplit(a,3)
np.hsplit(a, (3,4)) # 在第三列第四列切分
拷贝(copy)与视图(view)
根本不拷贝
简单的赋值不会发生任何拷贝行为:
a = np.arange(12)
b = a # 不会新建对象
b is a # a 和 b 是对同一个 ndarray对象的两个名字
b.shape = 3,4 # 同时会修改a的形状
a.shape
Python以引用的方式传递对象,所以函数调用不会产生拷贝:
def f(x):
print( id(x))
print(id(a))
f(a)
视图和浅拷贝
不同的数据对象可以共享相同的数据。view方法新建一个数组对象,但仍然使用相同的数据。
c = a.view()
c is a
c.base is a # c仅仅是a中数据的一个视图
c.flags.owndata
c.shape = 2,6 # a的形状不会改变
a
c[0, 4] = 1234 # a的数据会改变
a
c
对一个数组进行切片会返回它的视图:
s = a[:, 1:3]
s[:] = 10
a
深拷贝
copy()方法会对数据及其数据做一次完整的拷贝。
d = a.copy()
d is a
d
d[0, 0] = 999
a
d
palettle = np.array([ [ 0,0]])