1、函数用途:
reshape函数的主要功能是将python中用numpy声明的矩阵快速的变形成为自己想要的矩阵样式。
2、注意事项:
和reshape相关的一个属性是shape,如果你对一个矩阵a求a.shape一般返回一个tuple,这个tuple的三个元素依次为矩阵的维度,矩阵行数,矩阵列数。
3、调用方式:
需要明确的是调用reshape函数有两种格式:
第一种:a.reshape(矩阵维度数,矩阵行数,矩阵列数)
第二种:np.reshape(a, 矩阵维度数,矩阵行数,矩阵列数)
我一般喜欢使用第一种调用方式是,所以以下以第一种调用方式说明用法。
4.官方文档:
接下来看下官方文档对reshape函数的解释:
输入以下代码查看reshape函数官方注释
import numpy as np
print(np.reshape.__doc__)
解释如下:
Gives a new shape to an array without changing its data.
Parameters
----------
a : array_like
Array to be reshaped.
newshape : int or tuple of ints
The new shape should be compatible with the original shape. If
an integer, then the result will be a 1-D array of that length.
One shape dimension can be -1. In this case, the value is
inferred from the length of the array and remaining dimensions.
order : {'C', 'F', 'A'}, optional
Read the elements of `a` using this index order, and place the
elements into the reshaped array using this index order. 'C'
means to read / write the elements using C-like index order,
with the last axis index changing fastest, back to the first
axis index changing slowest. 'F' means to read / write the
elements using Fortran-like index order, with the first index
changing fastest, and the last index changing slowest. Note that
the 'C' and 'F' options take no account of the memory layout of
the underlying array, and only refer to the order of indexing.
'A' means to read / write the elements in Fortran-like index
order if `a` is Fortran *contiguous* in memory, C-like order
otherwise.
从文档可以看出,reshape函数的基本参数就是三个,第一个待reshape的矩阵,第二个是想要reshape成什么样子的矩阵,第三个是order参数。
对于reshape函数的操作我们可以将其理解成两步,第一步即取数,第二步即放数,取数按什么顺序,放数就按什么顺序。以上三个参数里面最关键的是order参数,接下来对其进行讲解:
黄色语句的意思是如果你将order指定为‘C’,那么将按照C语言的格式首先从a里面取数然后放置成你指定的格式,请注意这里是一取一放操作,由于C语言按行存储,所以‘C’表示按行取数,然后按你指定的格式按行放数。如果按照官方文档的翻译就叫做,最后一维(矩阵列)变化最快,第一维(矩阵维度)变化最慢,这个意思翻译过来就是按行取了按行放。说的再直白一点就是先列再行后维。
红色语句的意思是如果你将order指定为‘F’,那么将按照Fortran语言的格式首先从a里面取数然后放置成你指定的格式,请注意这里也是一取一放操作,由于Fortran语言按列存储,所以‘F’表示按列取数,然后按你指定的格式按列放数。如果按照官方文档的翻译就叫做,最后一维(矩阵列)变化最慢,第一维(矩阵维度)变化最快,这个意思翻译并不像上面那样容易理解,但直白总结就是取数和放数都是先维再行后列。但这个‘F’选项其实要比‘C’选项复杂一点,接下来你就懂了。
5、实例
先以a为简单的二维矩阵,对order参数为‘C’参数和‘F’分别举例,后面会以a为三维矩阵为例进行升级讨论,假设a=[[1,2,3],[4,5,6]],验证代码如下:
a=np.array([[1,2,3],
[4,5,6]
])
print("a=",a)
y=a.reshape(3,2,order='C')
print("按行取数按行放数y=",y)
y=a.reshape(3,2,order='F')
print("按列取数按列放数y=",y)
实验结果:
a= [[1 2 3]
[4 5 6]]
按行取数按行放数y=
[[1 2]
[3 4]
[5 6]]
将order设置为‘C’的时候,得到y的过程可以用下面这张图来示意,
将order设置为‘F'的时候,得到y的过程可以用下面这张图来示意,
a= [[1 2 3]
[4 5 6]]
y=[[1 5]
[4 3]
[2 6]]
道理大家应该懂了,不过就二维的a,我们再提供一组验证数据:
a=np.array([[1,2,3],
[4,5,6]
])
print("a=\n",a)
#-1表示指定了一个值之后让程序自己计算剩下的另一个值应是什么
y=a.reshape(6,-1,order='C')
print("按行取数y=\n",y)
y=a.reshape(6,-1,order='F')
print("按列取数y=\n",y)
实验结果:
a=
[[1 2 3]
[4 5 6]]
按行取数y=
[[1]
[2]
[3]
[4]
[5]
[6]]
按列取数y=
[[1]
[4]
[2]
[5]
[3]
[6]]
二维的例子举到这里,这下我们开始最关注的三维例子,毕竟图像总是三维的矩阵,经常操作的是三维的矩阵。假设我们想将2*2*3(第一个2表示有两个2*3的二维矩阵,后面的2和3分别表示单个矩阵行为2,列为3)的三维矩阵
a=[[1,2,3],
[4,5,6]],
[[7, 8, 9],
[10,11,12]]
]
变为如下的矩阵y,该如何操作
y=[[ 1]
[ 2]
[ 3]
[ 4]
[ 5]
[ 6]
[ 7]
[ 8]
[ 9]
[10]
[11]
[12]]
这个实现还是比较容易的,大家可能会写出如下的代码来实现:
import numpy as np
a=np.array([[[1,2,3],
[4,5,6]],
[[7, 8, 9],
[10,11,12]]
]
)
print(a)
print(a.shape)
#注意这里下面这句代码如果我写成,y=a.reshape(1,#a.shape[0]*a.shape[1]*a.shape[2],1,order='C')结果会有不同,后面将会用到
y=a.reshape(a.shape[0]*a.shape[1]*a.shape[2],1,order='C')
print(y.shape)
print(y)
实验结果
a=
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
a的shape= (2, 2, 3)
y=
(12, 1)
y的shape= [[ 1]
[ 2]
[ 3]
[ 4]
[ 5]
[ 6]
[ 7]
[ 8]
[ 9]
[10]
[11]
[12]]
以上结果很好推断,按照‘C’的取和放方法,可知是先列再行后维,所以不难得到以上结果,但是如果我想得到的是:
y=[[ 1]
[ 7]
[ 4]
[ 10]
[ 2]
[ 8]
[ 5]
[ 11]
[ 3]
[9]
[6]
[12]]
这个代码该怎么写呢?其实这个代码也很简单,只需要将上面代码中的‘C’改为‘F’即可,因为根据我们总结的‘F’的规则为先维再行后列不难推断出它的结果就是我们想要的这个结果。
实验代码:
import numpy as np
a=np.array([[[1,2,3],
[4,5,6]],
[[7, 8, 9],
[10,11,12]]
]
)
print("a=\n",a)
print("a的shape=",a.shape)
y=a.reshape(a.shape[0]*a.shape[1]*a.shape[2],1,order='F')
print("y=\n",y.shape)
print("y的shape=",y)
最终目标
最难的是我们有时候想要先按列串接一个矩阵,然后再串接第二个矩阵,即想要得到如下结果:
y=[[ 1]
[ 4]
[ 2]
[ 5]
[ 3]
[ 6]
[ 7]
[10]
[ 8]
[11]
[ 9]
[12]]
显然将order参数设置为‘C’和‘F’都不能满足要求,那怎么办呢?
看以下代码:
import numpy as np
a=np.array([[[1,2,3],
[4,5,6]],
[[7, 8, 9],
[10,11,12]]
]
)
print("a=\n",a)
print("a的shape=",a.shape)
y=a.reshape(2,a.shape[1]*a.shape[2],1,order='F')
print("y=\n",y.shape)
print("y的shape=",y)
print(y.reshape(y.shape[0]*y.shape[1]*y.shape[2],1,order='C'))
实验结果:
a=
[[[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]]]
a的shape= (2, 2, 3)
y的shape=(2, 6, 1)
y=[[[ 1]
[ 4]
[ 2]
[ 5]
[ 3]
[ 6]]
[[ 7]
[10]
[ 8]
[11]
[ 9]
[12]]]
想要的结果为:
[[ 1]
[ 4]
[ 2]
[ 5]
[ 3]
[ 6]
[ 7]
[10]
[ 8]
[11]
[ 9]
[12]]
可以看出上面代码最巧妙的地方就是这句:
y=a.reshape(2,a.shape[1]*a.shape[2],1,order='F')
它的意思是保持矩阵个数即维不变,对每一个矩阵进行‘F’操作,那么结果可想而知就是这个了:
[[[ 1]
[ 4]
[ 2]
[ 5]
[ 3]
[ 6]]
[[ 7]
[10]
[ 8]
[11]
[ 9]
[12]]]
这个结果从它的shape就可以看出,它是一个2*6*1的三维矩阵,那么如果再对它做一个‘C’操作,你想想那就是先列再行后维,其实就是上面最终想要的结果:
[[ 1]
[ 4]
[ 2]
[ 5]
[ 3]
[ 6]
[ 7]
[10]
[ 8]
[11]
[ 9]
[12]]
至此难题解决。
6、总结:
最重要的还是两点:
1、shape[0]、shape[1]、shape[2]依次存放矩阵维、行、列数目;
2、‘C’:先列再行后维
‘F’:先维再行后列
如果你深入理解了这两句,再结合上矩阵个数有时可以先让它保持不变,先进行每个矩阵内部变换,然后在进行矩阵间的串接,就可以实现出各种想要的矩阵形式,其实最后一个例子也是我们经常要用到的例子,希望大家能学会。楼主任务完成!