파이썬에서 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 apr

12
이것은 NumPy 배열 또는 유사한 개체에서만 의미가 있으며 실험의 동작 또는 두 답변에서 설명 된 목록 기반 동작과 완전히 다르게 동작합니다.
user2357112 모니카 지원

11
이것은 Python 3에서는 작동하지 않습니다. 유형은 비교가 타당 할 때만 비교할 수 있습니다. Python 3에서이 예제는 TypeError: unorderable types: list() < int().
Morgan Thrapp 2016

2
정보가 너무 적습니다. 배열이 numpy 배열이라고 언급 했어야합니다.
lmaooooo

3
나는 이것이 너무 많은 찬성표를 얻었습니다 (실제로 SO 형식에 대한 좋은 질문이지만) 충격을 받았습니다.
PascalVKooten

답변:


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. 숫자 형과 비숫 자형을 주문하면 숫자 형이 먼저 나옵니다.

  3. 둘 다 숫자가 아닌 호환되지 않는 두 가지 유형을 주문하면 유형 이름의 알파벳 순서로 정렬됩니다.

그래서 우리는 다음과 같은 순서를 가지고 있습니다.

숫자 <목록 <문자열 <튜플

Python은 string과 int어떻게 비교합니까?.

x가 NumPy 배열 이면 부울 배열 인덱싱 때문에 구문이 더 의미가 있습니다. 이 경우 x < 2에는 전혀 부울이 아닙니다. 의 각 요소 x가 2보다 작은 지 여부를 나타내는 부울 배열입니다 . x[x < 2] = 0그런 다음 x2보다 작은 요소를 선택하고 해당 셀을 0으로 설정합니다 . Indexing을 참조하십시오 .

>>> 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가보고있는 코드를 위로 스크롤하면 다음과 같은 점을 지적 할 가치가 있습니다. 거의 확실하게 importnumpy를 볼 수 있습니다.
J Richard Snape 2016

2
여전히 지나치게 영리한 방법일까요? (예를 들어,과 비교하면 [0 if i < 2 else i for i in x].) 아니면 Numpy에서 권장되는 스타일입니까?
Tim Pederick

6
@TimPederick : NumPy와 함께 목록 이해력을 사용하는 것은 꽤 나쁜 생각입니다. 수십 배에서 수백 배 더 느리고 임의 차원 배열에서 작동하지 않으며 요소 유형을 망가 뜨리는 것이 더 쉽고 배열 대신 목록을 생성합니다. 부울 배열 인덱싱은 완전히 정상이며 NumPy에서 예상됩니다.
user2357112 모니카 지원

@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
당신은 말할 수 x하고 2있다 " 일관하지만, 임의의 명령 " 과 순서가 다른 파이썬 구현에서 변경 될 수 있음.
Robᵩ apr

2
나는 또한 이것이 일을하는 영리한 방법이며 내 의견으로는 피해야한다고 덧붙였다. 그것을 명시 적으로하십시오-OP가이 질문을해야했다는 사실은 나의 요지를 뒷받침합니다.
kratenko 16.04.13

11
자세한 내용을 추가 할 수 x<2 == false있습니까? 이유는 무엇입니까?
Iłya Bursov 16.04.13

15
bool정수로 변환되지 않습니다하는 bool파이썬은 정수입니다
안티 Haapala

2
그냥 따라 오는 다른 사람에 대한 AnttiHaapala의 문 @ 명확하게 bool 서브 클래스int.
porglezomp

14

귀하의 질문에있는 원본 코드는 Python 2에서만 작동합니다. Python 2 에서 xa list인 경우 비교 x < yFalseif yinteger입니다. 이는 목록을 정수와 비교하는 것이 의미가 없기 때문입니다. 그러나 Python 2에서 피연산자가 비교할 수없는 경우 비교는 유형 이름의 알파벳 순서 에 따라 CPython을 기반 으로합니다 . 추가적으로 모든 숫자는 혼합 유형 비교에서 첫 번째가됩니다. . 이것은 CPython 2의 문서에도 나와 있지 않으며, 다른 Python 2 구현은 다른 결과를 제공 할 수 있습니다. 즉 [1, 2, 3, 4, 5] < 2평가 False하기 때문에 2숫자와보다 따라서 "작은"입니다 listCPython을한다. 이 혼합 비교는 결국기능이 너무 모호한 것으로 간주 되어 Python 3.0에서 제거되었습니다.


