首页 > 其他分享 >数据中shape变换会用到的函数

数据中shape变换会用到的函数

时间:2024-05-05 17:22:05浏览次数:25  
标签:变换 用到 维度 shape 数组 np array stack axis

前言:在处理数据的时候,经常需要存储、读取、变换等等操作,其中一个很重要的方面就是对数据进行升维和降维,如何正确的、按照我们自己的处理思路完成数据的操作非常重要,在本文中我们简单了解一些经常使用的函数。

concatenate

沿着现有的轴连接一系列数组。无论是numpy中、还是pytorch、tensorflow中,concatenate的用法都是相同的,知只是一些参数名字表达不同。在这里我们以numpy为例,结合官方文档做一些通俗易懂的解释。

numpy.concatenate((a1a2...)axis=0out=Nonedtype=Nonecasting="same_kind")

  - (a1, a2, ...):可以同时concat多个,shape要一致,除了要连接的axis那一维度(当axis参数为0,形如(m,k)和形如(n,k),在现有轴上concat后是(m+n,k)不是吗?对于本来就要连接的那一维度形状是不限制的,但是为了保证concat后的形状仍然是统一的,所以shape要保持一致)

  - axis:整数,可选,默认是0。如果特别设置axis=None,会把所有数据先展平再连接。

  - out:可选,指定一个已经存在的数组来存储 concatenate 操作的结果。这可以避免分配新的内存,从而在某些情况下提高性能。对新手来说还有一个功能就是用于验证concat后的shape结果是否是自己所想要达到的结果。

  - dtype:可选,指定数组数据的数据类型。注意1:不能和out参数结合使用,因为out已经指定了一个数据类型。注意2:如果数组中原本的数据类型各不相同,那么指定数据类型后会区分情况,如str的内容是数值,转换到int是可以的,否则会报错,也就是说dtype会对所有的数据进行指定。

  - casting:可选{‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’},默认为same_kind,一般和dtype配合使用,制定了在对数据进行类型转换时的规则。

(大多数场景下仅指定(a1, a2, ...)和axis参数即可)

# 简单例子

a = np.array([[1, 2], [3, 4]])
b = np.array([[5, 6]])
np.concatenate((a, b), axis=0)
array([[1, 2],
       [3, 4],
       [5, 6]])
np.concatenate((a, b.T), axis=1)
array([[1, 2, 5],
       [3, 4, 6]])
np.concatenate((a, b), axis=None)
array([1, 2, 3, 4, 5, 6])
# out参数的使用方法

a = np.array([1, 2, 3])
b = np.array([4, 5, 6])

# 创建一个足够大的输出数组
out_array = np.empty((6,), dtype=int)  # 确保有足够的空间和适当的数据类型

# 使用 out 参数进行合并
np.concatenate((a, b), out=out_array)

最后,当使用 np.concatenate 来合并两个或多个 MaskedArray 时,输出的数组将不再是 MaskedArray,并且合并后的数组不会继承任何输入数组的掩码。换句话说,即使输入数组中的某些数据被掩蔽,输出数组也会将这些数据视为普通数据,不再标记为掩蔽。如果你的数据中包含 MaskedArray 并且你希望保留掩码信息,你需要在使用 np.concatenate 后手动处理或恢复这些掩码。这通常意味着你需要重新创建一个 MaskedArray 并应用原始的掩码或根据需要生成一个新的掩码。

# 创建两个 MaskedArray,其中包含一些掩蔽元素
a = ma.array([1, 2, 3], mask=[0, 1, 0])
b = ma.array([4, 5, 6], mask=[1, 0, 0])

# 使用 np.concatenate 合并这两个数组
result = np.concatenate((a, b))

# 查看合并后的结果
print("合并后的数组:", result)
print("数组的掩码:", ma.getmaskarray(result))  # 这将显示没有掩码

# 重新应用掩码
new_mask = np.concatenate((a.mask, b.mask))
result_masked = ma.array(result, mask=new_mask)

print("重新掩蔽后的数组:", result_masked)

最后对于使用concat的一点快速思考的trick,axis设置的那个维度是长度可以不一致的,axis所在的那个维度是各数据长度的和,其它的长度不变,如axis=1,(2,3,3)和(2,4,3)->(2,3+4,3)==(2,7,3)


 

stack

stack的的含义是在一个新的轴(维度)上连接一系列张量,无论是numpy中、还是pytorch、tensorflow中,stack的用法都是相同的,只是一些参数名字表达不同。

