Python:将numpy字符串数组转换为数字数组的最快方法

4
任何人都可以告诉我将以下字符串数组转换为数字数组的最快方法:
import numpy as np
strarray = np.array([["123456"], ["654321"]])

     to

numberarray = np.array([[1,2,3,4,5,6], [6,5,4,3,2,1]])

对于大型数组,将字符串映射到列表然后再将字符串映射到整数的速度太慢了!

请帮忙优化!


3
可能是重复的问题,如何在NumPy中将字符串数组转换为浮点数数组? - idjaw
2
这是一个打字错误吗?["12456"] -> [1,2,3,4,5,6] - Ian
所有元素的长度是否保证相同(例如在示例中为6)? - Divakar
给兰:是的,那是个打字错误!已经纠正过了! - zshtom
给Divakar:是的,保证长度相同!! - zshtom
给idjaw:那与我的问题不同。我想将一个没有分隔符的字符串(数组)分离成数字数组,原始字符串非常长(320位数),我正在寻找一种高效的方法来进行这种转换。 - zshtom
2个回答

3
你可以使用数组view方法将字符串拆分成单个字符:
In [18]: strarray = np.array([[b"123456"], [b"654321"]])

In [19]: strarray.dtype
Out[19]: dtype('S6')

In [20]: strarray.view('S1')
Out[20]: 
array([['1', '2', '3', '4', '5', '6'],
       ['6', '5', '4', '3', '2', '1']], 
      dtype='|S1')

请查看这里以获取数据类型字符代码。

然后最明显的下一步是使用astype

In [23]: strarray.view('S1').astype(int)
Out[23]: 
array([[1, 2, 3, 4, 5, 6],
       [6, 5, 4, 3, 2, 1]])

然而,将字符串底层内存重新解释为单字节整数并减去48会更快。这是因为ASCII字符只占用一个字节,而字符'0''9'的二进制等价于(u)int8的48到57(请检查ord builtin)。

速度比较:

In [26]: ar = np.array([[''.join(np.random.choice(list('123456789'), size=320))] for _ in range(1000)], bytes)

In [27]: %timeit _ = ar.view('S1').astype(np.uint8)
1 loops, best of 3: 284 ms per loop

In [28]: %timeit _ = ar.view(np.uint8) - ord('0')
1000 loops, best of 3: 1.07 ms per loop

如果使用Unicode而不是ASCII,则需要稍微不同的步骤。或者只需使用 astype(bytes) 先转换为ASCII即可。

可能是版本问题,我得到了strarray.dtype的Unicode编码。我使用的是Python 3.4版本。而且ar.view('S1')中除了字符串本身之外,还有很多"b'" - Divakar
@Divakar - 我将字符串更改为字节以适应Python 3的兼容性。 - user2379410
但是如果OP将它们作为字符串,那么他/她必须先转换为字节,对吧?这该怎么做呢? - Divakar
@Divakar - Python 2.x 默认使用 ASCII 字符串,对于这些字符串它可以正常工作。 - user2379410
啊,是的,你在帖子中提到了.astype(bytes)进行转换!很好,现在对我有效。 - Divakar
@morningsun 太棒了!非常感谢你的解决方案! - zshtom

0
这里有一种方法,将输入字符串转换为N长度的数字数组,即每个字符串都被转换为长度为N的1D数组,其中N是这些字符串的长度。 这里建议的方法基本上将字符串转换为它们的int等效项,然后使用其前面元素的power-10缩放版本的微分来获取所有数字。实现如下 -
A = (strarray.astype(int)/(10**np.arange(len(strarray[0][0])))).astype(int)
out = np.column_stack((A[:,-1],(A[:,:-1] - 10*A[:,1:])[:,::-1]))

示例运行 -

In [177]: strarray  = np.array([["0308468"], ["6540542"], ["4973473"]])

In [178]: A = (strarray.astype(int)/(10**np.arange(len(strarray[0][0])))).astype(int)
     ...: out = np.column_stack((A[:,-1],(A[:,:-1] - 10*A[:,1:])[:,::-1]))
     ...: 

In [179]: out
Out[179]: 
array([[0, 3, 0, 8, 4, 6, 8],
       [6, 5, 4, 0, 5, 4, 2],
       [4, 9, 7, 3, 4, 7, 3]])

棘手的解决方案!感谢提供这种方法让我茅塞顿开! - zshtom

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接