J'ai un tableau de flotteurs que j'ai normalisé à un (c'est-à-dire que le plus grand nombre dans le tableau est 1), et je voulais l'utiliser comme indices de couleur pour un graphique. En utilisant matplotlib pour utiliser des niveaux de gris, cela nécessite d'utiliser des chaînes entre 0 et 1, donc je voulais convertir le tableau de flottants en un tableau de chaînes. J'essayais de le faire en utilisant "astype ('str')", mais cela semble créer des valeurs qui ne sont pas les mêmes (ou même proches) des originaux.
Je le remarque car matplotlib se plaint de trouver le nombre 8 dans le tableau, ce qui est étrange car il a été normalisé à un!
En bref, j'ai un tableau phis, de float64, tel que:
numpy.where(phis.astype('str').astype('float64') != phis)
n'est pas vide. C'est déroutant car (espérons-le naïvement) cela semble être un bug dans numpy, y a-t-il quelque chose que j'aurais pu faire de mal pour provoquer cela?
Edit: après enquête, cela semble être dû à la façon dont la fonction chaîne gère les flottants de haute précision. En utilisant une fonction toString vectorisée (comme dans la réponse robbles), c'est également le cas, cependant si la fonction lambda est:
lambda x: "%.2f" % x
Ensuite, le graphisme fonctionne - curieux et curieux. (Évidemment, les tableaux ne sont plus égaux cependant!)
Vous semblez un peu confus quant à la façon dont les tableaux numpy fonctionnent en arrière-plan. Chaque élément d'un tableau doit être même taille.
La représentation sous forme de chaîne d'un flottant ne fonctionne pas de cette façon. Par exemple, repr(1.3)
donne '1.3'
, Mais repr(1.33)
donne '1.3300000000000001'
.
Une représentation sous forme de chaîne précise d'un nombre à virgule flottante produit une chaîne longueur variable.
Étant donné que les tableaux numpy sont constitués d'éléments de même taille, numpy vous oblige à spécifier la longueur des chaînes dans le tableau lorsque vous utilisez des tableaux de chaînes.
Si vous utilisez x.astype('str')
, il convertira toujours les choses en un tableau de chaînes de longueur 1.
Par exemple, l'utilisation de x = np.array(1.344566)
, x.astype('str')
donne '1'
!
Vous devez être plus explicite et utiliser la syntaxe dtype '|Sx'
, Où x
est la longueur de la chaîne pour chaque élément du tableau.
Par exemple, utilisez x.astype('|S10')
pour convertir le tableau en chaînes de longueur 10.
Encore mieux, évitez simplement d'utiliser des tableaux de chaînes numpy. C'est généralement une mauvaise idée, et il n'y a aucune raison que je puisse voir dans votre description de votre problème pour les utiliser en premier lieu ...
Si vous avez un tableau de numbers
et que vous voulez un tableau de strings
, vous pouvez écrire:
strings = ["%.2f" % number for number in numbers]
Si vos nombres sont des flottants, le tableau serait un tableau avec les mêmes nombres que des chaînes avec deux décimales.
>>> 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']
Notez qu'il fonctionne également avec les tableaux 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']
Une méthodologie similaire peut être utilisée si vous disposez d'un tableau multidimensionnel:
new_array = numpy.array(["%.2f" % x for x in old_array.reshape(old_array.size)])
new_array = new_array.reshape(old_array.shape)
Exemple:
>>> 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 vous cochez exemple Matplotlib pour la fonction que vous utilisez , vous remarquerez qu'ils utilisent une méthodologie similaire: créez une matrice vide et remplissez-la de chaînes construites avec la méthode d'interpolation. La partie pertinente du code référencé est:
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)
Si le problème principal est la perte de précision lors de la conversion d'un flottant en chaîne, une solution possible consiste à convertir les flottants en decimal
S: http://docs.python.org /library/decimal.html .
Dans python 2.7 et supérieur, vous pouvez directement convertir un flotteur en objet decimal
.
C'est probablement plus lent que ce que vous voulez, mais vous pouvez le faire:
>>> tostring = vectorize(lambda x: str(x))
>>> numpy.where(tostring(phis).astype('float64') != phis)
(array([], dtype=int64),)
Il semble qu'il arrondisse les valeurs lors de la conversion en str de float64, mais de cette façon, vous pouvez personnaliser la conversion comme vous le souhaitez.