Μόλις ανακάλυψα ένα λογικό σφάλμα στον κώδικά μου, το οποίο προκαλούσε ένα σωρό προβλήματα. Εκ παραδρομής έκανα ένα bitwise AND αντί για ένα logical AND.
Άλλαξα τον κώδικα από:
r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]
r = mlab.csv2rec(datafile, delimiter=',', names=COL_HEADERS)
mask = ((r["dt"] >= startdate) and (r["dt"] <= enddate))
selected = r[mask]
Προς έκπληξή μου, έλαβα το μάλλον αινιγματικό μήνυμα σφάλματος:
ValueError: The truth value of an array with more than one element is αμφίσημη. Χρησιμοποιήστε a.any() ή a.all()
Γιατί δεν εκπέμπεται παρόμοιο σφάλμα όταν χρησιμοποιώ μια πράξη bitwise - και πώς μπορώ να το διορθώσω;
Το "r" είναι ένας πίνακας numpy (rec)array. Οπότε το r["dt"] >= startdate
είναι επίσης ένα (boolean)
array. Για τους πίνακες numpy η πράξη &
επιστρέφει το στοιχειομετρικό-και των δύο
boolean πινάκων.
Οι προγραμματιστές της NumPy θεώρησαν ότι δεν υπήρχε ένας κοινά κατανοητός τρόπος για την αποτίμηση
ενός πίνακα σε boolean πλαίσιο: θα μπορούσε να σημαίνει True
αν οποιοδήποτε στοιχείο είναι
Αληθινό
, ή θα μπορούσε να σημαίνει Αληθινό
αν όλα τα στοιχεία είναι Αληθινά
, ή Αληθινό
αν ο πίνακας έχει μη μηδενικό μήκος, για να αναφέρουμε μόνο τρεις δυνατότητες.
Δεδομένου ότι διαφορετικοί χρήστες μπορεί να έχουν διαφορετικές ανάγκες και διαφορετικές παραδοχές, η
προγραμματιστές της NumPy αρνήθηκαν να μαντέψουν και αντ' αυτού αποφάσισαν να εγείρουν ένα ValueError
κάθε φορά που κάποιος προσπαθεί να αξιολογήσει έναν πίνακα σε boolean πλαίσιο. Εφαρμόζοντας το και
στο
δύο πίνακες numpy προκαλεί την αξιολόγηση των δύο πινάκων σε boolean πλαίσιο (από την
καλώντας το __bool__
στην Python3 ή το __nonzero__
στην Python2).
Ο αρχικός σας κώδικας
mask = ((r["dt"] >= startdate) & (r["dt"] <= enddate))
selected = r[mask]
φαίνεται σωστός. Ωστόσο, αν θέλετε και
, τότε αντί για a και b
χρησιμοποιήστε (a-b).any()
ή (a-b).all()
.
Είχα το ίδιο πρόβλημα (δηλ. ευρετηρίαση με πολλαπλές συνθήκες, εδώ είναι η εύρεση δεδομένων σε ένα συγκεκριμένο εύρος ημερομηνιών). Το (a-b).any()
ή το (a-b).all()
δεν φαίνεται να λειτουργεί, τουλάχιστον για μένα.
Εναλλακτικά, βρήκα μια άλλη λύση που λειτουργεί τέλεια για την επιθυμητή λειτουργικότητα (https://stackoverflow.com/questions/12647471/the-truth-value-of-an-array-with-more-than-one-element-is-ambigous-when-trying-t).
Αντί για τη χρήση του προτεινόμενου κώδικα παραπάνω, θα λειτουργούσε απλά η χρήση ενός numpy.logical_and(a,b)
. Εδώ μπορεί να θέλετε να ξαναγράψετε τον κώδικα ως εξής
selected = r[numpy.logical_and(r["dt"] >= startdate, r["dt"] <= enddate)]
Ο λόγος της εξαίρεσης είναι ότι το and
καλεί σιωπηρά το bool
. Πρώτα στον αριστερό τελεστή και (εάν ο αριστερός τελεστής είναι True
) στη συνέχεια στον δεξιό τελεστή. Έτσι το x και y
είναι ισοδύναμο με το bool(x) και bool(y)
.
Ωστόσο, το bool
σε μια numpy.ndarray
(αν περιέχει περισσότερα από ένα στοιχεία) θα προκαλέσει την εξαίρεση που είδατε:
>>> import numpy as np
>>> arr = np.array([1, 2, 3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Η κλήση bool()
είναι σιωπηρή στο and
, αλλά και στα if
, while
, or
, οπότε οποιοδήποτε από τα παρακάτω παραδείγματα θα αποτύχει επίσης:
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> if arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> while arr: pass
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr or arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
Υπάρχουν περισσότερες συναρτήσεις και δηλώσεις στην Python που κρύβουν κλήσεις bool
, για παράδειγμα 2 < x < 10
είναι απλά ένας άλλος τρόπος να γράψετε 2 < x και x < 10
. Και το και
θα καλέσει το bool
: bool(2 < x) και bool(x < 10)
.
Το element-wise ισοδύναμο για το και
θα ήταν η συνάρτηση np.logical_and
, ομοίως θα μπορούσατε να χρησιμοποιήσετε το np.logical_or
ως ισοδύναμο για το ή
.
Για πίνακες boolean - και συγκρίσεις όπως οι <
, <=
, ==
, !=
, >=
και >
σε πίνακες NumPy που επιστρέφουν πίνακες boolean NumPy - μπορείτε επίσης να χρησιμοποιήσετε τις element-wise bitwise συναρτήσεις (και τελεστές): np.bitwise_and
(τελεστής &
)
>>> np.logical_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> np.bitwise_and(arr > 1, arr < 3)
array([False, True, False], dtype=bool)
>>> (arr > 1) & (arr < 3)
array([False, True, False], dtype=bool)
και `bitwise_or
(τελεστής ||
):
>>> np.logical_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> np.bitwise_or(arr <= 1, arr >= 3)
array([ True, False, True], dtype=bool)
>>> (arr <= 1) | (arr >= 3)
array([ True, False, True], dtype=bool)
Ένας πλήρης κατάλογος των λογικών και δυαδικών συναρτήσεων μπορεί να βρεθεί στην τεκμηρίωση του NumPy: