如何在NumPy数组中反转字符串?

pqwbnv8z  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(80)

我想颠倒NumPy数组的每个字符串元素中的字符顺序。例如,给定以下输入:

array(['2', '3', '5', '7', '11', '13', '17', '19', '23', '29', '31', '37',
       '41', '43', '47', '53', '59', '61', '67', '71', '73', '79', '83',
       '89', '97'], dtype='<U2')

我想获得以下输出(不使用Python for循环):

array(['2', '3', '5', '7', '11', '31', '71', '91', '32', '92', '13', '73',
       '14', '34', '74', '35', '95', '16', '76', '17', '37', '97', '38',
       '98', '79'], dtype='<U2')

我知道我可以使用arr[::-1]来颠倒NumPy数组中元素的顺序,但这不是这个问题的主题,而且np.array([e[::-1] for e in arr])效率低下,与NumPy的观点背道而驰。
该数组是使用基本转换函数np.vectorize(to_base_str)的矢量化版本创建的。
如何使用向量化反转NumPy数组的每个字符串元素中的字符顺序?我在网上找过,但没有找到解决办法。注意arr[..., ::-1]不适用于NumPy数组中的字符串元素。
(Code是我的,但我确实使用了“AI建议编辑”功能)

jk9hmnmh

jk9hmnmh1#

np.array([e[::-1] for e in arr])是这样做的直接方法,并且不是坏的numpy。或者用[e[::-1] for e in arr.tolist()]完全绕过numpy。您也可以对np.vectorizenp.frompyfunc执行类似的操作。这些可能会扩展得更好一点。
numpy中的“vectorize”意味着使用编译方法(和运算符)在编译代码中进行必要的迭代。这些几乎都是数字运算。对于字符串,numpy使用Python字符串方法。它没有自己的编译字符串操作。甚至np.char函数也使用python字符串方法。
所以没有numpy等价于astr[::-1]
一些比较时代

In [16]: timeit np.array([s[::-1] for s in arr])
36.1 µs ± 151 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [17]: timeit np.array([s[::-1] for s in arr.tolist()])
21.1 µs ± 76.5 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [18]: timeit [s[::-1] for s in arr.tolist()]
8.29 µs ± 23.2 ns per loop (mean ± std. dev. of 7 runs, 100,000 loops each)

In [20]: timeit np.vectorize(lambda s: s[::-1])(arr)
65.9 µs ± 165 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)

In [21]: timeit np.frompyfunc(lambda s: s[::-1],1,1)(arr)
20.3 µs ± 76.5 ns per loop (mean ± std. dev. of 7 runs, 10,000 loops each)
klsxnrf1

klsxnrf12#

下面的代码通过考虑原始数组的不同视图来完成这项工作。这意味着不需要额外的数组(以及内存)。No for loops:)

import numpy as np

A = np.array(['2', '3', '5', '7', '11', '13', '17', '19', '23', '29', '31', '37',
       '41', '43', '47', '53', '59', '61', '67', '71', '73', '79', '83',
       '89', '97'], dtype='<U2')

B = A.view(np.uint32)           # Interpret as individual numbers
B = B.reshape((A.shape[0],2))   # Group numbers in pairs
B[B[:,1] != 0, :] = B[B[:,1] != 0, ::-1] # Flip pairs if more than 1 digit

print(A) # ['2' '3' '5' '7' '11' '31' '71' '91' '32' '92' '13' '73' '14' '34' '74' '35' '95' '16' '76' '17' '37' '97' '38' '98' '79']

对于短数组,比如你给出的那个,@hpaulj的答案更快。但是对于更大的数组,这种方法更快。例如,对于100,000个元素的数组,与@hpaulj的最快方法([s[::-1] for s in arr.tolist()])相比,该方法快了大约5倍。

相关问题