1. 程式人生 > >Numpy 修煉之道 (10)—— 結構化陣列

Numpy 修煉之道 (10)—— 結構化陣列

 

之前我們操作Numpy的陣列時,都是通過索引來操作的。針對二維陣列,使用索引可以完成對行、列的操作。但是這是非常不直觀的。可以把二維陣列想象成一個excel表格,如果表格沒有列名,操作起來會非常麻煩,針對這種情況,Numpy提供了結構化陣列用來操作每列資料。
之前我們操作Numpy的陣列時,都是通過索引來操作的。針對二維陣列,使用索引可以完成對行、列的操作。但是這是非常不直觀的。可以把二維陣列想象成一個excel表格,如果表格沒有列名,操作起來會非常麻煩,針對這種情況,Numpy提供了結構化陣列用來操作每列資料。
來看一個示例:
>>> x = np.array([('Bob', 18,
2000.0),('Tom', 23, 4000.0)],
... dtype=[('name', 'S10'), ('age', np.int_), ('incom', np.float_)])
>>> x
array([('Bob', 18,  2000.), ('Tom', 23,  4000.)],
     dtype=[('name',
'S10'), ('age', '<i4'), ('incom', '<f8')])
>>> x.shape
(2L,)
>>> row = x[0]
>>> row
('Bob', 18,  2000.)
>>> col = x['name']
>>> col
array(['Bob', 'Tom'],
     dtype='|S10')
上面我們建立了一個二維陣列,行數為2,列數為3,其中每列的型別分別是長度為10或者更小的字串、32位整數、64位浮點數。之後分別使用數字索引訪問了第一行資料得到row,以及使用名稱索引訪問了第一列資料得到col。
需要注意的是,不管是row還是col,獲取到的都是隻是檢視,所以更改結構化陣列x時,對應的檢視也會發生改變。
>>> x['name'] = ['Bob01', 'Tom01']
>>> x
array([('Bob01', 18,  2000.), ('Tom01', 23,  4000.)],
     dtype=[('name',
'S10'), ('age', '<i4'), ('incom', '<f8')])
>>> row
('Bob01', 18,  2000.)
>>> col
array(['Bob01', 'Tom01'],
     dtype='|S10')

構建結構化陣列

通過dtype物件定義一個結構化陣列。。使用引數(如提供給dtype函式關鍵字或dtype物件建構函式本身)通過四種可選方法之一指定記錄結構。此引數必須是以下之一:string,tuple,list,或 dictionary。
在這種情況下,建構函式需要一個逗號分隔的型別說明符列表,可選地包含額外的形狀資訊。欄位被賦予預設名稱'f0','f1','f2'等。型別說明符可以採用4種不同的形式: 

字串引數
在這種情況下,建構函式需要一個逗號分隔的型別說明符列表,可選地包含額外的形狀資訊。欄位被賦予預設名稱'f0','f1','f2'等。型別說明符可以採用4種不同的形式:
a) b1, i1, i2, i4, i8, u1, u2, u4, u8, f2, f4, f8, c8, c16, a<n>
  (代表 bytes, ints, unsigned ints, floats, complex and
   fixed length strings of specified byte lengths)b) int8,...,uint8,...,float16, float32, float64, complex64, complex128
  (this time with bit sizes)c) older Numeric/numarray type specifications (e.g. Float32).
  不推薦使用!d) Single character type specifiers (e.g H for unsigned short ints).
  一般也避免使用!

