1 数组的两种内存布局方式

行优先与列优先

首先我们回顾一下,矩阵数据在内存中的两种布局方式:

  • 行优先(row-major):以行为优先单位,在内存中逐存储/读取;对于多维,意味着当线性扫描内存时,第一个维度的变化最慢。
  • 列优先(column-major):以列为优先单位,在内存中逐存储/读取;对于多维,意味着当线性扫描内存时,最后一个维度的变化最慢。

以下面的[2, 2, 2]张量为例:

a = [[[1, 2],[3, 4]],[[5, 6],[7, 8]]]

在内存中的数据排布:

行优先:1, 2 | 3, 4 || 5, 6 | 7, 8a[0,0] a[0,1] a[1,0] a[1,1]
列优先:1, 5 | 3, 7 || 2, 6 | 4, 8a[0,0] a[1,0] a[0,1] a[1,1]

谁更好?

选择行优先还是列优先,主要取决于我们访问数组的模式。由于每次从内存中获取数据时,CPU都会自动将该数据及其相邻的内存加载到缓存中,希望利用引用的局部性。因此,如果访问数组时是逐列访问的,我们就希望同一列的数据在内存中靠得更近,便于一次性加载到CPU缓存中从而避免反复加载,亦即更加的“Cache-friendly”,此时列优先显然是最好的选择。而对于逐行访问的情况,则应该选择行优先。

C和大多数DeepLearning库用的都是行优先,而Fortran和matlab等一些用于科学计算的语言,使用的是列优先。不要问为什么,这是历史的偶然选择而已。如果要强行解释,可以说Fortran是考虑到线性代数中的向量默认为列向量,所以用列优先与数学符号更匹配,虽然用列优先并不会加速矩阵运算(比如矩阵乘法中第一个矩阵是逐行访问,第二个是逐列访问,不可兼得),但是更能显现出科学家与众不同的装逼特性 :-) 。

2 numpy 中的行优先和列优先

numpy支持这两种内存布局方式,默认采用行优先。可以在新建array,或者进行reshape等操作时,通过指定order参数来决定数据的内存布局方式。

array() 新建

函数原型:

array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0)

参数:

  • dtype: 存储单元格式,有np.float32、np.bool、np.int32等。
  • copy: 是否在内存中新建array。
  • subok: (不用管)If True, then sub-classes will be passed-through, otherwise the returned array will be forced to be a base-class array (default).
  • ndmin: 返回的数组应该具有至少ndmin个维数,不足时补充若干个大小为1的维度。
np.array([[1,2,3],[4,5,6]]).shape
Out[52]: (2, 3)
np.array([[1,2,3],[4,5,6]], ndmin=4).shape
Out[53]: (1, 1, 2, 3)

  • order: 新建的array在内存中的布局方式(该参数在copy==True时才有意义),从 {‘K’, ‘A’, ‘C’, ‘F’} 中选择;

举个例子:

s = [[1,2,3], ['a','b','c']]  # python序列采用行优先布局
# 内存中 s :1, 2, 3, 'a', 'b', 'c'a = np.array(s, order='C')
# a.reshape(-1) :'1', '2', '3', 'a', 'b', 'c'b = np.array(s, order='F')
# b.reshape(-1) :'1', 'a', '2', 'b', '3', 'c'

reshape() 重整维度

函数原型:

reshape(array, newshape, order='C')
array.reshape(newshape, order='C')

参数:

  • newshape: 一个描述各维度大小的序列,也可以是单个int。
  • order: 从 {‘A’, ‘C’, ‘F’} 中选择。

b = reshape(a, newshape, order)相当于:

b = np.array(a, order)  # 在内存中新建一个 b ,以 order 布局方式存储从 a 中读取的数据
b.shape = newshape  # 设定index指针的计算方式

3 “lazy”的 transpose() 转置

注意,numpy中的转置transpose()是非常“lazy”的,亦即不对内存中的数据进行重排,仅仅改变读取方式

举个例子:

''' a.shape = [1,2,3] '''
transpose_scheme = [2,1,0]  # 维度0与2交换位置
b = np.transpose(a, axes=transpose_scheme)
'''
此时 b.shape 虽然变成了 [3,2,1]
但是 b 与 a 在内存的排布是一样的
'''

transpose()等效于:在读取/写入函数函数外,包了一个能改变维度顺序的函数装饰器。

def change_axis_order(transpose_scheme):def get_func(func):@wraps(func)def wrapper(self, axes):transposed_axes = [axes[i] for i in transpose_scheme]return func(self, transposed_axes)return wrapperreturn get_func'''
b = np.transpose(a, axes=transpose_scheme)
相当于:
'''
b = a.copy()
b.__getitem__ = change_axis_order(transpose_scheme)(b.__getitem__)
b.__setitem__ = change_axis_order(transpose_scheme)(b.__setitem__)

之所以采用这种“lazy”的方式,是因为重新在内存中排列数据的非常耗时的。

如果一定要在内存中重新排列数据,可以采用以下方法:

b = np.zeros_like(a)
b[:] = np.array(a, axes=transpose_scheme)

