我有一个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
答案 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库对数据执行几乎所有操作的方式:在每次操作后创建其新副本。