2014-10-09 27 views
24

tôi đang tạo ra ma trận đối xứng/mảng trong Python với NumPy, sử dụng một phương pháp tiêu chuẩn:kết quả bất ngờ với + = trên mảng NumPy

x = rand(500,500) 
x = (x+x.T) 
all(x==x.T) 
> True 

Bây giờ chúng ta hãy trở nên thông minh:

x = rand(500,500) 
x += x.T 
all(x==x.T) 
> False 

Chờ, gì ?

x==x.T 
> array([[ True, True, True, ..., False, False, False], 
     [ True, True, True, ..., False, False, False], 
     [ True, True, True, ..., False, False, False], 
     ..., 
     [False, False, False, ..., True, True, True], 
     [False, False, False, ..., True, True, True], 
     [False, False, False, ..., True, True, True]], dtype=bool) 

Phần trên bên trái và dưới bên phải là đối xứng. Nếu tôi chọn một mảng nhỏ hơn thì sao?

x = rand(50,50) 
x += x.T 
all(x==x.T) 
> True 

OK ....

x = rand(90,90) 
x += x.T 
all(x==x.T) 
> True 

x = rand(91,91) 
x += x.T 
all(x==x.T) 
> False 

Và chỉ để đảm bảo ...

x = rand(91,91) 
x = (x+x.T) 
all(x==x.T) 
> True 

Đây có phải là một lỗi, hay tôi về để tìm hiểu điều gì đó điên về += và NumPy mảng?

+13

Câu hỏi này cần có tiêu đề phù hợp. – plaes

+0

@AndrewJaffe đây là Numpy 1.9 trên Python 3.4.1, được phân phối trong Anaconda. – jeffalstott

+0

@jeffalstott yep, tôi hiểu sai câu hỏi - Tôi cũng thấy hành vi này. –

Trả lời

24

transpose operation trả về chế độ xem của mảng, điều đó có nghĩa là không có mảng mới nào được phân bổ. Trong đó, lần lượt, có nghĩa là bạn đang đọc và sửa đổi mảng cùng một lúc. Thật khó để nói lý do tại sao một số kích thước hoặc một số khu vực của kết quả làm việc, nhưng rất có thể nó phải làm gì với các giao dịch hỗn hợp với mảng bổ sung (có thể nó tạo ra các bản sao của submatric) và/hoặc các khung nhìn (có thể cho các kích thước nhỏ mà nó tạo ra) một mảng mới).

Thao tác x = x + x.T hoạt động vì bạn đang tạo một mảng mới và sau đó gán cho x, tất nhiên.

4

Vấn đề là việc bổ sung không được thực hiện "cùng một lúc"; x.T là chế độ xem của x để bạn bắt đầu thêm vào từng thành phần của x, x.T bị tắt tiếng. Điều này messes lên sau này bổ sung.

Thực tế nó hoạt động với các kích thước bên dưới (91, 91) gần như chắc chắn là chi tiết triển khai. Sử dụng

x = numpy.random.rand(1000, 1000) 
x += x.T.copy() 
numpy.all(x==x.T) 
#>>> True 

khắc phục điều đó, nhưng sau đó bạn thực sự không có bất kỳ lợi ích nào.

20

Chi tiết triển khai được đề cập bởi những người khác được gọi là đệm. Bạn có thể đọc thêm về nó trong the docs on array iteration.

Nếu bạn nhìn vào ví dụ thất bại của bạn trong một ít chi tiết hơn:

>>> a = np.random.rand(91, 91) 
>>> a += a.T 
>>> a[:5, -1] 
array([ 0.83818399, 1.06489316, 1.23675312, 0.00379798, 1.08967428]) 
>>> a[-1, :5] 
array([ 0.83818399, 1.06489316, 1.75091827, 0.00416305, 1.76315071]) 

Vì vậy, các giá trị sai đầu tiên là 90*91 + 2 = 8192, trong đó, không ngạc nhiên là những gì chúng tôi nhận được từ:

>>> np.getbufsize() 
8192 

Và chúng tôi cũng có thể đặt giá thầu cao hơn và sau đó:

>>> np.setbufsize(16384) # Must be a multiple of 16 
8192 # returns the previous buffer size 
>>> a = np.random.rand(91, 91) 
>>> a += a.T 
>>> np.all(a == a.T) 
True 

Mặc dù bây giờ:

>>> a = np.random.rand(129, 129) 
>>> a += a.T 
>>> np.all(a == a.T) 
False 

Điều này tất nhiên là điều nguy hiểm để dựa vào chính xác, vì nó thực sự là chi tiết triển khai có thể thay đổi.

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