numpy.stack(arraysaxis=0out=None*dtype=Nonecasting='same_kind')

  - arrays:多个shape相同的数组,值得注意的是,这里的每个数组shape一定要一致

  - axis:可选,默认为0,新添加轴所在的位置

  - out: 可选,和上一个concatenate函数参数意义一致,不再赘述

  - dtype:可选,指定堆叠后的数据类型

  - castring: {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional

 与concatenate最大的不同就是,stack会产生一个新轴,新轴的长度就是堆叠前数组的个数。在pytorch中该函数的实现是基于调用concat函数,是在指定维度上unsqueeze然后再在该维度上进行concat。

 所以我更觉得,在这里要理解stack后数据的组织形式,即是如何对数据进行切分和粘接的

# 从1维到2维
a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) np.stack((a, b)) array([[1, 2, 3], [4, 5, 6]]) np.stack((a, b), axis=-1) array([[1, 4], [2, 5], [3, 6]])
# 从二维到三维
arrays = [np.random.randn(3, 4) for _ in range(10)]
np.stack(arrays, axis=0).shape
(10, 3, 4)
np.stack(arrays, axis=1).shape
(3, 10, 4)
np.stack(arrays, axis=2).shape
(3, 4, 10)

 

column_stack

numpy.column_stack(tup)

  - tup: 一些1-D维或者2-D的数组,1-D和2-D混合也可

当输入为多维数组时,hstackcolumn_stack 的行为是一致的。但当输入数组为有且只有一维数组时,hstack 会将它们简单地并排放置,就像concat一维数组一样,而不会将其视为列向量。而column_stack会把所有的1-D数组先转换为列向量(或者简单的说是转置也一样),然后再按照列进行拼接

a = np.array((1,2,3))
b = np.array((2,3,4))
np.column_stack((a,b))
array([[1, 2],
       [2, 3],
       [3, 4]])
z = np.ones((3,3))
x = np.zeros(3)
print(np.column_stack((z,x)))

[[1. 1. 1. 0.]
 [1. 1. 1. 0.]
 [1. 1. 1. 0.]]

上述第一个例子如果把column_stack 替换为hstack,结果会是[1,2,3,2,3,4]

上述第二个例子如果把column_stack 替换为hstack就会报错,因为两个数组的shape不一致(不符合规则)。


 

row_stack

又名vstack,等同于concatenate指定了沿着第一列进行拼接

