Numpy将数组从浮点数转换为字符串
我有一个浮点数数组,我把它归一化到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 个回答
这可能比你想要的速度慢,但你可以这样做:
>>> tostring = vectorize(lambda x: str(x))
>>> numpy.where(tostring(phis).astype('float64') != phis)
(array([], dtype=int64),)
看起来在把浮点数(float64)转换成字符串(str)时,它会把数值四舍五入。不过通过这种方式,你可以根据自己的需要来定制转换的方式。
如果你有一个包含 数字
的数组,想要把它变成一个包含 字符串
的数组,你可以这样写:
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)
你似乎对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数组。这通常不是个好主意,从你描述的问题来看,也没有理由使用它们……