关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究

hstack()

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()函数并没有将他们按常规意义上的行连接,
而是按其第二个维度连接。

我们不妨将它们放到坐标系中去看看,
首先,
一维数组的情况:
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第1张图片
连接后
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第2张图片
二维数组连接后的情况:
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第3张图片
三维连接前的情况:
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第4张图片
连接后(为了表现清楚,这里用不同颜色表示了z轴坐标不同的数,下面四维图同理):
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第5张图片
从这张图里,我们可以清楚地看到它其实是按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)))

做连接操作前的四维数组:
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第6张图片

预期它们连接后的图片(按z轴连接):
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第7张图片
这里的图片转译成数组语言后是这样的:

[[[[ 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()

经试验,vstack()与hactack()一样将高维数组视为二维数组运算。
不同的是,它是按最高维连接,而非第二维。

值得一提的是,hstack()并不会改变数组的维度。
而用Vstack()对一维 数组进行合并时则会使其变为二维数组。

numpy.vstack()



Stack()

先来看一段代码:

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轴。

看图:
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第8张图片
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第9张图片
关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第10张图片

对于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]]]]

关于python numpy包 hastack() vstack() stack()三个函数功能的实验性探究_第11张图片
这是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()

你可能感兴趣的:(python,numpy)