示例如下:
>>> x = np.zeros(3, dtype='3int8,
float32, (2,3)float64')
>>> x
array([([0, 0, 0],  0., [[ 0.,  0.,  0.], [ 0.,  0.,0.]]),
      ([0, 0, 0],0., [[ 0.,  0.,  0.], [ 0.,  0.,  0.]]),
      ([0, 0, 0],0., [[ 0.,  0.,  0.], [ 0.,  0.,  0.]])],
     dtype=[('f0', 'i1',(3,)), ('f1', '<f4'), ('f2', '<f8', (2, 3))])

元祖引數
適用於記錄結構的唯一相關元組是當結構對映到現有資料型別時。這是通過在元組中配對現有資料型別與匹配的dtype定義(使用此處描述的任何變體)來完成的。
>>> x = np.zeros(3,
dtype=('i4',[('r','u1'), ('g','u1'), ('b','u1'), ('a','u1')]))
>>> x
array([0, 0, 0])
>>> x['r']
array([0, 0, 0], dtype=uint8)

列表引數
在這種情況下,記錄結構用元組列表定義。每個元組具有2或3個元素,指定:欄位的名稱(允許使用''),欄位的型別,以及形狀(可選)。
>>> x = np.zeros(3,
dtype=[('x','f4'),('y',np.float32),('value','f4',(2,2))])
>>> x
array([(0.0, 0.0, [[0.0, 0.0], [0.0, 0.0]]),
      (0.0, 0.0, [[0.0,0.0], [0.0, 0.0]]),
      (0.0, 0.0, [[0.0,0.0], [0.0, 0.0]])],
     dtype=[('x','>f4'), ('y', '>f4'), ('value', '>f4', (2, 2))])

字典引數
允許兩種不同的形式。第一個包含一個具有兩個必需鍵('names'和'formats')的字典,每個鍵都有一個相等大小的值列表。格式列表包含在其他上下文中允許的任何型別/形狀說明符。名稱必須是字串。有兩個可選鍵:“offsets”和“titles”。每個都必須是相應匹配的列表,其中偏移量包含每個欄位的整數偏移量,標題是包含每個欄位的元資料的物件(這些物件不必是字串),其中允許值為None。舉個例子:
>>> x = np.zeros(3,
dtype={'names':['col1', 'col2'], 'formats':['i4','f4']})
>>> x
array([(0, 0.0), (0, 0.0), (0, 0.0)],
     dtype=[('col1',
'>i4'), ('col2', '>f4')])
允許的其他字典形式是具有指定型別,偏移和可選標題的元組值的名稱鍵的字典。
>>> x = np.zeros(3,
dtype={'col1':('i1',0,'title 1'), 'col2':('f4',1,'title 2')})
>>> x
array([(0, 0.0), (0, 0.0), (0, 0.0)],
     dtype=[(('title 1',
'col1'), '|i1'), (('title 2', 'col2'), '>f4')])

   訪問欄位標題
欄位標題提供了一個標準位置來放置欄位的關聯資訊。他們不必是字串。
>>> x.dtype.fields['x'][2]
'title 1'

   訪問和修改欄位名稱
>>> x.dtype.names
('col1', 'col2')
>>>
>>> x.dtype.names = ('x', 'y')
>>> x
array([(0,  0.), (0,  0.), (0,  0.)],
     dtype=[(('title 1',
'x'), 'i1'), (('title 2', 'y'), '<f4')])

   一次訪問多個欄位
您可以使用欄位名稱列表一次訪問多個欄位:
>>> x =np.array([(1.5,2.5,(1.0,2.0)),(3.,4.,(4.,5.)),(1.,3.,(2.,6.))],
dtype=[('x','f4'),('y',np.float32),('value','f4',(2,2))])
請注意,x是使用元組列表建立的。
>>> x[['x','y']]
array([(1.5, 2.5), (3.0, 4.0), (1.0, 3.0)],
    dtype=[('x', '<f4'),('y', '<f4')])
>>> x[['x','value']]
array([(1.5, [[1.0, 2.0], [1.0, 2.0]]), (3.0, [[4.0, 5.0], [4.0, 5.0]]),
     (1.0, [[2.0, 6.0],[2.0, 6.0]])],
    dtype=[('x', '<f4'),
('value', '<f4', (2, 2))])
>>> x[x['y'] == 4]
array([( 3., 4., [[ 4., 5.], [ 4., 5.]])],
    dtype=[('x', '<f4'),
('y', '<f4'), ('value', '<f4', (2, 2))])
欄位按請求的順序返回(可以用來調整陣列順序):
>>> x[['y','x']]
array([(2.5, 1.5), (4.0, 3.0), (3.0, 1.0)],
    dtype=[('y', '<f4'),
('x', '<f4')])

 記錄陣列

雖然結構化陣列已經能夠通過欄位索引來運算元組了,記錄陣列允許通過Python中屬性的方式(就是以“.”的方式)來操作。
記錄陣列也使用特殊的資料型別numpy.record
建立記錄陣列的最簡單的方法是使用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.0, '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'World'
numpy.rec.array可以將各種引數轉換為記錄陣列,包括正常的結構化陣列:
>>> arr =array([(1,2.,'Hello'),(2,3.,"World")], 
...           
dtype=[('foo', 'i4'), ('bar', 'f4'), ('baz', 'S10')])
>>> recordarr = np.rec.array(arr)


腦洞科技棧專注於人工智慧與量化投資領域

瞭解更多幹貨文章,可以關注小程式八斗問答