've' (boolean) vs '&' (bitsel) - Listelerle numpy dizileri arasındaki davranış farkı neden?


142

NumPy dizileri ve listelerdeki boole ve bitsel işlemlerin davranışlarındaki farkı açıklayan nedir?

Ben uygun kullanımı hakkında karıştı &vs andaşağıdaki örneklerde gösterilmektedir Python,.

mylist1 = [True,  True,  True, False,  True]
mylist2 = [False, True, False,  True, False]

>>> len(mylist1) == len(mylist2)
True

# ---- Example 1 ----
>>> mylist1 and mylist2
[False, True, False, True, False]
# I would have expected [False, True, False, False, False]

# ---- Example 2 ----
>>> mylist1 & mylist2
TypeError: unsupported operand type(s) for &: 'list' and 'list'
# Why not just like example 1?

>>> import numpy as np

# ---- Example 3 ----
>>> np.array(mylist1) and np.array(mylist2)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
# Why not just like Example 4?

# ---- Example 4 ----
>>> np.array(mylist1) & np.array(mylist2)
array([False,  True, False, False, False], dtype=bool)
# This is the output I was expecting!

Bu cevap ve bu cevap , andbunun bir mantıksal işlem olduğunu ancak &bitsel bir işlem olduğunu anlamama yardımcı oldu .

Kavramı daha iyi anlamak için bitsel işlemler hakkında okudum , ancak bu bilgileri 4'ün üzerinde örneğimi anlamlandırmak için kullanmakta zorlanıyorum.

Örnek 4 beni istediğim çıktıya götürdü, bu iyi, ama hala andvs / ne zaman / neden kullanmalıyım konusunda kafam karıştı &. Listeler ve NumPy dizileri neden bu işleçlerle farklı davranıyor?

Listeleri ve NumPy dizilerini neden farklı şekilde ele aldıklarını açıklamak için herkes boole ve bitwise işlemleri arasındaki farkı anlamama yardımcı olabilir mi?


2
Numpy ise orada np.bitwise_and()ve np.logical_and()ve arkadaşlar karışıklığı önlemek için.
Dietrich

1
Örnek 1'de, mylist1 and mylist2sonuç mylist2 and mylist1döndürülmez, çünkü döndürülen şey delnan'ın işaret ettiği ikinci listedir.
user2015487

Yanıtlar:


113

andiki salgılama olup testler mantıksal olarak Trueise &(kullanıldığında True/ Falseher ikisi de, eğer değerleri) testleri True.

Python'da, boş yerleşik nesneler genellikle mantıksal olarak ele Falsealınırken , boş olmayan yerleşik nesneler mantıksal olarak ele alınır True. Bu, liste boşsa bir şey yapmak ve liste boş değilse başka bir şey yapmak istediğiniz ortak kullanım durumunu kolaylaştırır. Bunun, [False] listesinin mantıklı olduğu anlamına geldiğini unutmayın True:

>>> if [False]:
...    print 'True'
...
True

Örnek 1'de, ilk liste boş değildir ve bu nedenle mantıksal olarak True, bu nedenle 'in gerçek değeri andikinci listeninkiyle aynıdır. (Bizim durumumuzda, ikinci liste boş değildir ve bu nedenle mantıklıdır True, ancak bunun belirlenmesi gereksiz bir hesaplama adımı gerektirir.)

Örneğin 2, listeler anlamlı olarak bitsel bir şekilde birleştirilemez, çünkü rastgele farklı öğeler içerebilirler. Bitsel olarak birleştirilebilecek şeyler şunları içerir: Trues ve Falses, tamsayılar.

Buna karşılık, NumPy nesneleri vektörize hesaplamaları destekler. Yani, aynı işlemleri birden çok veri parçası üzerinde yapmanıza izin verir.

Örnek 3 başarısız olur, çünkü NumPy dizilerinin (uzunluk> 1), vektör tabanlı mantık karışıklığını önlediği için hiçbir gerçek değeri yoktur.

