Подтвердить что ты не робот

Матрица преобразования чисел из float в строки

У меня есть массив поплавков, который я нормализовал к одному (т.е. наибольшее число в массиве равно 1), и я хотел использовать его в качестве цветовых индексов для графика. В использовании matplotlib для использования оттенков серого для этого требуется использовать строки от 0 до 1, поэтому я хотел преобразовать массив float в массив строк. Я пытаюсь сделать это, используя "astype (" str ")", но это создает некоторые значения, которые не совпадают (или даже близки) к оригиналам.

Я замечаю это, потому что matplotlib жалуется на поиск числа 8 в массиве, что является нечетным, поскольку оно было нормализовано для одного!

Короче говоря, у меня есть массив phis, float64, такой, что:

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

не пусто. Это озадачивает, как (надеюсь, наивно), похоже, это ошибка в numpy, есть ли что-нибудь, что я мог бы сделать неправильно, чтобы вызвать это?

Изменить: после исследования это, по-видимому, связано с тем, как функция string обрабатывает высокоточные поплавки. Использование векторизованной функции toString (как из ответа грабителей), это также имеет место, однако, если лямбда-функция:

lambda x: "%.2f" % x

Тогда графическое произведение работает - любопытно и любопытно. (Очевидно, что массивы уже не равны!)

4b9b3361

Ответ 1

Похоже, вы немного смущены тем, как массивы numpy работают за кулисами. Каждый элемент массива должен быть одного размера.

Строковое представление поплавка не работает таким образом. Например, repr(1.3) дает '1.3', но repr(1.33) дает '1.3300000000000001'.

Точное строковое представление числа с плавающей точкой создает строку переменной длины.

Поскольку массивы numpy состоят из элементов с одинаковым размером, numpy требует указать длину строк в массиве при использовании строковых массивов.

Если вы используете x.astype('str'), он всегда будет преобразовывать объекты в массив строк длиной 1.

Например, используя x = np.array(1.344566), x.astype('str') дает '1'!

Вам нужно быть более эксплицитным и использовать синтаксис '|Sx' dtype, где x - длина строки для каждого элемента массива.

Например, используйте x.astype('|S10') для преобразования массива в строки длиной 10.

Еще лучше, просто избегайте использования массивов numpy строк. Это, как правило, плохая идея, и нет причин, которые я могу видеть из вашего описания вашей проблемы, чтобы использовать их в первую очередь...

Ответ 2

Если у вас есть массив numbers и вам нужен массив strings, вы можете написать:

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

Если ваши числа являются поплавками, массив будет массивом с теми же числами, что и строки с двумя десятичными знаками.

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

Обратите внимание, что он также работает с 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']

Аналогичную методологию можно использовать, если у вас многомерный массив:

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

Пример:

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

Если вы проверите пример Matplotlib для используемой функции, вы заметите, что они используют аналогичную методологию: постройте пустую матрицу и заполните ее с строками, построенными методом интерполяции. Соответствующая часть ссылочного кода:

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)

Ответ 3

Это, вероятно, медленнее, чем вы хотите, но вы можете сделать:

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

Похоже, он округляет значения, когда он преобразуется в str из float64, но таким образом вы можете настроить преобразование, как вам нравится.

Ответ 4

Если основной проблемой является потеря точности при преобразовании из float в строку, одним из возможных способов перехода является преобразование float в decimal S: http://docs.python.org/library/decimal.html.

В python 2.7 и выше вы можете напрямую преобразовать float в объект decimal.