2013-03-22 36 views
11

Tôi có một câu hỏi cơ bản khác, rằng tôi đã không thể tìm thấy câu trả lời cho, nhưng có vẻ như một điều gì đó nên dễ thực hiện.Làm thế nào để bạn loại bỏ một cột khỏi một mảng có cấu trúc?

Ok, hãy tưởng tượng bạn có mảng kết cấu có cấu trúc, được tạo từ csv với hàng đầu tiên làm tên trường. Mảng có dạng:

dtype([('A', '<f8'), ('B', '<f8'), ('C', '<f8'), ..., ('n','<f8']) 

Bây giờ, giả sử bạn muốn loại bỏ khỏi mảng này 'cột'. Có cách nào thuận tiện để làm điều đó không?

Tôi muốn một nó hoạt động như xóa:

new_array = np.delete(old_array, 'i') 

Bất kỳ ý tưởng?

+0

Tất cả đều là dtypes f8? –

Trả lời

13

Nó không hẳn là một chức năng cuộc gọi duy nhất, nhưng các chương trình sau đây là một cách để thả các lĩnh vực thứ i:

In [67]: a 
Out[67]: 
array([(1.0, 2.0, 3.0), (4.0, 5.0, 6.0)], 
     dtype=[('A', '<f8'), ('B', '<f8'), ('C', '<f8')]) 

In [68]: i = 1 # Drop the 'B' field 

In [69]: names = list(a.dtype.names) 

In [70]: names 
Out[70]: ['A', 'B', 'C'] 

In [71]: new_names = names[:i] + names[i+1:] 

In [72]: new_names 
Out[72]: ['A', 'C'] 

In [73]: b = a[new_names] 

In [74]: b 
Out[74]: 
array([(1.0, 3.0), (4.0, 6.0)], 
     dtype=[('A', '<f8'), ('C', '<f8')]) 

Wrapped lên như một chức năng:

def remove_field_num(a, i): 
    names = list(a.dtype.names) 
    new_names = names[:i] + names[i+1:] 
    b = a[new_names] 
    return b 

Nó có thể là nhiều hơn tự nhiên để xóa một trường nhất định tên:

Ngoài ra, ch eck ra số drop_rec_fields function là một phần của mlab module của matplotlib.


Cập nhật: Xem câu trả lời của tôi tại How to remove a column from a structured numpy array *without copying it*? cho một phương pháp để tạo ra một cái nhìn của các tập con của các lĩnh vực của một mảng cấu trúc mà không làm một bản sao của mảng.

+0

+1 Đánh bại tôi bằng 3 phút! – Jaime

+1

@Jaime: Barely. :) Vì bạn đã xóa câu trả lời của mình, tôi sẽ đề cập đến việc xóa theo tên trường thay vì số, điều này có thể tự nhiên hơn. –

5

Có googled cách của tôi ở đây và học được những gì tôi cần phải biết từ câu trả lời của Warren, tôi không thể cưỡng lại đăng một phiên bản ngắn gọn hơn, với các tùy chọn bổ sung để loại bỏ nhiều lĩnh vực có hiệu quả trong một đi:

def rmfield(a, *fieldnames_to_remove): 
    return a[ [ name for name in a.dtype.names if name not in fieldnames_to_remove ] ] 

Ví dụ:

a = rmfield(a, 'foo') 
a = rmfield(a, 'foo', 'bar') # remove multiple fields at once 

Hoặc nếu chúng ta thực sự sẽ golf nó, sau đây là tương đương:

rmfield=lambda a,*f:a[[n for n in a.dtype.names if n not in f]] 
+0

Giải pháp thứ hai của bạn khá xấu nếu tôi có thể nói như vậy. Đặc biệt, tôi không thích việc bạn sử dụng một biểu thức lambda cho những gì có hiệu lực trong một khai báo hàm. Nó không phải là một phong cách tốt và khó đọc. Những người khác dường như đồng ý với tôi: http://stackoverflow.com/a/134638/1375015 –

+1

Có lẽ bạn đã không đọc cụm từ "nếu chúng tôi thực sự đang chơi golf" .... Mục đích của "mã sân golf "là tạo mã ngắn nhất bất kể khả năng đọc và hầu như không bao giờ thất bại. – jez

+0

Tôi không biết về cụm từ đó. Tôi vẫn không nhìn thấy vấn đề, nhưng trong bối cảnh đó có lẽ phản ứng của tôi hơi khắc nghiệt. –

Các vấn đề liên quan