2.2.1.3 数据类型

2.2.1.3.1 描述符

dtype描述了数组里的一个项目:

type数据的标量类型,int8、int16、float64等之一(固定大小),str、unicode、void(可变大小)
itemsize数据块的大小
byteorder字节序: big-endian > / little-endian < / 不可用
fields子-dtypes,如果是一个结构化的数据类型
shape数组的形状,如果是一个子数组

In [13]:

  1. np.dtype(int).type

Out[13]:

  1. numpy.int64

In [14]:

  1. np.dtype(int).itemsize

Out[14]:

  1. 8

In [15]:

  1. np.dtype(int).byteorder

Out[15]:

  1. '='

2.2.1.3.2 例子:读取.wav文件

The.wav file header:

chunk_id"RIFF"
chunk_size4字节无符号little-endian整型
format"WAVE"
fmt_id"fmt "
fmt_size4字节无符号little-endian整型
audio_fmt2字节无符号little-endian整型
num_channels2字节无符号little-endian整型
sample_rate4字节无符号little-endian整型
byte_rate4字节无符号little-endian整型
block_align2字节无符号little-endian整型
bits_per_sample2字节无符号little-endian整型
data_id"data"
data_size4字节无符号little-endian整型
  • 44字节块的原始数据(在文件的开头)
  • …接下来是data_size 实际声音数据的字节。

.wav文件头是Numpy结构化数据类型:

In [6]:

  1. wav_header_dtype = np.dtype([
  2. ("chunk_id", (str, 4)), # flexible-sized scalar type, item size 4
  3. ("chunk_size", "<u4"), # little-endian unsigned 32-bit integer
  4. ("format", "S4"), # 4-byte string
  5. ("fmt_id", "S4"),
  6. ("fmt_size", "<u4"),
  7. ("audio_fmt", "<u2"), #
  8. ("num_channels", "<u2"), # .. more of the same ...
  9. ("sample_rate", "<u4"), #
  10. ("byte_rate", "<u4"),
  11. ("block_align", "<u2"),
  12. ("bits_per_sample", "<u2"),
  13. ("data_id", ("S1", (2, 2))), # sub-array, just for fun!
  14. ("data_size", "u4"),
  15. #
  16. # the sound data itself cannot be represented here:
  17. # it does not have a fixed size
  18. ])

也可以看一下wavreader.py

In [5]:

  1. wav_header_dtype['format']

Out[5]:

  1. dtype('S4')

In [6]:

  1. wav_header_dtype.fields

Out[6]:

  1. <dictproxy {'audio_fmt': (dtype('uint16'), 20),
  2. 'bits_per_sample': (dtype('uint16'), 34),
  3. 'block_align': (dtype('uint16'), 32),
  4. 'byte_rate': (dtype('uint32'), 28),
  5. 'chunk_id': (dtype('S4'), 0),
  6. 'chunk_size': (dtype('uint32'), 4),
  7. 'data_id': (dtype(('S1', (2, 2))), 36),
  8. 'data_size': (dtype('uint32'), 40),
  9. 'fmt_id': (dtype('S4'), 12),
  10. 'fmt_size': (dtype('uint32'), 16),
  11. 'format': (dtype('S4'), 8),
  12. 'num_channels': (dtype('uint16'), 22),
  13. 'sample_rate': (dtype('uint32'), 24)}>

In [7]:

  1. wav_header_dtype.fields['format']

Out[7]:

  1. (dtype('S4'), 8)
  • 第一个元素是结构化数据中对应于名称format的子类型
  • 第二个是它的从项目开始的偏移(以字节计算)

练习

小练习,通过使用偏移来创造一个“稀释”的dtype,只使用一些字段:

In [ ]:

  1. wav_header_dtype = np.dtype(dict(
  2. names=['format', 'sample_rate', 'data_id'],
  3. offsets=[offset_1, offset_2, offset_3], # counted from start of structure in bytes
  4. formats=list of dtypes for each of the fields,
  5. ))

并且用它来读取sample rate和data_id(就像子数组)。

In [7]:

  1. f = open('data/test.wav', 'r')
  2. wav_header = np.fromfile(f, dtype=wav_header_dtype, count=1)
  3. f.close()
  4. print(wav_header)
  1. [ ('RIFF', 17402L, 'WAVE', 'fmt ', 16L, 1, 1, 16000L, 32000L, 2, 16, [['d', 'a'], ['t', 'a']], 17366L)]

In [8]:

  1. wav_header['sample_rate']

Out[8]:

  1. array([16000], dtype=uint32)

让我们访问子数组:

In [9]:

  1. wav_header['data_id']

Out[9]:

  1. array([[['d', 'a'],
  2. ['t', 'a']]],
  3. dtype='|S1')

In [10]:

  1. wav_header.shape

Out[10]:

  1. (1,)

In [11]:

  1. wav_header['data_id'].shape