Örnek 4 basitçe bir vektörize bit andişlemidir.

Sonuç olarak

  • Dizilerle uğraşmıyorsanız ve tamsayıların matematik işlemlerini yapmıyorsanız, muhtemelen istersiniz and.

  • Eğer gerçeği değerlerin vektörleri varsa, kullanımı birleştirmek istediklerini numpyile &.


27

hakkında list

İlk önce her şeyin takip edileceği çok önemli bir nokta (umarım).

Sıradan Python'da, listhiçbir şekilde özel değildir (çoğunlukla tarihi bir kaza olan inşaat için sevimli sözdizimine sahip olmak dışında). Bir liste yapıldıktan sonra [3,2,6], tüm niyet ve amaçlar için, bir sayı 3, küme {3,7}veya bir fonksiyon gibi sıradan bir Python nesnesi içindir lambda x: x+5.

(Evet, öğelerini değiştirmeyi destekler ve yinelemeyi ve diğer birçok şeyi destekler, ancak bu sadece bir türdür: bazı işlemleri desteklerken bazılarını destekler. İnt bir güce yükseltmeyi destekler, ancak bu çok özel kılmak - int bir şey budur. lambda aramayı destekler, ama bu çok özel yapmaz - sonuçta lambda bunun için ne var :).

hakkında and

andbir operatör değil ("operatör" diyebilirsiniz, ancak "operatör" için de arayabilirsiniz :). Python'daki işleçler, genellikle bu türün bir parçası olarak yazılan, belirli türdeki nesneler üzerinde çağrılan yöntemlerle uygulanır. Bir yöntemin bazı işlenenlerinin değerlendirmesini yapmasının bir yolu yoktur, ancak andbunu yapabilir (ve yapmalıdır).

Bunun sonucu, andaşırı yüklenememesi, aşırı foryüklenememesidir. Tamamen geneldir ve belirli bir protokol aracılığıyla iletişim kurar. Ne yapabilirsiniz yapmak protokolün sizin bölümünü özelleştirmek olduğunu, ama bu davranışını değiştirebilir anlamına gelmez andtamamen. Protokol:

Python'un "a ve b" yi yorumladığını düşünün (bu tam anlamıyla bu şekilde gerçekleşmez, ancak anlamaya yardımcı olur). "Ve" söz konusu olduğunda, az önce değerlendirdiği (a) nesnesine bakar ve şunu sorar: doğru musunuz? ( NOT : siz misiniz True?) Eğer bir sınıfın yazarıysanız, bu yanıtı özelleştirebilirsiniz. Eğer acevaplar "hayır" ise and(b'yi tamamen atlar, hiç değerlendirilmez ve) diyor ki: abenim sonucum ( NOT : Yanlış benim sonucum).

Yanıt avermezse andsoruyor: uzunluğunuz nedir? (Yine, bunu asınıfının yazarı olarak özelleştirebilirsiniz ). Eğer acevaplar 0, andyukarıdaki ile aynı ise - yanlış olduğunu düşünmez (yanlış değil ), b'yi atlar ve asonuç olarak verir .

Eğer aikinci soruya 0'dan farklı cevaplar şey ( "sizin süresi nedir"), ya da hiç cevap vermez veya ilk one ( "true") olduğu için "evet" cevapları, andb değerlendirir ve diyor ki: bbenim sonucum. O unutmayın DEĞİL sormak bherhangi bir soru.

Tüm bunları söylemenin diğer yolu , a'nın sadece bir kez değerlendirilmesi dışında a and bneredeyse aynı b if a else aolmasıdır.

Şimdi bir kalem ve kağıtla birkaç dakika oturun ve {a, b}, {True, False} öğesinin bir alt kümesi olduğunda, tam olarak Boole operatörlerinden beklediğiniz gibi çalıştığına ikna edin. Ama umarım seni çok daha genel olduğuna ikna ettim ve göreceğin gibi, bu şekilde çok daha kullanışlı.

