Pythonでx [x <2] = 0とはどういう意味ですか?


85

私は次のような行を持ついくつかのコードに出くわしました

x[x<2]=0

バリエーションをいじってみても、私はまだこの構文が何をするのか悩んでいます。

例:

>>> x = [1,2,3,4,5]
>>> x[x<2]
1
>>> x[x<3]
1
>>> x[x>2]
2
>>> x[x<2]=0
>>> x
[0, 2, 3, 4, 5]

7
リストを使用してこれを行うことは決して意味がありません。
dbliss 2016

12
これは、実験での動作やいずれかの回答で説明されているリストベースの動作とはまったく異なる動作をするNumPy配列または同様のオブジェクトでのみ意味があります。
user2357112は、2016

11
これはPython3では機能しないことに注意してください。タイプは、比較に意味がある場合にのみ比較できます。Python 3では、この例はをスローしTypeError: unorderable types: list() < int()ます。
モーガンスラップ2016

2
情報が少なすぎます。配列がnumpy配列であることを言及する必要があります。
lmaooooo 2016

3
私はこれが非常に多くの賛成票を得たことにショックを受けました(それは確かにSOフォーマットにとって良い質問ですが)。
pascalVKooten 2016

回答:


120

これは、NumPy配列でのみ意味があります。リストを使用した動作は役に立たず、Python 2(Python 3ではない)に固有です。元のオブジェクトが実際にNumPy配列(以下を参照)であり、リストではないかどうかを再確認することをお勧めします。

しかし、ここのコードでは、xは単純なリストです。

以来

x < 2

False、つまり0であるため、

x[x<2] です x[0]

x[0] 変更されます。

逆に、x[x>2]ありますx[True]x[1]

だから、x[1]変更されます。

なぜこれが起こるのですか?

比較のルールは次のとおりです。

  1. 2つの文字列または2つの数値タイプを注文する場合、注文は期待どおりに行われます(文字列の辞書式順序、整数の数値順序)。

  2. 数値型と非数値型を注文する場合、数値型が最初になります。

  3. どちらも数値ではない2つの互換性のないタイプを注文する場合、それらはタイプ名のアルファベット順に並べられます。

したがって、次の順序があります

数値<リスト<文字列<タプル

Pythonはstringとintどのように比較しますか?の受け入れられた答えを参照してください

xがNumPy配列の場合ブール配列のインデックス付けにより、構文の意味がわかります。その場合、x < 2ブール値ではありません。これは、の各要素がx2未満であるかどうかを表すブール値の配列です。x[x < 2] = 0次に、2未満の要素を選択し、xそれらのセルを0に設定します。「索引付け」を参照してください。

>>> x = np.array([1., -1., -2., 3])
>>> x < 0
array([False,  True,  True, False], dtype=bool)
>>> x[x < 0] += 20   # All elements < 0 get increased by 20
>>> x
array([  1.,  19.,  18.,   3.]) # Only elements < 0 are affected

11
OPが特に「このようなコードに出くわした...」と言っていることを考えると、numpyブールインデックスを説明するあなたの答えは非常に役立つと思います-OPが見たコードを上にスクロールすると、彼らはllはほぼ確実importにnumpyを参照してください。
Jリチャード・スネイプ

2
それでもそれを行うには過度に賢い方法ですよね?(たとえば、と比較して[0 if i < 2 else i for i in x]。)または、これはNumpyで推奨されるスタイルですか?
Tim Pederick 2016

6
@TimPederick:NumPyでリスト内包表記を使用するのはかなり悪い考えです。数十倍から数百倍遅く、任意の次元の配列では機能せず、要素タイプを台無しにするのが簡単で、配列の代わりにリストを作成します。ブール配列のインデックス付けは完全に正常であり、NumPyで期待されています。
user2357112は、2016

