Numpy преобразование массива из числа с плавающей точкой в ​​строки - PullRequest
19 голосов
/ 20 марта 2011

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

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

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

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

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

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

lambda x: "%.2f" % x

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

Ответы [ 4 ]

31 голосов
/ 21 марта 2011

Вы, кажется, немного озадачены тем, как за кулисами работают массивы Каждый элемент в массиве должен быть одинакового размера .

Строковое представление с плавающей точкой не работает таким образом. Например, 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.

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

13 голосов
/ 20 марта 2011

Если у вас есть массив 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 для функции, которую вы используете , вы заметите, что они используют аналогичную методологию: buildочистите матрицу и заполните ее строками, построенными методом интерполяции.Соответствующая часть ссылочного кода:

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)
1 голос
/ 20 марта 2011

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

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

1 голос
/ 20 марта 2011

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

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...