Numpy基础
NumPy基础
NumPy的主要对象是同类型的多维数组,是一张表,所有元素(通常是数字)的类型都相同。
维度称为axes,axes的数目为rank。如下rank为2(2维的),第一维度axes长度为2,第二维度axes长度为3.[[ 1., 0., 0.],
[ 0., 1., 2.]]
NumPy的数组的类称为ndarray。Python的数组提供较少的功能,而ndarray一下重要的属性。
属性
- ndarray.ndim:数组的axes(维度)的个数,维度的数量称为rank。
- ndarray.shape:数组的维度。这是一个整数元组,
(n, m)
表示一个n行,m列的矩阵。- ndarray.size:为shape元素的乘积,其实就是矩阵元素个数。
- ndarray.dtype:描述矩阵中元素的类型的对象。可以使用Python标准的类型,也提供其他类型,例如:numpy.int32、numpy.int16和numpy.float64。
- ndarray.itemsize:数组中每个元素的字节大小。例如float64字节数为8。
- ndarray.data:该缓冲区包含数组的实际元素。通常不适用这个,我们一般使用索引进行访问(前面矢量化又说不要遍历,后续看看是怎么回事)。
打开中文API查看示例:属性示例
数组创建
有几种方法来创建数组
- 可以使用array函数从常规的Python列表或元组中创建数组,得到的数组类型从序列中元素的类型推到而出。
>>> numpy.array([3, 4, 5])
- array函数传入列表的列表产生2维阵列,同理3维。
>>> numpy.array([1, 2, 3], [4, 5, 6])
array([[1, 2, 3]
[4, 5, 6]
])
- 数组的类型可以在创建的时候指定
>>> numpy.array([1, 2, 3], dtype=complex)
#元素为复数形式 1. + 0.j- 通常数组的元素是位置的,所有NumPy提供创建具体初始占位符的数组,减少数组增长的必要。
- 函数zeros创建一个由0组成的数组;
- 函数ones创建一个由1数组的数组;
- 函数empty内容是随机的并且取决于存储器的状态,元素默认类型是float64。
- 为了创建数组序列,NumPy提供了类似于range的函数,返回数组而不是列表。
>>> numpy.arange(1, 10, 2)
#使用如上的reshape函数可以改变形状。起始为1步长为2。- 当arange与浮点参数一起使用时,由于浮点数的精度是有限的,通常不可能预测获得的元素数量。出于这个原因,通常最好使用函数linspace,它接收我们想要的元素数量而不是步长作为参数:
>>> numpy.linspace(1, 2, 9)
# 1到二之间的9个数,感觉是平均分配的样子。步长0.125
‘>>> numpy.sin(numpy.linspace(0, 2*pi, 100))’ #求sin。
其他函数:
array, zeros, zeros_like, ones, ones_like, empty, empty_like, arange,
linspace, numpy.random.rand, numpy.random.randn, fromfunction, fromfile
打印数组
当打印数组时,NumPy以类似于嵌套列表的方式显示它,但是使用以下布局:
- 最后一个axes从左到右打印,
- 第二个到最后一个从上到下打印,
- 其余的也从上到下打印,每个切片与下一个用空行分开
- 如果数组太大,会跳过中间的部分,只打印边角部分。
- 如果需要强制打印整个数组,可以使用set_printoptions来更改打印选项
numpy.set_printoptions(threshold='nan')
#官方api说传入的是int值,nan目前不知道什么意思:后面查看可以传入numpy.nan,而非str类型
reshape改变数组形状
a.ravel()
#平坦化序列,比如3 * 4的矩阵,变成一维矩阵。a.reshape(x, y)
#转变形状到x*y 元素需要支持转换该形状才行,如果y=-1则会自动计算维度。a.T
#转置 transposednumpy.resize
方法直接改变数组本身
基本操作
数组上的算术运算符使用元素基本,将创建一个新数组并用结果填充,差不多就是对应到每个元素,然后返回计算结果。
>>> a = numpy.array([20, 30, 40, 50])
>>> b = numpy.arange(4)
>>> c = a - b
#对应求其差值>>> b**2
#b元素都乘2>>> 10*np.sin(a)
#对a每个元素求sin,并乘10倍值。>>> a < 35
#对a元素做判断,返回boolean矩阵。- dot函数做矩阵的乘法:a.dot(b) np.dot(a, b)
- a * b 是对a和b对应位置的元素做乘积
+= *= 类似的操作会修改当前数组,而不是创建新的数组:
- ‘>>> a = np.ones((2,3), dtype=int)’
>>> b = np.random.random((2, 3))
>>> a *= 3
>>> b += a
>>> a += b
#报错, float64 to int32
不同类型的数组操作,结果数组的类型对应更精确的数组,向上转型。
- 比如int32 和 float64计算 结果类型为float64
许多一元操作,求和sum,可以使用ndarray的方法
sum(), max(), min()
默认的这些操作适用于数组,就像一个数字列表求最大值,不管其形状(shape = (2*3))
通过axis参数,可以指定沿数组的指定轴应用操作
b.sum(axis=0)
# 每列求和b.sum(axis=1)
# 每行求和b.cumsum(axis=1)
# 沿着行累积和,相反沿着列累积和
另见
all, any, apply_along_axis, argmax, argmin, argsort, average, bincount, ceil, clip, conj, corrcoef, cov, cross, cumprod, cumsum, diff, dot, floor, inner, inv, lexsort, max, maximum, mean, median, min, minimum, nonzero, outer, prod, re, round, sort, std, sum, trace, transpose, var, vdot, vectorize, where
- all:是判断所以元素是否都为True,可以定义axis来沿着某个轴判断。
- any:和all相反,判断是否有一个为Ture,是返回True,否返回False,可以传入axis 例如:b.any(0),纵轴是否有为真的。
apply_along_axis(func, axis, arr):将arr按照axis定义,行或者列取出作用在func上,并返回一个列表。
如果上述返回标量,则返回于源arr相同形状(shape)。比如传输sorted进行排序,返回还是列表。
argmax:查找最大值,返回索引,支持axis轴选择。如果多个大值,就返回第一次遇到的。
- argmin:和max相反。
- argsort:排序,返回排序完的索引值。可以选择算法。选择键排序。
- mean:平均值,可以按轴进行。axis
- diff:计算差分,out[n] = a[n+1] - a[n],可以按轴进行。
- vdot:计算点积。
- 还有很多函数,先不看了。
索引、切片和迭代
一维数组支持索引,切片和迭代,非常类似于列表和其他序列。
- a[1:2],其中
**
是次方,**(1/3) 求根号3
多维数组每个轴可以有一个索引。这些索引以逗号分隔的元组给出:
比如b[2,3]表示3行4列的元素,b[0:3, 1]表示行数是0,1,2的第2列,如果1数字缺失,则认为是全部列。
如果维度大于3,比如维度(轴,rank)为5的情况,x[1,2,:,:,:]可以等效为x[1,2,…]
- x[1,2,…]等效于x[1,2,:,:,:]
- x[…,3]到x[:,:,:,:,3]
- x[4,…,5,:]到x[4,:,:,5,:]
例子:y[1:5:2,::3]指的是1-4行间隔为2行,列数间隔为3进行抽取。
避免迭代使用索引提高性能。
可以使用一个数组来索引数组,提高的索引必须是索引值,比如a[np.array([1,2,3])] 索引a中的索引为1,2,3的元素。
并且索引数组可以是多维的生成的矩阵维度和索引一致,a[np.array([[1,2], [3,4]])],二维矩阵,1,2,3,4对应为a一维矩阵的索引。- Boolean型索引,比如
>>> y = np.arange(35).reshape(5,7)
>>> b = y > 22
>>> y[b] # 这样就将y里边的大于22的数索引出来了,但是维度只有一维,并且如果索引的布尔数组和y具有相同的形状
通常,当布尔数组具有比被索引的数组更少的维度时,这等同于y [b,…],这意味着y被索引为b,然后是多个:如同填充y。因此,结果的形状是包含布尔数组的True元素的数目的一个维度,后面是被索引的数组的剩余维度。
组合索引和切片,感觉就是行和列的索引,三维的话相当于两个数组,就分别对两个进行索引y[1:3, 2:3] #类似的就是1-2行并且列是2列
结构化索引工具>>> y.shape
(5, 7)
>>> y[:,np.newaxis,:].shape # np.newaxis 对象来新建一个维度'
(5, 1, 7)`- 可以使用索引来改变相应位置的值
y[2:7] = 1 #将2-6位置的数更改为1
y[2:7] = np.arange(5) #或者直接使用数组的形式
如果高类型分配给低类型的,会转型,损失精度,或者抛出错误
下面的一个例子比较特殊:>>> x = np.arange(0, 50, 10)
>>> x
array([ 0, 10, 20, 30, 40])
>>> x[np.array([1, 1, 3, 1])] += 1
>>> x
array([ 0, 11, 20, 31, 40])
实际上我们认为1位置的数应该增加3才对,但是最终只增加1,其实是我们每次计算都采用了临时数组的方式,导致最终只增加1.- Ellipsis 等同于 ‘…’
- 元组不像列表索引那样会自动处理,如下例子:
>>> z[[1,1,1,1]] # produces a large array
array([[[[27, 28, 29],
[30, 31, 32], ...
>>> z[(1,1,1,1)] # returns a single value
40
多维数组迭代是相对于第一个轴进行的。
可以使用flat,是一个迭代器。
如果使用x[0][2]会降低性能。因为2索引需要在前面0索引创建的数组上面继续操作。
另见indexing。
形状操作
以下的命令不会修改数组,只会返回新的数组
- ravel 返回连续的平坦的数组,降成一维
- reshape 修改形状
- T 转置
修改数组本身- resize:对应的reshape是返回修改的数组
将不同的数组堆叠- vstack
- hstack h v 分别对应水平方向和垂直方向。
- column_stack
- row_stack column 和 row 分别对应,并且这两个方法允许1D的数组堆叠到2D数组中
将数组分隔成几个小的数组np.hsplit(a, 3) #将a划分为3个 h是水平
np.hsplit(a, (3, 4)) #将列为3-4但是不等于4的索引分隔开来
- 同理vsplit是垂直划分
- array_split 可以指定某个轴进行划分
复制和视图
当计算和操作数组时,它们的数据有时被复制到新的数组中,有时不复制。这通常是初学者的混乱的来源。有三种情况:
- 完全不复制
简单赋值不会创建数组对象或其数据的拷贝:如果将b = a 那么b和a指向的是同一个数组,改变b,a也跟着改变。
可变对象传递到函数引用,函数不会复制。- 视图或浅复制
不同的数组对象可以共享相同的数据。view方法创建一个新数组对象,该对象看到相同的数据。c=a.view()
, 这样改变c.shape = (2,6)
,a的形状不会改变,但是如果c[0,4] = 1234
,a的相应位置就会赋值为1234c.base is a = True
对数组切片返回的也是视图- 深复制
d = a.copy()
这样d就是一个新的数组
函数和方法概述
这里是一些有用的NumPy函数和方法名称按类别排序的列表。有关完整列表,请参见Routines。
- 数组创建
arange, array, copy, empty, empty_like, eye, fromfile, fromfunction, identity, linspace, logspace, mgrid, ogrid, ones, ones_like, r, zeros, zeros_like
- 转换
ndarray.astype,atleast_1d,atleast_2d,atleast_3d,mat
- 操纵
array_split, column_stack, concatenate, diagonal, dsplit, dstack, hsplit, hstack, ndarray.item, newaxis, ravel, repeat, reshape, resize, squeeze, swapaxes, take, transpose, vsplit, vstack
- 问题
all,any,nonzero,where
- 顺序
argmax, argmin, argsort, max, min, ptp, searchsorted, sort
- 操作
choose, compress, cumprod, cumsum, inner, ndarray.fill, imag, prod, put, putmask, real, sum
- 基本统计
cov,mean,std,var
基本线性代数cross,dot,outer,linalg.svd,vdot
其他基础
广播规则
- Broadcasting允许通用函数以有意义的方式处理具有不完全相同形状的输入。
- Broadcasting的第一个规则是,如果所有输入数组不具有相同数量的维度,则“1”将被重复地添加到较小数组的形状,直到所有数组具有相同数量的维度。
- Broadcasting的第二个规则确保沿着特定维度具有大小为1的数组表现得好像它们具有沿着该维度具有最大形状的数组的大小。假定数组元素的值沿“Broadcasting”数组的该维度相同。
花式索引技巧
NumPy提供了比常规Python序列更多的索引能力。除了通过整数和切片索引之外,如前所述,数组可以由整数数组和布尔数组索引。
- 使用索引数组索引
a[j]
j = np.array([1,1,3]) #得出索引a是1,1,3组成的数组
如果索引的数组是多维的,结果与之对应,j = np.array([[1,2,3], [4, 5, 6]])
,结果是形状是(2, 3)
- 可以对每个维度进行单独索引
i = np.array([[0,1], [1, 2]])
j = np.array([[2,1], [1, 3]])
a[i, j]
同样的l=[i,j]
a[l]=a[i,j]
函数
np.ix_[a,b,c] ???雨里雾里
np.ufunc.reduce ???云里雾里
线性代数 基础
简单的数组操作
a.transpose() # 矩阵转置
np.linalg.inv(a) # 逆矩阵
np.eye(2) # 2*2的矩阵,返回对角线是1其他都是0的矩阵
np.dot(i, j) # 求矩阵乘积
np.trace(a) # 对a矩阵的对角线值求和
np.linalg.solve(a, y) # 解线性方程组 a矩阵对应参数,y对应等于后边的数
np.linalg.eig(j) # 特征向量,线性代数当时没有学好