1. ホーム
  2. python-2.7

[解決済み] np.deleteとnp.s_。np_sの何がそんなに特別なんだ?

2022-03-13 18:24:50

質問

np.deleteに通常のインデックスを使用できない理由がよくわかりません。 np.s_は何がそんなに特別なのでしょうか?

例えば、この配列のいくつかの行を削除するために使用されるコードです。

inlet_names = np.delete(inlet_names, np.s_[1:9], axis = 0)

なぜ、通常のインデックス作成ではダメなのでしょうか?

inlet_names = np.delete(inlet_names, [1:9], axis = 0)

または

inlet_names = np.delete(inlet_names, inlet_names[1:9], axis = 0)

私が調べたところでは、np.s_はタプルを返さない以外はnp.index_expと同じですが、どちらもPythonコードのどこでも使うことができます。

それから、np.delete関数を調べると、次のような使い方ができることがわかります。 [1,2,3] を使用すると、配列全体に沿った特定のインデックスを削除することができます。 では、同じような方法で配列から特定の行や列を削除できないのでしょうか?

このタイプのインデックスは、np.deleteでは別のものとして読み取られるので、指定するにはnp.s_を使う必要があると単純に考えていますが、2番目のコードを試すと単に "無効な構文"を返すので、正確に何として読み取られるのか、真相がわかりません。このコードは動作するので、奇妙なことですが...。

inlet_names = np.delete(inlet_names, [1,2,3,4,5,6,7,8,9], axis = 0)   

つまり、np.deleteは削除したいインデックスのリストのみを受け付けるというのが答えになるかと思います。そして、np._sはスライスに指定したインデックスのリストを返します。

というのも、これらの多くは私が理解したもので、ドキュメントには私が理解しようとしたことすべてが正確に説明されているわけではないからです。私が考えすぎているだけだと思うのですが、もし誰かが説明してくれるなら、実際に理解したいのです。

どのように解決するのですか?

np.delete はユニークで特別なことは何もしていません。 ただ、元の配列のコピーからいくつかの項目を取り除いたものを返しているだけです。 コードの大部分は、このコピーを作成するための準備として入力を解釈しているだけです。

ご質問の内容は obj パラメータ

obj : スライス、intまたはintの配列

わかりやすく言うと np.s_ でスライスを指定することができます。 : の構文があります。 そのため x:y という表記は、関数のパラメータとして使用できません。

代替案を試してみましょう(results and errorsで暗示していますが、本文に埋もれています)。

In [213]: x=np.arange(10)*2   # some distinctive values

In [214]: np.delete(x, np.s_[3:6])
Out[214]: array([ 0,  2,  4, 12, 14, 16, 18])

だから deletes_ は、値の範囲、すなわち 6 8 10 3番目から5番目のものです。

In [215]: np.delete(x, [3:6])
  File "<ipython-input-215-0a5bf5cc05ba>", line 1
    np.delete(x, [3:6])
                   ^
SyntaxError: invalid syntax

なぜエラーになるのか? それは [3:4] はインデックス式です。 np.delete は関数です。 でも s_[[3:4]] は問題があります。 np.delete(x, 3:6) もダメで、Pythonが受け入れるのは : の構文は、インデックス作成コンテキストで、自動的に slice オブジェクトを作成します。 であることに注意してください。 syntax error これは、計算や関数呼び出しを行う前にインタプリタがキャッチするものです。

In [216]: np.delete(x, slice(3,6))
Out[216]: array([ 0,  2,  4, 12, 14, 16, 18])

A slice の代わりに動作します。 s_ 実際、これは s_ 生み出す

In [233]: np.delete(x, [3,4,5])
Out[233]: array([ 0,  2,  4, 12, 14, 16, 18])

リストでも動作しますが、動作の仕方が異なります(下記参照)。

In [217]: np.delete(x, x[3:6])
Out[217]: array([ 0,  2,  4,  6,  8, 10, 14, 18])

これは動作しますが、異なる結果を生成します。 x[3:6] とは異なります。 range(3,6) . また np.delete のように動作しません。 list を削除します。 一致する値ではなく、インデックスによって削除されます。

np.index_exp と同じ理由で失敗します。 np.delete(x, (slice(3,6),)) があります。 1 , [1] , (1,) はすべて有効で、1つの項目を削除します。 ただし '1' という文字列は、機能します。 delete はこの引数を解析し、このレベルでは、整数に変換できるものを期待します。 obj.astype(intp) . (slice(None),) はスライスではなく、1アイテムのタプルです。 そのため、別の場所で処理され delete のコードになります。 これは TypeError するものによって生成されます。 delete とは全く異なる呼び方をします。 SyntaxError . 理論的には delete は、タプルからスライスを抽出し、次のように処理することができます。 s_ の場合ですが、開発者はこのバリエーションを考慮することを選択しませんでした。

コードをざっと見てみると np.delete は、スライスによるコピーとブールマスクによるコピーの2つの異なる方法を使用しています。 もし obj がスライスである場合、この例のように(1d配列の場合)そうなります。

out = np.empty(7)
out[0:3] = x[0:3]
out[3:7] = x[6:10]

しかし [3,4,5] (スライスの代わりに)そうなります。

keep = np.ones((10,), dtype=bool)
keep[[3,4,5]] = False
return x[keep]

同じ結果ですが、構築方法が異なります。 x[np.array([1,1,1,0,0,0,1,1,1,1],bool)] も同じことをします。

実際には、このようなブーリアンインデックスやマスキングは np.delete そして、一般に、それと同じくらい強力です。


から lib/index_tricks.py のソースファイルです。

index_exp = IndexExpression(maketuple=True)
s_ = IndexExpression(maketuple=False)

これらは、同じものの微妙に異なるバージョンです。 そして、どちらも単なる便利な機能です。

In [196]: np.s_[1:4]
Out[196]: slice(1, 4, None)
In [197]: np.index_exp[1:4]
Out[197]: (slice(1, 4, None),)
In [198]: np.s_[1:4, 5:10]
Out[198]: (slice(1, 4, None), slice(5, 10, None))
In [199]: np.index_exp[1:4, 5:10]
Out[199]: (slice(1, 4, None), slice(5, 10, None))

maketuple ビジネスは、単一のアイテム、スライスまたはインデックスがある場合にのみ適用されます。