Bu ikisini bir araya getirmek

Şimdi umarım örnek 1'i anlarsınız. andMylist1'in bir sayı, liste, lambda veya Argmhbl sınıfının bir nesnesi olup olmadığı umrunda değildir. Sadece mylist1'in protokolün sorularına cevabını önemsiyor. Ve elbette, mylist1 uzunluk hakkındaki soruya 5 cevap verir ve mylist2 öğesini döndürür. Ve bu kadar. Mylist1 ve mylist2 unsurları ile ilgisi yoktur - resme hiçbir yere girmezler.

İkinci örnek: &açıklist

Öte yandan, örneğin &diğerleri gibi bir operatör +. Bir sınıf için o sınıfta özel bir yöntem tanımlanarak tanımlanabilir. intbunu bitsel "ve" olarak tanımlar ve bool bunu mantıksal "ve" olarak tanımlar, ancak bu sadece bir seçenektir: örneğin, setler ve dikte tuşları görünümleri gibi diğer bazı nesneler bunu küme kesişimi olarak tanımlar. listmuhtemelen bunu tanımlamaz, çünkü Guido onu tanımlamanın açık bir yolunu düşünmemiştir.

dizi

Diğer bacak üzerinde: -D, numpy diziler vardır , özel ya da en azından onlar için çalışıyoruz. Elbette, numpy.array sadece bir sınıftır, andherhangi bir şekilde geçersiz kılınamaz , bu yüzden bir sonraki en iyi şeyi yapar: "doğru mısın" sorulduğunda, numpy.array etkili bir şekilde "lütfen soruyu yeniden ifade et, msgstr "Doğrunun görüşü modelinize uymuyor" + + msgid ". (ValueError mesajının bahsetmediğini unutmayın and- çünkü numpy.array soruyu kimin sorduğunu bilmiyor ; sadece gerçek hakkında konuşuyor.)

Çünkü &tamamen farklı bir hikaye. numpy.array onu istediği gibi tanımlayabilir &ve diğer işleçlerle tutarlı olarak tanımlar : nokta. Sonunda istediğini elde edersin.

HTH,


23

Kısa devre yapan boole işleçleri ( and, or) geçersiz kılınamaz çünkü yeni dil özellikleri getirmeden veya kısa devre yapmadan ödün vermeden bunu yapmanın tatmin edici bir yolu yoktur. Bildiğiniz ya da bilmediğiniz gibi, ilk işleneni gerçek değeri için değerlendirirler ve bu değere bağlı olarak, ya ikinci argümanı değerlendirir ve döndürür ya da ikinci argümanı değerlendirmez ve ilkini döndürmez:

something_true and x -> x
something_false and x -> something_false
something_true or x -> something_true
something_false or x -> x

Gerçek işlenenin (değerlendirilmesinin sonucu) gerçek değerinin döndürülmediğine dikkat edin.

