将NumPy np.uint8数组的列表转换为np.unicode_数组

时间:2019-06-15 17:21:13

标签: python string numpy unicode

我有一个dtype=np.uint8的NumPy可变大小数组的列表(这些数组代表UTF-8编码的字符串)。如何高效快捷地将此列表转换为单个dtype=np.unicode_数组?

l = [np.frombuffer(b'asd', dtype = np.uint8), np.frombuffer(b'asdasdas', dtype = np.uint8)]

# The following will work, but will first create a temporary string which is inefficient. 
# I'm looking for a method that would directly allocate a target np.unicode_-typed array 
# and encode the data into it.
a = np.array([s.tostring().decode('utf-8') for s in l])

数组不仅是ASCII编码的,而且还包含其他字符:

s = b'8 \xd0\x93\xd0\xbe\xd1\x80\xd0\xbe\xd0\xb4 \xd0\x91\xd0\xb0\xd0\xb9\xd0\xba\xd0\xbe\xd0\xbd\xd1\x83\xd1\x80 (\xd0\xa0\xd0\xb5\xd1\x81\xd0\xbf\xd1\x83\xd0\xb1\xd0\xbb ...: \xd0\xb8\xd0\xba\xd0\xb0 \xd0\x9a\xd0\xb0\xd0\xb7\xd0\xb0\xd1\x85\xd1\x81\xd1\x82\xd0\xb0\xd0\xbd)' 

s.decode('utf-8') # works

1 个答案:

答案 0 :(得分:0)

更新

事实证明Python utf-8编解码器可用于解码 直接使用ndarray,无需复制其内容 首先用.tostring()转换为字节串:使用编解码器 模块可以检索可调用的 将utf-8字节序列转换为unicode字符串而无需 必须经历str.decode

lst = [np.frombuffer(b'asd', dtype = np.uint8), np.frombuffer(b'asdasdas', dtype = np.uint8)]

import codecs

decoder = codes.getdecoder("utf-8")    
data = np.array([decoder(item)[0] for item in lst], dtype="unicode")

这避免了转换的第一步-还有另一步可以 避免使用,因为这仍将创建内存中所有字符串的列表 在调用最后一个.array构造函数之前-numpy有一个.fromiter数组构造函数-但它无法创建具有任意unicode对象的数组-它需要固定的字符宽度。最终将消耗比您目前更多的内存:

data = np.fromiter((decoder(item) for item in lst), count=len(lst), dtype="U120")  # For max-length of 120 characters.

原始答案(主要是罗马骚扰)

现代Python对Unicode文本的内部处理非常有效,内部unicode点表示取决于字符串中最宽的字符。

另一方面,Numpy只为每个unicode字符存储一个32位的值-并且它没有商业上的“理解” utf-8。 Python语言可以很好地做到这一点-而且速度很快。尽管在将utf-8字节解码为文本时,Python不会使用任何多线程,多核或硬件加速策略,但是解码是在本机代码中进行的,并且速度与在单个CPU内核中获得的速度一样快。

在我的系统中,使用纯Python将4MB大小的文本解码为unicode所需的时间不到30ms。

换句话说:您正在担心错误的问题-除非您编码的内容需要以持续的方式每秒转换约100个圣经大小的文本语料库。

只需让Python执行utf-8解码,然后将结果处理回numpy(它将再次以其32bit格式对其进行编码)-在此花费的费用对于大多数现实世界的任务是如此微不足道,以至于例如,这就是Pandas库对数据执行几乎所有操作的方式:在每次操作后创建其新副本。