import numpy as np
a = np.array([0])
b = np.array([None])
c = np.array([''])
d = np.array([' '])
なぜこの矛盾が必要なのか:
>>> bool(a)
False
>>> bool(b)
False
>>> bool(c)
True
>>> bool(d)
False
import numpy as np
a = np.array([0])
b = np.array([None])
c = np.array([''])
d = np.array([' '])
なぜこの矛盾が必要なのか:
>>> bool(a)
False
>>> bool(b)
False
>>> bool(c)
True
>>> bool(d)
False
要素が 1 つの配列の場合、配列の真理値はその要素の真理値によって決まります。
重要なポイントは、1 つの空の Python 文字列を含む配列でnp.array([''])
はないということです。この配列は、それぞれ正確に 1 バイトの文字列を保持するために作成され、NumPy は短すぎる文字列を null 文字で埋めます。これは、配列が に等しいことを意味しnp.array(['\0'])
ます。
この点で、NumPy は として評価される Python と一致してbool('\0')
いTrue
ます。
実際、False
NumPy 配列にある唯一の文字列は、非空白文字を含まない文字列です ('\0'
は空白文字ではありません)。
このブール評価の詳細を以下に示します。
NumPy の迷路のようなソース コードをナビゲートするのは必ずしも簡単ではありませんが、arraytypes.c.srcファイルで、さまざまなデータ型の値をブール値にマップする方法を管理するコードを見つけることができます。bool(a)
これは、 、bool(b)
、bool(c)
およびがどのようにbool(d)
決定されるかを説明します。
bool()
そのファイルのコードに到達する前に、NumPy 配列を呼び出すと内部_array_nonzero()
関数が呼び出されることがわかります。配列が空の場合、取得しFalse
ます。2 つ以上の要素がある場合、エラーが発生します。しかし、配列に要素が 1 つだけある場合は、次の行にヒットします。
return PyArray_DESCR(mp)->f->nonzero(PyArray_DATA(mp), mp);
現在、PyArray_DESCR
配列のさまざまなプロパティを保持する構造体です。配列の関数を保持f
する別の構造体へのポインタです。言い換えれば、NumPy は配列自体の特別な関数を呼び出して、その 1 つの要素のブール値をチェックします。PyArray_ArrFuncs
nonzero
nonzero
要素が非ゼロかどうかの判断は、明らかに要素のデータ型に依存します。型固有の非ゼロ関数を実装するコードは、 arraytypes.c.srcファイルの「非ゼロ」セクションにあります。
予想どおり、浮動小数点数、整数、および複素数は、ゼロと等しいFalse
場合です。これは説明します。オブジェクト配列の場合、NumPyは関数を呼び出すだけなので、同様に と評価されます。これは説明します。bool(a)
None
False
PyObject_IsTrue
bool(b)
bool(c)
との結果を理解するために、文字列型配列の関数が次の関数にマップされてbool(d)
いることがわかります。nonzero
STRING_nonzero
static npy_bool
STRING_nonzero (char *ip, PyArrayObject *ap)
{
int len = PyArray_DESCR(ap)->elsize; // size of dtype (not string length)
int i;
npy_bool nonz = NPY_FALSE;
for (i = 0; i < len; i++) {
if (!Py_STRING_ISSPACE(*ip)) { // if it isn't whitespace, it's True
nonz = NPY_TRUE;
break;
}
ip++;
}
return nonz;
}
(Unicode の場合もほぼ同じ考えです。)
したがって、文字列または Unicode データ型の配列では、文字列は、False
空白文字のみを含む場合にのみ使用されます。
>>> bool(np.array([' ']))
False
質問の配列の場合、一見空の文字列をパディングc
する実際にはヌル文字があります。\0
>>> np.array(['']) == np.array(['\0'])
array([ True], dtype=bool)
関数はこのSTRING_nonzero
非空白文字を認識し、そうbool(c)
ですTrue
。
この回答の冒頭で述べたように、これは単一の null 文字を含む文字列の Python の評価と一致しています: bool('\0')
is also True
.
更新: Wim は、NumPy のマスター ブランチで上記の動作を修正し、null 文字のみ、または空白と null 文字のみの混合を含む文字列を に評価するようにしましたFalse
。これは、NumPy 1.10+ が is を認識することを意味しますbool(np.array(['']))
。False
これは、Python の「空の」文字列の扱いとより一致しています。
Scalarsで説明されているように、答えは次のとおりであると確信しています。
配列スカラーには、ndarray と同じ属性とメソッドがあります。[1] これにより、配列の項目を部分的に配列と同じ立場で扱うことができ、スカラー操作と配列操作を混合したときに生じる粗いエッジを滑らかにします。
したがって、bool
スカラーを呼び出すことが許容される場合bool
、 shape の配列を呼び出すことも許容される必要があります(1,)
。これらは可能な限り同じものであるためです。
また、私が知っているドキュメントのどこにも直接言及されていませんが、NumPy のスカラーがネイティブ Python オブジェクトのように動作することになっていることは設計から明らかです。
それで、それはなぜnp.array([0])
あなたが最初に驚いたのか、真実ではなく虚偽である理由を説明しています.
それで、それは基本を説明します。しかし、ケースの詳細はc
どうですか?
np.array([''])
まず、配列が 1 つの Python の配列ではなく、長さ 1object
の 1 つの NumPy null 終端文字列の配列であることに注意してください<U1
。固定長の文字列値には、Python 文字列と同じ真偽規則はありません。できませんでした。固定長の文字列型の場合、空ではないため、「空の場合は false」は意味がありません。NumPy がそのように設計されるべきかどうかについて議論することはできますが、明らかに一貫してその規則に従っており、反対の規則がここで混乱を招くとは思いません。単に異なるだけです。
しかし、文字列には他にも奇妙なことが起こっているようです。このことを考慮:
>>> np.array(['a', 'b']) != 0
True
<U2
これは、文字列を 0 と要素ごとに比較して返すのではなくarray([True, True])
( から得られるようにnp.array(['a', 'b'], dtype=object)
)、配列全体の比較を行って、文字列の配列が 0 に等しくないと判断するのですが、これは奇妙に思えます...よくわかりませんこれがここで別の答えを出すに値するのか、それともまったく別の質問に値するのかはわかりませんが、ここで何が起こっているのか見当がつかないので、その答えを書くのは私ではないと確信しています。:)
shape の配列を超えて、 shape(1,)
の配列は()
同じように扱われますが、それ以外はすべて a です。そうしないと、NumPy が自動的に要素ごとの演算に変換できない やその他の Python 演算子でValueError
配列を誤用するのが非常に簡単になるためです。and
個人的には、ここでスカラーと一貫性を保つよりも、他の配列と一貫性を保つ方が便利だと思いますValueError
。また、ここでスカラーとの一貫性が重要である場合は、ボックス化されていない Python の値と一貫性を保つ方がよいと思います。言い換えると、bool(array([v]))
とが許可される場合、 と一貫性がなくても、bool(array(v))
常に とまったく同じものを返す必要があります。しかし、私はその議論を逆に見ることができます。bool(v)
np.nonzero
現在、マスターで修正されています。
これはバグだと思い、numpy
開発者も同意したので、このパッチは本日より早くマージされました。今後の 1.10 リリースで新しい動作が見られるはずです。
Numpy は、組み込みの python **と同じキャストに従っているようnonzero
です。も使用len
できるようですが、ここでは、これらの配列はどれも空 (長さ0
) ではないため、直接関係ありません。呼び出しもこれらの規則に従ってbool([False])
返されることに注意してください。True
a = np.array([0])
b = np.array([None])
c = np.array([''])
>>> nonzero(a)
(array([], dtype=int64),)
>>> nonzero(b)
(array([], dtype=int64),)
>>> nonzero(c)
(array([0]),)
bool
これは、キャストのより列挙的な説明とも一致しているようです---あなたの例はすべて明示的に議論されています。
興味深いことに、文字列配列では体系的に異なる動作があるようです。
>>> a.astype(bool)
array([False], dtype=bool)
>>> b.astype(bool)
array([False], dtype=bool)
>>> c.astype(bool)
ERROR: ValueError: invalid literal for int() with base 10: ''
numpy が何かを bool に変換するとき、PyArray_BoolConverter
関数を使用し、関数を呼び出すだけです。PyObject_IsTrue
つまり、組み込みの python が使用するのとまったく同じ関数ですnumpy
結果が非常に一貫している理由です。