Davranışlarını özelleştirmenin tek yolu geçersiz kılmaktır __nonzero__(__bool__ Python 3'te ), böylece hangi işlenenin döndürüleceğini etkileyebilir, ancak farklı bir şey döndüremezsiniz. Listeler (ve diğer koleksiyonlar), herhangi bir şey içerdiklerinde "doğruluk" ve boş olduklarında "falsey" olarak tanımlanır.

NumPy dizileri bu görüşü reddeder: Amaçladıkları kullanım durumlarında iki farklı doğruluk kavramı yaygındır: (1) Herhangi bir öğenin doğru olup olmadığı ve (2) tüm öğelerin doğru olup olmadığı. Bu ikisi tamamen (ve sessizce) uyumsuz olduğundan ve ikisi de açıkça daha doğru veya daha yaygın olmadığından, NumPy tahmin etmeyi reddeder ve açıkça .any()veya kullanmanızı gerektirir .all().

&ve |(ve not, bu arada) olabilir onlar kısa devre gibi tamamen overriden. Geçersiz kılındığında herhangi bir şeyi geri döndürebilirler ve NumPy, pratik olarak diğer skaler operasyonlarda olduğu gibi, eleman bazlı işlemler yapmak için bunu iyi kullanır. Öte yandan listeler, öğeleri arasında işlem yayınlamaz. Tıpkı mylist1 - mylist2hiçbir şey ifade etmediği ve mylist1 + mylist2tamamen farklı bir şey ifade ettiği gibi , &listeler için operatör yoktur .


3
Bunun üretebileceğinin özellikle ilginç bir örneği, [False] or [True]değerlendirmek [False]ve [False] and [True]değerlendirmektir [True].
Rob Watts

16

Örnek 1:

Bu nasıl ve operatör çalışır.

x ve y => x yanlışsa, x , başka y

Yani başka bir deyişle, mylist1olmadığı için False, ifadenin sonucu mylist2. (Yalnızca boş listeler olarak değerlendirilir False.)

Örnek 2:

&Eğer söz olarak operatör bir bitwise içindir ve. Bitsel işlemler yalnızca sayılar üzerinde çalışır. Sonucu bir ve b hem de 1 olduğu bit 1s oluşan bir sayıdır a ve b . Örneğin:

>>> 3 & 1
1

İkili bir değişmez değer kullanarak neler olduğunu görmek daha kolaydır (yukarıdakiyle aynı sayılar):

>>> 0b0011 & 0b0001
0b0001

Bitsel işlemler, kavram olarak boole (gerçek) işlemlerine benzer, ancak yalnızca bitlerde çalışırlar.

Yani, arabam hakkında birkaç açıklama verildi

  1. Benim arabam kırmızı
  2. Arabamın tekerlekleri var

Bu iki ifadenin mantıksal "ve" ifadesi:

(arabam kırmızı mı?) ve (arabanın tekerlekleri var mı?) => yanlış değer mantıksal doğru

Her ikisi de en azından arabam için doğrudur. Yani ifadenin bir bütün olarak değeri mantıksal olarak doğrudur.

Bu iki ifadenin bitsel "ve" ifadesi biraz daha belirsiz:

('arabam kırmızı' ifadesinin sayısal değeri) & ('arabamın tekerlekleri var' ifadesinin sayısal değeri) => sayı

Python, ifadelerin sayısal değerlere nasıl dönüştürüleceğini bilirse, bunu yapar ve iki değerin bitselini ve değerini hesaplar. Bu, bunun birbiriyle &değiştirilebilir olduğuna inanmanıza neden olabilir and, ancak yukarıdaki örnekte olduğu gibi farklı şeylerdir. Ayrıca, dönüştürülemeyen nesneler için sadece bir TypeError.

Örnek 3 ve 4:

Numpy , diziler için aritmetik işlemleri uygular :

Ndarraylar üzerindeki aritmetik ve karşılaştırma işlemleri, eleman bazında işlemler olarak tanımlanır ve genellikle sonuç olarak ndarray nesneleri verir.

Ancak diziler için mantıksal işlemler gerçekleştirmez, çünkü python'daki mantıksal işleçleri aşırı yükleyemezsiniz . Bu yüzden örnek üç işe yaramaz, ancak örnek dört işe yarar.

Bu yüzden andvs &sorunuzu cevaplamak için : kullanın and.

Bitsel işlemler, bir sayının yapısını incelemek için kullanılır (hangi bitler ayarlanır, hangi bitler ayarlanmamıştır). Bu tür bilgiler çoğunlukla düşük seviyeli işletim sistemi arayüzlerinde kullanılır ( örneğin unix izin bitleri ). Çoğu python programının bunu bilmesine gerek yoktur.

Mantıksal işlemler ( and, or, not), ancak, her zaman kullanılmaktadır.


14
  1. Python'da , False verilen veya bu değerlerden herhangi biri verilen veya değerlendirilen bir X and Ydöndürme ifadesi , örneğin:Ybool(X) == TrueXY

    True and 20 
    >>> 20
    
    False and 20
    >>> False
    
    20 and []
    >>> []
  2. Bitsel işleci, listeler için tanımlanmamıştır. Ancak sayıların ikili gösterimi üzerinde çalışan tamsayılar için tanımlanır. 16 (01000) ve 31 (11111) 'i düşünün:

    16 & 31
    >>> 16
  3. NumPy bir psişik değildir, örneğin mantıklı bir ifadede [False, False]eşit olması gerektiği anlamına gelip gelmediğini bilmez True. "Herhangi bir boş koleksiyonu ile: Bu sırf bir standart Python davranışını, geçersiz kılar len(collection) == 0ise False."

  4. Muhtemelen NumPy dizilerinin ve operatörünün beklenen bir davranışı.


False ve 20 False döndürür
Rahul

4

İlk örnek ve django'nun dokümanı için
Her zaman ikinci listeyi döndürür, aslında boş olmayan bir liste Python için bir True değeri olarak görülür, böylece python 'son' Doğru değerini döndürür, böylece ikinci liste

In [74]: mylist1 = [False]
In [75]: mylist2 = [False, True, False,  True, False]
In [76]: mylist1 and mylist2
Out[76]: [False, True, False, True, False]
In [77]: mylist2 and mylist1
Out[77]: [False]

4

Python listesiyle Operasyonlar üzerinde işlem listesinde . boş list1 and list2olup olmadığını kontrol eder ve eğer varsa ve değilse list1geri döner . ekler için size yeni bir listesini almak, böylece elemanlar.list1list2list1 + list2list2list1len(list1) + len(list2)

Sadece mantıklı Operatörler zaman uygulamalı öğeye göre, örneğin &, zam aTypeError öğeye göre işlemler gibi, elemanlar döngü olmadan desteklenmez.

Numpy dizileri eleman bazında işlemleri destekler . ve array1 & array2içindeki her bir karşılık gelen öğe için bitsel veya hesaplar . ve öğelerinde karşılık gelen her bir öğenin toplamını hesaplar .array1array2array1 + array2array1array2

Bu andve için işe yaramaz or.

array1 and array2 aslında aşağıdaki kod için bir kısa eldir:

if bool(array1):
    return array2
else:
    return array1

Bunun için iyi bir tanımlamaya ihtiyacınız var bool(array1). Python listelerinde eskisi gibi küresel operasyonları için tanım olmasıdır bool(list) == Trueeğer listolduğunu boş değil ve Falseboş olup olmadığını. Numpy'nin öğe bazında işlemleri için, herhangi bir öğenin değerlendirilip değerlendirilmeyeceğini Trueveya tüm öğelerin değerlendirip değerlendirilmediğini kontrol etmek için bazı belirsizlikler vardır True. Her ikisi de tartışmalı olarak doğru olduğundan, numpy tahmin etmez ve bir dizide (dolaylı olarak) çağrıldığında bir ValueErrorzaman yükseltir bool().


0

İyi soru. Mantıksal andbitsel &operatörler üzerinde örnek 1 ve 4 (ya da 1 ve 4 demeliyim) hakkında sahip olduğunuz gözlemlere benzer şekilde, operatörde yaşadım sum. Numpy sumve pysum de farklı davranır. Örneğin:

Diyelim ki "mat" aşağıdaki gibi bir 5x5 2d dizisidir:

array([[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20],
       [21, 22, 23, 24, 25]])

Sonra numpy.sum (mat) tüm matrisin toplamını verir. Oysa toplam (mat) gibi Python'daki yerleşik toplam yalnızca eksen boyunca toplanır. Aşağıya bakınız:

np.sum(mat)  ## --> gives 325
sum(mat)     ## --> gives array([55, 60, 65, 70, 75])
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.