hstack()函数通常被我们称为行连接函数,即按行连接数组,
但它真的是按行连接吗?
对于三维及以上的数组,行又指什么呢?
我们先来看几段代码(代码后面是输出):
import numpy as np
a=np.array([1,2,3])
b=a.copy()
print(np.hstack((a,b)))
[1 2 3 1 2 3]
import numpy as np
a=np.array([[1,2,3],[4,5,6]])
b=a.copy()
print(np.hstack((a,b)))
[[1 2 3 1 2 3]
[4 5 6 4 5 6]]
import numpy as np
a=np.array([[[1,2,3],[4,5,6]],[[7,8,9],[10,11,12]]])
b=a.copy()
print(np.hstack((a,b)))
[[[ 1 2 3]
[ 4 5 6]
[ 1 2 3]
[ 4 5 6]]
[[ 7 8 9]
[10 11 12]
[ 7 8 9]
[10 11 12]]]
对于一维及二维数组,我们可以看到,hstack()函数确实是常规意义上的按行连接。
但是对于三维数组,hstack()函数并没有将他们按常规意义上的行连接,
而是按其第二个维度连接。
我们不妨将它们放到坐标系中去看看,
首先,
一维数组的情况:
连接后
二维数组连接后的情况:
三维连接前的情况:
连接后(为了表现清楚,这里用不同颜色表示了z轴坐标不同的数,下面四维图同理):
从这张图里,我们可以清楚地看到它其实是按y轴连接,而非此前的x轴。
但如果我们把x轴给压没了(比如:认为[1 2 3]这样一个数组是一个整体元素),
这样三维数组变成二维;
相应地,z轴变了y轴,y轴变成x轴,
hstack()函数按新的x轴连接,倒也勉强称地上“按行连接”;
这里给出一个猜测:
hastack()函数会将多维数组都视为二维数组,最高两维分别视为y轴与x轴,并按”行“连接。
接下来,我们拿四维数组的情况验证一下这个猜测。
import numpy as np
a=np.arange(16).reshape(2,2,2,2)
b=a.copy()
print(np.hstack((a,b)))
预期它们连接后的图片(按z轴连接):
这里的图片转译成数组语言后是这样的:
[[[[ 0 1]
[ 2 3]]
[[ 4 5]
[ 6 7]]
[[ 0 1]
[ 2 3]]
[[ 4 5]
[ 6 7]]]
[[[ 8 9]
[10 11]]
[[12 13]
[14 15]]
[[ 8 9]
[10 11]]
[[12 13]
[14 15]]]]
这与我们的代码输出完全一致!
这里官方文档链接:numpy.hstack()
经试验,vstack()与hactack()一样将高维数组视为二维数组运算。
不同的是,它是按最高维连接,而非第二维。
值得一提的是,hstack()并不会改变数组的维度。
而用Vstack()对一维 数组进行合并时则会使其变为二维数组。
numpy.vstack()
先来看一段代码:
import numpy as np
a=np.arange(5)
b=np.arange(5,10)
c=np.stack((a,b),axis=0)
d=np.stack((a,b),axis=1)
print(c)
print('------')
print(d)
[[0 1 2 3 4]
[5 6 7 8 9]]
------
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
可以看到stack()函数的功能依然是连接数组。
与hstack() vstack()函数不同的是,
stack()函数得到的数组比起输入的数组一定会多一个维度。
axis=0时,直接增加了一个维度,将合并前的数组们作为这个维度的元素;
如:stack((a,b),axis=0)==[a b] (a,b是待合并的数组们)
axis=1时,并不直接在外面增加一个维度,而是对应顺序重组了一维,再并上。
在这里,我们先将[0 1 2 3 4] [5 6 7 8 9]最外面的括号拿掉,再依次并上对应位置的数,
如[0 5] [1 6]…最后再整个并起来。
眼神好的小伙伴们可能已经发现了,
axis=0与axis=1时的函数输出,是对称的。
我们来看一段代码跟输出 :
(这一段代码是跟在上一段后面的)
print(c.T)
print('-----')
print(c.T==d)
[[0 5]
[1 6]
[2 7]
[3 8]
[4 9]]
-----
[[ True True]
[ True True]
[ True True]
[ True True]
[ True True]]
我们看到,d是c的转置。
我们再来看看两个二维数组合并的情况。
import numpy as np
a=np.arange(6).reshape(2,3)
b=np.arange(6,12).reshape(2,3)
c=np.stack((a,b),axis=0)
d=np.stack((a,b),axis=1)
e=np.stack((a,b),axis=2)
print(c)
print('-----')
print(d)
print('-----')
print(e)
[[[ 0 1 2]
[ 3 4 5]]
[[ 6 7 8]
[ 9 10 11]]]
-----
[[[ 0 1 2]
[ 6 7 8]]
[[ 3 4 5]
[ 9 10 11]]]
-----
[[[ 0 6]
[ 1 7]
[ 2 8]]
[[ 3 9]
[ 4 10]
[ 5 11]]]
axis参数为0时,依旧是直接接起两个数组。
axis参数为1时,可以看成是在axis=0 的情况下再转置z轴和y轴。
axis参数为2时,可以看成是在axis=1 的情况下再转置y轴和x轴。
对于stack()函数,
我们看到,
在axis参数为0 时,它新增一维并在新的维度上直接连接两个数组。
在axis参数为1 时,它在axis=0 的基础上转置了最高两维。
在axis参数为2 时,它在axis=1 的基础上转置了第二和第三维。
由于三维数组只有三维,故对于二维数组用stack()合并的情况,axis参数最大为2。
下面我们再看一下三个三维数组的合并。
import numpy as np
a=np.arange(8).reshape(2,2,2)
b=np.arange(8,16).reshape(2,2,2)
c=np.arange(16,24).reshape(2,2,2)
print(np.stack((a,b,c),axis=0))
[[[[ 0 1]
[ 2 3]]
[[ 4 5]
[ 6 7]]]
[[[ 8 9]
[10 11]]
[[12 13]
[14 15]]]
[[[16 17]
[18 19]]
[[20 21]
[22 23]]]]
print(np.stack((a,b,c),axis=1))
[[[[ 0 1]
[ 2 3]]
[[ 8 9]
[10 11]]
[[16 17]
[18 19]]]
[[[ 4 5]
[ 6 7]]
[[12 13]
[14 15]]
[[20 21]
[22 23]]]]
print(np.stack((a,b,c),axis=2))
[[[[ 0 1]
[ 8 9]
[16 17]]
[[ 2 3]
[10 11]
[18 19]]]
[[[ 4 5]
[12 13]
[20 21]]
[[ 6 7]
[14 15]
[22 23]]]]
print(np.stack((a,b,c),axis=3))
[[[[ 0 8 16]
[ 1 9 17]]
[[ 2 10 18]
[ 3 11 19]]]
[[[ 4 12 20]
[ 5 13 21]]
[[ 6 14 22]
[ 7 15 23]]]]
这是axis=0时的图,大家可以按之前的规则试着读一读,加深一下理解,读的顺序:(x,y,z,t)。
按之前的想法:
axis=1 时,转置最高两维,那么读取顺序是:(x,y,t,z)
axis=2 时,转置第二维与第三维,顺序:(x,t,y,z)
axis=3 时,转置第三维与第四维,顺序:(t,x,y,z)
(按这样的顺序读出来的数组与我们的代码输出是完全一致的。)
可以看到,axis参数其实只是改变了t轴(新增轴)的位置,并没有使原轴的相对顺序发生改变。
换而言之,stack()函数只是合并数组后新增了一轴,
而这个新增的轴增在哪个位置,靠axis参数决定。
或许在计算机内部,axis参数也并没有改变数据本身,只是改变了数据被读取的方式。
又或者可以试着用这种方式来管理多维数据。
官方文档:numpy.stack()