Inicializando la matriz numpy desde np.empty

¿Cómo se determinan los bits de signo al inicializar un ndarray desde la memoria vacía?

>>> np.random.randn(3,3) array([[-0.35557367, -0.0561576 , -1.84722985], [ 0.89342124, -0.50871646, 1.31368413], [ 0.0062188 , 1.62968789, 0.72367089]]) >>> np.empty((3,3)) array([[0.35557367, 0.0561576 , 1.84722985], [0.89342124, 0.50871646, 1.31368413], [0.0062188 , 1.62968789, 0.72367089]]) 

Estos valores flotantes inicializados desde la memoria vacía han perdido sus signos . ¿Porqué es eso?

Nota: este resultado se basa en los detalles de implementación de la reutilización de la memoria. La pregunta pregunta qué está haciendo la implementación.

numpy.empty no está borrando los bits de signo manualmente ni nada. Los bits de signo son simplemente cualquier basura que quede en esos bits del valor de retorno de malloc . El efecto que estás viendo se debe a una llamada numpy.absolute en otro lugar.

La cosa es que, numpy.empty no está reutilizando el randn valor de retorno de randn . Después de todo, el valor de retorno de randn sigue vivo cuando empty crea su matriz, debido a la variable _ .

numpy.empty es reutilizar el búfer de una matriz creada en el proceso de cadena de la primera matriz. Creo que es este :

 def fillFormat(self, data): # only the finite values are used to compute the number of digits finite_vals = data[isfinite(data)] # choose exponential mode based on the non-zero finite values: abs_non_zero = absolute(finite_vals[finite_vals != 0]) ... 

¿Ves esa llamada absolute ? Ese es.

Aquí hay algunas pruebas adicionales que apoyan esa conclusión:

 >>> a = numpy.random.randn(3, 3) >>> b = numpy.arange(-5, 4, dtype=float) >>> c = numpy.arange(-5, 13, 2, dtype=float) >>> a array([[-0.96810932, 0.86091026, -0.32675013], [-1.23458136, 0.56151178, -0.37409982], [-1.71348979, 0.64170792, -0.20679512]]) >>> numpy.empty((3, 3)) array([[ 0.96810932, 0.86091026, 0.32675013], [ 1.23458136, 0.56151178, 0.37409982], [ 1.71348979, 0.64170792, 0.20679512]]) >>> b array([-5., -4., -3., -2., -1., 0., 1., 2., 3.]) >>> numpy.empty((3, 3)) array([[ 0.96810932, 0.86091026, 0.32675013], [ 1.23458136, 0.56151178, 0.37409982], [ 1.71348979, 0.64170792, 0.20679512]]) >>> c array([ -5., -3., -1., 1., 3., 5., 7., 9., 11.]) >>> numpy.empty((3, 3)) array([[ 5., 3., 1.], [ 1., 3., 5.], [ 7., 9., 11.]]) >>> numpy.array([1.0, 0, 2, 3, 4, 5, 6, 7, 8, 9]) array([ 1., 0., 2., 3., 4., 5., 6., 7., 8., 9.]) >>> numpy.empty((3, 3)) array([[ 1., 2., 3.], [ 4., 5., 6.], [ 7., 8., 9.]]) 

Los resultados de numpy.empty se ven afectados por la impresión de a y c , en lugar del proceso de creación de esos arreglos. b no tiene efecto, porque tiene 8 elementos distintos de cero. La array([1.0, 0, 2, ...]) final array([1.0, 0, 2, ...]) tiene un efecto, porque aunque tiene 10 elementos, exactamente 9 de ellos son distintos de cero.

Teniendo en cuenta que NumPy está escrito en C (y en algunos de Fortran, C ++), y que la respuesta puede no estar relacionada con Python, trataré de usar algunos ejemplos para aclarar lo que está sucediendo. El aspecto multilingüe hace que esto sea bastante complicado, por lo que es posible que deba inspeccionar la implementación de la función np.empty () aquí: https://github.com/numpy/numpy/blob/master/numpy/matlib.py# L13

Has probado:

 import numpy as np print(np.random.randn(3,3)) print(np.empty((3,3))) 

Obtengo salida: (se conservan los signos)

 [[-1.13898052 0.99079467 -0.07773854] [ 1.18519122 1.30324795 -0.38748375] [-1.46435162 0.53163777 0.22004651]] [[-1.13898052 0.99079467 -0.07773854] [ 1.18519122 1.30324795 -0.38748375] [-1.46435162 0.53163777 0.22004651]] 

Notarás los cambios de comportamiento basados ​​en dos cosas:

  1. Si imprime o simplemente imprime el valor
  2. cuantos arrays vacíos creas

Por ejemplo, intente ejecutar estos dos ejemplos:

 # Run this over and over and you'll always get different results! a = np.random.randn(3,3) b = np.empty((3,3)) c = np.empty((3,3)) print(a, id(a)) # id gives memory address of array print(b, id(b)) print(c, id(c)) 

con salida:

 [[ 0.25754195 1.13184341 -0.46048928] [-0.80635852 0.92340661 2.08962923] [ 0.09552521 0.14940356 0.5644782 ]] 139865678073408 [[-1.63665076 -0.41916461 0.9251386 ] [ 2.72595838 0.10575355 -0.03555088] [ 0.71242678 0.09749262 0.24742165]] 139865678071568 [[-0.41824453 0.66565604 1.52995102] [ 0.8365397 0.32796832 -0.07150151] [-0.08558753 0.96326938 -0.56601338]] 139865678072688 

versus

 # Run this 2 or more times and b and c will always be the same! a = np.random.randn(3,3) b = np.empty((3,3)) c = np.empty((3,3)) >>> a, id(a) # output without using print (array([[-0.04230878, 0.18081425, 0.36880091], [ 0.4426956 , -1.31697583, 1.53143212], [ 0.58197615, 0.42028897, 0.27644022]]), 139865678070528) >>> b, id(b) (array([[-0.41824453, 0.66565604, 1.52995102], [ 0.8365397 , 0.32796832, -0.07150151], [-0.08558753, 0.96326938, -0.56601338]]), 139865678048912) >>> c, id(c) # c will have the same values as b! (array([[-0.41824453, 0.66565604, 1.52995102], [ 0.8365397 , 0.32796832, -0.07150151], [-0.08558753, 0.96326938, -0.56601338]]), 139865678069888) 

Intenta ejecutar cada una varias veces seguidas para que la memoria tenga la oportunidad de caer en un patrón. Además, obtendrá un comportamiento diferente según el orden en que ejecute esos dos bloques.

Al observar el comportamiento de las matrices ‘vacías’ byc cuando imprimimos y no imprimimos, supongo que se está produciendo una “evaluación perezosa” con el uso de la salida y porque la memoria permanece “libre” (por eso c obtiene el mismo valor que b en el último ejemplo), Python no tiene la obligación de imprimir valores exactos para una matriz que aún no tiene memoria asignada (malloc’d), es decir, representaciones sin firma, o realmente todo es un juego justo hasta que usted utilizar’. En mis ejemplos, ‘uso’ la matriz imprimiéndola, y eso puede explicar por qué en mi primer ejemplo usted ve que los signos se conservan con la impresión.