1、向量与矩阵的正确表示。
2、向量与矩阵的数学四则运算;
一、Python中的数据表示
只考虑数字类型的数据(其他的类型与数学运算关系不大,这里不考虑)。
(1)标量数据
#标量数据
scalar=20
(2)元组与列表
#元组列表数据
vector_1=[1,2,3,4]
vector_2=(1,2,3,4)
vector_3=np.array((1,2,3,4))
Python语言内置了元组与列表的数据表述类型(其区别在于稳定与不稳定的区别),这今后主要使用科学计算库,所以使用了numpy中的封装类型。可以使用Python内置列表类型构造numpy的ndarray对象,ndarray可以提供更加强大的运算。
注意:在元组与列表的使用选择上,建议使用列表(list)。
(3)二维与多维列表
#2.二维与多维数据
matrix_1=[
[1,2,3], [4,5,6],[7,8,9]]
matrix_2=(
(1,2,3), (4,5,6), (7,8,9))
matrix_3=(
(1,2,3), (4,5,6), [7,8,9])
vector_4=np.array([
[1,2,3], [4,5,6],[7,8,9]])
(4)元组、列表与标量的运算
元组、列表与标量的运算只支持乘法(*),其他运算+、-、%、//、**都不支持。
#元组、列表与标量的运算
#print(5-truple_1) #不支持+-
#print(list_1+5) #不支持+-
print(5*truple_1)#5倍克隆 (1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4)
print(list_1*5)#5倍克隆 [1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4]
#print(5/truple_1) #不支持/ // % **
#print(list_1**5) #不支持/ // % **
(5)元组、列表间运算
元组、列表间只支持+运算,其他运算(*、=、%、//、**)不支持
#元组、列表间的运算
print(truple_1+truple_2)#(1, 2, 3, 4, 0.1, 0.2, 0.3, 0.4)
#print(truple_1-truple_2)#不支持
print(truple_1*truple_2)#不支持
(6)向量与矩阵表示
使用一维ndarray表示向量,使用二维ndarray表示矩阵。由于内置元组与列表类型的运算比较简单,所以向量与矩阵,都使用numpy中的ndarray类型,不直接使用原元组与列表(元组与列表也支持一些数学四则运算)。从上面的运算我们可以看到这点。
【结论】:
【1】 不使用内置类型元组与列表表示向量与矩阵。
【2】不使用一维ndarray对象表示矩阵。
【3】矩阵使用二维ndarray对象,向量使用一维ndarray对象。
二、ndarray类型与向量、矩阵
numpy官网:http://www.numpy.org
numpy1.14.5的参考手册下载:【 下载 】
numpy1.14.5的用户教程下载:【 下载 】
1、ndarray类型
(1)ndarray构造器说明
如果没有buffer参数,则只有shape,dtype与order三个参数被使用,其他参数没有作用。
如果buffer参数被设置,则所有参数被使用,如果没有设置,则使用参数的默认值。
参数说明:
【shape】:数组的维数,也就是向量、矩阵的形状,用元组表示。
【dtype】:数组的类型;
【buffer】:数组的数据来源缓冲;
【offset】:数缓冲数据的开始获取位置;
【strides】:数据的步长,要求一个元组,元组对应数组维数的大小;
【order】: 数组数据取值的优先顺序,C风格(行优先),Fortran风格(列优先)
(2)构造器使用例子
其中重点理解dtype,buffer,offset,strides,order。
【dtype】需要是numpy中定义的数据类型,numpy定义的类型是使用python内置类型规范后重定义的。
【bufder】一般对缓冲使用字节码,不考虑维数,都是线性的字节流,元组与列表表示为缓冲字节流,可以直接使用ndarray对象,代码中array是一个创建ndarray对象的函数工具(下面会介绍这些工具,理解ndarray对象的结构后,使用这些工具非常简便,根据不同情况可以提高效率)。
【offset】是缓冲开始位置,单位是字节(byte),根据buffer中数据项大小确定。一般是buffer数据项大小的倍数,比如:0,8,16。
【strides】是数组的取值步长,隔多长取值,单位是字节。 一般也是数据项大小的倍数,比如对int类型而言就是0,8,16等。类型元组,对应数组维数大小,表示对应纬度的取值不长。
【order】表示取值的优先方式,「C」优先取行,「F」优先取列。
(3)理解dtype数据类型
在numpy中使用数据类型,兼容python的数据类型,同时定义了新的数据类型dtype。
下面是来自官方文档对numpy的数据类型的定义与说明:
【bool类型】
【int类型】
【无符号unsigned int类型】
【float类型】
【复数类型】
【对象类型】
(4)理解strides
【代码】
v=np.ndarray(shape=(3,3),#数组的维数大小,矩阵、向量的形状
dtype=np.int,#数组的元素类型
buffer=np.array((1,2,3,4,5,6,7,8,9)),#数组数据的存放缓冲(字节码格式)
offset=0,#数组数据缓冲的有效开始位置
strides=(24,8),#数组数据缓冲的数据获取步长
order='C')#数组的显示格式,C风格与Fortran风格
【理解】
其中strides=(24,8),因为buffer中使用的数据类型是int_,该类型大小是8,所以strides的数据是8的倍数。(24,8)表示行按照隔3个整数取值,列按照隔一个整取值。运行的结果为:
[ [1 2 3]
[4 5 6]
[7 8 9] ]
行的开始,按照3个间隔取值,就是1,4,7;列按照1个间隔取值分别从1,4,7后面开始取值。注意要确保缓冲是足够的。
如果buffer是(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16)
问:strides=(32,8)构造什么样的数组?
[ [ 1 2 3],[ 5 6 7],[ 9 10 11] ]
问:strides=(32,24)构造什么样的数组?
[ [ 1 4 7],[ 5 8 11],[ 9 12 15] ]
附加:整数类型的数据类型长度获取结果:
print(np.int_().itemsize) #8
print(np.byte().itemsize) #1
print(np.int8().itemsize) #1
print(np.int16().itemsize) #2
print(np.int32().itemsize) #4
print(np.int64().itemsize) #8
(5)理解C风格与Fortran风格
【代码】
【运行结果】
F风格结果:
[ [1 3 5 7]
[2 4 6 8] ]
C风格结果
[ [1 2 3 4]
[5 6 7 8] ]
【理解】
一般在设置strides的情况下,order就不起效果,因为是用户定制的取值风格。一但设置strides情况下,就采用两种取值风格:Fortran风格与C风格。
【Fortran风格】:按照缓冲的顺序,从第1列,第2列,......,取值填充数组。
【C风格】:按照缓冲的顺序,从第1行,第2行,......,取值填充数组。
2、ndarray构造工具
(1)构建空、0与1值数组
【例子】
运行效果
(2)使用已有数据构建数组
【例子】略
(3)使用数组范围构建数组
【例子】略
(4)构建特殊矩阵
【例子】略
(5)直接使用数据构建矩阵
【例子】略
(6)构建数据集数组
【例子】略
(7)构建字符数组
【例子】略
提示:上述函数的使用比较简单,结果也是显而易见的,这里省略。
三、构建随机数组
在numpy中提供了随机数组构建工具,如下:
实际上numpy.random提供更多的随机分布来构建数组或者矩阵,这里列出一部分,我们常用会使用uniform,normal(高斯正态分布)等。
如果是专门针对矩阵,则官方参考文档列出如下相关参考:
四、向量与矩阵的四则运算
上面讲述了数组对象ndarray对象的构建,在今后的数学运算中,我们都采用ndarray表示向量与矩阵。
向量与矩阵本身区别不大,向量我们都称为行矩阵,或者列矩阵。
向量与矩阵的运算我们考虑三类:标量与向量,向量与向量,向量的函数运算。
首先构造一个向量矩阵与普通矩阵:
m_1_3=np.array((1,2,3))
m_3_4=np.array([
[1,2,3,4],
[4,5,6,7],
[7,8,9,10]
])
1、标量与ndarray对象的四则运算
标量与ndarray对象运算,等于变量与数组的每个元素对应运算,+,-,*,/,//,**都支持。
【代码】
【结果】
2、ndarray对象与ndarray对象的四则运算
(1)形状相同的运算
1)要求形状不同的不能运算。
2)形状相同可以运算,运算规则是ndarray数组对应元素相运算,运算支持+,-,*,/,//,**。
【例子】
对乘积来说就是数学中的【哈达马积(hadamard product)】
下面是乘法,除法,整除,求余,幂运算的例子
运行结果如下:
注意:
1)ndarray的四则运算支持,就可以支持函数运算,因为大部分函数中使用的运算符号,还是基于经典的四则运算意义。
2)所以在函数中使用向量与矩阵,一定要清楚对应的运算的含义。
尽管对普通意义的四则运算,只支持形状相同的向量与矩阵。对不同形状的矩阵或者向量,只对乘法赋予更多的定义:内积与Kronecker积。这两个积支持不同形状的向量与矩阵的运算,尽管还是有条件要求,换句话说就是:向量可以与矩阵做内积乘积与Kronecker积。
三种乘积的表示如下:
(2)内积
【条件】
被乘矩阵(向量)的列数必须与乘矩阵的行数相等。表示为公式就是如下:
注意:如果不写出表达式,则默认表示内积,因为内积是矩阵与向量最常见的运算,而不是哈马达积与克罗内克积。
【运算规则】
k×m的矩阵A与m×n的矩阵相乘B,得到k×n的新矩阵C,新矩阵的元素的值为:
矩阵的内积实现:dot函数介绍:
【例子】
运行结果:
注意:在numpy库中也定义了哈马达积的集中实现方式。
(3)Kronecker积(直积/张量积)
该乘积方式以德国数学家利奥波德·克罗内克命名。Kronecker积的定义如下:
numpy的Kronecker积实现:kron函数参考
Kronecker积分左右,其定义就是每个元素都全部相乘,m×n形状的矩阵与p×q形状的矩阵做Kronecker积,得到形状为mp×nq的矩阵。
【例子】
运行结果
提示:在数学上定义了两个矩阵的Khatri-Rao积。每种矩阵乘积都有其物理与现实意义,如果在深度学习中用到这个乘积,在详细阐述,目前还没有见到用过。
注意:
1)我们这里关注Kronecker积的目的在于,在卷积神经网络的池化层会使用这类运算。
2)numpy提供的outer函数与Kronecker积也有差异,后面专门主题说明。
本主题的代码下载:【 代码 】
本主题的公式下载:【 公式 】