numpy.row_stack(tup, *, dtype=None, casting='same_kind')

  - tup:除了第一维外的形状必须相同;当是一位数组时,各个数组的的长度必须相同   - dtype:与上述所有的参数要求一致(有趣的是,在官方文档中也说明了不能用out参数公用,但是官方文档中其实并没有out参数)   - castring: {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional   - return:至少是2-D的数组,所以该函数会把1维的数组升维到2维,但是在高维(2维以上又不会添加新轴,等同于concatenate-axis=0)
# 1维长度相同,并返回2-D数组
a = np.array([1, 2, 3]) b = np.array([4, 5, 6]) np.vstack((a,b)) array([[1, 2, 3], [4, 5, 6]])
# 高维数组等同于concatenate指定axis为0,两个(3,1)stack后变为(6,1)
a = np.array([[1], [2], [3]]) b = np.array([[4], [5], [6]]) np.vstack((a,b)) array([[1], [2], [3], [4], [5], [6]])

 

expand_dims/unsqueeze

在现有的数据维度上增加一个新的维度,正确理解维度的添加方式是理解stack的的第一步、

numpy.expand_dims(a, axis)

  - array_like: 输入n维数组

  - axis: 整数型or元组,新增轴所在位置

# 从1维到2维
x = np.array([1, 2]) x.shape (2,)
# The following is equivalent to x[np.newaxis, :] or x[np.newaxis]: y = np.expand_dims(x, axis=0) y array([[1, 2]]) y.shape (1, 2)
# The following is equivalent to x[:, np.newaxis]: y = np.expand_dims(x, axis=1) y array([[1], [2]]) y.shape (2, 1)

axis 参数是一个元组时,函数会按照元组中指定的每个轴的顺序依次添加新维度。这样,你可以一次性扩展数组的多个维度,而不需要多次调用 expand_dims

当原始数组为(3,4):

axis=(0, 2)

  1. 首先在原数组最前面(最外层)添加一个新维度,数组形状从 (3, 4) 变为 (1, 3, 4)
  2. 然后在新的第三维添加一个新维度,数组形状从 (1, 3, 4) 变为 (1, 3, 1, 4)

axis=(2, 0)

  1. 首先在原数组的第三个轴位置(实际上是在最后,因为原数组只有两维)添加一个新维度,数组形状从 (3, 4) 变为 (3, 4, 1)
  2. 然后在最外层(现在是新的第一维)添加一个新维度,数组形状从 (3, 4, 1) 变为 (1, 3, 4, 1)

 

newaxis

numpy.newaxis

在 Python 的 NumPy 库中,np.newaxis 是一个非常有用的工具,用于增加数组的维度。它通常用在索引操作中,来改变现有数组的形状,从而添加一个新的轴(维度)。他和上述的expand_dims/unsequzzez的效果是一致的,我的感受是这样更显式一些。

a = np.array([1, 2, 3])
# 在数组前面添加一个新的轴,变成1x3的二维数组
row_vec = a[np.newaxis, :]
>>>
[[1,2,3]] # 在数组后面添加一个新的轴,变成3x1的二维数组 col_vec = a[:, np.newaxis]
>>>
[[1],
[2],
[3]]

 有趣的是,numpy.newaxis还能作为一个None的常量/别名

print(newaxis is None)
True
print(np.newaxis)
None

 

squeeze

维度压缩是expand_dims/unsqueeze的反操作,顾名思义就是在现有维度的层数上再减少一维

numpy.squeeze(a, axis=None)

  - array_like:Input data.
  - axis:None or int or tuple of ints, optional,默认参数是None 当使用expand_dims时,新添加的轴的长度是1,同理,去压缩的维度也一定得是1,当axis=None时,所有长度为1的维度都会被移除,官方文档中给出如果一个ndarray的所有维度长度都为1,那么不指定维度后会退化为数组:0 d array
x = np.array([[[0], [1], [2]]])
x.shape
(1, 3, 1)
# axis=None
np.squeeze(x).shape
(3,)
# axis=0/1/2
np.squeeze(x, axis=0).shape
(3, 1)
np.squeeze(x, axis=1).shape
Traceback (most recent call last):
...
ValueError: cannot select an axis to squeeze out which has size not equal to one
np.squeeze(x, axis=2).shape
(1, 3)
# 所有的维度都为1
x = np.array([[1234]])
x.shape
(1, 1)
np.squeeze(x)
array(1234)  # 0d array
np.squeeze(x).shape
()
np.squeeze(x)[()]
1234

 

reshape

在不更改数组数据的情况下为数组提供新形状。这个函数有点像是上述两个函数的升级款,如果想做,也是能做到上述两个函数做的事。

numpy.reshape(a, newshape, order='C')

   - a:array_like   - newshape:整数或者整数型元组。当是整数时,意味着把数据规整为1维,此时参数可以指定为-1,意味着由函数自动推理总元素数,或者直接指定整数为元素个数,其它整数会报错。当是元组时,就意味着转换为指定的shape,其中也可以设置某一维度为-1,这意味着由函数推算该维的的长度。   - order: 可选,{‘C’, ‘F’, ‘A’},默认为’C‘。这里指定了数组重塑操作中的对元素的读取顺序,’C‘意味着按照行展开读取,即更容易理解的哪一种顺序,’F‘是按照列的形式展开读取。 ‘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.
np.reshape(a, (2, 3)) # C-like index ordering
array([[0, 1, 2],
       [3, 4, 5]])
np.reshape(np.ravel(a), (2, 3)) # equivalent to C ravel then C reshape
array([[0, 1, 2],
       [3, 4, 5]])
np.reshape(a, (2, 3), order='F') # Fortran-like index ordering
array([[0, 4, 3],
       [2, 1, 5]])
np.reshape(np.ravel(a, order='F'), (2, 3), order='F')
array([[0, 4, 3],
       [2, 1, 5]])
# order选择的区别
a = np.array([[1,2,3], [4,5,6]]) np.reshape(a, 6) array([1, 2, 3, 4, 5, 6]) np.reshape(a, 6, order='F') array([1, 4, 2, 5, 3, 6])
# 自动推算维度长度
np.reshape(a, (3,-1))       # the unspecified value is inferred to be 2
array([[1, 2],
       [3, 4],
       [5, 6]])

 

flatten

该函数用法直观简单且单一,就是无论什么维度的数组都展成1维的数组

ndarray.flatten(order='C')

  - order: {‘C’, ‘F’, ‘A’, ‘K’}, optional

  • 'C':C风格,按行的顺序展平数组(默认值)。
  • 'F':Fortran风格,按列的顺序展平数组。
  • 'A':如果数组是在Fortran连续内存中,按列顺序展平,否则按行顺序。
  • 'K':按照元素在内存中的出现顺序展平,不考虑特定的风格。
a = np.array([[1,2], [3,4]])
a.flatten()
>>>
array([1, 2, 3, 4])
a.flatten('F')
>>>
array([1, 3, 2, 4])

 

总结

  • concat是在现有的轴上进行连接,元素总数肯定是两个分离数组的和,维度层数不变,只有连接的那个轴的长度发生变化,且变化后的长度是变化前一些列数组的在那一维度的和。
  • stack是在新建的轴上进行的连接,所以维度层数发生了变化,元素总是也是一系列被链接数组元素的和。特别地与concat不同又相同的是,只有新建的轴的长度发生变化且其它轴的shape要完全一样。
  • expand_dims和squeeze都是针对某一轴长度为1的操作,不过是一个指定在那个维度层数增加一个长度为1的轴,另一个是决定将哪个长度为1的轴给删除。
  • reshape也是对单个数组进行的shape重塑,reshape、expand_dims和squeeze这三者操作前后的总元素个数是不发生任何变化的。

参考链接:

chatGPT4

numpy官方文档:https://numpy.org/doc/stable/index.html

标签:变换,用到,维度,shape,数组,np,array,stack,axis
From: https://www.cnblogs.com/HOI-Yzy/p/18136205

相关文章

  • 四元数在旋转变换和插值中的有趣的可视化解释
    四元数可以旋转三维空间中的向量,而最近刚好硬着头皮读《复分析可视化方法》(见[1]),这本书中,作者非常巧妙地运用球极射影的方法,将三维空间单位球面上绕向量轴旋转的变换,映射为复平面上旋转矩阵的表示,对四元数的插值给出可视化的有趣并且直观的解释。四元数的基本定义(参考2),两个四元数......
  • 基于DCT变换的彩色图像双重水印嵌入和提取算法matlab仿真
    1.算法运行效果图预览灰度图   彩色图   2.算法运行软件版本matlab2022a  3.算法理论概述      双重水印嵌入算法涉及两个独立的水印:主水印和辅水印,它们可以是灰度图像、二进制序列或其他形式的数据。以下简述嵌入过程: 图像预处理:将彩色图像从R......
  • opencv距离变换函数distanceTransform
    当图像内的各个子图没有连接时,可以直接使用形态学的腐蚀操作确定前景对象,但是如果图像内的子图连接在一起时,就很难确定前景对象了。此时,借助于距离变换函数cv2.distanceTransform()可以方便地将前景对象提取出来。距离变换函数cv2.distanceTransform()计算二值图像内任意点到最......
  • 浅析OpenCV分水岭变换watershed函数的markers参数[C++]
    0.前言本文是笔者在学习C++OpenCV库时学习心得,在学习分水岭变换函数时,由于缺少相关学习资料,导致笔者理解吃力,故写此文章阐述一下对该函数的理解,希望对其他学习人士提供帮助。本文主要介绍了watershed函数参数以及参数实际表示。请您按文章次序阅读。您需要提前了解的相关知......
  • [转]Git清除贡献者信息和历史提交记录,将开源项目拉取二次开发时可用到
     如果我们用git与github扒了别人的开源代码,想拿来用到自己项目中,但是提交过后,会发现仓库的历史记录又臭又长,贡献者里还有别人的名字,打算把历史记录全部清除并且让目前所有文件全部变成首次commit的状态。可以试试以下这个方法,包你百试百灵!1.Checkout检出新的分支#orphan参......
  • 论文笔记-Non-intrusive classification of gas-liquid flow regimes in an S-shaped
    目标:使用深度神经网络对S形立管中的流态进行分类该分类器与四种传统的机器学习分类器进行了比较:即AdaBoost分类器、bagging分类器、额外树分类器和决策树分类器小波分析在流态分类中的应用可以有效地提取多相流行为的特征。使用信号处理方法进行流态分类,包括峰值点计数、......
  • 前端工程师-自动拉取iconfont的批处理文件-windows10版本-用到了powershell的解压功能
    直接上代码,有任何问题直接留言,我们一起讨论  @echooffSETdirName=替换成压缩包解压后希望叫的名字SETOldPattern=font_*_*rmdir/q/s"删除原来的iconfont文件夹,这里替换成原来的文件夹的地址"curl--output%这里的地址是你想把从iconfont上下载下来的安装包......
  • 计算机图形:三维观察之投影变换
    目录投影变换正投影轴测、等轴测正投影正投影坐标系裁剪窗口、正投影观察体正投影的规范化变换斜投影斜*行投影斜等测、斜二测*行投影斜*行投影变换透视投影投影参考点与观察原点坐标变换特殊透视投影灭点灭点与投影参考点透视投影观察体透视投影变换矩阵对称透视投影椎体斜透视投......
  • jmeter有很多个接口需要用到token,怎么简单操作?
     一、实现方法添加HTTP请求默认值:在你的测试计划中,添加一个HTTP请求默认值配置元件(HTTPRequestDefaults),用于设置所有HTTP请求的公共属性,包括服务器地址、端口号等。你可以在这里设置token,以便在所有请求中都能使用它。获取token:在测试计划中,添加一个HTTP请求,......
  • 无源RLC电路和阻抗匹配 part2:串并联网络变换+L型匹配
    串并联变换(以RL串联→并联为例)若使上述变换成立,串联支路(Ls、Rs)总阻抗应等于并联支路(Lp、Rp)总阻抗因为可得RC串联→并联:上述变换为窄带阻抗变换,仅在以w0为中心的窄带内成立L型匹配L型匹配所用元件较少,仅用两个无源器件即可构成(电容or电感),根据Rs和Rl的大小关系可分......