Numpy将数组从浮点数转换为字符串

33 投票
5 回答
169220 浏览
提问于 2025-04-16 14:03

我有一个浮点数数组,我把它归一化到1(也就是说,数组里最大的数字变成了1),然后我想用这个数组作为图表的颜色索引。在使用matplotlib绘制灰度图时,需要用到0到1之间的字符串,所以我想把这个浮点数数组转换成字符串数组。我试着用“astype('str')”来实现,但发现这样得到的值和原来的不太一样,甚至有些根本不相近。

我注意到这一点是因为matplotlib报错说在数组中找到了数字8,这很奇怪,因为我明明把它归一化到1了!

简单来说,我有一个名为phis的float64数组,它是:

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

这个数组不是空的。这让我很困惑,因为(希望我不是太天真)这看起来像是numpy的一个bug,我是不是做错了什么导致了这个问题?

补充:经过调查,这似乎是因为字符串函数处理高精度浮点数的方式。使用一个向量化的toString函数(就像robbles的回答中提到的),情况也是这样,不过如果lambda函数是:

lambda x: "%.2f" % x

那么绘图就能正常工作了——真是越来越奇怪了。(显然,这样一来数组就不再相等了!)

5 个回答

1

这可能比你想要的速度慢,但你可以这样做:

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

看起来在把浮点数(float64)转换成字符串(str)时,它会把数值四舍五入。不过通过这种方式,你可以根据自己的需要来定制转换的方式。

22

如果你有一个包含 数字 的数组,想要把它变成一个包含 字符串 的数组,你可以这样写:

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)
42

你似乎对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'的类型语法,其中x是数组中每个元素的字符串长度。

例如,使用x.astype('|S10')可以把数组转换成长度为10的字符串。

更好的办法是,干脆避免使用字符串的numpy数组。这通常不是个好主意,从你描述的问题来看,也没有理由使用它们……

撰写回答