原文链接:
http://blackblog.tech/2018/02/07/NumPyQuickStart/
更多干货就在我的个人博客 http://blackblog.tech 欢迎关注!
如果想要python进行数据处理,机器学习,那么必然离不开一个科学计算包——NumPy(Numeric Python)。甚至可以算是将python变成一个
NumPy中包括:
1.一个强大的N维数组对象Array
2.比较成熟的(广播)函数库
3.用于整合C/C++和Fortran代码的工具包
4.实用的线性代数、傅里叶变换和随机数生成函数。numpy和稀疏矩阵运算包scipy配合使用更加方便。
除此之外,NumPy提供了许多高级的数值编程工具,如:矩阵数据类型、矢量处理,以及精密的运算库。
官网:https://docs.scipy.org/doc/numpy-dev/user/index.html
今天这篇博客就对NumPy的基础操作进行讲解
NumPy的安装
两种方式Pip与Anaconda,这里我还是推荐Anaconda,集中管理环境非常方便。
Pip:
pip install -U numpy
Anaconda安装Anaconda的时候会自动装NumPy,如果不幸没装上,那么自己手动装一下。
conda install numpy
安装完成后,进入python测试一下,不报错就证明安装成功了。
>>> import numpy
NumPy第一步
>>> import numpy
一般我们用
>>> import numpy as np
有的人也会用
>>> from numpy import *
但是我喜欢第二种写法,也只推荐第二种写法,因为不容和其他package搞混。
NumPy基本数据类型
数据类型NumPy数组
NumPy数组是一个多维数组的对象,成为ndarray,由数组实际的数据和描述这些数据的元数据组成,一般来说,大部分操作仅针对于元数据,而不改变底层实际的数据。
注意:
1.NumPy数组的下标起始是0,不是1
2.同一个NumPy数组中所有元素的类型必须相同
特别:NumPy数组的创建访问中的[]与()功能无异
例如
>>> data = np.zeros((5,5))
也可以写为
>>> data = np.zeros([5,5])
下面的代码[]和()会出现混用的情况
NumPy基本数组的创建
NumPy数组有很多种创建方式,一般最为常用的方式为将list转换为np.array
>>> data = [1,2,3,4,5]
>>> data =np.array(data)
>>> data
array([1, 2, 3, 4, 5])
或者
>>> data = np.array([1,2,3,4,5],float)
>>> data
array([ 1., 2., 3., 4., 5.])
这里的float用于指定类型,可以不写,也可以写为int等其他类型。
注意,使用array函数创建时,参数必须是由方括号括起来的列表,而不能使用多个数值作为参数调用array。
>>> data = np.array([1,2,3]) #对!!!
>>> data = np.array(1,2,3) #错!!!
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: only 2 non-keyword arguments accepted
创建二维数组,多维数组以此类推。
>>> data = np.array([(1,2,3),(4,5,6)])
>>> data
array([[1, 2, 3],
[4, 5, 6]])
NumPy特殊数组的创建
NumPy提供了一些使用占位符创建数组的函数。这些函数有助于满足除了数组扩展的需要,同时降低了高昂的运算开销。
下方代码
创建一个全0的数组
>>> data = np.zeros((5,5))
>>> data
array([[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 0.]])
创建一个全1的数组
>>> data = np.ones((5,5))
>>> data
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., 1.]])
创建一个对角阵
>>> data = np.eye(5)
>>> data
array([[ 1., 0., 0., 0., 0.],
[ 0., 1., 0., 0., 0.],
[ 0., 0., 1., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 1.]])
创建一个内容随机并且依赖与内存状态的数组,主要起占位作用
>>> data = np.empty(10)
>>> data
array([ -1.28822975e-231, -1.49457028e-154, 6.92642698e-310,
2.30467739e-314, 6.92642708e-310, 2.30467739e-314,
6.92642698e-310, 2.30467739e-314, 6.92642699e-310,
2.30467739e-314])
同样创建的过程中,可以指定数组元素的类型
data = np.ones((3,3),dtype=float)
>>> data
array([[ 1., 1., 1.],
[ 1., 1., 1.],
[ 1., 1., 1.]])
NumPy甚至可以直接创建等差数列,不仅支持整数,也支持浮点数。
以10开始,50结束,8为差的等差数列,最后一项一定会小于等于50。
>>> data =np.arange(10, 50, 8)
>>> data
array([10, 18, 26, 34, 42])
NumPy数组的访问
和list的访问方式基本一致,支持切片等操作。
以二维数组为例
>>> data = np.array([(1,2,3),(4,5,6),(7,8,9)])
>>> data[0] #第一行
array([1, 2, 3])
>>> data[:,0] #第一列
array([1, 4, 7])
>>> data[:2] #前两行
array([[1, 2, 3],
[4, 5, 6]])
>>> data[:,:2] #前两列
array([[1, 2],
[4, 5],
[7, 8]])
>>> data[1][2] #访问特定元素
6
可以使用take操作
>>> #一维数组
>>> data = np.array([1,2,3])
>>> data.take(1)
2
>>> i = np.array([0,0,1,2,1,0])
>>> data.take(i)
array([1, 1, 2, 3, 2, 1])
>>> #二维数组
>>> data = np.array([(1,2,3),(4,5,6)])
>>> data.take(1,axis=1)
array([2, 5])
与take对应的是put,put可以快速修改一个array内的元素
>>> a = np.array([0, 1, 2, 3, 4, 5])
>>> b = np.array([10,11,12])
>>> a.put([0,2],b)
>>> a
array([10, 1, 11, 3, 4, 5])
可以使用比较符访问元素
>>> data = np.array([1,2,3])
>>> data[data>1]
array([2, 3])
NumPy数组的遍历
一维数组的遍历
>>> data = np.array([2,3,4])
>>> for i in data:
... print(i)
...
2
3
4
二维数组的遍历
>>> data = np.array([(1,3),(5,7),(9,11)])
>>> for i in data:
... print(i)
...
[1 3]
[5 7]
[ 9 11]
当然还可以这么玩
>>> data = np.array([(1,3),(5,7),(9,11)])
>>> for (a,b) in data:
... print(a*b)
...
3
35
99
NumPy数组的常用属性
下面这些属性属于非常常用的属性,很容易记忆
1.ndarray.ndim:数组的维数(即数组轴的个数),等于秩。
2.ndarray.shape:数组的大小。为一个表示数组在每个维度上大小的整数元组。例如二维数组中,表示数组的“行数”和“列数”。
3.ndarray.size:数组元素的总个数,等于shape属性中元组元素的乘积。
4.ndarray.dtype:表示数组中元素类型的对象。
5.ndarray.itemsize:数组中每个元素的字节大小。
6.ndarray.data:包含实际数组元素的缓冲区,一般不用。
>>> data = np.array([(1,2,3),(4,5,6),(7,8,9)])
>>> data.ndim
2
>>> data.shape
(3, 3)
>>> data.size
9
>>> data.dtype
dtype('int64')
>>> data.itemsize
8
>>> data.data
<memory at 0x1151f1dc8>
NumPy数组的基本操作
in:测试数值是否在数组中
>>> data = np.array([(1,2,3),(4,5,6),(7,8,9)])
>>> 2 in data
True
>>> 10 in data
False
reshape:数组的重排列
例:一维数组变为二维数组
>>> data = np.array((1,2,3,4,5,6))
>>> data
array([1, 2, 3, 4, 5, 6])
>>> data.reshape((2,3))
array([[1, 2, 3],
[4, 5, 6]])
insert:插入元素
参数:
arr:数组
obj:插入某一轴的对应标号
values:插入的值
axis:axis=0 插入行,axis=1 插入列
>>> data = np.array([(1,2,3),(4,5,6),(7,8,9)])
>>> #第一行插入1
>>> data = np.insert(data,0,1,axis=0)
>>> data
array([[1, 1, 1],
[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> #第三列插入5
>>> data = np.insert(data,2,5,axis=1)
>>> data
array([[1, 1, 5, 1],
[1, 2, 5, 3],
[4, 5, 5, 6],
[7, 8, 5, 9]])
delete:删除元素
参数:
arr:数组
obj:删除某一轴的对应标号
axis:axis=0 删除行,axis=1 删除列
>>> data = np.array([(1,2,3),(4,5,6),(7,8,9)])
>>> data
array([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
>>> data = np.delete(data,0,axis=0) #删除第一行
>>> data
array([[4, 5, 6],
[7, 8, 9]])
>>> data = np.delete(data,0,axis=1) #删除第一列
>>> data
array([[5, 6],
[8, 9]])
copy:创建一个新的,内存分离的拷贝
>>> data = np.array((1,2,3))
>>> val = data
>>> val is data
True
>>> val = data.copy()
>>> val is data
False
赋值与copy的区别在于一个是浅拷贝,一个是深拷贝
使用上的区别:赋值操作,val与data指向同一个空间,data变,val变;copy操作,val与data指向不同的空间,data变,val不变。
>>> data = np.array((1,2,3))
>>> val = data
>>> data[0]=5
>>> val
array([5, 2, 3])
>>> data = np.array((1,2,3))
>>> val = data.copy()
>>> data[0]=5
>>> val
array([1, 2, 3])
transpose:转置 (可以直接.T)
>>> data = np.array(((1,2,3),(4,5,6),(7,8,9)))
>>> data.transpose()
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
>>> data.T
array([[1, 4, 7],
[2, 5, 8],
[3, 6, 9]])
fill:用一个值填充数组
>>> data = np.array((1,2,3))
>>> data
array([1, 2, 3])
>>> data.fill(0)
>>> data
array([0, 0, 0])
flatten:把多维数组转为一维数组
>>> data = np.array(((1,2,3),(4,5,6),(7,8,9)))
>>> data.flatten()
array([1, 2, 3, 4, 5, 6, 7, 8, 9])
concatenate:把多个数组串联起来
>>> a=np.array([1,2,3])
>>> b=np.array([4,5])
>>> c=np.array([7,8,9,10])
>>> np.concatenate((a,b,c))
array([ 1, 2, 3, 4, 5, 7, 8, 9, 10])
>>> a=np.array([(1,2,3),(4,5,6)])
>>> b=np.array([(99,88),(77,66)])
>>> np.concatenate((a,b),axis=1)
array([[ 1, 2, 3, 99, 88],
[ 4, 5, 6, 77, 66]])
多维数组连接的过程中要注意连接轴的大小相同,不然会报错
>>> np.concatenate((a,b),axis=0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: all the input array dimensions except for the concatenation axis must match exactly
newaxis:增加维度
>>> data=np.array([1,2,3])
>>> data.shape
(3,)
>>> data=data[:,np.newaxis]
>>> data.shape
(3, 1)
tile:重复某个数组(类似于Matlab中的remat)
>>> data = np.array([[1,2],[3,4]])
>>> np.tile(data,2)
array([[1, 2, 1, 2],
[3, 4, 3, 4]])
>>> np.tile(data,[2,3])
array([[1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4],
[1, 2, 1, 2, 1, 2],
[3, 4, 3, 4, 3, 4]])
vstack, hstack:数组按列堆叠,按行堆叠
>>> a = np.array([(2,3),(1,4)])
>>> b = np.array([(4,9),(6,2)])
>>> array([[2, 3],
[1, 4],
[4, 9],
[6, 2]])
>>> np.hstack((a,b))
array([[2, 3, 4, 9],
[1, 4, 6, 2]])
NumPy数组的数学操作
加减乘除,乘法是对应元素相乘,点乘使用.dot()
>>> a =np.ones((2,2))
>>> b= np.array([-2,5])
>>> a
array([[ 1., 1.],
[ 1., 1.]])
>>> b
array([-2, 5])
>>> a+b
array([[-1., 6.],
[-1., 6.]])
>>> a-b
array([[ 3., -4.],
[ 3., -4.]])
>>> a*b
array([[-2., 5.],
[-2., 5.]])
>>> a/b
array([[-0.5, 0.2],
[-0.5, 0.2]])
>>> a.dot(b)
array([ 3., 3.])
常量
>>> np.e
2.718281828459045
>>> np.pi
3.141592653589793
>>> np.Inf
inf
>>> np.NaN
nan
sum:求和,可以用数组的成员函数也可以用NumPy的标准函数
>>> a=np.array([2,4,6])
>>> a.sum()
12
>>> np.sum(a)
12
prod:求积,可以用数组的成员函数也可以用NumPy的标准函数
>>> a=np.array([2,4,6])
>>> a.prod()
48
>>> np.prod(a)
48
mean,var,std:平均数,方差,标准差
>>> a=np.array([2,6,13])
>>> a.mean()
7.0
>>> a.var()
20.666666666666668
>>> a.std()
4.5460605656619517
max,min:最大,最小元素
>>> a=np.array([2,6,10])
>>> a.max()
10
>>> a.min()
2
argmax,argmin:最大,最小元素对应的索引值
>>> a=np.array([2,6,10])
>>> a.argmax()
2
>>> a.argmin()
0
ceil,floor,rint:取上限,取下限,四舍五入
>>> a = np.array([1.4,2.5,3.8])
>>> np.ceil(a) #上限
array([ 2., 3., 4.])
>>> np.floor(a) #下限
array([ 1., 2., 3.])
>>> np.rint(a) #四舍五入
array([ 1., 2., 4.])
unique:去除数组中重复的值
>>> a=np.array([2,2,2,3,4,5,6,6,7,8,9,9,10])
>>> np.unique(a)
array([ 2, 3, 4, 5, 6, 7, 8, 9, 10])
clip:把数组里的元素限制到指定范围,即把大于上限的设为上限,小于下限的设为下限
>>> a=np.array([2,2,2,3,4,5,6,6,7,8,9,9,10])
>>> a.clip(0,6)
array([2, 2, 2, 3, 4, 5, 6, 6, 6, 6, 6, 6, 6])
diagonal:取出对角元素
>>> a=np.array([(1,2,3),(4,5,6),(7,8,9)])
>>> a.diagonal()
array([1, 5, 9])
sort:排序
>>> a=np.array([5,8,1,23,2,2,5,4,2,2,2,3,6,9,8,7,41])
>>> a.sort()
>>> a
array([ 1, 2, 2, 2, 2, 2, 3, 4, 5, 5, 6, 7, 8, 8, 9, 23, 41])
还有一些数学运算操作:abs, sign, sqrt, log, log10, exp, sin, cos, tan, arcsin, arccos, arctan, sinh, cosh, tanh, arcsinh, arccosh,和 arctanh,太多了,就不一个一个展示了。
>>> a = np.array([1.4,2.5,3.8])
>>> np.cos(a)
array([ 0.16996714, -0.80114362, -0.79096771])
>>> np.sin(a)
array([ 0.98544973, 0.59847214, -0.61185789])
>>> np.tan(a)
array([ 5.79788372, -0.7470223 , 0.77355609])
>>> np.log10(a)
array([ 0.14612804, 0.39794001, 0.5797836 ])
NumPy矩阵
matrix是array的分支,matrix和array在很多时候都是通用的,你用哪一个都一样。但这时候,官方建议大家如果两个可以通用,那就选择array,因为array更灵活,速度更快。
但是matrix的优势就是相对简单的运算符号,比如两个矩阵相乘,就是用符号*,但是array相乘不能这么用,得用.dot()
array的优势就是不仅仅表示二维,还能表示3、4、5...维,而且在大部分Python程序里,array也是更常用的。
在这里只说一些NumPy矩阵的基本操作
创建矩阵
方法与创建数组类似
>>> data = np.mat([(1,2,3),(2,4,6),(3,5,7)])
>>> data
matrix([[1, 2, 3],
[2, 4, 6],
[3, 5, 7]])
通过array转换为mat
>>> a=np.array([[1,5],[3,6]])
>>> b=np.mat(a)
>>> a
array([[1, 5],
[3, 6]])
>>> b
matrix([[1, 5],
[3, 6]])
元素读取
元素读取与array有所区别
>>> a = np.mat([(1,2,3),(2,4,10),(3,5,3)])
>>> a[0,1]
2
>>> a[0][1]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/Users/zhangxuancheng/anaconda3/lib/python3.6/site-packages/numpy/matrixlib/defmatrix.py", line 284, in __getitem__
out = N.ndarray.__getitem__(self, index)
IndexError: index 1 is out of bounds for axis 0 with size 1
快速的符号运算
matrix.T transpose:返回矩阵的转置矩阵
matrix.I inverse:返回矩阵的逆矩阵
matrix.H hermitian (conjugate) transpose:返回复数矩阵的共轭元素矩阵
matrix.A base array:返回矩阵基于的数组
>>> data = np.mat([(1,2,3),(2,4,10),(3,5,3)])
>>> data.I
matrix([[-9.5 , 2.25, 2. ],
[ 6. , -1.5 , -1. ],
[-0.5 , 0.25, 0. ]])
>>> data = np.mat([(1,2,3),(2,4,10),(3,5,3)])
>>> data.T
matrix([[ 1, 2, 3],
[ 2, 4, 5],
[ 3, 10, 3]])
>>> data.I
matrix([[-9.5 , 2.25, 2. ],
[ 6. , -1.5 , -1. ],
[-0.5 , 0.25, 0. ]])
>>> data.H
matrix([[ 1, 2, 3],
[ 2, 4, 5],
[ 3, 10, 3]])
>>> data.A
array([[ 1, 2, 3],
[ 2, 4, 10],
[ 3, 5, 3]])
矩阵差乘
>>> a = np.mat([(1,2,3),(2,4,10),(3,5,3)])
>>> b = np.mat([(8,2,2),(2,5,10),(3,5,2)])
>>> a*b
matrix([[21, 27, 28],
[54, 74, 64],
[43, 46, 62]])
注意此时.dot()表示叉乘
>>> a.dot(b)
matrix([[21, 27, 28],
[54, 74, 64],
[43, 46, 62]])
NumPy的比较操作
为什么把比较操作拿出来单独说一下?
因为NumPy的比较操作非常方便,而且我最开始不太会用,每次改代码都卡在这里。- -!
比较操作
按照元素比较
>>> a = np.array([1,3,2])
>>> b = np.array([2,6,0])
>>> a>b
array([False, False, True], dtype=bool)
>>> a==b
array([False, False, False], dtype=bool)
>>> a<b
array([ True, True, False], dtype=bool)
any:判断数组内元素是否存在True
all:判断数组内元素是否都为True
>>> a = np.array([True,False,True])
>>> any(a)
True
>>> all(a)
False
logical_and,logical_or,logical_not:对数组的每个元素执行与或非
>>> a = np.array([1,3,2])
>>> b = np.array([2,6,0])
>>> np.logical_and(a > 0, b< 3)
array([ True, False, True], dtype=bool)
>>> np.logical_or(a > 0, b< 3)
array([ True, True, True], dtype=bool)
>>> np.logical_not(a > 0, b< 3)
array([False, False, False], dtype=bool)
>>> c = np.array([False, True, False])
>>> d = np.array([False, True, True])
>>> np.logical_and(c,d)
array([False, True, False], dtype=bool)
>>> np.logical_or(c,d)
array([False, True, True], dtype=bool)
>>> np.logical_not(c,d)
array([ True, False, True], dtype=bool)
where:类似于C的a > b ? a : b
如果a!=2则a*2,否则1/a
>>> a = np.array([1,3,2])
>>> np.where(a!=1,1/a,a*2)
array([ 2. , 0.33333333, 0.5 ])
isnan,isfinite判断是否为 NaN 和 Inf:
>>> a = np.array([1, np.NaN, np.Inf])
>>> np.isnan(a)
array([False, True, False], dtype=bool)
>>> np.isfinite(a)
array([ True, False, False], dtype=bool)
nonzero:返回非零元素的索引
>>> a = np.array([0,3,2,0,2,4,0,1,0,2,0])
>>> a.nonzero()
(array([1, 2, 4, 5, 7, 9]),)
使用比较操作进行访问
前文提到的使用比较符访问元素的实质是用bool类型进行数组的访问,其操作非常多样
>>> data = np.array([1,2,3])
>>> data[data>1]
array([2, 3])
>>> data = np.array([1,2,3])
>>> data[np.logical_and(data>1,data<3)]
array([2])
更为复杂的数学运算
NumPy内部支持线性代数,逻辑,随机数,多项式,傅立叶等多种更为复杂的数学运算,在这里就仅仅给出常用的函数,不再做演示。
线性代数
所有有关线性代数的运算均在np.linalg中
dot 矩阵乘法。两个一维数组计算点乘,两个多维数组计算叉乘
diag 返回矩阵对角线元素
trace 对角线元素和
det 行列式
eig 特征值、特征向量
inv 逆
qr QR分解
svd 奇异值分解
solve 解线性方程Ax=b
lstsq 计算Ax=b的最小二乘解
使用方法:
>>> a = np.array([[4, 2, 1], [5, 3, 7], [4, 12, 1]])
>>> vals,vecs=np.linalg.eig(a)
>>> vals
array([ 12.77471879, 2.48129495, -7.25601373])
>>> vecs
array([[ 0.2296414 , 0.78053395, 0.02907888],
[ 0.64158394, -0.32601736, -0.57313025],
[ 0.7318708 , -0.53336613, 0.81894819]])
随机数
所有有关线性代数的运算均在np.random中
rand 均匀分布的样本值
randint 给定上下限的随机整数
randn 标准正态分布
binomial 二项分布
normal 正态分布
chisquare 卡方分布
gamma Gamma分布
uniform [0,1]之间的均匀分布
poisson 泊松分布
shuffle 洗牌
使用方法:
>>> np.random.normal(1.2,4.0)
1.7491764117192623
>>> np.random.normal(size=10)
array([-0.23043955, 0.62456816, 1.40737576, 0.54461331, 1.90235434,
-1.04516153, -0.00286667, 0.71792032, -0.37120643, 0.68524438])
>>> np.random.poisson(10.0) #10.0表示拉姆达
12
多项式
poly 给定一组根,寻找多项式系数
roots 给顶一组系数,寻找根
polyint 求积分
polyder 求导数
polyval 求函数在某一点的值
polyfit 使用最小二乘法做曲线拟合
polyadd, polysub, polymul, 和 polydiv 函数处理多项式系统的加,减,乘除
使用方法:
>>> #参数均为多项式的系数
>>> np.polyint([2,2,2,1])
array([ 0.5 , 0.66666667, 1. , 1. , 0. ])
>>> np.polyder([ 0.5 , 0.66666667, 1. , 1. , 0. ])
array([ 2. , 2.00000001, 2. , 1. ])
>>> #求x=4时,曲线9x^3-5x^2+2x+2=0的值
>>> np.polyval([9, -5, 2, 2], 4)
506
统计
median 求中值
corrcoef 求相关系数
cov 求协方差
使用方法:
>>> a = np.array([1, 4, 6, 7, 1, 9, 3])
>>> np.median(a)
4.0
>>> np.corrcoef(a)
1.0
>>> np.cov(a)
array(9.285714285714286)
唯一化以及其它的集合逻辑
unique(x) 返回唯一元素
intersect1d(x,y) 交集
union1d(x,y) 并集
in1d(x,y) 布尔型数组,表示x中的元素是否存在于y中
setdiff1d(x,y) 差
setxor1d(x,y) 异或
使用方法:
>>> a = np.array([1, 4, 6, 7, 1, 9, 3])
>>> b = np.array([4, 10, 6, 2, 3, 8, 5])
>>> np.intersect1d(a,b)
array([3, 4, 6])
文件操作
二进制文件: np.save 、np.load
文本文件: np.loadtxt、np.savetxt
二进制文件会存储为.npy的格式
NumPy的Broadcasting(广播)机制
Broadcasting是NumPy矩阵运算的核心,也是与Matlab不同的地方。为什么放到这里呢,因为这属于原理级别的内容,开始并不需要掌握过多,但是debug的时候很有用。
官方的定义:
The term broadcasting describes how numpy treats arrays with different shapes during arithmetic operations. Subject to certain constraints, the smaller array is “broadcast” across the larger array so that they have compatible shapes. Broadcasting provides a means of vectorizing array operations so that looping occurs in C instead of Python. It does this without making needless copies of data and usually leads to efficient algorithm implementations. There are, however, cases where broadcasting is a bad idea because it leads to inefficient use of memory that slows computation.
大概的意思:
广播用以描述numpy中对两个形状不同的阵列进行数学计算的处理机制。较小的阵列“广播”到较大阵列相同的形状尺度上,使它们对等以可以进行数学计算。广播提供了一种向量化阵列的操作方式,因此Python不需要像C一样循环。广播操作不需要数据复制,通常执行效率非常高。然而,有时广播是个坏主意,可能会导致内存浪费以致计算减慢。
说白了:Broadcasting机制的功能是为了方便不同shape的array进行数学运算。
举个栗子:
我们的操作:
>>> a = np.array([1, 2, 3])
>>> b = np.array([2, 2, 2])
>>> a*b
array([2, 4, 6])
但对于Broadcating来说
>>> a = np.array([1, 2, 3])
>>> b = 2
>>> a*b
array([2, 4, 6])
所以:
这解释了为什么(3, )不同于(3, 1)!!!
重点:(3, )不同于(3, 1)!!!
关键:
当操作两个array时,NumPy会逐个比较它们的shape(构成的元组tuple),只有在下述情况下,两array才算兼容:
1.相等
2.其中一个为1,(进而可进行拷贝拓展已至,shape匹配)
那么:
执行 broadcast 的前提在于,两个 ndarray 执行的是 element-wise(按位加,按位减) 的运算,而不是矩阵乘法的运算,矩阵乘法运算时需要维度之间严格匹配。
矩阵乘法运算时需要维度之间严格匹配!!!
需要维度之间严格匹配!!!
严格匹配!!!
其实也就这样,一般报了broadcast的错误时,去检查维度一般都能查出来。
小结
基本上NumPy的常用操作都在这里了,当然肯定还有很多没有总结到。可以看出,NumPy的确是处理数据的好手,NumPy的运行速度非常快,并且在一定程度上弥补了python在运算效率上的不足,仅仅使用numpy就可以实现很多机器学习中比较复杂的算法了,过几天传一个用NumPy写的SVM。
希望大家喜欢这一期,嘿嘿!
网友评论