Python numpy.where () hoạt động như thế nào?


94

Tôi đang chơi numpyvà đào bới tài liệu và tôi đã bắt gặp một phép thuật nào đó. Cụ thể là tôi đang nói về numpy.where():

>>> x = np.arange(9.).reshape(3, 3)
>>> np.where( x > 5 )
(array([2, 2, 2]), array([0, 1, 2]))

Làm thế nào để họ đạt được nội bộ rằng bạn có thể truyền một cái gì đó giống như x > 5một phương pháp? Tôi đoán nó có liên quan gì đó __gt__nhưng tôi đang tìm lời giải thích chi tiết.

Câu trả lời:


75

Làm thế nào để họ đạt được nội bộ rằng bạn có thể chuyển một cái gì đó như x> 5 vào một phương thức?

Câu trả lời ngắn gọn là họ không.

Bất kỳ loại hoạt động logic nào trên một mảng numpy đều trả về một mảng boolean. (tức là __gt__, __lt__v.v. tất cả đều trả về mảng boolean trong đó điều kiện đã cho là đúng).

Ví dụ

x = np.arange(9).reshape(3,3)
print x > 5

sản lượng:

array([[False, False, False],
       [False, False, False],
       [ True,  True,  True]], dtype=bool)

Đây cũng là lý do tại sao một cái gì đó như if x > 5:tăng một ValueError nếu xlà một mảng numpy. Đó là một mảng các giá trị Đúng / Sai, không phải một giá trị duy nhất.

Hơn nữa, mảng numpy có thể được lập chỉ mục bởi mảng boolean. Ví dụ: x[x>5]lợi tức [6 7 8], trong trường hợp này.

Thành thật mà nói, khá hiếm khi bạn thực sự cần numpy.wherenhưng nó chỉ trả về các chỉ báo nơi có một mảng boolean True. Thông thường, bạn có thể làm những gì bạn cần với lập chỉ mục boolean đơn giản.


10
Chỉ cần chỉ ra rằng numpy.wherecó 2 'chế độ hoạt động', một chế độ đầu tiên trả về indices, ở đâu condition is Truevà nếu các tham số tùy chọn xycó mặt (cùng hình dạng conditionhoặc có thể phát sóng với hình dạng đó!), Nó sẽ trả về giá trị từ xkhi nào condition is Truekhác y. Vì vậy, điều này làm cho wherelinh hoạt hơn và cho phép nó được sử dụng thường xuyên hơn. Cảm ơn
ăn

1
Cũng có thể có chi phí trong một số trường hợp bằng cách sử dụng __getitem__cú pháp của []một trong hai numpy.wherehoặc numpy.take. Vì __getitem__cũng phải hỗ trợ cắt lát, nên có một số chi phí. Tôi đã thấy sự khác biệt về tốc độ đáng chú ý khi làm việc với cấu trúc dữ liệu Python Pandas và lập chỉ mục một cách hợp lý các cột rất lớn. Trong những trường hợp đó, nếu bạn không cần cắt lát, thì takewherethực sự tốt hơn.
ely

24

Câu trả lời cũ nó là loại khó hiểu. Nó cung cấp cho bạn VỊ TRÍ (tất cả chúng) về nơi mà trạng thái của bạn là đúng.

vì thế:

>>> a = np.arange(100)
>>> np.where(a > 30)
(array([31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
       48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64,
       65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81,
       82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98,
       99]),)
>>> np.where(a == 90)
(array([90]),)

a = a*40
>>> np.where(a > 1000)
(array([26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42,
       43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
       60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76,
       77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93,
       94, 95, 96, 97, 98, 99]),)
>>> a[25]
1000
>>> a[26]
1040

Tôi sử dụng nó như một sự thay thế cho list.index (), nhưng nó cũng có nhiều cách sử dụng khác. Tôi chưa bao giờ sử dụng nó với mảng 2D.