@TimPederickパフォーマンスの低下に加えて、numpy配列を使い続けることを目的としたコードを書いた人もいる可能性があります。x[x<2]numpy配列を[0 if i<2 else i for i in x]返しますが、リストを返します。これは、x[x<2]がインデックス作成操作(numpy / scipy / pandasではデータをマスクする機能のためにスライス操作と呼ばれる)であるのに対し、リスト内包表記は新しいオブジェクト定義であるためです。NumPyのインデックス作成を
Michael Delgado

45
>>> x = [1,2,3,4,5]
>>> x<2
False
>>> x[False]
1
>>> x[True]
2

ブール値は単純に整数に変換されます。インデックスは0または1のいずれかです。


7
あなたは、ことは言うかもしれないx2されている一貫して注文したが、任意にと順序が異なるPythonの実装で変更される可能性がありますことを。
Robᵩ

2
また、これは物事を行うための賢い方法であり、私の意見では避けるべきであると付け加えます。明示的に行ってください-OPがこの質問をしなければならなかったという事実は私の主張を裏付けています。
kratenko 2016

11
詳細を追加できますx<2 == falseか、なぜですか?
イリヤBursov

15
bool整数に変換されず、boolPythonでは整数である
アンティHaapala

2
一緒に来る他の人のための@AnttiHaapalaのステートメントを明確にするために、はのbool サブクラスですint
porglezomp 2016

14

あなたの質問の元のコードでは、場合にのみPythonの2で動作しxているlistのPython 2には、比較がx < yあるFalse場合yであるintエゲル。これは、リストを整数と比較することは意味がないためです。ただし、Python 2では、オペランドが比較できない場合、比較はCPythonで型の名前のアルファベット順に基づいています。さらに、混合タイプの比較では、すべての数値が最初になります。これはCPython2のドキュメントでも詳しく説明されておらず、Python2の実装が異なれば結果も異なる可能性があります。それはある[1, 2, 3, 4, 5] < 2と評価されたFalseため2、が数値でありlist、CPythonのaよりも「小さい」ます。この混合比較は最終的に機能がわかりにくいと見なされ、Python3.0で削除されました。


さて、の結果<bool;です。そして、boolあるサブクラスint

>>> isinstance(False, int)
True
>>> isinstance(True, int)
True
>>> False == 0
True
>>> True == 1
True
>>> False + 5
5
>>> True + 5
6

したがって、基本的には、比較が真であるか偽であるかに応じて、要素0または1を使用します。


上記のコードをPython3で試してみると、Python3.0での変更TypeError: unorderable types: list() < int()原因で発生します。

注文の比較

Python 3.0は、比較の順序付けのルールを簡素化しました。

注文比較演算子(<<=>=>)上げるTypeErrorオペランドが意味のある自然順序付けを持っていない場合に例外を。このように、のような表現1 < ''0 > Noneまたはlen <= lenもはや有効であり、例えばNone < None昇給TypeErrorの代わりに返しますFalse。当然の結果として、異種リストの並べ替えはもはや意味がありません。すべての要素が互いに比較可能でなければなりません。これは==!=演算子には適用されないことに注意してください。異なるタイプの比較できないオブジェクトは、常に互いに等しくないように比較されます。


比較演算子をオーバーロードして別のことを行うデータ型はたくさんあります(パンダのデータフレーム、numpyの配列)。使用しているコードが他のことを行った場合、それはでxなく、list演算子が<オーバーライドされてbool;ではない値を返す他のクラスのインスタンスであったためです。そして、この値はx[](aka __getitem__/ __setitem__)によって特別に処理されました。


6
+FalseこんにちはPerl、ちょっとJavaScript、お元気ですか?

@catはJavascript、Perlで、値を数値として変換します。PythonではUNARY_POSITIVE__pos__
Antti Haapala 2016

私はあなたがあなたの最後のセクションの__setitem__代わりに意味したと思います__getitem__。また、私の答えがあなたの答えのその部分に触発されたことを気にしないでください。
MSeifert 2016

