2011-03-19 15 views
18

Tengo una matriz de flotantes que he normalizado a uno (es decir, el número más grande en la matriz es 1), y quería usarlo como índices de color para un gráfico. Al usar matplotlib para usar escala de grises, esto requiere usar cadenas entre 0 y 1, así que quería convertir la matriz de flotantes a una matriz de cadenas. Intentaba hacer esto usando "astype ('str')", pero esto parece crear algunos valores que no son iguales (o incluso cercanos) a los originales.Numerada matriz de conversión de flotante a cadenas

Me doy cuenta porque matplotlib se queja de encontrar el número 8 en la matriz, lo cual es extraño, ya que estaba normalizado a uno.

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

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

es no vacía. Esto es tan desconcertante como (con suerte ingenua) parece ser un error en Numpy, ¿hay algo que podría haber hecho mal para causar esto?

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

lambda x: "%.2f" % x 

trabaja entonces la gráfica - más curioso. (Obviamente las matrices ya no iguales son, sin embargo!)

Respuesta

29

Parece un poco confundido en cuanto a cómo las matrices numpy funcionan detrás de las escenas. Cada elemento en una matriz debe ser 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 coma flotante produce una cadena de longitud variable.

Como las matrices numpy constan de elementos del mismo tamaño, Numpy requiere que especifique la longitud de las cadenas dentro de la matriz cuando se utilizan matrices de cadenas.

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

Por ejemplo, el uso de x = np.array(1.344566), x.astype('str') rendimientos '1'!

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

Por ejemplo, el uso x.astype('|S10') para convertir la matriz en cadenas de longitud 10.

Incluso mejor, sólo evitar el uso de matrices numpy de cadenas por completo. Por lo general, es una mala idea, y no hay ninguna razón que pueda ver en la descripción de su problema para usarlos en primer lugar ...

+0

El razonamiento para usar matrices numpy de cadenas fue porque matplotlib requiere una iteración de cadenas con forma correcta que representa números entre 0 y 1 para representar la escala de grises, (que en ese momento yo quería).Parecía más fácil convertir la matriz de números que tuve a una serie de cadenas. No estaba anticipando la complicación de la longitud. – VolatileStorm

+0

útil también en esta situación: 1.) leer datos del archivo 2.) asumir que todas las entradas son 'float', sin embargo, algunas son' nan'. 3.) si todos son leídos como float, habrá variables 'double64' en la lista que aparecerán como' nan' pero no se reconocerán como 'numpy.nan' 4.) para reemplazarlas, utilicé con éxito : 'si V [-1] .astype ('| S3') == 'nan': V [-1] = numpy.nan' – Schorsch

+0

puede usar np.genfromtxt y tratar esto (más o menos) automáticamente. Siempre es una mala idea convertir flotadores en cadenas si tiene la intención de usarlos como float. – Vincenzooo

12

Si usted tiene una serie de numbers y desea una serie de strings, se puede escribir:

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

Si los números son los flotadores, la matriz sería ser 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 numpy matrices:

>>> 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'] 

Una metodología similar se puede usar si usted 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 marca el Matplotlib example for the function you are using, observará que usan una metodología similar: construir una matriz vacía y llenarla con cadenas creadas con el método de interpolación. La parte pertinente del código de referencia 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) 
+0

Esa no era la pregunta. Estás creando una 'lista', él quiere una matriz numpy. –

+0

Mis disculpas si no estaba claro, pero estoy lidiando con matrices numpy, no con listas de Python. Además, mi matriz es bidimensional, por lo que una comprensión de la lista de 1dim no funcionaría. Soy plenamente consciente de que puedo crear una lista python intermedia y luego convertirla en una matriz numpy, pero parece que este método anterior debería funcionar y que es una programación extra (lenta) para usar una lista intermedia. – VolatileStorm

+0

Si un objeto puede repetirse (como una lista o una matriz numpy), admite la comprensión de la lista. No necesita ser una lista (pato) – Escualo

1

Esto es probablemente más lento que lo que quiere, pero se puede hacer:

>>> 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.

+0

Esto tampoco funciona, lo que me lleva a sugerir que la conversión de números muy pequeños a cadenas, ¿falla? Es decir. la matriz contiene números del orden 10^-30. – VolatileStorm

+0

¿Quiere decir que obtiene un resultado diferente? Lo intenté hace un momento con una pequeña matriz 2D y funcionó. Quizás sea un error ... – robbles

+0

Ok, ahora veo lo mismo con números realmente pequeños. Tal vez es un problema matemático general de coma flotante. – robbles

1

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 flotadores en decimal S: .

En python 2.7 y superior, puede convertir directamente un flotador en un objeto decimal.

Cuestiones relacionadas