I'd like to have Numpy efficiently convert each element of a numeric array (e.g. float32) to a formatted array (i.e. string-like). I can make this work as I expect by iterating each element to a list:
import numpy as np
a = (10 ** np.arange(-5, 6, 2, dtype='d') * 3.14159).astype('f')
# array([3.14159e-05, 3.14159e-03, 3.14159e-01, 3.14159e+01, 3.14159e+03,
# 3.14159e+05], dtype=float32)
# Good conversion to a list
print([str(x) for x in a])
# ['3.14159e-05', '0.00314159', '0.314159', '31.4159', '3141.59', '314159.0']
print(list(map(lambda x: str(x), a))) # also does the same
# Expected result: a string-like Numpy array
print(repr(np.array([str(x) for x in a])))
# array(['3.14159e-05', '0.00314159', '0.314159', '31.4159', '3141.59',
# '314159.0'], dtype='<U11')
However, this example doesn't easily scale to multidimensional arrays, since map() or list comprehensions don't understand how additional dimensions work. I'd like a result provided as a Numpy array with a string-like datatype, as shown above.
Typically, numpy.vectorize could be used to do this, however each of my attempts with Numpy 1.15 do not return the expected result:
# Bad conversions with np.vectorize, all show the same result
f = np.vectorize(lambda x: str(x))
f = np.vectorize('%s'.__mod__) # equivalent; gives same result
f = np.vectorize(lambda x: '{!s}'.format(x)) # also same, but modern formatter
print(f(a))
# array(['3.141590059385635e-05', '0.003141589928418398',
# '0.31415900588035583', '31.4158992767334', '3141.590087890625',
# '314159.0'], dtype='<U21')
(The reason why these results are bad is that it appears that Numpy upgraded the datatype from float32 to Python's native double precision; similar to [str(x) for x in a.tolist()])
Any ideas on how to either use map()/list comprehensions on arbitrary dimension Numpy arrays and/or fix np.vectorize to achieve an equivalent result?
a.astype(str)gives 32 (either'<U32'or'|S32', depending on which Python version)