2010-09-01 45 views
22

Tôi đang cố chuyển đổi mảng hai chiều thành mảng có cấu trúc với các trường được đặt tên. Tôi muốn mỗi hàng trong mảng 2D là một bản ghi mới trong mảng có cấu trúc. Thật không may, không có gì tôi đã cố gắng làm việc theo cách tôi mong đợi.Chuyển đổi mảng 2D thành mảng có cấu trúc

tôi bắt đầu với:

>>> myarray = numpy.array([("Hello",2.5,3),("World",3.6,2)]) 
>>> print myarray 
[['Hello' '2.5' '3'] 
['World' '3.6' '2']] 

Tôi muốn chuyển đổi sang cái gì đó trông như thế này:

>>> newarray = numpy.array([("Hello",2.5,3),("World",3.6,2)], dtype=[("Col1","S8"),("Col2","f8"),("Col3","i8")]) 
>>> print newarray 
[('Hello', 2.5, 3L) ('World', 3.6000000000000001, 2L)] 

Những gì tôi đã cố gắng:

>>> newarray = myarray.astype([("Col1","S8"),("Col2","f8"),("Col3","i8")]) 
>>> print newarray 
[[('Hello', 0.0, 0L) ('2.5', 0.0, 0L) ('3', 0.0, 0L)] 
[('World', 0.0, 0L) ('3.6', 0.0, 0L) ('2', 0.0, 0L)]] 

>>> newarray = numpy.array(myarray, dtype=[("Col1","S8"),("Col2","f8"),("Col3","i8")]) 
>>> print newarray 
[[('Hello', 0.0, 0L) ('2.5', 0.0, 0L) ('3', 0.0, 0L)] 
[('World', 0.0, 0L) ('3.6', 0.0, 0L) ('2', 0.0, 0L)]] 

Cả hai các phương pháp này cố gắng chuyển đổi từng mục nhập trong myarray thành một bản ghi với dtype đã cho, do đó các số 0 bổ sung được chèn vào. Tôi không thể tìm ra cách để làm cho nó chuyển đổi từng hàng thành một bản ghi.

Một nỗ lực:

>>> newarray = myarray.copy() 
>>> newarray.dtype = [("Col1","S8"),("Col2","f8"),("Col3","i8")] 
>>> print newarray 
[[('Hello', 1.7219343871178711e-317, 51L)] 
[('World', 1.7543139673493688e-317, 50L)]] 

Lần này không chuyển đổi thực tế được thực hiện. Dữ liệu hiện có trong bộ nhớ chỉ được hiểu là kiểu dữ liệu mới.

Mảng mà tôi đang bắt đầu đang được đọc từ tệp văn bản. Các kiểu dữ liệu không được biết trước, vì vậy tôi không thể đặt kiểu dtype tại thời điểm tạo. Tôi cần một giải pháp hiệu suất cao và thanh lịch sẽ hoạt động tốt cho các trường hợp thông thường vì tôi sẽ thực hiện loại chuyển đổi này nhiều lần, nhiều lần cho nhiều ứng dụng khác nhau.

Cảm ơn!

Trả lời

26

Bạn có thể "tạo ra một mảng bản ghi từ một (phẳng) danh sách các mảng" sử dụng numpy.core.records.fromarrays như sau:

>>> import numpy as np 
>>> myarray = np.array([("Hello",2.5,3),("World",3.6,2)]) 
>>> print myarray 
[['Hello' '2.5' '3'] 
['World' '3.6' '2']] 


>>> newrecarray = np.core.records.fromarrays(myarray.transpose(), 
              names='col1, col2, col3', 
              formats = 'S8, f8, i8') 

>>> print newrecarray 
[('Hello', 2.5, 3) ('World', 3.5999999046325684, 2)] 

Tôi đã cố gắng để làm một cái gì đó tương tự. Tôi thấy rằng khi numpy tạo ra một mảng có cấu trúc từ một mảng 2D hiện có (sử dụng np.core.records.fromarrays), nó xem xét mỗi cột (thay vì mỗi hàng) trong mảng 2-D làm bản ghi. Vì vậy, bạn phải chuyển nó. Hành vi này có vẻ rất trực quan, nhưng có lẽ có lý do chính đáng cho nó.

+2

với 'fromrecords' bạn có thể tránh' transpose() ' –

2

Được rồi, tôi đã phải vật lộn với điều này trong một thời gian nhưng tôi đã tìm thấy một cách để làm điều này mà không mất quá nhiều công sức. Tôi xin lỗi nếu mã này là "bẩn" ....

Hãy bắt đầu với một mảng 2D:

mydata = numpy.array([['text1', 1, 'longertext1', 0.1111], 
        ['text2', 2, 'longertext2', 0.2222], 
        ['text3', 3, 'longertext3', 0.3333], 
        ['text4', 4, 'longertext4', 0.4444], 
        ['text5', 5, 'longertext5', 0.5555]]) 

Vì vậy, chúng tôi kết thúc với một mảng với 4 cột và 5 dòng 2D:

mydata.shape 
Out[30]: (5L, 4L) 

Để sử dụng numpy.core.records.mảng - chúng ta cần phải cung cấp đối số đầu vào như một danh sách các mảng như vậy:

tuple(mydata) 
Out[31]: 
(array(['text1', '1', 'longertext1', '0.1111'], 
     dtype='|S11'), 
array(['text2', '2', 'longertext2', '0.2222'], 
     dtype='|S11'), 
array(['text3', '3', 'longertext3', '0.3333'], 
     dtype='|S11'), 
array(['text4', '4', 'longertext4', '0.4444'], 
     dtype='|S11'), 
array(['text5', '5', 'longertext5', '0.5555'], 
     dtype='|S11')) 

này tạo ra một mảng riêng biệt cho mỗi hàng dữ liệu NHƯNG, chúng ta cần các mảng đầu vào được theo cột vì vậy những gì chúng ta cần là:

tuple(mydata.transpose()) 
Out[32]: 
(array(['text1', 'text2', 'text3', 'text4', 'text5'], 
     dtype='|S11'), 
array(['1', '2', '3', '4', '5'], 
     dtype='|S11'), 
array(['longertext1', 'longertext2', 'longertext3', 'longertext4', 
     'longertext5'], 
     dtype='|S11'), 
array(['0.1111', '0.2222', '0.3333', '0.4444', '0.5555'], 
     dtype='|S11')) 

Cuối cùng nó cần phải được một danh sách các mảng, không phải là một tuple, vì vậy chúng tôi quấn trên trong danh sách() như sau:

list(tuple(mydata.transpose())) 

đó là lập luận đầu vào dữ liệu của chúng tôi được sắp xếp ... tiếp theo là dtype:

mydtype = numpy.dtype([('My short text Column', 'S5'), 
         ('My integer Column', numpy.int16), 
         ('My long text Column', 'S11'), 
         ('My float Column', numpy.float32)]) 
mydtype 
Out[37]: dtype([('My short text Column', '|S5'), ('My integer Column', '<i2'), ('My long text Column', '|S11'), ('My float Column', '<f4')]) 

Được rồi, vì vậy bây giờ chúng ta có thể vượt qua mà đến numpy.core.records.array():

myRecord = numpy.core.records.array(list(tuple(mydata.transpose())), dtype=mydtype) 

... và các ngón tay chéo:

myRecord 
Out[36]: 
rec.array([('text1', 1, 'longertext1', 0.11110000312328339), 
     ('text2', 2, 'longertext2', 0.22220000624656677), 
     ('text3', 3, 'longertext3', 0.33329999446868896), 
     ('text4', 4, 'longertext4', 0.44440001249313354), 
     ('text5', 5, 'longertext5', 0.5554999709129333)], 
     dtype=[('My short text Column', '|S5'), ('My integer Column', '<i2'), ('My long text Column', '|S11'), ('My float Column', '<f4')]) 

Voila! Bạn có thể chỉ mục theo tên cột như trong:

myRecord['My float Column'] 
Out[39]: array([ 0.1111 , 0.22220001, 0.33329999, 0.44440001, 0.55549997], dtype=float32) 

Tôi hy vọng điều này sẽ giúp khi tôi lãng phí quá nhiều thời gian với numpy.asarray và mydata.astype vv cố gắng để có được điều này để làm việc cuối cùng trước khi làm việc ra phương pháp này.

8

Tôi đoán

new_array = np.core.records.fromrecords([("Hello",2.5,3),("World",3.6,2)], 
             names='Col1,Col2,Col3', 
             formats='S8,f8,i8') 

là những gì bạn muốn.

1

Nếu dữ liệu bắt đầu như một danh sách của các bộ, sau đó tạo ra một mảng có cấu trúc là thẳng về phía trước:

In [228]: alist = [("Hello",2.5,3),("World",3.6,2)] 
In [229]: dt = [("Col1","S8"),("Col2","f8"),("Col3","i8")] 
In [230]: np.array(alist, dtype=dt) 
Out[230]: 
array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
     dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 

Các biến chứng ở đây là rằng danh sách các hàng đã được biến thành một mảng chuỗi 2d:

In [231]: arr = np.array(alist) 
In [232]: arr 
Out[232]: 
array([['Hello', '2.5', '3'], 
     ['World', '3.6', '2']], 
     dtype='<U5') 

chúng ta có thể sử dụng nổi tiếng zip* cách tiếp cận để 'transposing' mảng này - thực sự chúng tôi muốn có một chuyển vị kép:

In [234]: list(zip(*arr.T)) 
Out[234]: [('Hello', '2.5', '3'), ('World', '3.6', '2')] 

zip đã thuận tiện cho chúng tôi danh sách các bộ dữ liệu. Bây giờ chúng ta có thể tái tạo mảng với dtype mong muốn:

In [235]: np.array(_, dtype=dt) 
Out[235]: 
array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
     dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 

Câu trả lời được chấp nhận sử dụng fromarrays:

In [236]: np.rec.fromarrays(arr.T, dtype=dt) 
Out[236]: 
rec.array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
      dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 

Bên trong, fromarrays mất một recfunctions tiếp cận phổ biến: tạo mảng mục tiêu, và sao chép giá trị của tên trường. Có hiệu quả:

In [237]: newarr = np.empty(arr.shape[0], dtype=dt) 
In [238]: for n, v in zip(newarr.dtype.names, arr.T): 
    ...:  newarr[n] = v 
    ...:  
In [239]: newarr 
Out[239]: 
array([(b'Hello', 2.5, 3), (b'World', 3.6, 2)], 
     dtype=[('Col1', 'S8'), ('Col2', '<f8'), ('Col3', '<i8')]) 
Các vấn đề liên quan