Matriz de conversión Numpy de float a cadenas

Tengo una matriz de flotadores que he normalizado a uno (es decir, el número más grande en la matriz es 1), y quería usarla como índices de color para una gráfica. Al usar matplotlib para usar escala de grises, esto requiere el uso de cadenas entre 0 y 1, así que quería convertir la matriz de flotadores en una matriz de cadenas. Intenté hacer esto usando “astype (‘str’)”, pero esto parece crear algunos valores que no son los mismos (o incluso cercanos) a los originales.

Noté esto porque matplotlib se queja de encontrar el número 8 en la matriz, lo cual es extraño ya que se normalizó a uno.

En resumen, tengo una matriz phis, de float64, tal que:

numpy.where(phis.astype('str').astype('float64') != phis) 

no esta vacio Esto es desconcertante ya que (esperemos que ingenuamente) parece ser un error en el número, ¿hay algo que podría haber hecho mal para causar esto?

Edición: después de la investigación, esto parece deberse a la forma en que la función de cadena maneja flotadores de alta precisión. Usando una función toString vectorizada (a partir de la respuesta de robbles), este también es el caso, sin embargo, si la función lambda es:

 lambda x: "%.2f" % x 

Entonces el grafico funciona – más curioso y más curioso. (¡Obviamente las matrices ya no son iguales sin embargo!)

Pareces un poco confundido en cuanto a cómo funcionan las matrices numpy entre bastidores. Cada elemento de una matriz debe tener el mismo tamaño .

La representación de cadena de un flotador no funciona de esta manera. Por ejemplo, repr(1.3) produce '1.3' , pero repr(1.33) produce '1.3300000000000001' .

Una representación de cadena precisa de un número de punto flotante produce una cadena de longitud variable .

Debido a que las matrices numpy se componen de elementos que tienen el mismo tamaño, numpy requiere que especifique la longitud de las cadenas dentro de la matriz cuando esté usando matrices de cadenas.

Si usa x.astype('str') , siempre convertirá las cosas a una matriz de cadenas de longitud 1.

Por ejemplo, utilizando x = np.array(1.344566) , x.astype('str') produce '1' !

Debe ser más explícito y usar la syntax de tipo de '|Sx' , donde x es la longitud de la cadena para cada elemento de la matriz.

Por ejemplo, use x.astype('|S10') para convertir la matriz a cadenas de longitud 10.

Aún mejor, simplemente evite el uso de múltiples matrices de cadenas por completo. Por lo general, es una mala idea, y no hay ninguna razón por la que pueda ver su descripción de su problema para usarlos en primer lugar …

Si tienes una matriz de numbers y quieres una matriz de strings , puedes escribir:

 strings = ["%.2f" % number for number in numbers] 

Si sus números son flotantes, la matriz sería una matriz con los mismos números que las cadenas con dos decimales.

 >>> a = [1,2,3,4,5] >>> min_a, max_a = min(a), max(a) >>> a_normalized = [float(x-min_a)/(max_a-min_a) for x in a] >>> a_normalized [0.0, 0.25, 0.5, 0.75, 1.0] >>> a_strings = ["%.2f" % x for x in a_normalized] >>> a_strings ['0.00', '0.25', '0.50', '0.75', '1.00'] 

Tenga en cuenta que también funciona con matrices numpy :

 >>> a = numpy.array([0.0, 0.25, 0.75, 1.0]) >>> print ["%.2f" % x for x in a] ['0.00', '0.25', '0.50', '0.75', '1.00'] 

Se puede utilizar una metodología similar si tiene una matriz multidimensional:

 new_array = numpy.array(["%.2f" % x for x in old_array.reshape(old_array.size)]) new_array = new_array.reshape(old_array.shape) 

Ejemplo:

 >>> x = numpy.array([[0,0.1,0.2],[0.3,0.4,0.5],[0.6, 0.7, 0.8]]) >>> y = numpy.array(["%.2f" % w for w in x.reshape(x.size)]) >>> y = y.reshape(x.shape) >>> print y [['0.00' '0.10' '0.20'] ['0.30' '0.40' '0.50'] ['0.60' '0.70' '0.80']] 

Si verifica el ejemplo de Matplotlib para la función que está usando , notará que usan una metodología similar: construya una matriz vacía y rellénela con cadenas creadas con el método de interpolación. La parte relevante del código referenciado es:

 colortuple = ('y', 'b') colors = np.empty(X.shape, dtype=str) for y in range(ylen): for x in range(xlen): colors[x, y] = colortuple[(x + y) % len(colortuple)] surf = ax.plot_surface(X, Y, Z, rstride=1, cstride=1, facecolors=colors, linewidth=0, antialiased=False) 

Esto es probablemente más lento de lo que quieres, pero puedes hacerlo:

 >>> tostring = vectorize(lambda x: str(x)) >>> numpy.where(tostring(phis).astype('float64') != phis) (array([], dtype=int64),) 

Parece que redondea los valores cuando se convierte a str desde float64, pero de esta manera puedes personalizar la conversión como quieras.

Si el problema principal es la pérdida de precisión al convertir de un flotador a una cadena, una forma posible de hacerlo es convertir los flotantes al decimal S: http://docs.python.org/library/decimal.html .

En Python 2.7 y versiones superiores, puedes convertir directamente un objeto flotante en un objeto decimal .