python - dtypes - Numpy casting float32 a float64
python dataframe astype (1)
Quiero realizar algunas operaciones estándar en matrices numpy float32
en python 3, sin embargo, estoy viendo un comportamiento extraño al trabajar con numpy sum()
. Aquí hay una sesión de ejemplo:
Python 3.6.1 |Anaconda 4.4.0 (x86_64)| (default, May 11 2017, 13:04:09)
[GCC 4.2.1 Compatible Apple LLVM 6.0 (clang-600.0.57)] on darwin
import numpy as np
np.__version__
Out[3]: ''1.12.1''
a = np.ones(10).astype(np.float32)
np.sum(a).dtype
Out[5]: dtype(''float32'')
(np.sum(a)+1).dtype
Out[6]: dtype(''float64'')
(np.sum(a)+1.).dtype
Out[7]: dtype(''float64'')
(a+1).dtype
Out[8]: dtype(''float32'')
¿Alguna razón por la que agregar un escalar al resultado de una suma (que parece tener el dtype
de float32
) lo devolvería a float64
? Para ser claros, sé que puedo convertir explícitamente el escalar a float32
, sin embargo, como muestra la última línea, numpy aún respeta float32
cuando agrega un escalar a una matriz. ¿Alguna explicación o sugerencia de cómo mantener las cosas como float32
sin conversión explícita?
El resultado de np.sum(a)
es un escalar NumPy, en lugar de una matriz. Las operaciones que involucran solo escalares utilizan reglas de conversión diferentes de las operaciones que involucran matrices NumPy (de dimensión positiva), descritas en los documentos para numpy.result_type
.
Cuando una operación involucra solo escalares (incluidas las matrices de 0 dimensiones), el tipo de resultado se determina únicamente por los dtypes de entrada. Lo mismo es cierto para las operaciones que involucran solo arreglos (de dimensiones positivas).
Sin embargo, cuando se mezclan escalares y matrices (de dimensiones positivas), en lugar de utilizar los dítopes reales de los escalares, NumPy examina los valores de los escalares para ver si un tipo de letra "más pequeño" puede contenerlos, y luego usa ese tipo para el tipo promoción. (Las matrices no pasan por este proceso, incluso si sus valores caben en un tipo más pequeño).
Así,
np.sum(a)+1
es una operación escalar, convirtiendo 1
a un escalar NumPy de dtype int_
(ya sea int32 o int64 dependiendo del tamaño de una C larga) y luego realizando una promoción basada en los dtypes float32 e int32 / int64, pero
a+1
implica una matriz, por lo que el tipo de 1
se trata como int8 para fines de promoción.
Como un float32 no puede contener todos los valores de dtype int32 (o int64), NumPy se actualiza a float64 para la primera promoción. (float64 no puede contener todos los valores de dtype int64, pero NumPy no promocionará numpy.longdouble para esto.) Como float32 puede contener todos los valores de dtype int8, NumPy se queda con float32 para la segunda promoción.
Si usa un número mayor que 1, entonces no cabe en un int8:
In [16]: (a+1).dtype
Out[16]: dtype(''float32'')
In [17]: (a+1000000000).dtype
Out[17]: dtype(''float64'')
puedes ver diferentes comportamientos de promoción.