いいえ、私は意味と考えていた__getitem__ものの均等にされている可能性__setitem____delitem__
アンティHaapala

9

これにはもう1つの用途があります。コードゴルフです。コードゴルフは、可能な限り少ないソースコードバイトでいくつかの問題を解決するプログラムを書く技術です。

return(a,b)[c<d]

とほぼ同等です

if c < d:
    return b
else:
    return a

ただし、aとbの両方が最初のバージョンで評価されますが、2番目のバージョンでは評価されません。

c<dTrueまたはに評価されFalseます。
(a, b)タプルです。
タプルのインデックス付けは、リストのインデックス付けと同じように機能します:(3,5)[1]== 5
Trueに等しい1Falseに等しい0

  1. (a,b)[c<d]
  2. (a,b)[True]
  3. (a,b)[1]
  4. b

またはFalse

  1. (a,b)[c<d]
  2. (a,b)[False]
  3. (a,b)[0]
  4. a

スタック交換ネットワークには、数バイトを節約するためにPythonに対して実行できる多くの厄介なことの良いリストがあります。/codegolf/54/tips-for-golfing-in-python

通常のコードではこれを使用しないでください。あなたの場合はx、整数と比較できるものとして、また非常に珍しい組み合わせであるスライスをサポートするコンテナーとして機能することを意味します。他の人が指摘しているように、それはおそらくNumpyコードです。


6
Code Golf is the art of writing programs: ')

1
マイナーな問題:boolはintにキャストされず、1つだけです(他の回答を参照)
cat

6

一般的に、それは何を意味する可能性があります。それは、すでにあれば、それが何を意味するのかを説明してxいるlistか、numpy.ndarray一般的にはそれだけで(どのように比較演算子に依存し<>そしてまた、取得/設定項目(どのように...、)[...]-syntax)が実装されていますが。

x.__getitem__(x.__lt__(2))      # this is what x[x < 2] means!
x.__setitem__(x.__lt__(2), 0)   # this is what x[x < 2] = 0 means!

理由:

  • x < value と同等です x.__lt__(value)
  • x[value] と(ほぼ)同等です x.__getitem__(value)
  • x[value] = othervalueは(大まかに)と同等x.__setitem__(value, othervalue)です。

これを行うためにカスタマイズすることができます何もしたいし。例として(少しnumpys-booleanインデックスを模倣):

class Test:
    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        # You could do anything in here. For example create a new list indicating if that 
        # element is less than the other value
        res = [item < other for item in self.value]
        return self.__class__(res)

    def __repr__(self):
        return '{0} ({1})'.format(self.__class__.__name__, self.value)

    def __getitem__(self, item):
        # If you index with an instance of this class use "boolean-indexing"
        if isinstance(item, Test):
            res = self.__class__([i for i, index in zip(self.value, item) if index])
            return res
        # Something else was given just try to use it on the value
        return self.value[item]

    def __setitem__(self, item, value):
        if isinstance(item, Test):
            self.value = [i if not index else value for i, index in zip(self.value, item)]
        else:
            self.value[item] = value

それでは、それを使用するとどうなるか見てみましょう。

>>> a = Test([1,2,3])
>>> a
Test ([1, 2, 3])
>>> a < 2  # calls __lt__
Test ([True, False, False])
>>> a[Test([True, False, False])] # calls __getitem__
Test ([1])
>>> a[a < 2] # or short form
Test ([1])

>>> a[a < 2] = 0  # calls __setitem__
>>> a
Test ([0, 2, 3])

これは1つの可能性にすぎないことに注意してください。必要なほとんどすべてを自由に実装できます。


受け入れられた答えのような論理的に説明可能な振る舞いには、実際には何かを使用することはあまりにも一般的すぎると思います。
pascalVKooten 2016

@PascalvKooten「何か」または一般的な答えに同意しませんか?Pythonのほとんどの論理的な動作は慣例によるものであるため、これは重要なポイントだと思います。
MSeifert 2016
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.