numpy维度交换_“lazy”的transpose()函数——从numpy 数组的内存布局讲起相关推荐

  1. numpy维度交换_数据分析-gt;基本操作numpy(1)

    1.Numpy介绍与安装 Numpy是什么? Numpy(Numerical Python)是目前Python数值计算中最为重要的基础包.大多数计算包都提供了基于Numpy的科学函数功能,将Numpy ...

  2. numpy维度交换_如何将2个不同维度的numpy数组相乘

    默认情况下,ND数组(例如A)与一维1(B)的乘法是在最后一个轴上执行的,这意味着乘法A * B仅在下有效 A.shape[-1] == len(B) 要在另一个轴上将A与B相乘而不是-1,一种解决方 ...

  3. 基类成员的public访问权限在派生类中变为_第17篇:C++继承中虚表的内存布局

    我们已经表明,非虚类的对象实例不包含虚指针,编译器在编译阶段也没有为非虚类没有构建虚表.而本篇我们会从简单的单继承链分析虚类中虚表构造过程和内存布局.这一切假定你有如下基础 对gdb调试器使用有一个比 ...

  4. python transpose函数_Python Numpy.transpose函数可视化解释

    二维情况 例如以下代码: x = np.arange(4).reshape((2,2)) 输出: x = ([[0, 1], [2, 3]]) 对于二维的数组,np.transpose()即为将矩阵进 ...

  5. c 语言 函数返回数组_如何在C ++函数中返回数组

    c 语言 函数返回数组 介绍 (Introduction) In this tutorial, we are going to understand how we can return an arra ...

  6. numpy维度交换_numpy之转置(transpose)和轴对换

    转置(transpose)和轴对换 转置可以对数组进行重置,返回的是源数据的视图(不会进行任何复制操作). 转置有三种方式,transpose方法.T属性以及swapaxes方法. 1 .T,适用于一 ...

  7. numpy维度交换_15年!NumPy论文终出炉,还登上了Nature

    NumPy 团队撰写了一篇综述文章,介绍 NumPy 的发展过程.主要特性和数组编程等.这篇文章现已发表在 Nature 上. 机器之心报道,编辑:魔王.杜伟.小舟. NumPy 是什么?它是大名鼎鼎 ...

  8. numpy 矩阵乘法_一起学习Python常用模块——numpy

    关注微信公众号:一个数据人的自留地 作者介绍 知乎@王多鱼 百度的一名推荐算法攻城狮. 主要负责商品推荐的召回和排序模型的优化工作. 1 前言 Python在数据科学.机器学习.AI领等域中占据主导地 ...

  9. python numpy 子数组_详解:Python 取numpy数组的某几行某几列方法(含对与错示例)...

    前言: 今天为大家带来的内容是Python 取numpy数组的某几行某几列方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,要是喜欢的话记得点赞转发收藏不迷路哦!!! ...

最新文章

  1. 作为产品经理,你需要了解的基本算法知识和实操
  2. python学习书籍推荐-推荐python机器学习实践的书籍?
  3. leetcode算法题--相交链表
  4. JVM:gc什么时候开始?System.gc()能保证gc一定发生吗?
  5. linux 查看flash大小,Linux OpenWRT查看CPU,RAM,Flash信息参数
  6. android 自定义图片上传,android自定义ImageView仿图片上传示例
  7. java日期大小比较(亲测)
  8. java日志框架log4j详细配置及与slf4j联合使用教程
  9. 位置服务器的操作方法,hpproliantml系列服务器上机架操作方法.doc.docx
  10. 2022年的第一个工作日,整理了风控的这些内容
  11. python解析http数据包_python 3 处理HTTP 请求的包
  12. 你以为我在玩游戏?其实我在学 Java
  13. 无法删除的文件夹怎么办?如何删除删不掉的文件夹
  14. BugKu-CTF(杂项篇MISC)--disordered_zip
  15. php 邮件 延迟发送,PHP后台隔5分钟发送email邮件_php
  16. 各个开发工具格式化代码的快捷键
  17. 计算机显卡调研,75%以上的人都想换显卡! MC调研报告告诉你吃鸡“帧”香
  18. 几种求函数最值的算法
  19. 论如何写好一篇需求报告(或者说产品报告)
  20. 工业相机与普通相机的区别

热门文章

  1. 神经网络模型遇到瓶颈?这些Tricks让你相见恨晚!
  2. 谈谈实习期间应该注意的几点问题,助你早日拿到转正offer
  3. sql server2008如何修改mac地址_如何查看本机的MAC地址和IP地址?
  4. php mysql插入的数据有引号_php – 由于’引号’的不同,数据没有插入到mysql数据库中...
  5. 【TypeScript系列教程14】Array数组对象的常见的方法
  6. java大佬是如何快速配置IntelliJ IDEA的Tomcat及安装配置Tomcat及java开发环境
  7. linux下编译ios,为iOS安装OpenCV
  8. html js点击字图片下拉,JavaScript实现文字与图片拖拽效果的方法
  9. webpack css打包为一个css
  10. 注意安全!XSS 和 XSRF