zoukankan      html  css  js  c++  java
  • 『Numpy』内存分析_高级切片和内存数据解析

    在计算机中,没有任何数据类型是固定的,完全取决于如何看待这片数据的内存区域。
    在numpy.ndarray.view中,提供对内存区域不同的切割方式,来完成数据类型的转换,而无须要对数据进行额外的copy,可以节约内存空间,我们可以将view看做对内存的展示方式。
    如:
    import numpy as np
    x = np.arange(10, dtype=np.int)
    
    print('An integer array:', x)
    print ('An float array:', x.view(np.float))
    
    An integer array: [0 1 2 3 4 5 6 7 8 9]

    An float array:
    [ 0.00000000e+000 4.94065646e-324 9.88131292e-324 1.48219694e-323 1.97626258e-323 2.47032823e-323 2.96439388e-323 3.45845952e-323 3.95252517e-323 4.44659081e-323]

    在实际使用中我们往往会采取更复杂的dtype(也就是说view可以与dtype搭配使用)输出内存中的值,后面我们会示范对于结构化数组的较为复杂的view使用。

    一、view和copy

    我们从numpy.reshape()函数入手,文档对于其返回值的解释:

    Returns
        -------
        reshaped_array : ndarray
            This will be a new view object if possible; otherwise, it will
            be a copy.  Note there is no guarantee of the *memory layout* (C- or
            Fortran- contiguous) of the returned array.
    其返回值可能是一个view,或是一个copy。相应的条件为:
      1、返回一个view条件:数据区域连续的时候
      2、反之,则返回一个copy
    我们得到了一个新概念,数组内存区域是否连续,numpy数组有flags['C_CONTIGUOUS']表示是否连续,有np.may_share_memory方法判断两个数组内存区域是否一致:
    a = np.zeros([2,10], dtype=np.int32)
    b = a.T  # 转置破坏连续结构
    
    a.flags['C_CONTIGUOUS']  # True
    b.flags['C_CONTIGUOUS']  # False
    
    np.may_share_memory(a,b)  # True
    b.base is a  # True
    id(b)==id(a)  # False
    
    
    a.shape = 20  # a的shape变了
    a.flags['C_CONTIGUOUS']  # True
    
    # b.shape = 20
    # AttributeError: incompatible shape for a non-contiguous array
    # 想要使用指定shape的方式,只能是连续数组,但是reshape方法由于不改变原数组,所以reshape不受影响
    

    数组切片是否会copy数据?

    不过,数组的切片对象虽然并非contiguous,但是对它的reshape操作并不会copy新的对象,

    a = np.arange(16).reshape(4,4)  
    
    print(a.T.flags['C_CONTIGUOUS'],a[:,0].flags['C_CONTIGUOUS'])
    # False False
    
    print (np.may_share_memory(a,a.T.reshape(16)),
           np.may_share_memory(a,a[:,0].reshape(4)))
    # False True
    

    但是,下一小节会介绍,高级切片会copy数组,开辟新的内存。

    二、numpy的结构数组

    利用np.dtype可以构建结构数组,numpy.ndarray.base会返回内存主人的信息,文档如下,

    Help on getset descriptor numpy.ndarray.base:

    base
        Base object if memory is from some other object.
        
        Examples
        --------
        The base of an array that owns its memory is None:
        
        >>> x = np.array([1,2,3,4])
        >>> x.base is None
        True
        
        Slicing creates a view, whose memory is shared with x:
        
        >>> y = x[2:]
        >>> y.base is x
        True

    1、建立结构数组

    persontype = np.dtype({
        'names':['name','age','weight','height'],
        'formats':['S30','i','f','f']}, align=True)
    a = np.array([('Zhang',32,72.5,167),
                  ('Wang',24,65,170)],dtype=persontype)
    a['age'].base
    

     array([(b'Zhang', 32, 72.5, 167.),

                (b'Wang', 24, 65. , 170.)],

                dtype={'names':['name','age','weight','height'],

                'formats':['S30','<i4','<f4','<f4'], 

                'offsets':[0,32,36,40],

                'itemsize':44,

                'aligned':True})

    2、高级切片和普通切片的不同

    In [26]: a.base
    In [27]: a[0].base
    In [28]: a[:1].base
    Out[28]: array([123,   4,   5,   6,  78])
    In [29]: a[[0,1]].base
    
    In [30]: a.base is None
    Out[30]: True
    In [31]: a[0].base is None
    Out[31]: True
    In [32]: a[:1].base is None
    Out[32]: False
    In [33]: a[[0,1]].base is None
    Out[33]: True
    

     由上可见高级切片会开辟新的内存,复制被切出的数据,这是因为这种不规则的内存访问使用原来的内存结构效率很低(逻辑相邻元素内存不相邻,标准的访问由于固定了起始和步长相当于访问相邻元素,所以效率较高),拷贝出来就是连续的内存数组了。

    3、高级切片且不开辟新内存的方法

    回到上上小节的结构数组,

    print(a['age'].base is a)
    print(a[['age', 'height']].base is None)
    

    True

    True

    我们通过指定内存解析方式,实现不开辟新内存,将原内存解析为高级切片指定的结构数组,

    def fields_view(arr, fields):
        dtype2 = np.dtype({name:arr.dtype.fields[name] for name in fields})
        # print(dtype2)
        # {'names':['age','weight'], 'formats':['<i4','<f4'], 'offsets':[32,36], 'itemsize':40}
        # print([(name,arr.dtype.fields[name]) for name in fields])
        # [('age', (dtype('int32'), 32)), ('weight', (dtype('float32'), 36))]
        # print(arr.strides)
        # (44,)
        return np.ndarray(arr.shape, dtype2, arr, 0, arr.strides)
    '''
    ndarray(shape, dtype=float, buffer=None, offset=0,
     |          strides=None, order=None)
     
    参数 	类型 	作用
    shape 	int型tuple 	多维数组的形状
    dtype 	data-type 	数组中元素的类型
    buffer 		用于初始化数组的buffer
    offset 	int 	buffer中用于初始化数组的首个数据的偏移
    strides 	int型tuple 	每个轴的下标增加1时,数据指针在内存中增加的字节数
    order 	'C' 或者 'F' 	'C':行优先;'F':列优先
    '''
    
    v = fields_view(a, ['age', 'weight'])
    print(v.base is a)
    
    v['age'] += 10
    print('+++'*10)
    print(v)
    print(v.dtype)
    print(v.dtype.fields)
    print('+++'*10)
    print(a)
    print(a.dtype)
    print(a.dtype.fields)
    
    True
    ++++++++++++++++++++++++++++++
    [(42,  72.5) (34,  65. )]
    {'names':['age','weight'], 'formats':['<i4','<f4'], 'offsets':[32,36], 'itemsize':40}
    {'age': (dtype('int32'), 32), 'weight': (dtype('float32'), 36)}
    ++++++++++++++++++++++++++++++
    [(b'Zhang', 42,  72.5,  167.) (b'Wang', 34,  65. ,  170.)]
    {'names':['name','age','weight','height'], 'formats':['S30','<i4','<f4','<f4'], 'offsets':[0,32,36,40], 'itemsize':44, 'aligned':True}
    {'name': (dtype('S30'), 0), 'age': (dtype('int32'), 32), 'weight': (dtype('float32'), 36), 'height': (dtype('float32'), 40)}

    这里注意一下.dtype的’itemsize‘参数,表示添加一条(行)数据,内存增加了多少字节,由于保存了'offsets'偏移信息,我们生成的dtype展示的是一个稀疏的结构,但是每一行不会有多余的尾巴,这是因为空元素是由实元素记录偏移量的空隙产生的。

    『Numpy』内存分析_numpy.dtype解析内存数据中我们会更详细的介绍有关数组内存解析的方法。

  • 相关阅读:
    Oracle 按一行里某个字段里的值分割成多行进行展示
    Property or method "openPageOffice" is not defined on the instance but referenced during render. Make sure that this property is reactive, either in the data option, or for class-based components, by
    SpringBoot 项目启动 Failed to convert value of type 'java.lang.String' to required type 'cn.com.goldenwater.dcproj.dao.TacPageOfficePblmListDao';
    Maven 设置阿里镜像
    JS 日期格式化,留作参考
    JS 过滤数组里对象的某个属性
    原生JS实现简单富文本编辑器2
    Chrome控制台使用详解
    android权限(permission)大全
    不借助第三方网站四步实现手机网站转安卓APP
  • 原文地址:https://www.cnblogs.com/hellcat/p/8715830.html
Copyright © 2011-2022 走看看