Asignar valor de dtype usando array.dtype = en matrices NumPy da resultados ambiguos

Soy nuevo en progtwigción y numpy … Al leer tutoriales y experimentar en jupyter-notebook … Pensé en convertir el tipo de letra de una matriz numpy de la siguiente manera:

import numpy as np c = np.random.rand(4)*10 print c #Output1: [ 0.12757225 5.48992242 7.63139022 2.92746857] c.dtype = int print c #Output2: [4593764294844833304 4617867121563982285 4620278199966380988 4613774491979221856] 

Sé que la forma correcta de cambiar es:

 c = c.astype(int) 

Pero quiero saber la razón detrás de esos números ambiguos en Output2. ¿Qué son y qué significan?

Los numpy.float64 y enteros ( numpy.float64 s y numpy.int64 s) se representan de manera diferente en la memoria. El valor 42 almacenado en estos diferentes tipos corresponde a un patrón de bits diferente en la memoria.

Cuando está reasignando el atributo dtype de una matriz, mantiene los datos subyacentes sin cambios, y le está diciendo a Numpy que interprete ese patrón de bits de una manera nueva. Ya que la interpretación ahora no coincide con la definición original de los datos, terminas con un galimatías (números sin sentido).

Por otro lado, convertir su matriz a través de .astype() convertirá realmente los datos en la memoria:

 >>> import numpy as np >>> arr = np.random.rand(3) >>> arr.dtype dtype('float64') >>> arr array([ 0.7258989 , 0.56473195, 0.20885672]) >>> arr.data  >>> arr.dtype = np.int64 >>> arr.data  >>> arr array([4604713535589390862, 4603261872765946451, 4596692876638008676]) 

Conversión adecuada:

 >>> arr = np.random.rand(3)*10 >>> arr array([ 3.59591191, 1.21786042, 6.42272461]) >>> arr.astype(np.int64) array([3, 1, 6]) 

Como puede ver, el uso de astype convertirá de manera significativa los valores originales de la matriz, en este caso se truncará a la parte entera y devolverá una nueva matriz con los valores y dtype correspondientes.

Tenga en cuenta que asignar un nuevo tipo de dtype no dtype ninguna comprobación, por lo que puede hacer cosas muy extrañas con su matriz. En el ejemplo anterior, 64 bits de flotadores se reinterpretaron como 64 bits de enteros. Pero también puedes cambiar el tamaño del bit:

 >>> arr = np.random.rand(3) >>> arr.shape (3,) >>> arr.dtype dtype('float64') >>> arr.dtype = np.float32 >>> arr.shape (6,) >>> arr array([ 4.00690371e+35, 1.87285304e+00, 8.62005305e+13, 1.33751166e+00, 7.17894062e+30, 1.81315207e+00], dtype=float32) 

¡Al decirle a numpy que sus datos ocupan la mitad del espacio que originalmente, numpy deducirá que su matriz tiene el doble de elementos! Claramente no es lo que deberías querer hacer.


Otro ejemplo: considere el entero sin signo de 8 bits 255 == 2 ** 8-1: corresponde a 11111111 en binario. Ahora, intente reinterpretar dos de estos números como un solo entero sin signo de 16 bits:

 >>> arr = np.array([255,255],dtype=np.uint8) >>> arr.dtype = np.uint16 >>> arr array([65535], dtype=uint16) 

Como puede ver, el resultado es el número único 65535. Si eso no suena, es exactamente 2 ** 16-1, con 16 unidades en su patrón binario. Los dos patrones completos se reinterpretaron como un solo número de 16 bits, y el resultado cambió en consecuencia. La razón por la que a menudo ve números más raros es que la reinterpretación de los flotadores como ints y viceversa conducirá a una manipulación de datos mucho más fuerte, debido a la forma en que los números de punto flotante se representan en la memoria.


Como señaló hpaulj , puede realizar directamente esta reinterpretación de los datos construyendo una nueva view de la matriz con un dtype modificado. Probablemente esto sea más útil que tener que reasignar el dtype de dtype de una matriz dada, pero nuevamente, cambiar el tipo de dtype solo es útil en casos de uso muy raros y muy específicos.