2013-02-13 46 views
15

Tôi muốn kiểm tra xem tất cả các giá trị trong các cột của mảng/ma trận có khối u đều giống nhau không. Tôi cố gắng để sử dụng reduce của ufuncequal, nhưng nó dường như không làm việc trong mọi trường hợp:Làm thế nào để kiểm tra xem tất cả các giá trị trong các cột của một ma trận có khối u đều giống nhau không?

In [55]: a = np.array([[1,1,0],[1,-1,0],[1,0,0],[1,1,0]]) 

In [56]: a 
Out[56]: 
array([[ 1, 1, 0], 
     [ 1, -1, 0], 
     [ 1, 0, 0], 
     [ 1, 1, 0]]) 

In [57]: np.equal.reduce(a) 
Out[57]: array([ True, False, True], dtype=bool) 

In [58]: a = np.array([[1,1,0],[1,0,0],[1,0,0],[1,1,0]]) 

In [59]: a 
Out[59]: 
array([[1, 1, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 1, 0]]) 

In [60]: np.equal.reduce(a) 
Out[60]: array([ True, True, True], dtype=bool) 

Tại sao cột giữa trong trường hợp thứ hai cũng đánh giá để True, trong khi nó phải được False?

Cảm ơn bạn đã trợ giúp!

+1

Sự cố này đã khiến tôi lo lắng một thời gian. Trong khi giải pháp của Ubuntu là đủ thanh lịch, nó không phải là rất dễ chịu để cố gắng chạy này trên một mảng 4096 ** 3 đôi chỉ để có được một mảng boolean mà hogs bất cứ điều gì bộ nhớ bạn đã để lại. Tôi đã chơi đùa với việc triển khai Python thuần túy bằng cách sử dụng 'np.equal (a, a [:, 0, None])', nhưng điều đó kết thúc với cùng một vấn đề. Do đó, tôi đang làm việc trên một PR cho numpy để thêm một hàm mới 'np.same' để xử lý chính xác kiểu tình huống này. –

Trả lời

24
In [45]: a 
Out[45]: 
array([[1, 1, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 1, 0]]) 

Hãy so sánh mỗi giá trị với giá trị tương ứng trong hàng đầu tiên:

In [46]: a == a[0,:] 
Out[46]: 
array([[ True, True, True], 
     [ True, False, True], 
     [ True, False, True], 
     [ True, True, True]], dtype=bool) 

Một cột chia sẻ một giá trị phổ biến nếu tất cả các giá trị trong cột đó là True:

In [47]: np.all(a == a[0,:], axis = 0) 
Out[47]: array([ True, False, True], dtype=bool) 

Sự cố với np.equal.reduce có thể được xem bằng vi phân tích những gì xảy ra khi được áp dụng cho [1, 0, 0, 1]:

In [49]: np.equal.reduce([1, 0, 0, 1]) 
Out[50]: True 

Hai mục đầu tiên, 10 được kiểm tra cho sự bình đẳng và kết quả là False:

In [51]: np.equal.reduce([False, 0, 1]) 
Out[51]: True 

Bây giờ False0 được kiểm tra cho sự bình đẳng và kết quả là True:

In [52]: np.equal.reduce([True, 1]) 
Out[52]: True 

Nhưng True và 1 bằng nhau, vì vậy tổng số kết quả là True, không phải là kết quả mong muốn.

Vấn đề là reduce cố gắng tích lũy kết quả "cục bộ", trong khi chúng tôi muốn thử nghiệm "toàn cầu" như np.all.

+0

Câu trả lời hay. Có cách nào để làm một cái gì đó như thế này cho mảng lớn mà không tạo mảng mặt nạ? Đó phải là sự hấp dẫn ban đầu của OP khi sử dụng 'reduce'. –

+1

Tôi không biết về bất kỳ phương pháp NumPy nào mà bạn có thể tạo kết quả mà không cần các mảng tempory (boolean) . Nếu bạn đang làm việc với một mảng rất lớn và bộ nhớ là chặt chẽ, bạn có thể "cắt" mảng thành từng phần (ví dụ: mảng bao gồm N hàng) và kiểm tra từng phần riêng biệt. Sau đó kết hợp và kiểm tra các mảnh, tổng hợp kết quả. – unutbu

