結(jié)構(gòu)化數(shù)組
介紹
結(jié)構(gòu)化數(shù)組是ndarray,其數(shù)據(jù)類型是由一系列命名字段
組織的簡(jiǎn)單數(shù)據(jù)類型組成。例如:
>>> x = np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)],
... dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
>>> x
array([('Rex', 9, 81.), ('Fido', 3, 27.)],
dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
x
是一個(gè)長(zhǎng)度為2的一維數(shù)組,其數(shù)據(jù)類型是一個(gè)包含三個(gè)字段的結(jié)構(gòu):
- 長(zhǎng)度為10或更少的字符串,名為“name”。
- 一個(gè)32位整數(shù),名為“age”。
- 一個(gè)32位的名為'weight'的float類型。
如果您x
在位置1處索引,則會(huì)得到一個(gè)結(jié)構(gòu):
>>> x[1]
('Fido', 3, 27.0)
您可以通過(guò)使用字段名稱建立索引來(lái)訪問(wèn)和修改結(jié)構(gòu)化數(shù)組的各個(gè)字段:
>>> x['age']
array([9, 3], dtype=int32)
>>> x['age'] = 5
>>> x
array([('Rex', 5, 81.), ('Fido', 5, 27.)],
dtype=[('name', 'U10'), ('age', '<i4'), ('weight', '<f4')])
結(jié)構(gòu)化數(shù)據(jù)類型旨在能夠模仿C語(yǔ)言中的“結(jié)構(gòu)”,并共享類似的內(nèi)存布局。它們用于連接C代碼和低級(jí)操作結(jié)構(gòu)化緩沖區(qū),例如用于解釋二進(jìn)制blob。出于這些目的,它們支持諸如子數(shù)組,嵌套數(shù)據(jù)類型和聯(lián)合之類的專用功能,并允許控制結(jié)構(gòu)的內(nèi)存布局。
希望操縱表格數(shù)據(jù)的用戶(例如存儲(chǔ)在csv文件中)可能會(huì)發(fā)現(xiàn)其他更適合的pydata項(xiàng)目,例如xarray,pandas或DataArray。這些為表格數(shù)據(jù)分析提供了高級(jí)接口,并且針對(duì)該用途進(jìn)行了更好的優(yōu)化。例如,numpy中結(jié)構(gòu)化數(shù)組的類似C-struct的內(nèi)存布局可能導(dǎo)致較差的緩存行為。
結(jié)構(gòu)化數(shù)據(jù)類型
結(jié)構(gòu)化數(shù)據(jù)類型可以被認(rèn)為是一定長(zhǎng)度的字節(jié)序列(結(jié)構(gòu)的項(xiàng)目大小
),它被解釋為字段集合。每個(gè)字段在結(jié)構(gòu)中都有一個(gè)名稱,一個(gè)數(shù)據(jù)類型和一個(gè)字節(jié)偏移量。字段的數(shù)據(jù)類型可以是包括其他結(jié)構(gòu)化數(shù)據(jù)類型的任何numpy數(shù)據(jù)類型,也可以是子行數(shù)據(jù)類型,其行為類似于指定形狀的ndarray。字段的偏移是任意的,字段甚至可以重疊。這些偏移量通常由numpy自動(dòng)確定,但也可以指定。
結(jié)構(gòu)化數(shù)據(jù)類型創(chuàng)建
可以使用該函數(shù)創(chuàng)建結(jié)構(gòu)化數(shù)據(jù)類型numpy.dtype
。有4種不同的規(guī)范形式,
其靈活性和簡(jiǎn)潔性各不相同。這些在 “數(shù)據(jù)類型對(duì)象” 參考頁(yè)面中進(jìn)一步記錄,總結(jié)如下:
-
元組列表,每個(gè)字段一個(gè)元組
每個(gè)元組都具有以下形式
(字段名稱、數(shù)據(jù)類型、形狀)
,其中Shape是可選的。
fieldname
是字符串(如果使用標(biāo)題,則為元組,請(qǐng)參見(jiàn)下面的字段標(biāo)題),
datatype 可以是任何可轉(zhuǎn)換為數(shù)據(jù)類型的對(duì)象,而shape
是指定子數(shù)組形狀的整數(shù)元組。>>> np.dtype([('x', 'f4'), ('y', np.float32), ('z', 'f4', (2, 2))]) dtype([('x', '<f4'), ('y', '<f4'), ('z', '<f4', (2, 2))])
如果
fieldname
是空字符串''
,則將為字段指定格式為f#
的默認(rèn)名稱,
其中#
是字段的整數(shù)索引,從左側(cè)開(kāi)始從0開(kāi)始計(jì)數(shù):>>> np.dtype([('x', 'f4'), ('', 'i4'), ('z', 'i8')]) dtype([('x', '<f4'), ('f1', '<i4'), ('z', '<i8')])
自動(dòng)確定結(jié)構(gòu)內(nèi)字段的字節(jié)偏移量和總結(jié)構(gòu)項(xiàng)大小。
-
逗號(hào)分隔的數(shù)據(jù)類型規(guī)范字符串
在這個(gè)速記符號(hào)中,任何 字符串dtype規(guī)范 都可以在字符串中使用,
并用逗號(hào)分隔。
字段的項(xiàng)目大小和字節(jié)偏移是自動(dòng)確定的,并且字段名稱被賦予默認(rèn)名稱f0
、f1
等。>>> np.dtype('i8, f4, S3') dtype([('f0', '<i8'), ('f1', '<f4'), ('f2', 'S3')]) >>> np.dtype('3int8, float32, (2, 3)float64') dtype([('f0', 'i1', (3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])
-
字段參數(shù)組字典
這是最靈活的規(guī)范形式,因?yàn)樗试S控制字段的字節(jié)偏移和結(jié)構(gòu)的項(xiàng)目大小。
字典有兩個(gè)必需鍵 “names” 和 “format”,以及四個(gè)可選鍵 “offsets”、“itemsize”、“Aligned” 和 “title”。
名稱和格式的值應(yīng)該分別是相同長(zhǎng)度的字段名列表和dtype規(guī)范列表。
可選的 “offsets” 值應(yīng)該是整數(shù)字節(jié)偏移量的列表,結(jié)構(gòu)中的每個(gè)字段都有一個(gè)偏移量。
如果未給出 “Offsets” ,則自動(dòng)確定偏移量。可選的 “itemsize” 值應(yīng)該是一個(gè)整數(shù),
描述dtype的總大?。ㄒ宰止?jié)為單位),它必須足夠大以包含所有字段。>>> np.dtype({'names': ['col1', 'col2'], 'formats': ['i4', 'f4']}) dtype([('col1', '<i4'), ('col2', '<f4')]) >>> np.dtype({'names': ['col1', 'col2'], ... 'formats': ['i4', 'f4'], ... 'offsets': [0, 4], ... 'itemsize': 12}) dtype({'names':['col1','col2'], 'formats':['<i4','<f4'], 'offsets':[0,4], 'itemsize':12})
可以選擇偏移量,使得字段重疊,盡管這將意味著分配給一個(gè)字段可能會(huì)破壞任何重疊字段的數(shù)據(jù)。
作為一個(gè)例外,numpy.object類型的字段不能與其他字段重疊,因?yàn)榇嬖谄茐膬?nèi)部對(duì)象指針然后取消引用它的風(fēng)險(xiǎn)。可選的“Aligned”值可以設(shè)置為True,以使自動(dòng)偏移計(jì)算使用對(duì)齊的偏移量(請(qǐng)參閱自動(dòng)字節(jié)偏移量和對(duì)齊),
就好像numpy.dtype的“Align”關(guān)鍵字參數(shù)已設(shè)置為True一樣。可選的 ‘titles’ 值應(yīng)該是長(zhǎng)度與 ‘names’ 相同的標(biāo)題列表,請(qǐng)參閱下面的字段標(biāo)題。
-
字段名稱字典
不鼓勵(lì)使用這種形式的規(guī)范,但這里有文檔記錄,因?yàn)檩^舊的numpy代碼可能會(huì)使用它。
字典的關(guān)鍵字是字段名稱,值是指定類型和偏移量的元組:>>> np.dtype({'col1': ('i1', 0), 'col2': ('f4', 1)}) dtype([('col1', 'i1'), ('col2', '<f4')])
不鼓勵(lì)使用這種形式,因?yàn)镻ython字典在Python 3.6之前的Python版本中不保留順序,
并且結(jié)構(gòu)化dtype中字段的順序有意義。字段標(biāo)題可以通過(guò)使用3元組來(lái)指定,見(jiàn)下文。
操作和顯示結(jié)構(gòu)化數(shù)據(jù)類型
可以names
在dtype對(duì)象的屬性中找到結(jié)構(gòu)化數(shù)據(jù)類型的字段名稱列表:
>>> d = np.dtype([('x', 'i8'), ('y', 'f4')])
>>> d.names
('x', 'y')
可以通過(guò)names
使用相同長(zhǎng)度的字符串序列分配屬性來(lái)修改字段名稱。
dtype對(duì)象還具有類似字典的屬性,fields
其鍵是字段名稱(和字段標(biāo)題,見(jiàn)下文),
其值是包含每個(gè)字段的dtype和字節(jié)偏移量的元組。
>>> d.fields
mappingproxy({'x': (dtype('int64'), 0), 'y': (dtype('float32'), 8)})
對(duì)于非結(jié)構(gòu)化數(shù)組,names
和fields
屬性都相同None
。
測(cè)試 dtype 是否結(jié)構(gòu)化的推薦方法是, 如果dt.names不是None 而不是 dt.names ,則考慮具有0字段的dtypes。
如果可能,結(jié)構(gòu)化數(shù)據(jù)類型的字符串表示形式顯示在“元組列表”表單中,否則numpy將回退到使用更通用的字典表單。
自動(dòng)字節(jié)偏移和對(duì)齊
Numpy使用兩種方法之一自動(dòng)確定字段字節(jié)偏移量和結(jié)構(gòu)化數(shù)據(jù)類型的總項(xiàng)目大小,具體取決于是否
align=True
指定為關(guān)鍵字參數(shù)numpy.dtype
。
默認(rèn)情況下(align=False
),numpy將字段打包在一起,使得每個(gè)字段從前一個(gè)字段結(jié)束的字節(jié)偏移開(kāi)始,并且字段在內(nèi)存中是連續(xù)的。
>>> def print_offsets(d):
... print("offsets:", [d.fields[name][1] for name in d.names])
... print("itemsize:", d.itemsize)
>>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2'))
offsets: [0, 1, 2, 6, 7, 15]
itemsize: 17
如果align=True
設(shè)置了,numpy將以與許多C編譯器填充C結(jié)構(gòu)相同的方式填充結(jié)構(gòu)。在某些情況下,對(duì)齊結(jié)構(gòu)可以提高性能,但代價(jià)是增加了數(shù)據(jù)類型的大小。在字段之間插入填充字節(jié),使得每個(gè)字段的字節(jié)偏移量將是該字段對(duì)齊的倍數(shù),對(duì)于簡(jiǎn)單數(shù)據(jù)類型,通常等于字段的字節(jié)大小,請(qǐng)參閱PyArray_Descr.alignment
。該結(jié)構(gòu)還將添加尾隨填充,以使其itemsize是最大字段對(duì)齊的倍數(shù)。
>>> print_offsets(np.dtype('u1, u1, i4, u1, i8, u2', align=True))
offsets: [0, 1, 4, 8, 16, 24]
itemsize: 32
請(qǐng)注意,盡管默認(rèn)情況下幾乎所有現(xiàn)代C編譯器都以這種方式填充,但C結(jié)構(gòu)中的填充依賴于C實(shí)現(xiàn),因此不能保證此內(nèi)存布局與C程序中相應(yīng)結(jié)構(gòu)的內(nèi)容完全匹配。為了獲得確切的對(duì)應(yīng)關(guān)系,可能需要在numpy側(cè)或C側(cè)進(jìn)行一些工作。
如果使用offsets
基于字典的dtype規(guī)范中的可選鍵指定了偏移量,則設(shè)置align=True
將檢查每個(gè)字段的偏移量是其大小的倍數(shù),并且itemsize是最大字段大小的倍數(shù),如果不是,則引發(fā)異常。
如果結(jié)構(gòu)化數(shù)組的字段和項(xiàng)目大小的偏移滿足對(duì)齊條件,則數(shù)組將具有該ALIGNED
flag
集合。
便捷函數(shù)numpy.lib.recfunctions.repack_fields
將對(duì)齊的dtype或數(shù)組轉(zhuǎn)換為打包的dtype或數(shù)組,反之亦然。它需要一個(gè)dtype或結(jié)構(gòu)化的ndarray作為參數(shù),并返回一個(gè)帶有字段重新打包的副本,帶或不帶填充字節(jié)。
字段標(biāo)題
除了字段名稱之外,字段還可以具有關(guān)聯(lián)的標(biāo)題
,備用名稱,有時(shí)用作字段的附加說(shuō)明或別名。標(biāo)題可用于索引數(shù)組,就像字段名一樣。
要在使用dtype規(guī)范的list-of-tuples形式時(shí)添加標(biāo)題,可以將字段名稱指定為兩個(gè)字符串的元組而不是單個(gè)字符串,它們分別是字段的標(biāo)題和字段名稱。例如:
>>> np.dtype([(('my title', 'name'), 'f4')])
dtype([(('my title', 'name'), '<f4')])
當(dāng)使用第一種形式的基于字典的規(guī)范時(shí),標(biāo)題可以'titles'
作為如上所述的額外密鑰提供。當(dāng)使用第二個(gè)(不鼓勵(lì)的)基于字典的規(guī)范時(shí),可以通過(guò)提供3元素元組而不是通常的2元素元組來(lái)提供標(biāo)題:(datatype, offset, title)
>>> np.dtype({'name': ('i4', 0, 'my title')})
dtype([(('my title', 'name'), '<i4')])
該dtype.fields
字典將包含標(biāo)題作為鍵,如果使用任何頭銜。這有效地表示具有標(biāo)題的字段將在字典字典中表示兩次。這些字段的元組值還將具有第三個(gè)元素,即字段標(biāo)題。因此,并且因?yàn)?code>names屬性保留了字段順序而fields
屬性可能沒(méi)有,所以建議使用dtype的names
屬性迭代dtype的字段,該屬性不會(huì)列出標(biāo)題,如:
>>> for name in d.names:
... print(d.fields[name][:2])
(dtype('int64'), 0)
(dtype('float32'), 8)
聯(lián)合類型
默認(rèn)情況下,結(jié)構(gòu)化數(shù)據(jù)類型在numpy中實(shí)現(xiàn)為基本類型 numpy.void
,
但是可以使用 數(shù)據(jù)類型對(duì)象中 中描述的dtype規(guī)范的 (base_dtype, dtype)
形式將其他 numpy 類型解釋為結(jié)構(gòu)化類型。
這里,base_dtype
是所需的底層 dtype
,字段和標(biāo)志將從dtype復(fù)制。此 dtype 類似于 C 中的“Union”。
索引和分配給結(jié)構(gòu)化數(shù)組
將數(shù)據(jù)分配給結(jié)構(gòu)化數(shù)組
有許多方法可以為結(jié)構(gòu)化數(shù)組賦值:使用python元組,使用標(biāo)量值或使用其他結(jié)構(gòu)化數(shù)組。
從Python本機(jī)類??型(元組)分配
為結(jié)構(gòu)化數(shù)組賦值的最簡(jiǎn)單方法是使用python元組。每個(gè)賦值應(yīng)該是一個(gè)長(zhǎng)度等于數(shù)組中字段數(shù)的元組,而不是列表或數(shù)組,因?yàn)樗鼈儗⒂|發(fā)numpy的廣播規(guī)則。元組的元素從左到右分配給數(shù)組的連續(xù)字段:
>>> x = np.array([(1, 2, 3), (4, 5, 6)], dtype='i8, f4, f8')
>>> x[1] = (7, 8, 9)
>>> x
array([(1, 2., 3.), (7, 8., 9.)],
dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '<f8')])
Scalars的賦值
分配給結(jié)構(gòu)化元素的標(biāo)量將分配給所有字段。將標(biāo)量分配給結(jié)構(gòu)化數(shù)組時(shí),或者將非結(jié)構(gòu)化數(shù)組分配給結(jié)構(gòu)化數(shù)組時(shí),會(huì)發(fā)生這種情況:
>>> x = np.zeros(2, dtype='i8, f4, ?, S1')
>>> x[:] = 3
>>> x
array([(3, 3., True, b'3'), (3, 3., True, b'3')],
dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
>>> x[:] = np.arange(2)
>>> x
array([(0, 0., False, b'0'), (1, 1., True, b'1')],
dtype=[('f0', '<i8'), ('f1', '<f4'), ('f2', '?'), ('f3', 'S1')])
結(jié)構(gòu)化數(shù)組也可以分配給非結(jié)構(gòu)化數(shù)組,但前提是結(jié)構(gòu)化數(shù)據(jù)類型只有一個(gè)字段:
>>> twofield = np.zeros(2, dtype=[('A', 'i4'), ('B', 'i4')])
>>> onefield = np.zeros(2, dtype=[('A', 'i4')])
>>> nostruct = np.zeros(2, dtype='i4')
>>> nostruct[:] = twofield
Traceback (most recent call last):
...
TypeError: Cannot cast scalar from dtype([('A', '<i4'), ('B', '<i4')]) to dtype('int32') according to the rule 'unsafe'
來(lái)自其他結(jié)構(gòu)化數(shù)組的賦值
兩個(gè)結(jié)構(gòu)化數(shù)組之間的分配就像源元素已轉(zhuǎn)換為元組然后分配給目標(biāo)元素一樣。也就是說(shuō),源數(shù)組的第一個(gè)字段分配給目標(biāo)數(shù)組的第一個(gè)字段,第二個(gè)字段同樣分配,依此類推,而不管字段名稱如何。具有不同數(shù)量的字段的結(jié)構(gòu)化數(shù)組不能彼此分配。未包含在任何字段中的目標(biāo)結(jié)構(gòu)的字節(jié)不受影響。
>>> a = np.zeros(3, dtype=[('a', 'i8'), ('b', 'f4'), ('c', 'S3')])
>>> b = np.ones(3, dtype=[('x', 'f4'), ('y', 'S3'), ('z', 'O')])
>>> b[:] = a
>>> b
array([(0., b'0.0', b''), (0., b'0.0', b''), (0., b'0.0', b'')],
dtype=[('x', '<f4'), ('y', 'S3'), ('z', 'O')])
涉及子數(shù)組的分配
分配給子數(shù)組的字段時(shí),首先將指定的值廣播到子數(shù)組的形狀。
索引結(jié)構(gòu)化數(shù)組
訪問(wèn)單個(gè)字段
可以通過(guò)使用字段名稱索引數(shù)組來(lái)訪問(wèn)和修改結(jié)構(gòu)化數(shù)組的各個(gè)字段。
>>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
>>> x['foo']
array([1, 3])
>>> x['foo'] = 10
>>> x
array([(10, 2.), (10, 4.)],
dtype=[('foo', '<i8'), ('bar', '<f4')])
生成的數(shù)組是原始數(shù)組的視圖。它共享相同的內(nèi)存位置,寫入視圖將修改原始數(shù)組。
>>> y = x['bar']
>>> y[:] = 11
>>> x
array([(10, 11.), (10, 11.)],
dtype=[('foo', '<i8'), ('bar', '<f4')])
此視圖與索引字段具有相同的dtype和itemsize,因此它通常是非結(jié)構(gòu)化數(shù)組,但嵌套結(jié)構(gòu)除外。
>>> y.dtype, y.shape, y.strides
(dtype('float32'), (2,), (12,))
如果訪問(wèn)的字段是子數(shù)組,則子數(shù)組的維度將附加到結(jié)果的形狀:
>>> x = np.zeros((2, 2), dtype=[('a', np.int32), ('b', np.float64, (3, 3))])
>>> x['a'].shape
(2, 2)
>>> x['b'].shape
(2, 2, 3, 3)
訪問(wèn)多個(gè)字段
可以索引并分配具有多字段索引的結(jié)構(gòu)化數(shù)組,其中索引是字段名稱列表。
警告
多字段索引的行為從Numpy 1.15變?yōu)镹umpy 1.16。
使用多字段索引進(jìn)行索引的結(jié)果是原始數(shù)組的視圖,如下所示:
>>> a = np.zeros(3, dtype=[('a', 'i4'), ('b', 'i4'), ('c', 'f4')])
>>> a[['a', 'c']]
array([(0, 0.), (0, 0.), (0, 0.)],
dtype={'names':['a','c'], 'formats':['<i4','<f4'], 'offsets':[0,8], 'itemsize':12})
對(duì)視圖的賦值會(huì)修改原始數(shù)組。視圖的字段將按其索引的順序排列。請(qǐng)注意,與單字段索引不同,視圖的dtype與原始數(shù)組具有相同的項(xiàng)目大小,并且具有與原始數(shù)組相同的偏移量的字段,并且僅缺少未編入索引的字段。
警告
在Numpy 1.15中,使用多字段索引索引數(shù)組會(huì)返回上面結(jié)果的副本,但字段在內(nèi)存中打包在一起,就像通過(guò)一樣numpy.lib.recfunctions.repack_fields
。
從Numpy 1.16開(kāi)始的新行為導(dǎo)致在未編制索引的位置處的額外“填充”字節(jié)與1.15相比。您需要更新任何依賴于具有“打包”布局的數(shù)據(jù)的代碼。例如代碼如:
>>> a[['a', 'c']].view('i8') # Fails in Numpy 1.16
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: When changing to a smaller dtype, its size must be a divisor of the size of original dtype
需要改變。FutureWarning
自從Numpy 1.12以來(lái),這段代碼已經(jīng)提出了類似的代碼,FutureWarning
自1.7 以來(lái)也提出了類似的代碼。
在1.16中,numpy.lib.recfunctions
模塊中引入了許多功能,
以幫助用戶解釋此更改。這些是
numpy.lib.recfunctions.repack_fields
。
numpy.lib.recfunctions.structured_to_unstructured
,
numpy.lib.recfunctions.unstructured_to_structured
,
numpy.lib.recfunctions.apply_along_fields
,
numpy.lib.recfunctions.assign_fields_by_name
,和
numpy.lib.recfunctions.require_fields
。
該函數(shù)numpy.lib.recfunctions.repack_fields
始終可用于重現(xiàn)舊行為,因?yàn)樗鼘⒎祷亟Y(jié)構(gòu)化數(shù)組的打包副本。例如,上面的代碼可以替換為:
>>> from numpy.lib.recfunctions import repack_fields
>>> repack_fields(a[['a', 'c']]).view('i8') # supported in 1.16
array([0, 0, 0])
此外,numpy現(xiàn)在提供了一個(gè)新功能
numpy.lib.recfunctions.structured_to_unstructured
,對(duì)于希望將結(jié)構(gòu)化數(shù)組轉(zhuǎn)換為非結(jié)構(gòu)化數(shù)組的用戶來(lái)說(shuō),這是一種更安全,更有效的替代方法,因?yàn)樯厦娴囊晥D通常不符合要求。此功能允許安全地轉(zhuǎn)換為非結(jié)構(gòu)化類型,并考慮填充,通常避免復(fù)制,并且還根據(jù)需要轉(zhuǎn)換數(shù)據(jù)類型,這與視圖不同。代碼如:
>>> b = np.zeros(3, dtype=[('x', 'f4'), ('y', 'f4'), ('z', 'f4')])
>>> b[['x', 'z']].view('f4')
array([0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)
可以通過(guò)替換為:更安全
>>> from numpy.lib.recfunctions import structured_to_unstructured
>>> structured_to_unstructured(b[['x', 'z']])
array([0, 0, 0])
使用多字段索引分配數(shù)組會(huì)修改原始數(shù)組:
>>> a[['a', 'c']] = (2, 3)
>>> a
array([(2, 0, 3.), (2, 0, 3.), (2, 0, 3.)],
dtype=[('a', '<i4'), ('b', '<i4'), ('c', '<f4')])
這遵循上述結(jié)構(gòu)化數(shù)組分配規(guī)則。例如,這意味著可以使用適當(dāng)?shù)亩嘧侄嗡饕粨Q兩個(gè)字段的值:
>>> a[['a', 'c']] = a[['c', 'a']]
使用整數(shù)進(jìn)行索引以獲得結(jié)構(gòu)化標(biāo)量
索引結(jié)構(gòu)化數(shù)組的單個(gè)元素(帶有整數(shù)索引)將返回結(jié)構(gòu)化標(biāo)量:
>>> x = np.array([(1, 2., 3.)], dtype='i, f, f')
>>> scalar = x[0]
>>> scalar
(1, 2., 3.)
>>> type(scalar)
<class 'numpy.void'>
與其他numpy標(biāo)量不同,結(jié)構(gòu)化標(biāo)量是可變的,并且像原始數(shù)組中的視圖一樣,因此修改標(biāo)量將修改原始數(shù)組。結(jié)構(gòu)化標(biāo)量還支持按字段名稱進(jìn)行訪問(wèn)和分配:
>>> x = np.array([(1, 2), (3, 4)], dtype=[('foo', 'i8'), ('bar', 'f4')])
>>> s = x[0]
>>> s['bar'] = 100
>>> x
array([(1, 100.), (3, 4.)],
dtype=[('foo', '<i8'), ('bar', '<f4')])
與元組類似,結(jié)構(gòu)化標(biāo)量也可以用整數(shù)索引:
>>> scalar = np.array([(1, 2., 3.)], dtype='i, f, f')[0]
>>> scalar[0]
1
>>> scalar[1] = 4
因此,元組可能被認(rèn)為是本機(jī)Python等同于numpy的結(jié)構(gòu)化類型,就像本機(jī)python整數(shù)相當(dāng)于numpy的整數(shù)類型。結(jié)構(gòu)化標(biāo)量可以通過(guò)調(diào)用ndarray.item
以下方式轉(zhuǎn)換為元組:
>>> scalar.item(), type(scalar.item())
((1, 4.0, 3.0), <class 'tuple'>)
查看包含對(duì)象的結(jié)構(gòu)化數(shù)組
為了防止numpy.object
類型字段中的clobbering對(duì)象指針
,numpy當(dāng)前不允許包含對(duì)象的結(jié)構(gòu)化數(shù)組的視圖。
結(jié)構(gòu)比較
如果兩個(gè)void結(jié)構(gòu)化數(shù)組的dtypes相等,則測(cè)試數(shù)組的相等性將導(dǎo)致具有原始數(shù)組的維度的布爾數(shù)組,其中元素設(shè)置為True
相應(yīng)結(jié)構(gòu)的所有字段相等的位置。如果字段名稱,dtypes和標(biāo)題相同,忽略字節(jié)順序,并且字段的順序相同,則結(jié)構(gòu)化dtypes是相等的:
>>> a = np.zeros(2, dtype=[('a', 'i4'), ('b', 'i4')])
>>> b = np.ones(2, dtype=[('a', 'i4'), ('b', 'i4')])
>>> a == b
array([False, False])
目前,如果兩個(gè)void結(jié)構(gòu)化數(shù)組的dtypes不相等,則比較失敗,返回標(biāo)量值False
。從numpy 1.10開(kāi)始不推薦使用此行為,并且將來(lái)會(huì)引發(fā)錯(cuò)誤或執(zhí)行元素比較。
在<
與>
運(yùn)營(yíng)商總是返回False
比較空洞結(jié)構(gòu)數(shù)組時(shí),與算術(shù)和位操作不被支持。
記錄數(shù)組
作為一個(gè)可選的方便numpy numpy.recarray
numpy.rec
子模塊中提供了一個(gè)ndarray子類,以及相關(guān)的輔助函數(shù)
,它允許按屬性而不是僅通過(guò)索引訪問(wèn)結(jié)構(gòu)化數(shù)組的字段。記錄數(shù)組也使用特殊的數(shù)據(jù)類型,
numpy.record
允許通過(guò)屬性對(duì)從數(shù)組中獲取的結(jié)構(gòu)化標(biāo)量進(jìn)行字段訪問(wèn)。
創(chuàng)建記錄數(shù)組的最簡(jiǎn)單方法是numpy.rec.array
:
>>> recordarr = np.rec.array([(1, 2., 'Hello'), (2, 3., "World")],
... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'S10')])
>>> recordarr.bar
array([ 2., 3.], dtype=float32)
>>> recordarr[1:2]
rec.array([(2, 3., b'World')],
dtype=[('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')])
>>> recordarr[1:2].foo
array([2], dtype=int32)
>>> recordarr.foo[1:2]
array([2], dtype=int32)
>>> recordarr[1].baz
b'World'
numpy.rec.array
可以將各種參數(shù)轉(zhuǎn)換為記錄數(shù)組,包括結(jié)構(gòu)化數(shù)組:
>>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
... dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])
>>> recordarr = np.rec.array(arr)
該numpy.rec
模塊提供了許多其他便利函數(shù)來(lái)創(chuàng)建記錄數(shù)組,請(qǐng)參閱記錄數(shù)組創(chuàng)建例程。
可以使用適當(dāng)?shù)囊晥D獲取結(jié)構(gòu)化數(shù)組的記錄數(shù)組表示:
>>> arr = np.array([(1, 2., 'Hello'), (2, 3., "World")],
... dtype=[('foo', 'i4'),('bar', 'f4'), ('baz', 'a10')])
>>> recordarr = arr.view(dtype=np.dtype((np.record, arr.dtype)),
... type=np.recarray)
為方便起見(jiàn),將ndarray視為類型np.recarray
將自動(dòng)轉(zhuǎn)換為np.record
數(shù)據(jù)類型,因此dtype可以不在視圖之外:
>>> recordarr = arr.view(np.recarray)
>>> recordarr.dtype
dtype((numpy.record, [('foo', '<i4'), ('bar', '<f4'), ('baz', 'S10')]))
要返回普通的ndarray,必須重置dtype和type。以下視圖是這樣做的,考慮到recordarr不是結(jié)構(gòu)化類型的異常情況:
>>> arr2 = recordarr.view(recordarr.dtype.fields or recordarr.dtype, np.ndarray)
如果字段具有結(jié)構(gòu)化類型,則返回由index或by屬性訪問(wèn)的記錄數(shù)組字段作為記錄數(shù)組,否則返回普通ndarray。
>>> recordarr = np.rec.array([('Hello', (1, 2)), ("World", (3, 4))],
... dtype=[('foo', 'S6'),('bar', [('A', int), ('B', int)])])
>>> type(recordarr.foo)
<class 'numpy.ndarray'>
>>> type(recordarr.bar)
<class 'numpy.recarray'>
請(qǐng)注意,如果字段與ndarray屬性具有相同的名稱,則ndarray屬性優(yōu)先。這些字段將無(wú)法通過(guò)屬性訪問(wèn),但仍可通過(guò)索引訪問(wèn)。
Recarray Helper 函數(shù)
用于操作結(jié)構(gòu)化數(shù)組的實(shí)用程序的集合。
大多數(shù)這些功能最初由 John Hunter 為 matplotlib 實(shí)現(xiàn)。為方便起見(jiàn),它們已被重寫和擴(kuò)展。
-
numpy.lib.recfunctions.append_fields(base, names, data, dtypes=None, fill_value=-1, usemask=True, asrecarray=False)[點(diǎn)擊查看源碼]
將函數(shù)“func”簡(jiǎn)單的應(yīng)用于結(jié)構(gòu)化數(shù)組的各個(gè)字段的。
這類似于 apply_along_axis,但將結(jié)構(gòu)化數(shù)組的字段視為額外軸。這些字段首先被轉(zhuǎn)換為類型提升規(guī)則后 numpy.result_type
將n-D非結(jié)構(gòu)化數(shù)組轉(zhuǎn)換為(n-1)-D結(jié)構(gòu)化數(shù)組。
輸入數(shù)組的最后一維被轉(zhuǎn)換為結(jié)構(gòu),字段元素的數(shù)量等于輸入數(shù)組的最后一維的大小。默認(rèn)情況下,所有輸出字段都具有輸入數(shù)組的dtype,但是可以提供具有相等數(shù)量的field-element的輸出結(jié)構(gòu)化dtype。
嵌套字段以及任何子數(shù)組字段的每個(gè)元素都計(jì)入字段元素的數(shù)量。
參數(shù)表:
參數(shù)名 數(shù)據(jù)類型 描述 arr ndarray 要轉(zhuǎn)換的非結(jié)構(gòu)化數(shù)組或數(shù)據(jù)類型。 dtype dtype, optional 輸出數(shù)組的結(jié)構(gòu)化數(shù)據(jù)類型。 names list of strings, optional 如果未提供dtype,則按順序指定輸出dtype的字段名稱。字段dtype將與輸入數(shù)組相同。 align boolean, optional 是否創(chuàng)建對(duì)齊的內(nèi)存布局。 copy bool, optional 請(qǐng)參見(jiàn)將參數(shù)復(fù)制到ndarray.astype。如果為true,則始終返回副本。如果為false,并且滿足dtype要求,則返回視圖。 casting {‘no’, ‘equiv’, ‘safe’, ‘same_kind’, ‘unsafe’}, optional 請(qǐng)參見(jiàn)轉(zhuǎn)換ndarray.astype的參數(shù)??刂瓶赡馨l(fā)生的數(shù)據(jù)轉(zhuǎn)換類型。 返回值:
參數(shù)名 數(shù)據(jù)類型 描述 structured ndarray 維數(shù)較少的結(jié)構(gòu)化數(shù)組。 示例:
>>> from numpy.lib import recfunctions as rfn >>> dt = np.dtype([('a', 'i4'), ('b', 'f4,u2'), ('c', 'f4', 2)]) >>> a = np.arange(20).reshape((4,5)) >>> a array([[ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19]]) >>> rfn.unstructured_to_structured(a, dt) array([( 0, ( 1., 2), [ 3., 4.]), ( 5, ( 6., 7), [ 8., 9.]), (10, (11., 12), [13., 14.]), (15, (16., 17), [18., 19.])], dtype=[('a', '<i4'), ('b', [('f0', '<f4'), ('f1', '<u2')]), ('c', '<f4', (2,))])
作者:柯廣的網(wǎng)絡(luò)日志 ? 結(jié)構(gòu)化數(shù)組
微信公眾號(hào):Java大數(shù)據(jù)與數(shù)據(jù)倉(cāng)庫(kù)