Формат числового массива в строковый массив - PullRequest
0 голосов
/ 29 октября 2018

Я бы хотел, чтобы Numpy эффективно конвертировал каждый элемент числового массива (например, float32) в форматированный массив (то есть в виде строки). Я могу сделать эту работу, как я ожидаю, итерируя каждый элемент в список:

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

Однако этот пример нелегко масштабировать до многомерных массивов, так как map() или списки не понимают, как работают дополнительные измерения. Мне бы хотелось, чтобы результат был представлен в виде массива Numpy со строковым типом данных, как показано выше.


Как правило, numpy.vectorize может использоваться для этого, однако каждая из моих попыток с Numpy 1.15 не возвращает ожидаемый результат:

# 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')

(Причина, по которой эти результаты плохие, заключается в том, что Numpy обновил тип данных с float32 до собственной двойной точности Python; аналогично [str(x) for x in a.tolist()])


Есть какие-нибудь идеи о том, как использовать map () / списки в произвольном измерении Numpy и / или исправить np.vectorize для достижения эквивалентного результата?

Ответы [ 2 ]

0 голосов
/ 29 октября 2018

Вы можете просто использовать astype с dtype 'str'

a.astype(dtype=str)

# array(['3.14159e-05', '0.00314159', '0.314159', '31.4159', '3141.59',
#       '314159.0'], dtype='<U32')

Редактировать: только что увидел ваш комментарий, что вы выяснили это самостоятельно. Тем не менее я сохраню свой ответ.

0 голосов
/ 29 октября 2018

Как насчет np.char.mod?

import numpy as np
np.char.mod('%.2f', np.random.rand(8, 8))

выводит

array([['0.04', '0.86', '0.74', '0.45', '0.30', '0.09', '0.65', '0.58'],
       ['0.96', '0.58', '0.41', '0.29', '0.26', '0.54', '0.01', '0.59'],
       ['0.38', '0.86', '0.37', '0.14', '0.32', '0.57', '0.19', '0.28'],
       ['0.91', '0.80', '0.78', '0.39', '0.67', '0.51', '0.16', '0.70'],
       ['0.61', '0.12', '0.89', '0.68', '0.01', '0.23', '0.57', '0.18'],
       ['0.71', '0.29', '0.08', '0.01', '0.86', '0.03', '0.79', '0.75'],
       ['0.44', '0.84', '0.89', '0.75', '0.48', '0.88', '0.69', '0.20'],
       ['0.36', '0.69', '0.12', '0.60', '0.16', '0.39', '0.15', '0.02']],
      dtype='<U4')
...