Encontré un código con una línea similar a
x[x<2]=0
Jugando con variaciones, todavía estoy atascado en lo que hace esta sintaxis.
Ejemplos:
>>> 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]
Encontré un código con una línea similar a
x[x<2]=0
Jugando con variaciones, todavía estoy atascado en lo que hace esta sintaxis.
Ejemplos:
>>> 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]
TypeError: unorderable types: list() < int().
Respuestas:
Esto solo tiene sentido con matrices NumPy . El comportamiento con listas es inútil y específico de Python 2 (no Python 3). Es posible que desee volver a verificar si el objeto original era de hecho una matriz NumPy (ver más abajo) y no una lista.
Pero en su código aquí, x es una lista simple.
Ya que
x < 2
es falso, es decir, 0, por lo tanto
x[x<2] es x[0]
x[0] se cambia.
Por el contrario, x[x>2]es x[True]ox[1]
Entonces, x[1]se cambia.
¿Por qué pasó esto?
Las reglas de comparación son:
Cuando ordena dos cadenas o dos tipos numéricos, el orden se realiza de la forma esperada (ordenamiento lexicográfico para cadenas, ordenamiento numérico para enteros).
Cuando solicita un tipo numérico y uno no numérico, el tipo numérico es lo primero.
Cuando ordena dos tipos incompatibles donde ninguno es numérico, se ordenan por orden alfabético de sus nombres de tipo:
Entonces, tenemos el siguiente orden
numérico <lista <cadena <tupla
Vea la respuesta aceptada para ¿Cómo compara Python string e int? .
Si x es una matriz NumPy , entonces la sintaxis tiene más sentido debido a la indexación de la matriz booleana . En ese caso, x < 2no es un booleano en absoluto; es una matriz de valores booleanos que representan si cada elemento de xera menor que 2. x[x < 2] = 0luego selecciona los elementos de xque eran menores que 2 y establece esas celdas en 0. Consulte Indexación .
>>> 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
importnumpy.
[0 if i < 2 else i for i in x],.) ¿O es este estilo fomentado en Numpy?
x[x<2]devolverá una matriz numpy, mientras que [0 if i<2 else i for i in x]devuelve una lista. Esto se debe a que x[x<2]es una operación de indexación (a la que se hace referencia en numpy / scipy / pandas como una operación de corte debido a la capacidad de enmascarar datos), mientras que la comprensión de la lista es una nueva definición de objeto. Ver indexación NumPy
>>> x = [1,2,3,4,5]
>>> x<2
False
>>> x[False]
1
>>> x[True]
2
El bool simplemente se convierte en un número entero. El índice es 0 o 1.
xy 2están " ordenados de forma coherente pero arbitraria " y que el orden puede cambiar en diferentes implementaciones de Python.
x<2 == false?
boolno se convierte en un número entero, boolen Python es un número entero
bool es una subclase de int.
El código original de su pregunta solo funciona en Python 2. Si xes un listen Python 2, la comparación x < yes Falsesi yes un integer. Esto se debe a que no tiene sentido comparar una lista con un número entero. Sin embargo, en Python 2, si los operandos no son comparables, la comparación se basa en CPython en el orden alfabético de los nombres de los tipos ; además, todos los números aparecen primero en las comparaciones de tipo mixto . Esto ni siquiera está detallado en la documentación de CPython 2, y diferentes implementaciones de Python 2 podrían dar resultados diferentes. Eso se [1, 2, 3, 4, 5] < 2evalúa Falseporque 2es un número y, por lo tanto, "más pequeño" que listen CPython. Esta comparación mixta fue finalmentese consideró una característica demasiado oscura y se eliminó en Python 3.0.
Ahora, el resultado de <es a bool; y booles una subclase deint :
>>> isinstance(False, int)
True
>>> isinstance(True, int)
True
>>> False == 0
True
>>> True == 1
True
>>> False + 5
5
>>> True + 5
6
Básicamente, estás tomando el elemento 0 o 1 dependiendo de si la comparación es verdadera o falsa.
Si prueba el código anterior en Python 3, obtendrá TypeError: unorderable types: list() < int()debido a un cambio en Python 3.0 :
Comparaciones de pedidos
Python 3.0 ha simplificado las reglas para ordenar comparaciones:
Los operadores de comparación de pedidos (
<,<=,>=,>) plantear unaTypeErrorexcepción cuando los operandos no tienen un orden natural significativo. Por lo tanto, expresiones como1 < '',0 > Noneolen <= lenya no son válidas y, por ejemplo,None < Nonesube enTypeErrorlugar de devolverFalse. Un corolario es que ordenar una lista heterogénea ya no tiene sentido: todos los elementos deben ser comparables entre sí. Tenga en cuenta que esto no se aplica a los operadores==y!=: los objetos de diferentes tipos incomparables siempre se comparan de manera desigual entre sí.
Hay muchos tipos de datos que sobrecargan los operadores de comparación para hacer algo diferente (marcos de datos de pandas, matrices de numpy). Si el código que estaba usando hizo algo más, fue porque nox era unlist , sino una instancia de otra clase con el operador <anulado para devolver un valor que no es un bool; y este valor fue manejado especialmente por x[](también conocido como __getitem__/ __setitem__)
+FalseHola Perl, hola JavaScript, ¿cómo están?
UNARY_POSITIVEcódigo de operación que llama al__pos__
__setitem__lugar de __getitem__en su última sección. También espero que no le importe que mi respuesta se haya inspirado en esa parte de su respuesta.
__getitem__aunque igualmente podría haber sido __setitem__y__delitem__
Esto tiene un uso más: código golf. Code golf es el arte de escribir programas que resuelven algún problema en el menor número posible de bytes de código fuente.
return(a,b)[c<d]
es aproximadamente equivalente a
if c < d:
return b
else:
return a
excepto que tanto a como b se evalúan en la primera versión, pero no en la segunda versión.
c<devalúa a Trueo False.
(a, b)es una tupla.
Indexar en una tupla funciona como indexar en una lista: (3,5)[1]== 5.
Truees igual 1y Falsees igual a 0.
(a,b)[c<d](a,b)[True](a,b)[1]bo para False:
(a,b)[c<d](a,b)[False](a,b)[0]aHay una buena lista en la red de intercambio de pilas de muchas cosas desagradables que puede hacer con Python para ahorrar unos pocos bytes. /codegolf/54/tips-for-golfing-in-python
Aunque en el código normal, esto nunca debería usarse, y en su caso significaría que xactúa tanto como algo que se puede comparar con un número entero como un contenedor que admite el corte, que es una combinación muy inusual. Probablemente sea código Numpy, como han señalado otros.
Code Golf is the art of writing programs: ')
En general, podría significar cualquier cosa . Ya era explicó lo que significa que si xes una listo numpy.ndarraypero en general sólo depende de cómo los operadores de comparación ( <, >también cómo, ...) y el / puesta a punto get ( [...]se implementan -Sintaxis).
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!
Porque:
x < value es equivalente a x.__lt__(value)x[value] es (aproximadamente) equivalente a x.__getitem__(value) x[value] = othervaluees (también aproximadamente) equivalente a x.__setitem__(value, othervalue).Esto se puede personalizar para hacer lo que desee. Solo como ejemplo (imita una indexación numpys-booleana):
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
Así que ahora veamos qué pasa si lo usas:
>>> 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])
Note que esta es solo una posibilidad. Eres libre de implementar casi todo lo que quieras.