Khó hiểu `logic_or` cho nhiều hơn hai đối số


88

logical_orHàm của Numpy không cần nhiều hơn hai mảng để so sánh. Làm cách nào để tìm hợp nhất của nhiều hơn hai mảng? (Câu hỏi tương tự có thể được đặt ra liên quan đến Numpy's logical_andvà lấy giao điểm của nhiều hơn hai mảng.)



có cách nào gây khó chịu cho bất kỳ () nào không?
user3074893

@ user3074893: Nó chính xác là một vấn đề. Bạn muốn tôi mở rộng câu trả lời của mình?
abarnert

Câu trả lời:


174

Nếu bạn đang hỏi về numpy.logical_or, thì không, như tài liệu nói rõ ràng, các tham số duy nhất là x1, x2và tùy chọn out:

numpy.logical_or( x1, x2[, out]) =<ufunc 'logical_or'>


Tất nhiên, bạn có thể xâu chuỗi nhiều logical_orcuộc gọi lại với nhau như thế này:

>>> x = np.array([True, True, False, False])
>>> y = np.array([True, False, True, False])
>>> z = np.array([False, False, False, False])
>>> np.logical_or(np.logical_or(x, y), z)
array([ True,  True,  True,  False], dtype=bool)

Cách tổng quát hóa loại chuỗi này trong NumPy là với reduce:

>>> np.logical_or.reduce((x, y, z))
array([ True,  True,  True,  False], dtype=bool)

Và tất nhiên điều này cũng sẽ làm việc nếu bạn có một mảng đa chiều thay vì mảng trong thực tế riêng biệt, đó là cách nó có nghĩa là để được sử dụng:

>>> xyz = np.array((x, y, z))
>>> xyz
array([[ True,  True, False, False],
       [ True, False,  True, False],
       [False, False, False, False]], dtype=bool)
>>> np.logical_or.reduce(xyz)
array([ True,  True,  True,  False], dtype=bool)

Nhưng một bộ ba mảng 1D có độ dài bằng nhau là một mảng_như theo thuật ngữ NumPy và có thể được sử dụng như một mảng 2D.


Ngoài NumPy, bạn cũng có thể sử dụng Python reduce:

>>> functools.reduce(np.logical_or, (x, y, z))
array([ True,  True,  True,  False], dtype=bool)

Tuy nhiên, không giống như NumPy's reduce, Python không thường xuyên cần thiết. Đối với hầu hết các trường hợp, có một cách đơn giản hơn để thực hiện mọi việc — ví dụ: chuỗi nhiều ortoán tử Python lại với nhau , đừng reducekết thúc operator.or_, chỉ cần sử dụng any. Và khi có không phải là , nó thường dễ đọc hơn để sử dụng một vòng lặp rõ ràng.

Và trên thực tế, NumPy's anycũng có thể được sử dụng cho trường hợp này, mặc dù nó không quá tầm thường; nếu bạn không cung cấp cho nó một trục rõ ràng, bạn sẽ kết thúc với một đại lượng vô hướng thay vì một mảng. Vì thế:

>>> np.any((x, y, z), axis=0)
array([ True,  True,  True,  False], dtype=bool)

Như bạn có thể mong đợi, logical_andcũng tương tự — bạn có thể xâu chuỗi nó, np.reducenó, functools.reducenó, hoặc thay thế allbằng một cách rõ ràng axis.

Điều gì về các hoạt động khác, như thế logical_xornào? Một lần nữa, cùng một thỏa thuận… ngoại trừ trường hợp này không có hàm all/ any-type nào được áp dụng. (Bạn sẽ gọi nó là gì odd?)


2
np.logical_or.reduce((x, y, z))chỉ là những gì tôi đang tìm kiếm!
blaylockbk

reducekhông còn là một hàm nội bộ trong python 3. Thay vào đó, hãy sử dụng:functools.reduce()
marvin

10

Trong trường hợp ai đó vẫn cần điều này - Giả sử bạn có ba mảng Boolean a, b, cvới hình dạng giống nhau, điều này mang lại andyếu tố khôn ngoan:

a * b * c

điều này mang lại or:

a + b + c

Đây có phải là những gì bạn muốn? Xếp chồng nhiều logical_andhoặc logical_orkhông thực tế.


6

Vì đại số boolean là cả giao hoán và kết hợp theo định nghĩa, các câu lệnh sau đây hoặc tương đương cho các giá trị boolean của a, b và c.

a or b or c

(a or b) or c

a or (b or c)

(b or a) or c

Vì vậy, nếu bạn có "logic_or" là dyadic và bạn cần chuyển cho nó ba đối số (a, b và c), bạn có thể gọi

logical_or(logical_or(a, b), c)

logical_or(a, logical_or(b, c))

logical_or(c, logical_or(b, a))

hoặc bất kỳ phép hoán vị nào bạn thích.


Quay lại python, nếu bạn muốn kiểm tra xem một điều kiện (được tạo ra bởi một hàm testnhận testee và trả về giá trị boolean) có áp dụng cho a hoặc b hoặc c hoặc bất kỳ phần tử nào của danh sách L hay không, bạn thường sử dụng

any(test(x) for x in L)

Nhưng Python orkhông thực sự là boolean or, cả vì nó hoạt động trên các giá trị khác với bools (trả về anếu alà true, bngược lại) và vì nó ngắn mạch (nghĩa a or bcó thể là True, trong khi b or atạo ra một ngoại lệ).
abarnert

@abarnert Cảm ơn bạn, tôi đã chỉnh sửa câu trả lời của mình để giải quyết vấn đề đó.
Hyperboreus

(Tôi không chắc chắn lý do tại sao người downvoted này, tuy nhiên ... OP dường như được nói cụ thể về giá trị boolean, mà ông gọi là "điều kiện logic".)
abarnert

@abarnert Đừng hỏi tôi. Tôi có ý kiến ​​rằng nếu bạn hiểu rõ các phép toán của mình (trong trường hợp này là đại số boolean) trong nền, thì rất nhiều vấn đề lập trình sẽ dễ giải quyết hơn.
Hyperboreus

4

Dựa trên câu trả lời của abarnert cho trường hợp n chiều:

TL; DR: np.logical_or.reduce(np.array(list))


4

bằng cách sử dụng hàm sum:

a = np.array([True, False, True])
b = array([ False, False,  True])
c = np.vstack([a,b,b])

Out[172]: 
array([[ True, False,  True],
   [False, False,  True],
   [False, False,  True]], dtype=bool)

np.sum(c,axis=0)>0
Out[173]: array([ True, False,  True], dtype=bool)

4

Tôi sử dụng cách giải quyết này có thể được mở rộng cho n mảng:

>>> a = np.array([False, True, False, False])
>>> b = np.array([True, False, False, False])
>>> c = np.array([False, False, False, True])
>>> d = (a + b + c > 0) # That's an "or" between multiple arrays
>>> d
array([ True,  True, False,  True], dtype=bool)

1

Tôi đã thử ba phương pháp khác nhau sau đây để lấy logical_anddanh sách l gồm k mảng có kích thước n :

  1. Sử dụng đệ quy numpy.logical_and(xem bên dưới)
  2. Sử dụng numpy.logical_and.reduce(l)
  3. Sử dụng numpy.vstack(l).all(axis=0)

Sau đó, tôi đã làm tương tự cho logical_orchức năng. Đáng ngạc nhiên là phương pháp đệ quy là phương pháp nhanh nhất.

import numpy
import perfplot

def and_recursive(*l):
    if len(l) == 1:
        return l[0].astype(bool)
    elif len(l) == 2:
        return numpy.logical_and(l[0],l[1])
    elif len(l) > 2:
        return and_recursive(and_recursive(*l[:2]),and_recursive(*l[2:]))

def or_recursive(*l):
    if len(l) == 1:
        return l[0].astype(bool)
    elif len(l) == 2:
        return numpy.logical_or(l[0],l[1])
    elif len(l) > 2:
        return or_recursive(or_recursive(*l[:2]),or_recursive(*l[2:]))

def and_reduce(*l):
    return numpy.logical_and.reduce(l)

def or_reduce(*l):
    return numpy.logical_or.reduce(l)

def and_stack(*l):
    return numpy.vstack(l).all(axis=0)

def or_stack(*l):
    return numpy.vstack(l).any(axis=0)

k = 10 # number of arrays to be combined

perfplot.plot(
    setup=lambda n: [numpy.random.choice(a=[False, True], size=n) for j in range(k)],
    kernels=[
        lambda l: and_recursive(*l),
        lambda l: and_reduce(*l),
        lambda l: and_stack(*l),
        lambda l: or_recursive(*l),
        lambda l: or_reduce(*l),
        lambda l: or_stack(*l),
    ],
    labels = ['and_recursive', 'and_reduce', 'and_stack', 'or_recursive', 'or_reduce', 'or_stack'],
    n_range=[2 ** j for j in range(20)],
    logx=True,
    logy=True,
    xlabel="len(a)",
    equality_check=None
)

Dưới đây là các biểu diễn cho k = 4.

Biểu diễn cho k = 4

Và ở đây bên dưới biểu diễn cho k = 10.

Biểu diễn cho k = 10

Có vẻ như cũng có một khoảng thời gian không đổi gần như không đổi đối với n cao hơn.

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.