+1

Bạn cũng có thể muốn xem xét [numpy.memmap] (http://docs.scipy.org/doc/numpy-1.10.0/reference/generated/numpy.memmap.html), hoặc [Pytables] (http://www.pytables.org/) hoặc [h5py] (http://www.h5py.org/) để lưu trữ mảng lớn của bạn trên đĩa để bạn có thể trích xuất và làm việc với một đoạn mảng tại thời gian mà không yêu cầu toàn bộ mảng được lưu trữ trong bộ nhớ. Bằng cách đó bạn có thể có nhiều không gian hơn cho các mảng tạm thời mà NumPy (thường) yêu cầu. – unutbu

7

Với lời giải thích tuyệt vời của ubuntu, bạn có thể sử dụng reduce để giải quyết vấn đề của mình, nhưng bạn phải áp dụng nó cho bitwise_andbitwise_or thay vì equal. Kết quả là, điều này sẽ không hoạt động với mảng dấu phẩy động:

Về cơ bản, bạn đang so sánh các bit của từng phần tử trong cột. Các bit giống nhau không thay đổi. Các bit khác nhau được đặt thành 0. Bằng cách này, bất kỳ số nào có số không thay vì một bit sẽ thay đổi giá trị đã giảm. bitwise_and sẽ không bẫy trường hợp bit được giới thiệu thay vì bị xóa:

In [62]: c = np.array([[1,0,0],[1,0,0],[1,0,0],[1,1,0]]) 

In [63]: c 
Out[63]: 
array([[1, 0, 0], 
     [1, 0, 0], 
     [1, 0, 0], 
     [1, 1, 0]]) 

In [64]: np.bitwise_and.reduce(c) == c[0] 
Out[64]: array([ True, True, True], dtype=bool) 

Cuộc đảo chính thứ hai rõ ràng là sai.Chúng ta cần phải sử dụng bitwise_or để bẫy bit mới:

In [66]: np.bitwise_or.reduce(c) == c[0] 
Out[66]: array([ True, False, True], dtype=bool) 

cuối cùng trả lời

In [69]: np.logical_and(np.bitwise_or.reduce(a) == a[0], np.bitwise_and.reduce(a) == a[0]) 
Out[69]: array([ True, False, True], dtype=bool) 

In [70]: np.logical_and(np.bitwise_or.reduce(b) == b[0], np.bitwise_and.reduce(b) == b[0]) 
Out[70]: array([ True, False, True], dtype=boo 

In [71]: np.logical_and(np.bitwise_or.reduce(c) == c[0], np.bitwise_and.reduce(c) == c[0]) 
Out[71]: array([ True, False, True], dtype=bool) 

Phương pháp này hạn chế hơn và ít thanh lịch hơn đề nghị ubunut của của việc sử dụng all, nhưng nó có lợi thế là không tạo ra các mảng tạm thời khổng lồ nếu đầu vào của bạn là rất lớn. Các mảng tạm thời chỉ nên lớn bằng hàng đầu tiên của ma trận của bạn.

EDIT

Dựa trên Q/A này và the bug I filed with numpy, giải pháp duy nhất cung cấp các công trình vì mảng của bạn có chứa số không và những người thân. Khi điều đó xảy ra, các hoạt động bitwise_and.reduce() được hiển thị chỉ có thể trả về 0 hoặc một vì bitwise_and.identity1, không phải -1. Tôi đang giữ câu trả lời này với hy vọng rằng numpy được sửa chữa và câu trả lời trở nên hợp lệ.

Sửa

Hình như có trong thực tế sẽ có một sự thay đổi để NumPy sớm. Chắc chắn là bitwise_and.identity và cũng có thể là thông số tùy chọn để giảm.

Sửa

Tin tốt tất cả mọi người. Danh tính cho np.bitwise_and đã được đặt thành -1 kể từ phiên bản 1.12.0.

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