http://docs.scipy.org/doc/numpy/reference/generated/numpy.where.html

Câu trả lời mới Có vẻ như người đó đang hỏi một điều gì đó cơ bản hơn.

Câu hỏi đặt ra là làm thế nào BẠN có thể triển khai thứ gì đó cho phép một chức năng (chẳng hạn như ở đâu) biết những gì được yêu cầu.

Trước tiên, hãy lưu ý rằng việc gọi bất kỳ toán tử so sánh nào sẽ làm một điều thú vị.

a > 1000
array([False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False, False,
       False, False, False, False, False, False, False, False,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True,  True,  True,  True,  True,  True,  True,  True,  True,
        True`,  True,  True,  True,  True,  True,  True,  True,  True,  True], dtype=bool)`

Điều này được thực hiện bằng cách nạp chồng phương thức "__gt__". Ví dụ:

>>> class demo(object):
    def __gt__(self, item):
        print item


>>> a = demo()
>>> a > 4
4

Như bạn có thể thấy, "a> 4" là mã hợp lệ.

Bạn có thể nhận được danh sách đầy đủ và tài liệu về tất cả các hàm quá tải tại đây: http://docs.python.org/reference/datamodel.html

Một điều không thể tin được là nó đơn giản như thế nào để làm điều này. Tất cả các hoạt động trong python được thực hiện theo cách như vậy. Nói a> b tương đương với a. gt (b)!


3
Mặc dù vậy, việc nạp chồng toán tử so sánh này dường như không hoạt động tốt với các biểu thức logic phức tạp hơn - ví dụ: tôi không thể làm được np.where(a > 30 and a < 50)hoặc np.where(30 < a < 50)vì nó kết thúc bằng cách đánh giá logic AND của hai mảng boolean, điều này khá vô nghĩa. Có cách nào để viết một điều kiện như vậy với np.where?
davidA

@meowsqueaknp.where((a > 30) & (a < 50))
tibalt

Tại sao np.where () trả về một danh sách trong ví dụ của bạn?
Andreas Yankopolus

0

np.wheretrả về một bộ giá trị có độ dài bằng với kích thước của dải numpy mà nó được gọi (nói cách khác ndim) và mỗi mục của bộ tuple là một dải chỉ số chứa tất cả các giá trị đó trong ndarray ban đầu mà điều kiện là True. (Xin đừng nhầm lẫn kích thước với hình dạng)

Ví dụ:

x=np.arange(9).reshape(3,3)
print(x)
array([[0, 1, 2],
      [3, 4, 5],
      [6, 7, 8]])
y = np.where(x>4)
print(y)
array([1, 2, 2, 2], dtype=int64), array([2, 0, 1, 2], dtype=int64))


y là bộ có độ dài 2 vì x.ndimlà 2. Mục đầu tiên trong bộ chứa số hàng của tất cả các phần tử lớn hơn 4 và mục thứ 2 chứa số cột của tất cả các mục lớn hơn 4. Như bạn thấy, [1,2,2 , 2] tương ứng với số hàng là 5,6,7,8 và [2,0,1,2] tương ứng với số cột là 5,6,7,8 Lưu ý rằng ndarray được duyệt dọc theo chiều thứ nhất (theo hàng ).

Tương tự,

x=np.arange(27).reshape(3,3,3)
np.where(x>4)


sẽ trả về một bộ chiều dài 3 vì x có 3 chiều.

Nhưng chờ đã, có nhiều thứ hơn để np.where!

khi hai đối số bổ sung được thêm vào np.where; nó sẽ thực hiện một hoạt động thay thế cho tất cả các kết hợp hàng-cột theo cặp được lấy bởi bộ tuple ở trên.

x=np.arange(9).reshape(3,3)
y = np.where(x>4, 1, 0)
print(y)
array([[0, 0, 0],
   [0, 0, 1],
   [1, 1, 1]])
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.