Out[11]:

  1. (1, 2, 2)

当访问子数组时,维度被添加到末尾!

注意:有许多模块可以用于加载声音数据,比如wavfileaudiolab等…

2.2.1.3.3 投射和再解释/视图

投射

  • 赋值
  • 数组构建
  • 算术
  • 等等
  • 手动:.astype(dtype)

data re-interpretation

  • 手动:.view(dtype)
2.2.1.3.3.1 投射
  • 算术投射,简而言之:
    • 只有类型(不是值!)操作符最重要
    • 最大的“安全”模式能代表选出的两者
    • 在一些情况下,数组中的量值可能“丢失”
  • 在通用复制数据中的投射:

In [4]:

  1. x = np.array([1, 2, 3, 4], dtype=np.float)
  2. x

Out[4]:

  1. array([ 1., 2., 3., 4.])

In [5]:

  1. y = x.astype(np.int8)
  2. y

Out[5]:

  1. array([1, 2, 3, 4], dtype=int8)

In [6]:

  1. y + 1

Out[6]:

  1. array([2, 3, 4, 5], dtype=int8)

In [7]:

  1. y + 256

Out[7]:

  1. array([257, 258, 259, 260], dtype=int16)

In [8]:

  1. y + 256.0

Out[8]:

  1. array([ 257., 258., 259., 260.])

In [9]:

  1. y + np.array([256], dtype=np.int32)

Out[9]:

  1. array([257, 258, 259, 260], dtype=int32)
  • 集合项目上的投射:数组的dtype在项目赋值过程中不会改变:

In [10]:

  1. y[:] = y + 1.5
  2. y

Out[10]:

  1. array([2, 3, 4, 5], dtype=int8)

注意 具体规则:见文档:http://docs.scipy.org/doc/numpy/reference/ufuncs.html#casting-rules

2.2.1.3.3.2 再解释/视图
  • 内存中的数据块(4字节)

0x01 || 0x02 || 0x03 || 0x04

  1. - 4 of uint8, OR,
  2. - 4 of int8, OR,
  3. - 2 of int16, OR,
  4. - 1 of int32, OR,
  5. - 1 of float32, OR,
  6. - ...

如何从一个切换另一个?

  • 切换dtype:

In [11]:

  1. x = np.array([1, 2, 3, 4], dtype=np.uint8)
  2. x.dtype = "<i2"
  3. x

Out[11]:

  1. array([ 513, 1027], dtype=int16)

In [12]:

  1. 0x0201, 0x0403

Out[12]:

  1. (513, 1027)

0x01 0x02 || 0x03 0x04

注意 little-endian:越不重要的字节在内存的左侧

  • 创建新视图:

In [14]:

  1. y = x.view("<i4")
  2. y

Out[14]:

  1. array([67305985], dtype=int32)

In [15]:

  1. 0x04030201

Out[15]:

  1. 67305985

0x01 0x02 0x03 0x04

注意:

  • .view()创建视图,并不复制(或改变)内存块
  • 只改变dtype(调整数组形状):

In [16]:

  1. x[1] = 5

In [17]:

  1. y

Out[17]:

  1. array([328193], dtype=int32)

In [18]:

  1. y.base is x

Out[18]:

  1. True

小练习:数据再解释

也可以看一下: view-colors.py

数组中的RGBA数据:

In [19]:

  1. x = np.zeros((10, 10, 4), dtype=np.int8)
  2. x[:, :, 0] = 1
  3. x[:, :, 1] = 2
  4. x[:, :, 2] = 3
  5. x[:, :, 3] = 4

后三个维度是R、B和G,以及alpha渠道。

如何用字段名‘r’, ‘g’, ‘b’, ‘a’创建一个(10,10)结构化数组而不用复制数据?

In [ ]:

  1. y = ...
  2. assert (y['r'] == 1).all()
  3. assert (y['g'] == 2).all()
  4. assert (y['b'] == 3).all()
  5. assert (y['a'] == 4).all()

答案

警告:另一个占有四个字节内存的数组:

In [21]:

  1. y = np.array([[1, 3], [2, 4]], dtype=np.uint8).transpose()
  2. x = y.copy()
  3. x

Out[21]:

  1. array([[1, 2],
  2. [3, 4]], dtype=uint8)

In [22]:

  1. y

Out[22]:

  1. array([[1, 2],
  2. [3, 4]], dtype=uint8)

In [23]:

  1. x.view(np.int16)

Out[23]:

  1. array([[ 513],
  2. [1027]], dtype=int16)

In [24]:

  1. 0x0201, 0x0403

Out[24]:

  1. (513, 1027)

In [25]:

  1. y.view(np.int16)

Out[25]:

  1. array([[ 769, 1026]], dtype=int16)
  • 发生了什么?
  • … 我们需要实际看一下x[0,1]里面是什么

In [26]:

  1. 0x0301, 0x0402

Out[26]:

  1. (769, 1026)