이제 결과 <는 다음과 같습니다 bool. 그리고 boolA는 서브 클래스 의는int :

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

따라서 기본적으로 비교가 참인지 거짓인지에 따라 요소 0 또는 1을 사용합니다.


Python 3에서 위의 코드를 시도하면 Python 3.0의 변경TypeError: unorderable types: list() < int() 으로 인해 다음과 같은 결과를 얻을 수 있습니다 .

주문 비교

Python 3.0은 순서 비교 규칙을 단순화했습니다.

순서 비교 연산자 ( <, <=, >=, >) 인상 TypeError피연산자가 의미있는 자연 순서가없는 경우 예외를. 따라서, 표현하고자하지 1 < '', 0 > None또는 len <= len더 이상 유효하며, 예를 None < None인상 TypeError하는 대신 반환 False. 결과적으로 이기종 목록을 정렬하는 것은 더 이상 의미가 없습니다. 모든 요소는 서로 비교할 수 있어야합니다. 이는 ==!=연산자 에는 적용되지 않습니다 . 비교할 수없는 다른 유형의 객체는 항상 서로 같지 않은 상태로 비교됩니다.


다른 작업을 수행하기 위해 비교 연산자를 오버로드 하는 많은 데이터 유형이 있습니다 (pandas의 데이터 프레임, numpy의 배열). 사용 중이던 코드가 다른 작업을 수행 한 경우는 이 아니고 연산자 가 아닌 다른 클래스의 인스턴스 가 아닌 값을 반환하도록 재정의 되었기 때문입니다 . 그리고이 값은 (aka / )에 의해 특별히 처리되었습니다.xlist<boolx[]__getitem____setitem__


6
+False안녕 Perl, 자바 스크립트, 잘 지내?
고양이

@cat Javascript, Perl에서 값을 숫자로 변환합니다. 파이썬에서 그것은을위한 UNARY_POSITIVE부르는 연산 코드__pos__
안티 Haapala

나는 당신이 마지막 섹션 __setitem__대신에 의미했다고 생각합니다 __getitem__. 또한 내 답변이 귀하의 답변에서 영감을 얻은 것에 대해 신경 쓰지 않기를 바랍니다.
MSeifert

아니, 의미 그리고 생각 __getitem__하지만 똑같이 수 있었다 __setitem____delitem__
안티 Haapala

9

이것은 또 하나의 용도가 있습니다 : 코드 골프. 코드 골프는 가능한 적은 소스 코드 바이트로 문제를 해결하는 프로그램을 작성하는 기술입니다.

return(a,b)[c<d]

대략 다음과 같습니다.

if c < d:
    return b
else:
    return a

단, a와 b는 첫 번째 버전에서는 평가되지만 두 번째 버전에서는 평가되지 않습니다.

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

스택 교환 네트워크에는 몇 바이트를 절약하기 위해 파이썬에 할 수있는 많은 불쾌한 일에 대한 좋은 목록이 있습니다. /codegolf/54/tips-for-golfing-in-python

일반 코드에서는 절대 사용해서는 안되며, 귀하의 경우 x에는 정수와 비교할 수있는 것과 매우 특이한 조합 인 슬라이싱을 지원하는 컨테이너 역할을 모두 수행 한다는 것을 의미합니다 . 다른 사람들이 지적했듯이 아마도 Numpy 코드 일 것입니다.


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

1
마이너 nitpick는 다음 부울이되지 캐스트 int로, 단지 하나 (다른 답변을 참조)
고양이

6

일반적으로 그것은 무엇이든 의미 할 수 있습니다 . 이미 있다면 그것이 무엇을 의미하는지 설명 xA는 list또는 numpy.ndarray그러나 일반적으로 만 비교 연산자 (방법에 따라 달라집니다 <, >...) 그리고이 또한 GET / SET-항목 (어떻게 [...]- 구문) 구현됩니다.

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])

이것은 하나의 가능성 일뿐입니다. 원하는 거의 모든 것을 자유롭게 구현할 수 있습니다.


나는 어떤 것을 사용하는 것이 허용되는 대답과 같이 논리적으로 설명 가능한 행동에 너무 일반적 이라고 말할 수 있습니다.
PascalVKooten

@PascalvKooten "무엇이든지"또는 일반화 된 대답에 동의하지 않습니까? 파이썬에서 대부분의 논리적 동작 은 관례에 의한 것이기 때문에 이것이 중요한 포인트라고 생각합니다 .
MSeifert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.