Numpy.array本质(内存块 + 索引体系 + 数据类型描述符)及as_strided方法重构数组

内存块

array切片之所以可以对原array数据进行修改,是因为两个array的内存地址在一个地方

import numpy as np
x = np.array(range(1,5))
y = x[:-1]
x[0] = 9
# 查看array的内存地址
x.__array_interface__['data'][0],y.__array_interface__['data'][0]
# 结果 => (1713365532096, 1713365532096)

通过.flags 可以查看出xy 哪个是原始array哪个是切片

x.flags
""" 结果
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : True       # 原始数据拥有数据
  WRITEABLE : True
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False
"""

y.flags
""" 结果
  C_CONTIGUOUS : True
  F_CONTIGUOUS : True
  OWNDATA : False   # 切片不拥有数据
  WRITEABLE : True  # 但是同样可以修改数据
  ALIGNED : True
  WRITEBACKIFCOPY : False
  UPDATEIFCOPY : False
"""

数据类型

dtype 存在的几个属性

np.dtype(np.int8).type # 元素数据类型<class 'numpy.int8'>
np.dtype(np.int8).itemsize # 一个元素占内存字节大小 1

dtype astype 类型改变 及运算后改变
以及不改变dtype 的运算办法

x = np.array(range(1,5), dtype = np.float)
y = x.astype(np.int8)
# 变成浮点型
a = y+1.0
print(a.dtype) # float64

# 以大的dtype类型为最后就
m = y + np.array([256], dtype=np.int32)
print(m.dtype) # int32

# 不改变dtype的运算办法
y[:] = y + 1.5    # 向下取整
print(y, y.dtype) # [2 3 4 5] int8

不常用,但效率挺高的dtype 转换方法,直接2进制转换

x = np.array([1,2,3,4], dtype=np.uint8)
x.__array_interface__['data'][0]   # 1713370045744
bytes(x)   # b'\x01\x02\x03\x04'
print(x)   # [1 2 3 4]

"""
给dtype 直接赋值 '<i1' int8 '<i2' int16 
i <=> 8,i1 <=> int 8*1
"""
x.dtype = '<i2' # int16
x.__array_interface__['data'][0]   # 1713370045744
bytes(x)   # b'\x01\x02\x03\x04'
print(x)   # [ 513 1027]

array的内存地址没变,直接二进制编码转换成,最后显示的array结果不一样。

创建视图
创建视图的时候同样可以用指定dtype 类型的办法执行

y = x.view('<i4')
y.__array_interface__['data'][0]  # 1713370045744
# 视图的内存地址依旧和 x 相同,所以修改原数值,y 也会变化
print(y)  # array([67305985])
x[1] = 5
print(y)  # array([328193])

# 同样修改视图 y , x 也会变化
y[0] = 1024
print(y.dtype) # int32
print(x, x.dtype) # [1024    0] int16

y.base is x # True

索引

索引的本质:
根据步伐查找位置
x = np.array([[1, 2, 3],
              [4, 5, 6],
              [7, 8, 9]], dtype = np.int8)
# 步伐 大小与dtype有关
x.strides # (3, 1)
byte_offset = sum(x.strides*np.array([1,2])) # 步伐*想要查找的位置
x.flat[byte_offset]  # 6
x[1, 2]              # 6

用步长改变维度

from numpy.lib.stride_tricks import as_strided

x = np.array([1, 2, 3, 4, 5, 6], dtype = np.int16)
# 维度 3行 2列
shape = (3, 2)
# 第一个维度间隔2个元素,第二个维度间隔1个元素
strides = x.itemsize*np.array([2, 1])
y = as_strided(x, shape = shape, strides = strides)
print(y)
""" 结果
array([[1, 2],
       [3, 4],
       [5, 6]], dtype=int16)
"""

上面的例子并不能看出该方法的优势,将数组维度和量增多时

from numpy.lib.stride_tricks import as_strided

# 生成9*9的数组 
## 采用np.int8 a.itemsize = 1 便于操作步伐strides
a = np.array(range(1,10),dtype=np.int8)         
b = as_strided(a, shape=(9, 9), strides = (0,1)).copy() # 第一维度步伐为0,即相等

## 将 9*9 转化成 3*3*3*3 数组                   ==直接在原array上切割==
shape = (3, 3, 3, 3)
"""
第一维度(数组间行)间隔 3*(3*3)个元素, 第二维度(数组间列)间隔3个维度
第三维度(数组内行)间隔3个元素,最后的维度(数组内列)间隔1个元素
"""
strides = b.itemsize*np.array([27, 3 , 9, 1])
out = as_strided(b, shape=shape , strides = strides)
array([[[[1, 2, 3],
         [1, 2, 3],
         [1, 2, 3]],

        [[4, 5, 6],
         [4, 5, 6],
         [4, 5, 6]],

        [[7, 8, 9],
         [7, 8, 9],
         [7, 8, 9]]],


       [[[1, 2, 3],
         [1, 2, 3],
         [1, 2, 3]],

        [[4, 5, 6],
         [4, 5, 6],
         [4, 5, 6]],

        [[7, 8, 9],
         [7, 8, 9],
         [7, 8, 9]]],


       [[[1, 2, 3],
         [1, 2, 3],
         [1, 2, 3]],

        [[4, 5, 6],
         [4, 5, 6],
         [4, 5, 6]],

        [[7, 8, 9],
         [7, 8, 9],
         [7, 8, 9]]]], dtype=int8)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Scc_hy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值