2016-12-26 16 views
21

Tôi muốn thay thế outliners từ một danh sách. Vì vậy, tôi xác định một ràng buộc trên và dưới. Bây giờ mọi giá trị trên upper_bound và dưới lower_bound được thay thế bằng giá trị bị ràng buộc. Cách tiếp cận của tôi là làm điều này trong hai bước bằng cách sử dụng một mảng numpy.Cách Pythonic để thay thế các giá trị danh sách với giới hạn trên và dưới (kẹp, cắt, đập)?

Bây giờ tôi tự hỏi liệu có thể thực hiện điều này trong một bước hay không, như tôi đoán nó có thể cải thiện hiệu suất và khả năng đọc.

Có cách nào ngắn hơn để thực hiện việc này không?

import numpy as np 

lowerBound, upperBound = 3, 7 

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

arr[arr > upperBound] = upperBound 
arr[arr < lowerBound] = lowerBound 

# [3 3 3 3 4 5 6 7 7 7] 
print(arr) 
+1

Mặc dù có một phương pháp 'clip' được biên dịch, nhưng không có gì không có ý nghĩa về mã của bạn. Đó là cách sử dụng 'numpy' hoàn hảo và chỉ có thể đọc được (đối với người dùng có kinh nghiệm). Giữ khái niệm đó trong hộp công cụ của bạn; nó hoạt động trong trường hợp không hoàn toàn phù hợp với mô hình 'clip'. – hpaulj

+1

Hoạt động này thường được gọi là *** kẹp ***, *** cắt *** hoặc người khác *** dập nổi *** – smci

+2

Bạn nên sử dụng phương thức 'clip' nhưng có một lý do khác hơn tốc độ; mã của bạn là thanh lịch nhưng tạo ra một mảng trung gian với 'arr> upperBound' có thể là một vấn đề nếu mảng lớn. –

Trả lời

31

Bạn có thể sử dụng numpy.clip:

In [1]: import numpy as np 

In [2]: arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 

In [3]: lowerBound, upperBound = 3, 7 

In [4]: np.clip(arr, lowerBound, upperBound, out=arr) 
Out[4]: array([3, 3, 3, 3, 4, 5, 6, 7, 7, 7]) 

In [5]: arr 
Out[5]: array([3, 3, 3, 3, 4, 5, 6, 7, 7, 7]) 
+0

Xin chào @arthur, cảm ơn đó chính là điều tôi đang tìm kiếm! Tôi bằng cách nào đó đã bỏ lỡ từ khóa 'clip' và không tự tìm ra phương pháp ... – ppasler

+3

Tôi tự hỏi làm thế nào' clip' được viết. Nó có thể làm điều tương tự, chỉ bọc trong một cuộc gọi hàm. – hpaulj

+0

@hpaulj bạn đã tìm ra? – djechlin

13

Đối với một sự thay thế mà không dựa vào numpy, bạn luôn có thể làm

arr = [max(lower_bound, min(x, upper_bound)) for x in arr] 

Nếu bạn chỉ muốn thiết lập một thượng ràng buộc, tất nhiên bạn có thể viết arr = [min(x, upper_bound) for x in arr]. Hoặc tương tự như vậy nếu bạn chỉ muốn một giới hạn thấp hơn, thay vào đó bạn sẽ sử dụng max.

Ở đây, tôi vừa áp dụng cả hai thao tác, được viết cùng nhau.

Edit: Dưới đây là một hơi sâu hơn giải thích:

Với một yếu tố x của mảng (và giả định rằng bạn upper_bound ít nhất là lớn như bạn lower_bound!), Bạn sẽ có một ba trường hợp:

i) x < lower_bound

ii) x > upper_bound

iii) lower_bound <= x <= upper_bound.

Trong trường hợp (i), biểu thức max/min trước tiên sẽ đánh giá là max(lower_bound, x), sau đó phân giải thành lower_bound.

Trong trường hợp (ii), biểu thức đầu tiên trở thành max(lower_bound, upper_bound), sau đó trở thành upper_bound.

Trong trường hợp (iii), chúng tôi nhận được max(lower_bound, x) để giải quyết chỉ x.

Trong cả ba trường hợp, đầu ra là những gì chúng tôi muốn.

+1

chỉ là khiếu nại của tôi (không bỏ phiếu), tôi có xu hướng phải suy nghĩ * thực sự * khó khăn khi tôi thấy kết hợp tối đa/phút và tìm thấy chúng không phải là có thể đọc được. – djechlin

+6

@djechlin Chắc chắn, tôi không đồng ý với điều đó. Mặt khác, câu trả lời khác cho điểm này sử dụng 'numpy.clip', điều này sẽ không thể đọc được ngay lập tức nếu tôi gặp nó ở đâu đó - tôi có thể muốn kiểm tra lại tài liệu khó hiểu, hoặc chỉ đoán nó đã làm gì, và hy vọng rằng tác giả đã làm đúng. – mathmandan

+0

Điều kỳ lạ là làm tổ. Đó là một hoạt động rất đối xứng bao gồm "clip một lần", clip hai lần. "Đây là" clip một lần, sau đó clip lại " – djechlin

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